Skip to content

Commit 49bc6cf

Browse files
mockersfcart
andauthored
support file operations in single threaded context (#10312)
# Objective - Fixes #10209 - Assets should work in single threaded ## Solution - In single threaded mode, don't use `async_fs` but fallback on `std::fs` with a thin layer to mimic the async API - file `file_asset.rs` is the async imps from `mod.rs` - file `sync_file_asset.rs` is the same with `async_fs` APIs replaced by `std::fs` - which module is used depends on the `multi-threaded` feature --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
1 parent fd232ad commit 49bc6cf

File tree

3 files changed

+533
-228
lines changed

3 files changed

+533
-228
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
use crate::io::{
2+
get_meta_path, AssetReader, AssetReaderError, AssetWriter, AssetWriterError, PathStream,
3+
Reader, Writer,
4+
};
5+
use async_fs::{read_dir, File};
6+
use bevy_utils::BoxedFuture;
7+
use futures_lite::StreamExt;
8+
9+
use std::path::Path;
10+
11+
use super::{FileAssetReader, FileAssetWriter};
12+
13+
impl AssetReader for FileAssetReader {
14+
fn read<'a>(
15+
&'a self,
16+
path: &'a Path,
17+
) -> BoxedFuture<'a, Result<Box<Reader<'a>>, AssetReaderError>> {
18+
Box::pin(async move {
19+
let full_path = self.root_path.join(path);
20+
match File::open(&full_path).await {
21+
Ok(file) => {
22+
let reader: Box<Reader> = Box::new(file);
23+
Ok(reader)
24+
}
25+
Err(e) => {
26+
if e.kind() == std::io::ErrorKind::NotFound {
27+
Err(AssetReaderError::NotFound(full_path))
28+
} else {
29+
Err(e.into())
30+
}
31+
}
32+
}
33+
})
34+
}
35+
36+
fn read_meta<'a>(
37+
&'a self,
38+
path: &'a Path,
39+
) -> BoxedFuture<'a, Result<Box<Reader<'a>>, AssetReaderError>> {
40+
let meta_path = get_meta_path(path);
41+
Box::pin(async move {
42+
let full_path = self.root_path.join(meta_path);
43+
match File::open(&full_path).await {
44+
Ok(file) => {
45+
let reader: Box<Reader> = Box::new(file);
46+
Ok(reader)
47+
}
48+
Err(e) => {
49+
if e.kind() == std::io::ErrorKind::NotFound {
50+
Err(AssetReaderError::NotFound(full_path))
51+
} else {
52+
Err(e.into())
53+
}
54+
}
55+
}
56+
})
57+
}
58+
59+
fn read_directory<'a>(
60+
&'a self,
61+
path: &'a Path,
62+
) -> BoxedFuture<'a, Result<Box<PathStream>, AssetReaderError>> {
63+
Box::pin(async move {
64+
let full_path = self.root_path.join(path);
65+
match read_dir(&full_path).await {
66+
Ok(read_dir) => {
67+
let root_path = self.root_path.clone();
68+
let mapped_stream = read_dir.filter_map(move |f| {
69+
f.ok().and_then(|dir_entry| {
70+
let path = dir_entry.path();
71+
// filter out meta files as they are not considered assets
72+
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
73+
if ext.eq_ignore_ascii_case("meta") {
74+
return None;
75+
}
76+
}
77+
let relative_path = path.strip_prefix(&root_path).unwrap();
78+
Some(relative_path.to_owned())
79+
})
80+
});
81+
let read_dir: Box<PathStream> = Box::new(mapped_stream);
82+
Ok(read_dir)
83+
}
84+
Err(e) => {
85+
if e.kind() == std::io::ErrorKind::NotFound {
86+
Err(AssetReaderError::NotFound(full_path))
87+
} else {
88+
Err(e.into())
89+
}
90+
}
91+
}
92+
})
93+
}
94+
95+
fn is_directory<'a>(
96+
&'a self,
97+
path: &'a Path,
98+
) -> BoxedFuture<'a, std::result::Result<bool, AssetReaderError>> {
99+
Box::pin(async move {
100+
let full_path = self.root_path.join(path);
101+
let metadata = full_path
102+
.metadata()
103+
.map_err(|_e| AssetReaderError::NotFound(path.to_owned()))?;
104+
Ok(metadata.file_type().is_dir())
105+
})
106+
}
107+
}
108+
109+
impl AssetWriter for FileAssetWriter {
110+
fn write<'a>(
111+
&'a self,
112+
path: &'a Path,
113+
) -> BoxedFuture<'a, Result<Box<Writer>, AssetWriterError>> {
114+
Box::pin(async move {
115+
let full_path = self.root_path.join(path);
116+
if let Some(parent) = full_path.parent() {
117+
async_fs::create_dir_all(parent).await?;
118+
}
119+
let file = File::create(&full_path).await?;
120+
let writer: Box<Writer> = Box::new(file);
121+
Ok(writer)
122+
})
123+
}
124+
125+
fn write_meta<'a>(
126+
&'a self,
127+
path: &'a Path,
128+
) -> BoxedFuture<'a, Result<Box<Writer>, AssetWriterError>> {
129+
Box::pin(async move {
130+
let meta_path = get_meta_path(path);
131+
let full_path = self.root_path.join(meta_path);
132+
if let Some(parent) = full_path.parent() {
133+
async_fs::create_dir_all(parent).await?;
134+
}
135+
let file = File::create(&full_path).await?;
136+
let writer: Box<Writer> = Box::new(file);
137+
Ok(writer)
138+
})
139+
}
140+
141+
fn remove<'a>(
142+
&'a self,
143+
path: &'a Path,
144+
) -> BoxedFuture<'a, std::result::Result<(), AssetWriterError>> {
145+
Box::pin(async move {
146+
let full_path = self.root_path.join(path);
147+
async_fs::remove_file(full_path).await?;
148+
Ok(())
149+
})
150+
}
151+
152+
fn remove_meta<'a>(
153+
&'a self,
154+
path: &'a Path,
155+
) -> BoxedFuture<'a, std::result::Result<(), AssetWriterError>> {
156+
Box::pin(async move {
157+
let meta_path = get_meta_path(path);
158+
let full_path = self.root_path.join(meta_path);
159+
async_fs::remove_file(full_path).await?;
160+
Ok(())
161+
})
162+
}
163+
164+
fn remove_directory<'a>(
165+
&'a self,
166+
path: &'a Path,
167+
) -> BoxedFuture<'a, std::result::Result<(), AssetWriterError>> {
168+
Box::pin(async move {
169+
let full_path = self.root_path.join(path);
170+
async_fs::remove_dir_all(full_path).await?;
171+
Ok(())
172+
})
173+
}
174+
175+
fn remove_empty_directory<'a>(
176+
&'a self,
177+
path: &'a Path,
178+
) -> BoxedFuture<'a, std::result::Result<(), AssetWriterError>> {
179+
Box::pin(async move {
180+
let full_path = self.root_path.join(path);
181+
async_fs::remove_dir(full_path).await?;
182+
Ok(())
183+
})
184+
}
185+
186+
fn remove_assets_in_directory<'a>(
187+
&'a self,
188+
path: &'a Path,
189+
) -> BoxedFuture<'a, std::result::Result<(), AssetWriterError>> {
190+
Box::pin(async move {
191+
let full_path = self.root_path.join(path);
192+
async_fs::remove_dir_all(&full_path).await?;
193+
async_fs::create_dir_all(&full_path).await?;
194+
Ok(())
195+
})
196+
}
197+
198+
fn rename<'a>(
199+
&'a self,
200+
old_path: &'a Path,
201+
new_path: &'a Path,
202+
) -> BoxedFuture<'a, std::result::Result<(), AssetWriterError>> {
203+
Box::pin(async move {
204+
let full_old_path = self.root_path.join(old_path);
205+
let full_new_path = self.root_path.join(new_path);
206+
if let Some(parent) = full_new_path.parent() {
207+
async_fs::create_dir_all(parent).await?;
208+
}
209+
async_fs::rename(full_old_path, full_new_path).await?;
210+
Ok(())
211+
})
212+
}
213+
214+
fn rename_meta<'a>(
215+
&'a self,
216+
old_path: &'a Path,
217+
new_path: &'a Path,
218+
) -> BoxedFuture<'a, std::result::Result<(), AssetWriterError>> {
219+
Box::pin(async move {
220+
let old_meta_path = get_meta_path(old_path);
221+
let new_meta_path = get_meta_path(new_path);
222+
let full_old_path = self.root_path.join(old_meta_path);
223+
let full_new_path = self.root_path.join(new_meta_path);
224+
if let Some(parent) = full_new_path.parent() {
225+
async_fs::create_dir_all(parent).await?;
226+
}
227+
async_fs::rename(full_old_path, full_new_path).await?;
228+
Ok(())
229+
})
230+
}
231+
}

0 commit comments

Comments
 (0)