1use fyrox_core::io::FileLoadError;
25use std::future::{ready, Future};
26use std::iter::empty;
27use std::pin::Pin;
28use std::{
29 fmt::Debug,
30 io::{Cursor, Read, Seek},
31 path::{Path, PathBuf},
32};
33
34pub trait FileReader: Debug + Send + Read + Seek + 'static {}
36
37impl<F> FileReader for F where F: Debug + Send + Read + Seek + 'static {}
38
39pub trait ResourceIo: Send + Sync + 'static {
42 fn load_file<'a>(
45 &'a self,
46 path: &'a Path,
47 ) -> ResourceIoFuture<'a, Result<Vec<u8>, FileLoadError>>;
48
49 fn move_file<'a>(
51 &'a self,
52 source: &'a Path,
53 dest: &'a Path,
54 ) -> ResourceIoFuture<'a, Result<(), FileLoadError>>;
55
56 fn canonicalize_path<'a>(
60 &'a self,
61 path: &'a Path,
62 ) -> ResourceIoFuture<'a, Result<PathBuf, FileLoadError>> {
63 Box::pin(ready(Ok(path.to_owned())))
64 }
65
66 fn read_directory<'a>(
71 &'a self,
72 #[allow(unused)] path: &'a Path,
73 ) -> ResourceIoFuture<'a, Result<Box<dyn Iterator<Item = PathBuf> + Send>, FileLoadError>> {
74 let iter: Box<dyn Iterator<Item = PathBuf> + Send> = Box::new(empty());
75 Box::pin(ready(Ok(iter)))
76 }
77
78 fn walk_directory<'a>(
83 &'a self,
84 #[allow(unused)] path: &'a Path,
85 ) -> ResourceIoFuture<'a, Result<Box<dyn Iterator<Item = PathBuf> + Send>, FileLoadError>> {
86 let iter: Box<dyn Iterator<Item = PathBuf> + Send> = Box::new(empty());
87 Box::pin(ready(Ok(iter)))
88 }
89
90 fn file_reader<'a>(
96 &'a self,
97 path: &'a Path,
98 ) -> ResourceIoFuture<'a, Result<Box<dyn FileReader>, FileLoadError>> {
99 Box::pin(async move {
100 let bytes = self.load_file(path).await?;
101 let read: Box<dyn FileReader> = Box::new(Cursor::new(bytes));
102 Ok(read)
103 })
104 }
105
106 fn exists<'a>(&'a self, path: &'a Path) -> ResourceIoFuture<'a, bool>;
108
109 fn is_file<'a>(&'a self, path: &'a Path) -> ResourceIoFuture<'a, bool>;
111
112 fn is_dir<'a>(&'a self, path: &'a Path) -> ResourceIoFuture<'a, bool>;
114}
115
116#[derive(Default)]
119pub struct FsResourceIo;
120
121#[cfg(target_arch = "wasm32")]
123pub type ResourceIoFuture<'a, V> = Pin<Box<dyn Future<Output = V> + 'a>>;
124#[cfg(not(target_arch = "wasm32"))]
126pub type ResourceIoFuture<'a, V> = Pin<Box<dyn Future<Output = V> + Send + 'a>>;
127
128#[cfg(target_arch = "wasm32")]
130pub type PathIter = Box<dyn Iterator<Item = PathBuf>>;
131#[cfg(not(target_arch = "wasm32"))]
133pub type PathIter = Box<dyn Iterator<Item = PathBuf> + Send>;
134
135impl ResourceIo for FsResourceIo {
136 fn load_file<'a>(
137 &'a self,
138 path: &'a Path,
139 ) -> ResourceIoFuture<'a, Result<Vec<u8>, FileLoadError>> {
140 Box::pin(fyrox_core::io::load_file(path))
141 }
142
143 fn move_file<'a>(
144 &'a self,
145 source: &'a Path,
146 dest: &'a Path,
147 ) -> ResourceIoFuture<'a, Result<(), FileLoadError>> {
148 Box::pin(async move {
149 std::fs::rename(source, dest)?;
150 Ok(())
151 })
152 }
153
154 fn canonicalize_path<'a>(
155 &'a self,
156 path: &'a Path,
157 ) -> ResourceIoFuture<'a, Result<PathBuf, FileLoadError>> {
158 Box::pin(async move { Ok(std::fs::canonicalize(path)?) })
159 }
160
161 #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
167 fn read_directory<'a>(
168 &'a self,
169 #[allow(unused)] path: &'a Path,
170 ) -> ResourceIoFuture<'a, Result<PathIter, FileLoadError>> {
171 Box::pin(async move {
172 let iter = std::fs::read_dir(path)?.flatten().map(|entry| entry.path());
173 let iter: PathIter = Box::new(iter);
174 Ok(iter)
175 })
176 }
177
178 #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
181 fn walk_directory<'a>(
182 &'a self,
183 path: &'a Path,
184 ) -> ResourceIoFuture<'a, Result<PathIter, FileLoadError>> {
185 Box::pin(async move {
186 use walkdir::WalkDir;
187
188 let iter = WalkDir::new(path)
189 .into_iter()
190 .flatten()
191 .map(|value| value.into_path());
192
193 let iter: PathIter = Box::new(iter);
194
195 Ok(iter)
196 })
197 }
198
199 #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
204 fn file_reader<'a>(
205 &'a self,
206 path: &'a Path,
207 ) -> ResourceIoFuture<'a, Result<Box<dyn FileReader>, FileLoadError>> {
208 Box::pin(async move {
209 let file = match std::fs::File::open(path) {
210 Ok(file) => file,
211 Err(e) => return Err(FileLoadError::Io(e)),
212 };
213
214 let read: Box<dyn FileReader> = Box::new(std::io::BufReader::new(file));
215 Ok(read)
216 })
217 }
218
219 fn exists<'a>(&'a self, path: &'a Path) -> ResourceIoFuture<'a, bool> {
220 Box::pin(fyrox_core::io::exists(path))
221 }
222
223 fn is_file<'a>(&'a self, path: &'a Path) -> ResourceIoFuture<'a, bool> {
224 Box::pin(fyrox_core::io::is_file(path))
225 }
226
227 fn is_dir<'a>(&'a self, path: &'a Path) -> ResourceIoFuture<'a, bool> {
228 Box::pin(fyrox_core::io::is_dir(path))
229 }
230}