[][src]Struct yaks::ExecutorBuilder

pub struct ExecutorBuilder<'closures, Resources, Handle = DummyHandle> where
    Resources: ResourceTuple, 
{ /* fields omitted */ }

A factory for Executor (and the only way of creating one).

Implementations

impl<'closures, Resources, Handle> ExecutorBuilder<'closures, Resources, Handle> where
    Resources: ResourceTuple,
    Handle: Eq + Hash
[src]

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, 
[src]

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);

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
[src]

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.

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
[src]

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.

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
[src]

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.

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

Consumes the builder and returns the finalized executor.

Auto Trait Implementations

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

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

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

The type returned in the event of a conversion error.