Replace the NestedLoader API with NestedLoadBuilder (matching LoadBuilder).#23979
Conversation
84c176d to
ef676a2
Compare
ef676a2 to
784449e
Compare
| /// (ex: [`AssetProcessor`]), a load will not be kicked off automatically. It is | ||
| /// then the calling context's responsibility to begin a load if necessary. | ||
| /// | ||
| /// # Lifetimes |
There was a problem hiding this comment.
Are the lifetimes still applicable to include as part of a doc comment?
There was a problem hiding this comment.
I did think about this but I decided it doesn't matter. IMO the only reason we needed docs about the lifetimes is because the usage of lifetimes was really complex, and that's in part due to the type-state stuff. Now that this is much simpler, I don't think we need to be very descriptive here. The same way how we don't need to be descriptive about the lifetimes of Query.
|
|
||
| /// Acquires the handle for the given type and path, and if necessary, begins a corresponding | ||
| /// (deferred) load. | ||
| fn load_internal<'a>( |
There was a problem hiding this comment.
should this be renamed to load_typed_internal to match the fn name and signature in bevy_asset server’s LoadBuilder? It might be easier to connect similarities between NestedLoadBuilder and the reg. LoadBuilder if function names and signatures match too (well, if they’re actually doing the similar/same things)
There was a problem hiding this comment.
I don't want to use load_typed_internal because I already use that for load_typed_async_internal which is when we use the generic type. Either way this is private so I don't really care much to bikeshed this.
| /// | ||
| /// # Load kickoff | ||
| /// | ||
| /// If the current context is a normal [`AssetServer::load`], an actual asset |
There was a problem hiding this comment.
I only briefly looked at the other PR, but this one looks good to me. The notion of "immediate" is now much clearer with load* variants returning a handle and load*_async returning assets. The doc comments regarding "load kickoff" (LoadContext::should_load_dependencies) got lost and maybe could be reinserted for the load variants that return a handle. I assume load kickoff is irrelevant for the async variants?
There was a problem hiding this comment.
The doc comments regarding "load kickoff" ... got lost
This was intentional - from the perspective of the user, whether should_load_dependencies is true or false is totally invisible: in either case they get back a handle that would refer to the asset they loaded. So I think explaining this in the doc comments makes it seem like something you should think about, but you shouldn't need to at all.
Good call out though!
I assume load kickoff is irrelevant for the async variants?
Correct! Even with should_load_dependencies = false, we need to load the dependency to return the actual data. For deferred loads, we only need a handle, which we can get without problems.
There was a problem hiding this comment.
I'm very much in favor of the direction this PR takes. I struggled to understand how to use the previous nested loader - this one is much simpler. But I think the new version is still confusing when it comes to deferred versus immediate loads.
Take load and load_async. At a glance I'd assume that load is just a synchronous version of load_async - so they do the same thing at different times. But that's not true! The important part is that load is "by reference" and load_async is "by value". These serve completely different purposes - the former is for linking separate assets together, the latter is for consuming the asset value within the loader. The fact that one is async is just a detail. I think the API should make the important part clear.
I've tried out an alternative - split the builder in two. Then one is framed as loading handles and the other is framed as loading values. Also added a convenience LoadContext::load_value. Quick and dirty test here: ef7bd02. I think this makes the behavior clearer.
-load_context.load(path);
+load_context.load_handle(path);
-load_context.load_builder().load_async(path);
+load_context.load_value(path);
-load_context.load_builder().with_settings(s).load(path);
+load_context.load_handle_builder().with_settings(s).load(path);
-load_context.load_builder().with_settings(s).load_async(path);
+load_context.load_value_builder().with_settings(s).load(path);| /// paths of assets used by the nested loader. | ||
| /// that path as a dependency of this asset. | ||
| pub async fn load_erased_async_from_reader<'a>( |
There was a problem hiding this comment.
| /// paths of assets used by the nested loader. | |
| /// that path as a dependency of this asset. | |
| pub async fn load_erased_async_from_reader<'a>( | |
| /// paths of assets used by the nested loader. | |
| pub async fn load_erased_async_from_reader<'a>( |
|
@greeble-dev I am strongly against renaming I am also against making separate builders - it adds more overhead to the I'm convinced enough though to rename |
b497334 to
5b09737
Compare
Objective
AssetServerwith a builder. #23663.Solution
NestedLoader. Make each way of calling load just be its own function.NestedLoader.NestedLoadertoNestedLoadBuilder(to matchLoadBuilder)..loader()to.load_builder()just likeAssetServer::load_builder.Some decisions:
override_unapprovedto match LoadBuilder. We could remove this to say "loaders shouldn't be able to override", but I don't think that's problematic, and I'd rather have it for completeness.with_guardfromNestedLoadBuilder. This option doesn't really make sense, plus you could just use the async methods to do this instead.with_guard(since it really doesn't make sense in this context), I decided not to reuseLoadBuilderin any way here. Either way, we need to deal with dependencies, so we couldn't just use it directly anyway.with_readerstuff as a type-state like we did withNestedLoader. I'm not a fan of how many variants we have, but I don't think there's a way to do this without opening up impossible configurations, like doing with_reader for a deferred call - this doesn't work!