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