bevy_asset/io/file/
sync_file_asset.rs1use futures_io::{AsyncRead, AsyncSeek, AsyncWrite};
2use futures_lite::Stream;
3
4use crate::io::{
5 get_meta_path, AssetReader, AssetReaderError, AssetWriter, AssetWriterError, PathStream,
6 Reader, Writer,
7};
8
9use std::{
10 fs::{read_dir, File},
11 io::{Read, Seek, Write},
12 path::{Path, PathBuf},
13 pin::Pin,
14 task::Poll,
15};
16
17use super::{FileAssetReader, FileAssetWriter};
18
19struct FileReader(File);
20
21impl AsyncRead for FileReader {
22 fn poll_read(
23 self: Pin<&mut Self>,
24 _cx: &mut std::task::Context<'_>,
25 buf: &mut [u8],
26 ) -> Poll<std::io::Result<usize>> {
27 let this = self.get_mut();
28 let read = this.0.read(buf);
29 Poll::Ready(read)
30 }
31}
32
33impl AsyncSeek for FileReader {
34 fn poll_seek(
35 self: Pin<&mut Self>,
36 _cx: &mut std::task::Context<'_>,
37 pos: std::io::SeekFrom,
38 ) -> Poll<std::io::Result<u64>> {
39 let this = self.get_mut();
40 let seek = this.0.seek(pos);
41 Poll::Ready(seek)
42 }
43}
44
45struct FileWriter(File);
46
47impl AsyncWrite for FileWriter {
48 fn poll_write(
49 self: Pin<&mut Self>,
50 _cx: &mut std::task::Context<'_>,
51 buf: &[u8],
52 ) -> Poll<std::io::Result<usize>> {
53 let this = self.get_mut();
54 let wrote = this.0.write(buf);
55 Poll::Ready(wrote)
56 }
57
58 fn poll_flush(
59 self: Pin<&mut Self>,
60 _cx: &mut std::task::Context<'_>,
61 ) -> Poll<std::io::Result<()>> {
62 let this = self.get_mut();
63 let flushed = this.0.flush();
64 Poll::Ready(flushed)
65 }
66
67 fn poll_close(
68 self: Pin<&mut Self>,
69 _cx: &mut std::task::Context<'_>,
70 ) -> Poll<std::io::Result<()>> {
71 Poll::Ready(Ok(()))
72 }
73}
74
75struct DirReader(Vec<PathBuf>);
76
77impl Stream for DirReader {
78 type Item = PathBuf;
79
80 fn poll_next(
81 self: Pin<&mut Self>,
82 _cx: &mut std::task::Context<'_>,
83 ) -> Poll<Option<Self::Item>> {
84 let this = self.get_mut();
85 Poll::Ready(this.0.pop())
86 }
87}
88
89impl AssetReader for FileAssetReader {
90 async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
91 let full_path = self.root_path.join(path);
92 match File::open(&full_path) {
93 Ok(file) => {
94 let reader: Box<Reader> = Box::new(FileReader(file));
95 Ok(reader)
96 }
97 Err(e) => {
98 if e.kind() == std::io::ErrorKind::NotFound {
99 Err(AssetReaderError::NotFound(full_path))
100 } else {
101 Err(e.into())
102 }
103 }
104 }
105 }
106
107 async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
108 let meta_path = get_meta_path(path);
109 let full_path = self.root_path.join(meta_path);
110 match File::open(&full_path) {
111 Ok(file) => {
112 let reader: Box<Reader> = Box::new(FileReader(file));
113 Ok(reader)
114 }
115 Err(e) => {
116 if e.kind() == std::io::ErrorKind::NotFound {
117 Err(AssetReaderError::NotFound(full_path))
118 } else {
119 Err(e.into())
120 }
121 }
122 }
123 }
124
125 async fn read_directory<'a>(
126 &'a self,
127 path: &'a Path,
128 ) -> Result<Box<PathStream>, AssetReaderError> {
129 let full_path = self.root_path.join(path);
130 match read_dir(&full_path) {
131 Ok(read_dir) => {
132 let root_path = self.root_path.clone();
133 let mapped_stream = read_dir.filter_map(move |f| {
134 f.ok().and_then(|dir_entry| {
135 let path = dir_entry.path();
136 if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
138 if ext.eq_ignore_ascii_case("meta") {
139 return None;
140 }
141 }
142 let relative_path = path.strip_prefix(&root_path).unwrap();
143 Some(relative_path.to_owned())
144 })
145 });
146 let read_dir: Box<PathStream> = Box::new(DirReader(mapped_stream.collect()));
147 Ok(read_dir)
148 }
149 Err(e) => {
150 if e.kind() == std::io::ErrorKind::NotFound {
151 Err(AssetReaderError::NotFound(full_path))
152 } else {
153 Err(e.into())
154 }
155 }
156 }
157 }
158
159 async fn is_directory<'a>(
160 &'a self,
161 path: &'a Path,
162 ) -> std::result::Result<bool, AssetReaderError> {
163 let full_path = self.root_path.join(path);
164 let metadata = full_path
165 .metadata()
166 .map_err(|_e| AssetReaderError::NotFound(path.to_owned()))?;
167 Ok(metadata.file_type().is_dir())
168 }
169}
170
171impl AssetWriter for FileAssetWriter {
172 async fn write<'a>(&'a self, path: &'a Path) -> Result<Box<Writer>, AssetWriterError> {
173 let full_path = self.root_path.join(path);
174 if let Some(parent) = full_path.parent() {
175 std::fs::create_dir_all(parent)?;
176 }
177 let file = File::create(&full_path)?;
178 let writer: Box<Writer> = Box::new(FileWriter(file));
179 Ok(writer)
180 }
181
182 async fn write_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Writer>, AssetWriterError> {
183 let meta_path = get_meta_path(path);
184 let full_path = self.root_path.join(meta_path);
185 if let Some(parent) = full_path.parent() {
186 std::fs::create_dir_all(parent)?;
187 }
188 let file = File::create(&full_path)?;
189 let writer: Box<Writer> = Box::new(FileWriter(file));
190 Ok(writer)
191 }
192
193 async fn remove<'a>(&'a self, path: &'a Path) -> std::result::Result<(), AssetWriterError> {
194 let full_path = self.root_path.join(path);
195 std::fs::remove_file(full_path)?;
196 Ok(())
197 }
198
199 async fn remove_meta<'a>(
200 &'a self,
201 path: &'a Path,
202 ) -> std::result::Result<(), AssetWriterError> {
203 let meta_path = get_meta_path(path);
204 let full_path = self.root_path.join(meta_path);
205 std::fs::remove_file(full_path)?;
206 Ok(())
207 }
208
209 async fn remove_directory<'a>(
210 &'a self,
211 path: &'a Path,
212 ) -> std::result::Result<(), AssetWriterError> {
213 let full_path = self.root_path.join(path);
214 std::fs::remove_dir_all(full_path)?;
215 Ok(())
216 }
217
218 async fn remove_empty_directory<'a>(
219 &'a self,
220 path: &'a Path,
221 ) -> std::result::Result<(), AssetWriterError> {
222 let full_path = self.root_path.join(path);
223 std::fs::remove_dir(full_path)?;
224 Ok(())
225 }
226
227 async fn remove_assets_in_directory<'a>(
228 &'a self,
229 path: &'a Path,
230 ) -> std::result::Result<(), AssetWriterError> {
231 let full_path = self.root_path.join(path);
232 std::fs::remove_dir_all(&full_path)?;
233 std::fs::create_dir_all(&full_path)?;
234 Ok(())
235 }
236
237 async fn rename<'a>(
238 &'a self,
239 old_path: &'a Path,
240 new_path: &'a Path,
241 ) -> std::result::Result<(), AssetWriterError> {
242 let full_old_path = self.root_path.join(old_path);
243 let full_new_path = self.root_path.join(new_path);
244 if let Some(parent) = full_new_path.parent() {
245 std::fs::create_dir_all(parent)?;
246 }
247 std::fs::rename(full_old_path, full_new_path)?;
248 Ok(())
249 }
250
251 async fn rename_meta<'a>(
252 &'a self,
253 old_path: &'a Path,
254 new_path: &'a Path,
255 ) -> std::result::Result<(), AssetWriterError> {
256 let old_meta_path = get_meta_path(old_path);
257 let new_meta_path = get_meta_path(new_path);
258 let full_old_path = self.root_path.join(old_meta_path);
259 let full_new_path = self.root_path.join(new_meta_path);
260 if let Some(parent) = full_new_path.parent() {
261 std::fs::create_dir_all(parent)?;
262 }
263 std::fs::rename(full_old_path, full_new_path)?;
264 Ok(())
265 }
266}