Struct ExecutorBuilder

Source
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>
where Resources: ResourceTuple, Handle: Eq + Hash,

Source

pub fn system<'a, Closure, ResourceRefs, Queries, Markers>( self, closure: Closure, ) -> Self
where 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 a hecs::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);
Source

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.
Source

pub fn system_with_deps<'a, Closure, ResourceRefs, Queries, Markers>( self, closure: Closure, dependencies: Vec<Handle>, ) -> Self
where Resources::Cells: 'a, Closure: FnMut(SystemContext<'a>, ResourceRefs, Queries) + Send + Sync + 'closures, ResourceRefs: Fetch<'a, WrappedResources<'a, Resources::Cells>, Markers> + 'a, Queries: QueryBundle, Handle: Eq + Hash + Debug,

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.
Source

pub fn system_with_handle_and_deps<'a, Closure, ResourceRefs, Queries, Markers>( self, closure: Closure, handle: Handle, dependencies: Vec<Handle>, ) -> Self
where Resources::Cells: 'a, Closure: FnMut(SystemContext<'a>, ResourceRefs, Queries) + Send + Sync + 'closures, ResourceRefs: Fetch<'a, WrappedResources<'a, Resources::Cells>, Markers> + 'a, Queries: QueryBundle, Handle: Eq + Hash + Debug,

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.
Source

pub fn build(self) -> Executor<'closures, Resources>

Consumes the builder and returns the finalized executor.

Auto Trait Implementations§

§

impl<'closures, Resources, Handle> Freeze for ExecutorBuilder<'closures, Resources, Handle>

§

impl<'closures, Resources, Handle = DummyHandle> !RefUnwindSafe for ExecutorBuilder<'closures, Resources, Handle>

§

impl<'closures, Resources, Handle> Send for ExecutorBuilder<'closures, Resources, Handle>
where Handle: Send,

§

impl<'closures, Resources, Handle = DummyHandle> !Sync for ExecutorBuilder<'closures, Resources, Handle>

§

impl<'closures, Resources, Handle> Unpin for ExecutorBuilder<'closures, Resources, Handle>
where Handle: Unpin,

§

impl<'closures, Resources, Handle = DummyHandle> !UnwindSafe for ExecutorBuilder<'closures, Resources, Handle>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.