Skip to content

Commit 10a922a

Browse files
andriyDevalice-i-cecilegreeble-dev
authored
Make building asset sources infallible. (#21721)
# Objective - Creating an asset source without a reader results in entirely skipping the asset source. ## Solution - Make the `AssetSourceBuilder` take a reader builder fn in a `new` method. - Remove `AssetSource::build` - users should just call the builder directly. ## Testing - Tests still pass. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Greeble <166992735+greeble-dev@users.noreply.github.com>
1 parent e499104 commit 10a922a

File tree

8 files changed

+106
-72
lines changed

8 files changed

+106
-72
lines changed

crates/bevy_asset/src/io/embedded/mod.rs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub use embedded_watcher::*;
66

77
use crate::io::{
88
memory::{Dir, MemoryAssetReader, Value},
9-
AssetSource, AssetSourceBuilders,
9+
AssetSourceBuilder, AssetSourceBuilders,
1010
};
1111
use crate::AssetServer;
1212
use alloc::boxed::Box;
@@ -19,7 +19,7 @@ use std::path::{Path, PathBuf};
1919
#[cfg(feature = "embedded_watcher")]
2020
use alloc::borrow::ToOwned;
2121

22-
/// The name of the `embedded` [`AssetSource`],
22+
/// The name of the `embedded` [`AssetSource`](crate::io::AssetSource),
2323
/// as stored in the [`AssetSourceBuilders`] resource.
2424
pub const EMBEDDED: &str = "embedded";
2525

@@ -38,8 +38,8 @@ pub struct EmbeddedAssetRegistry {
3838
impl EmbeddedAssetRegistry {
3939
/// Inserts a new asset. `full_path` is the full path (as [`file`] would return for that file, if it was capable of
4040
/// running in a non-rust file). `asset_path` is the path that will be used to identify the asset in the `embedded`
41-
/// [`AssetSource`]. `value` is the bytes that will be returned for the asset. This can be _either_ a `&'static [u8]`
42-
/// or a [`Vec<u8>`](alloc::vec::Vec).
41+
/// [`AssetSource`](crate::io::AssetSource). `value` is the bytes that will be returned for the asset. This can be
42+
/// _either_ a `&'static [u8]` or a [`Vec<u8>`](alloc::vec::Vec).
4343
#[cfg_attr(
4444
not(feature = "embedded_watcher"),
4545
expect(
@@ -58,8 +58,8 @@ impl EmbeddedAssetRegistry {
5858

5959
/// Inserts new asset metadata. `full_path` is the full path (as [`file`] would return for that file, if it was capable of
6060
/// running in a non-rust file). `asset_path` is the path that will be used to identify the asset in the `embedded`
61-
/// [`AssetSource`]. `value` is the bytes that will be returned for the asset. This can be _either_ a `&'static [u8]`
62-
/// or a [`Vec<u8>`](alloc::vec::Vec).
61+
/// [`AssetSource`](crate::io::AssetSource). `value` is the bytes that will be returned for the asset. This can be _either_
62+
/// a `&'static [u8]` or a [`Vec<u8>`](alloc::vec::Vec).
6363
#[cfg_attr(
6464
not(feature = "embedded_watcher"),
6565
expect(
@@ -83,7 +83,7 @@ impl EmbeddedAssetRegistry {
8383
self.dir.remove_asset(full_path)
8484
}
8585

86-
/// Registers the [`EMBEDDED`] [`AssetSource`] with the given [`AssetSourceBuilders`].
86+
/// Registers the [`EMBEDDED`] [`AssetSource`](crate::io::AssetSource) with the given [`AssetSourceBuilders`].
8787
pub fn register_source(&self, sources: &mut AssetSourceBuilders) {
8888
let dir = self.dir.clone();
8989
let processed_dir = self.dir.clone();
@@ -95,18 +95,18 @@ impl EmbeddedAssetRegistry {
9595
reason = "Variable is only mutated when `embedded_watcher` feature is enabled."
9696
)
9797
)]
98-
let mut source = AssetSource::build()
99-
.with_reader(move || Box::new(MemoryAssetReader { root: dir.clone() }))
100-
.with_processed_reader(move || {
101-
Box::new(MemoryAssetReader {
102-
root: processed_dir.clone(),
98+
let mut source =
99+
AssetSourceBuilder::new(move || Box::new(MemoryAssetReader { root: dir.clone() }))
100+
.with_processed_reader(move || {
101+
Box::new(MemoryAssetReader {
102+
root: processed_dir.clone(),
103+
})
103104
})
104-
})
105-
// Note that we only add a processed watch warning because we don't want to warn
106-
// noisily about embedded watching (which is niche) when users enable file watching.
107-
.with_processed_watch_warning(
108-
"Consider enabling the `embedded_watcher` cargo feature.",
109-
);
105+
// Note that we only add a processed watch warning because we don't want to warn
106+
// noisily about embedded watching (which is niche) when users enable file watching.
107+
.with_processed_watch_warning(
108+
"Consider enabling the `embedded_watcher` cargo feature.",
109+
);
110110

111111
#[cfg(feature = "embedded_watcher")]
112112
{
@@ -262,7 +262,7 @@ pub fn _embedded_asset_path(
262262
}
263263

264264
/// Creates a new `embedded` asset by embedding the bytes of the given path into the current binary
265-
/// and registering those bytes with the `embedded` [`AssetSource`].
265+
/// and registering those bytes with the `embedded` [`AssetSource`](crate::io::AssetSource).
266266
///
267267
/// This accepts the current [`App`] as the first parameter and a path `&str` (relative to the current file) as the second.
268268
///
@@ -306,7 +306,7 @@ pub fn _embedded_asset_path(
306306
/// ```
307307
///
308308
/// Some things to note in the path:
309-
/// 1. The non-default `embedded://` [`AssetSource`]
309+
/// 1. The non-default `embedded://` [`AssetSource`](crate::io::AssetSource)
310310
/// 2. `src` is trimmed from the path
311311
///
312312
/// The default behavior also works for cargo workspaces. Pretend the `bevy_rock` crate now exists in a larger workspace in

crates/bevy_asset/src/io/source.rs

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,9 @@ impl<'a> PartialEq for AssetSourceId<'a> {
116116

117117
/// Metadata about an "asset source", such as how to construct the [`AssetReader`](crate::io::AssetReader) and [`AssetWriter`](crate::io::AssetWriter) for the source,
118118
/// and whether or not the source is processed.
119-
#[derive(Default)]
120119
pub struct AssetSourceBuilder {
121120
/// The [`ErasedAssetReader`] to use on the unprocessed asset.
122-
pub reader: Option<Box<dyn FnMut() -> Box<dyn ErasedAssetReader> + Send + Sync>>,
121+
pub reader: Box<dyn FnMut() -> Box<dyn ErasedAssetReader> + Send + Sync>,
123122
/// The [`ErasedAssetWriter`] to use on the unprocessed asset.
124123
pub writer: Option<Box<dyn FnMut(bool) -> Option<Box<dyn ErasedAssetWriter>> + Send + Sync>>,
125124
/// The [`AssetWatcher`] to use for unprocessed assets, if any.
@@ -150,15 +149,31 @@ pub struct AssetSourceBuilder {
150149
}
151150

152151
impl AssetSourceBuilder {
152+
/// Creates a new builder, starting with the provided reader.
153+
pub fn new(
154+
reader: impl FnMut() -> Box<dyn ErasedAssetReader> + Send + Sync + 'static,
155+
) -> AssetSourceBuilder {
156+
Self {
157+
reader: Box::new(reader),
158+
writer: None,
159+
watcher: None,
160+
processed_reader: None,
161+
processed_writer: None,
162+
processed_watcher: None,
163+
watch_warning: None,
164+
processed_watch_warning: None,
165+
}
166+
}
167+
153168
/// Builds a new [`AssetSource`] with the given `id`. If `watch` is true, the unprocessed source will watch for changes.
154169
/// If `watch_processed` is true, the processed source will watch for changes.
155170
pub fn build(
156171
&mut self,
157172
id: AssetSourceId<'static>,
158173
watch: bool,
159174
watch_processed: bool,
160-
) -> Option<AssetSource> {
161-
let reader = self.reader.as_mut()?();
175+
) -> AssetSource {
176+
let reader = self.reader.as_mut()();
162177
let writer = self.writer.as_mut().and_then(|w| w(false));
163178
let processed_writer = self.processed_writer.as_mut().and_then(|w| w(true));
164179
let mut source = AssetSource {
@@ -202,15 +217,15 @@ impl AssetSourceBuilder {
202217
}
203218
}
204219
}
205-
Some(source)
220+
source
206221
}
207222

208223
/// Will use the given `reader` function to construct unprocessed [`AssetReader`](crate::io::AssetReader) instances.
209224
pub fn with_reader(
210225
mut self,
211226
reader: impl FnMut() -> Box<dyn ErasedAssetReader> + Send + Sync + 'static,
212227
) -> Self {
213-
self.reader = Some(Box::new(reader));
228+
self.reader = Box::new(reader);
214229
self
215230
}
216231

@@ -281,8 +296,7 @@ impl AssetSourceBuilder {
281296
/// For most platforms, this will use [`FileAssetReader`](crate::io::file::FileAssetReader) / [`FileAssetWriter`](crate::io::file::FileAssetWriter),
282297
/// but some platforms (such as Android) have their own default readers / writers / watchers.
283298
pub fn platform_default(path: &str, processed_path: Option<&str>) -> Self {
284-
let default = Self::default()
285-
.with_reader(AssetSource::get_default_reader(path.to_string()))
299+
let default = Self::new(AssetSource::get_default_reader(path.to_string()))
286300
.with_writer(AssetSource::get_default_writer(path.to_string()))
287301
.with_watcher(AssetSource::get_default_watcher(
288302
path.to_string(),
@@ -341,21 +355,20 @@ impl AssetSourceBuilders {
341355
pub fn build_sources(&mut self, watch: bool, watch_processed: bool) -> AssetSources {
342356
let mut sources = <HashMap<_, _>>::default();
343357
for (id, source) in &mut self.sources {
344-
if let Some(data) = source.build(
358+
let source = source.build(
345359
AssetSourceId::Name(id.clone_owned()),
346360
watch,
347361
watch_processed,
348-
) {
349-
sources.insert(id.clone_owned(), data);
350-
}
362+
);
363+
sources.insert(id.clone_owned(), source);
351364
}
352365

353366
AssetSources {
354367
sources,
355368
default: self
356369
.default
357370
.as_mut()
358-
.and_then(|p| p.build(AssetSourceId::Default, watch, watch_processed))
371+
.map(|p| p.build(AssetSourceId::Default, watch, watch_processed))
359372
.expect(MISSING_DEFAULT_SOURCE),
360373
}
361374
}
@@ -382,11 +395,6 @@ pub struct AssetSource {
382395
}
383396

384397
impl AssetSource {
385-
/// Starts building a new [`AssetSource`].
386-
pub fn build() -> AssetSourceBuilder {
387-
AssetSourceBuilder::default()
388-
}
389-
390398
/// Returns this source's id.
391399
#[inline]
392400
pub fn id(&self) -> AssetSourceId<'static> {

crates/bevy_asset/src/io/web.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
#[cfg(any(feature = "http", feature = "https"))]
2+
use crate::io::AssetSourceBuilder;
3+
use crate::io::PathStream;
14
use crate::io::{AssetReader, AssetReaderError, Reader};
2-
use crate::io::{AssetSource, PathStream};
35
use crate::{AssetApp, AssetPlugin};
46
use alloc::boxed::Box;
57
use bevy_app::{App, Plugin};
@@ -71,16 +73,14 @@ impl Plugin for WebAssetPlugin {
7173
#[cfg(feature = "http")]
7274
app.register_asset_source(
7375
"http",
74-
AssetSource::build()
75-
.with_reader(move || Box::new(WebAssetReader::Http))
76+
AssetSourceBuilder::new(move || Box::new(WebAssetReader::Http))
7677
.with_processed_reader(move || Box::new(WebAssetReader::Http)),
7778
);
7879

7980
#[cfg(feature = "https")]
8081
app.register_asset_source(
8182
"https",
82-
AssetSource::build()
83-
.with_reader(move || Box::new(WebAssetReader::Https))
83+
AssetSourceBuilder::new(move || Box::new(WebAssetReader::Https))
8484
.with_processed_reader(move || Box::new(WebAssetReader::Https)),
8585
);
8686
}

crates/bevy_asset/src/lib.rs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ mod tests {
713713
io::{
714714
gated::{GateOpener, GatedReader},
715715
memory::{Dir, MemoryAssetReader},
716-
AssetReader, AssetReaderError, AssetSource, AssetSourceEvent, AssetSourceId,
716+
AssetReader, AssetReaderError, AssetSourceBuilder, AssetSourceEvent, AssetSourceId,
717717
AssetWatcher, Reader,
718718
},
719719
loader::{AssetLoader, LoadContext},
@@ -906,7 +906,7 @@ mod tests {
906906
let (gated_memory_reader, gate_opener) = GatedReader::new(MemoryAssetReader { root: dir });
907907
app.register_asset_source(
908908
AssetSourceId::Default,
909-
AssetSource::build().with_reader(move || Box::new(gated_memory_reader.clone())),
909+
AssetSourceBuilder::new(move || Box::new(gated_memory_reader.clone())),
910910
)
911911
.add_plugins((
912912
TaskPoolPlugin::default(),
@@ -1845,7 +1845,7 @@ mod tests {
18451845
let mut app = App::new();
18461846
app.register_asset_source(
18471847
"unstable",
1848-
AssetSource::build().with_reader(move || Box::new(unstable_reader.clone())),
1848+
AssetSourceBuilder::new(move || Box::new(unstable_reader.clone())),
18491849
)
18501850
.add_plugins((TaskPoolPlugin::default(), AssetPlugin::default()))
18511851
.init_asset::<CoolText>()
@@ -1915,8 +1915,7 @@ mod tests {
19151915

19161916
app.register_asset_source(
19171917
AssetSourceId::Default,
1918-
AssetSource::build()
1919-
.with_reader(move || Box::new(MemoryAssetReader { root: dir.clone() })),
1918+
AssetSourceBuilder::new(move || Box::new(MemoryAssetReader { root: dir.clone() })),
19201919
)
19211920
.add_plugins((TaskPoolPlugin::default(), AssetPlugin::default()));
19221921

@@ -2039,7 +2038,7 @@ mod tests {
20392038
let memory_reader = MemoryAssetReader { root: dir };
20402039
app.register_asset_source(
20412040
AssetSourceId::Default,
2042-
AssetSource::build().with_reader(move || Box::new(memory_reader.clone())),
2041+
AssetSourceBuilder::new(move || Box::new(memory_reader.clone())),
20432042
)
20442043
.add_plugins((
20452044
TaskPoolPlugin::default(),
@@ -2177,7 +2176,7 @@ mod tests {
21772176
let reader = MemoryAssetReader { root: dir.clone() };
21782177
app.register_asset_source(
21792178
AssetSourceId::Default,
2180-
AssetSource::build().with_reader(move || Box::new(reader.clone())),
2179+
AssetSourceBuilder::new(move || Box::new(reader.clone())),
21812180
)
21822181
.add_plugins((TaskPoolPlugin::default(), AssetPlugin::default()));
21832182

@@ -2233,7 +2232,7 @@ mod tests {
22332232
let reader = MemoryAssetReader { root: dir.clone() };
22342233
app.register_asset_source(
22352234
AssetSourceId::Default,
2236-
AssetSource::build().with_reader(move || Box::new(reader.clone())),
2235+
AssetSourceBuilder::new(move || Box::new(reader.clone())),
22372236
)
22382237
.add_plugins((TaskPoolPlugin::default(), AssetPlugin::default()));
22392238

@@ -2299,12 +2298,12 @@ mod tests {
22992298

23002299
app.register_asset_source(
23012300
AssetSourceId::Default,
2302-
AssetSource::build()
2303-
.with_reader(move || Box::new(memory_reader.clone()))
2304-
.with_watcher(move |sender| {
2301+
AssetSourceBuilder::new(move || Box::new(memory_reader.clone())).with_watcher(
2302+
move |sender| {
23052303
sender_sender.send(sender).unwrap();
23062304
Some(Box::new(FakeWatcher))
2307-
}),
2305+
},
2306+
),
23082307
)
23092308
.add_plugins((
23102309
TaskPoolPlugin::default(),
@@ -2487,8 +2486,8 @@ mod tests {
24872486
let dir = Dir::default();
24882487
dir.insert_asset(Path::new("test.u8"), &[]);
24892488

2490-
let asset_source = AssetSource::build()
2491-
.with_reader(move || Box::new(MemoryAssetReader { root: dir.clone() }));
2489+
let asset_source =
2490+
AssetSourceBuilder::new(move || Box::new(MemoryAssetReader { root: dir.clone() }));
24922491

24932492
// Set up the app.
24942493

@@ -2551,8 +2550,8 @@ mod tests {
25512550
let dir = Dir::default();
25522551
dir.insert_asset(Path::new("test.txt"), &[]);
25532552

2554-
let asset_source = AssetSource::build()
2555-
.with_reader(move || Box::new(MemoryAssetReader { root: dir.clone() }));
2553+
let asset_source =
2554+
AssetSourceBuilder::new(move || Box::new(MemoryAssetReader { root: dir.clone() }));
25562555

25572556
app.register_asset_source(AssetSourceId::Default, asset_source)
25582557
.add_plugins((TaskPoolPlugin::default(), AssetPlugin::default()))
@@ -2603,8 +2602,8 @@ mod tests {
26032602
let dir = Dir::default();
26042603
dir.insert_asset(Path::new("test.txt"), &[]);
26052604

2606-
let asset_source = AssetSource::build()
2607-
.with_reader(move || Box::new(MemoryAssetReader { root: dir.clone() }));
2605+
let asset_source =
2606+
AssetSourceBuilder::new(move || Box::new(MemoryAssetReader { root: dir.clone() }));
26082607

26092608
app.register_asset_source(AssetSourceId::Default, asset_source)
26102609
.add_plugins((TaskPoolPlugin::default(), AssetPlugin::default()))

crates/bevy_asset/src/processor/tests.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ use bevy_tasks::BoxedFuture;
2525
use crate::{
2626
io::{
2727
memory::{Dir, MemoryAssetReader, MemoryAssetWriter},
28-
AssetReader, AssetReaderError, AssetSource, AssetSourceEvent, AssetSourceId, AssetWatcher,
29-
PathStream, Reader,
28+
AssetReader, AssetReaderError, AssetSourceBuilder, AssetSourceEvent, AssetSourceId,
29+
AssetWatcher, PathStream, Reader,
3030
},
3131
processor::{
3232
AssetProcessor, LoadTransformAndSave, LogEntry, ProcessorState, ProcessorTransactionLog,
@@ -146,8 +146,7 @@ fn create_app_with_asset_processor(extra_sources: &[String]) -> AppWithProcessor
146146

147147
app.register_asset_source(
148148
source_id,
149-
AssetSource::build()
150-
.with_reader(move || Box::new(source_memory_reader.clone()))
149+
AssetSourceBuilder::new(move || Box::new(source_memory_reader.clone()))
151150
.with_watcher(move |sender: async_channel::Sender<AssetSourceEvent>| {
152151
source_event_sender_sender.send_blocking(sender).unwrap();
153152
Some(Box::new(FakeWatcher))

0 commit comments

Comments
 (0)