pub struct ExecutorBuilder<'closures, Resources, Handle = DummyHandle>where
Resources: ResourceTuple,{ /* private fields */ }
Expand description
A factory for Executor
(and the only way of creating one).
Implementations§
Source§impl<'closures, Resources, Handle> ExecutorBuilder<'closures, Resources, Handle>
impl<'closures, Resources, Handle> ExecutorBuilder<'closures, Resources, Handle>
Sourcepub fn system<'a, Closure, ResourceRefs, Queries, Markers>(
self,
closure: Closure,
) -> Selfwhere
Resources::Cells: 'a,
Closure: FnMut(SystemContext<'a>, ResourceRefs, Queries) + Send + Sync + 'closures,
ResourceRefs: Fetch<'a, WrappedResources<'a, Resources::Cells>, Markers> + 'a,
Queries: QueryBundle,
pub fn system<'a, Closure, ResourceRefs, Queries, Markers>(
self,
closure: Closure,
) -> Selfwhere
Resources::Cells: 'a,
Closure: FnMut(SystemContext<'a>, ResourceRefs, Queries) + Send + Sync + 'closures,
ResourceRefs: Fetch<'a, WrappedResources<'a, Resources::Cells>, Markers> + 'a,
Queries: QueryBundle,
Creates a new system from a closure or a function, and inserts it into the builder.
The system-to-be must return nothing and have these 3 arguments:
SystemContext
,- any tuple (up to 16) or a single one of “resources”: references or mutable references
to
Send + Sync
values not contained in ahecs::World
that the system will be accessing, - any tuple (up to 16) or a single one of
QueryMarker
that represent the queries the system will be making.
Additionally, closures may mutably borrow from their environment for the lifetime
of the executor, but must be Send + Sync
.
All resources the system requires must correspond to a type in the executor’s
signature; e.g., if any number of systems require a &f32
or a &mut f32
,
executor’s generic parameter must contain f32
.
§Example
fn system_0(
context: SystemContext,
res_a: &A,
(query_0, query_1): (
QueryMarker<(&B, &mut C)>,
QueryMarker<hecs::Without<B, &C>>
),
) {
// This system may read resource of type `A`, and may prepare & execute queries
// of `(&B, &mut C)` and `hecs::Without<B, &C>`.
}
fn system_1(
context: SystemContext,
(res_a, res_b): (&mut A, &B),
query_0: QueryMarker<(&mut B, &mut C)>,
) {
// This system may read or write resource of type `A`, may read resource of type `B`,
// and may prepare & execute queries of `(&mut B, &mut C)`.
}
let mut increment = 0;
// All together, systems require resources of types `A`, `B`, and `C`.
let mut executor = Executor::<(A, B, C)>::builder()
.system(system_0)
.system(system_1)
.system(|context, res_c: &C, _queries: ()| {
// This system may read resource of type `C` and will not perform any queries.
increment += 1; // `increment` will be borrowed by the executor.
})
.build();
let (mut a, mut b, mut c) = (A, B, C);
executor.run(&world, (&mut a, &mut b, &mut c));
executor.run(&world, (&mut a, &mut b, &mut c));
executor.run(&world, (&mut a, &mut b, &mut c));
drop(executor); // This releases the borrow of `increment`.
assert_eq!(increment, 3);
Sourcepub fn system_with_handle<'a, Closure, ResourceRefs, Queries, Markers, NewHandle>(
self,
closure: Closure,
handle: NewHandle,
) -> ExecutorBuilder<'closures, Resources, NewHandle>where
Resources::Cells: 'a,
Closure: FnMut(SystemContext<'a>, ResourceRefs, Queries) + Send + Sync + 'closures,
ResourceRefs: Fetch<'a, WrappedResources<'a, Resources::Cells>, Markers> + 'a,
Queries: QueryBundle,
NewHandle: HandleConversion<Handle> + Debug,
pub fn system_with_handle<'a, Closure, ResourceRefs, Queries, Markers, NewHandle>(
self,
closure: Closure,
handle: NewHandle,
) -> ExecutorBuilder<'closures, Resources, NewHandle>where
Resources::Cells: 'a,
Closure: FnMut(SystemContext<'a>, ResourceRefs, Queries) + Send + Sync + 'closures,
ResourceRefs: Fetch<'a, WrappedResources<'a, Resources::Cells>, Markers> + 'a,
Queries: QueryBundle,
NewHandle: HandleConversion<Handle> + Debug,
Creates a new system from a closure or a function, and inserts it into
the builder with given handle; see ::system()
.
Handles allow defining relative order of execution between systems,
and using them is optional. They can be of any type that is Sized + Eq + Hash + Debug
and do not persist after ::build()
- the
resulting executor relies on lightweight opaque IDs;
see SystemContext::id()
.
Handles must be unique, and systems with dependencies must be inserted
into the builder after said dependencies.
If the default parallel
feature is disabled the systems will be executed in insertion
order, which these rules guarantee to be a valid order.
Since specifying a dependency between systems forbids them to run concurrently, this
functionality should be used only when necessary. In fact, for executors where systems
form a single chain of execution it is more performant to call them as functions,
in a sequence, inside a single rayon::scope()
or
rayon::ThreadPool::install()
block.
§Examples
These two executors are identical.
let _ = Executor::<()>::builder()
.system_with_handle(system_0, 0)
.system_with_handle(system_1, 1)
.system_with_handle_and_deps(system_2, 2, vec![0, 1])
.system_with_deps(system_3, vec![2])
.system_with_deps(system_4, vec![0])
.build();
let _ = Executor::<()>::builder()
.system_with_handle(system_0, "system_0")
.system_with_handle(system_1, "system_1")
.system_with_handle_and_deps(system_2, "system_2", vec!["system_1", "system_0"])
.system_with_deps(system_3, vec!["system_2"])
.system_with_deps(system_4, vec!["system_0"])
.build();
The order of execution (with the default parallel
feature enabled) is:
- systems 0 and 1,
- system 4 as soon as 0 is finished and system 2 as soon as both 0 and 1 is finished,
- system 3 as soon as 2 is finished.
This executor will behave identically to the two above if the default parallel
feature is enabled; otherwise, the execution order will be different, but
that doesn’t matter as long as the given dependencies truthfully reflect any
relationships the systems may have.
let _ = Executor::<()>::builder()
.system_with_handle(system_1, 1)
.system_with_handle(system_0, 0)
.system_with_deps(system_4, vec![0])
.system_with_handle_and_deps(system_2, 2, vec![0, 1])
.system_with_deps(system_3, vec![2])
.build();
§Panics
This function will panic if:
- a system with given handle is already present in the builder.
Sourcepub fn system_with_deps<'a, Closure, ResourceRefs, Queries, Markers>(
self,
closure: Closure,
dependencies: Vec<Handle>,
) -> Self
pub fn system_with_deps<'a, Closure, ResourceRefs, Queries, Markers>( self, closure: Closure, dependencies: Vec<Handle>, ) -> Self
Creates a new system from a closure or a function, and inserts it into
the builder with given dependencies; see ::system()
.
Given system will start running only after all systems in given list of dependencies have finished running.
This function cannot be used unless the builder already has
at least one system with a handle;
see ::system_with_handle()
.
§Panics
This function will panic if:
- given list of dependencies contains a handle that doesn’t correspond to any system in the builder.
Sourcepub fn system_with_handle_and_deps<'a, Closure, ResourceRefs, Queries, Markers>(
self,
closure: Closure,
handle: Handle,
dependencies: Vec<Handle>,
) -> Self
pub fn system_with_handle_and_deps<'a, Closure, ResourceRefs, Queries, Markers>( self, closure: Closure, handle: Handle, dependencies: Vec<Handle>, ) -> Self
Creates a new system from a closure or a function, and inserts it into
the builder with given handle and dependencies; see ::system()
.
Given system will start running only after all systems in given list of dependencies have finished running.
This function cannot be used unless the builder already has
at least one system with a handle;
see ::system_with_handle()
.
§Panics
This function will panic if:
- a system with given handle is already present in the builder,
- given list of dependencies contains a handle that doesn’t correspond to any system in the builder,
- given handle appears in given list of dependencies.