Skip to main content

DomainChain

Struct DomainChain 

Source
pub struct DomainChain<D, T, S> { /* private fields */ }
Expand description

A typed chain of sequential async command executions bound to a domain.

Created by DomainExecutor::exec or DomainExecutor::exec_discard. Extend the chain with exec, then, or exec_discard. Finish with go to spawn the entire chain.

Generic over T — the output type of the last executed command — which enables type-safe inter-command data passing via then.

§Execution model

All commands run sequentially: each completes fully before the next begins. The chain is a single composed future — there is no parallelism within a chain. If any command fails, the on_error callback is invoked and remaining commands are skipped (short-circuit).

§Type parameters

  • D: The domain data type.
  • T: The output type of the last command in the chain.
  • S: The services type.

Implementations§

Source§

impl<D, T, S> DomainChain<D, T, S>
where D: Clone + Send + Sync + 'static, T: Send + 'static, S: Clone + Send + 'static,

Source

pub fn exec<C>( self, cmd: C, setter: impl Fn(&mut D, &C::Output) + Send + Sync + 'static, ) -> DomainChain<D, C::Output, S>
where C: Command<S> + 'static, C::Output: Clone + Send + 'static, C::Error: CmdError,

Execute a command independently, ignoring the previous output.

This command runs after the previous command completes. The previous output is dropped — use then instead if you need to pass data forward.

If the chain has already short-circuited (previous error), this command is skipped.

Source

pub fn exec_discard<C>(self, cmd: C) -> DomainChain<D, (), S>
where C: Command<S> + 'static, C::Error: CmdError,

Execute a command and discard its output, ignoring the previous output.

This command runs after the previous command completes. The output is thrown away — no setter is needed.

Returns a chain with output type ().

Source

pub fn then<C, F>( self, factory: F, setter: impl Fn(&mut D, &C::Output) + Send + Sync + 'static, ) -> DomainChain<D, C::Output, S>
where C: Command<S> + 'static, C::Output: Clone + Send + 'static, C::Error: CmdError, F: FnOnce(&T) -> C + Send + 'static,

Execute a command whose input depends on the previous command’s output.

This command runs after the previous command completes. The factory closure receives &T (the previous output) and returns the next command, enabling multi-step pipelines where each step feeds the next:

use dbuff::*;
use std::time::Duration;
#[derive(Clone, Default)]
struct Data { total: i32 }

// Add(10) outputs 10, then Mul(3) receives 10 and outputs 30
domain.bind((), rt)
    .exec(Add(10), |d, val: &i32| d.total = *val)
    .then(|val: &i32| Mul(*val * 3), |d, val: &i32| d.total = *val)
    .go();

tokio::time::sleep(Duration::from_millis(10)).await;
assert_eq!(domain.read().total, 30);

If you don’t need the previous output, use exec instead.

If the chain has already short-circuited (previous error), the factory is not called and the chain remains short-circuited.

Source

pub fn tracked( self, status_setter: impl Fn(&mut D, TaskStatus<T>) + Send + Sync + 'static, ) -> Self
where T: Clone + Send + 'static,

Add lifecycle status tracking to the last command in the chain.

Wraps the chain’s composed future with status transitions:

The status_setter is called via SharedDomainData::modify at each transition, writing the current TaskStatus into domain state. This enables a render loop to poll status via domain.read():

use dbuff::*;
use std::time::Duration;


domain.bind((), rt)
    .exec(Fetch(42), |_, _: &i32| {})
    .tracked(|d, status: TaskStatus<i32>| d.status = status)
    .go();

// Later, in a render loop:
// match &domain.read().status {
//     TaskStatus::Pending => render_spinner(),
//     TaskStatus::Resolved(v) => render_value(v),
//     _ => {}
// }

Multiple .tracked() calls can be chained to track different steps:

use dbuff::*;
use std::time::Duration;


domain.bind((), rt)
    .exec(Step(1), |_, _: &i32| {})
    .tracked(|d, status: TaskStatus<i32>| d.step1 = status)
    .then(|v: &i32| Step(*v + 1), |_, _: &i32| {})
    .tracked(|d, status: TaskStatus<i32>| d.step2 = status)
    .go();

Note: .tracked() tracks the entire chain segment up to that point, including all previous commands. If a previous command in the chain fails, the status will transition to TaskStatus::Error.

Source

pub fn go(self) -> ChainHandle

Spawn the entire chain as a single sequential task on the tokio runtime.

Commands execute one at a time — each completes before the next begins. Returns a ChainHandle that resolves to ControlFlow::Continue if all commands succeeded, or ControlFlow::Break if any command failed (short-circuit).

Source

pub fn go_detach(self)

Spawn the chain as a fire-and-forget task.

Identical to Self::go but returns () instead of a ChainHandle, so no #[must_use] warning is emitted when the handle is not needed.

Source§

impl<D, T, S> DomainChain<D, T, S>
where D: Clone + Send + Sync + 'static, T: Send + 'static, S: Clone + Send + 'static,

Source

pub fn exec_parallel_2<C0, S0, C1, S1>( self, C0: (C0, S0), C1: (C1, S1), ) -> DomainChain<D, (), S>
where C0: Command<S> + 'static, C1: Command<S> + 'static, C0::Output: Clone + Send + 'static, C1::Output: Clone + Send + 'static, C0::Error: CmdError, C1::Error: CmdError, S0: Fn(&mut D, &C0::Output) + Send + Sync + 'static, S1: Fn(&mut D, &C1::Output) + Send + Sync + 'static,

Source§

impl<D, T, S> DomainChain<D, T, S>
where D: Clone + Send + Sync + 'static, T: Send + 'static, S: Clone + Send + 'static,

Source

pub fn exec_parallel_discard_2<C0, C1>( self, C0: C0, C1: C1, ) -> DomainChain<D, (), S>
where C0: Command<S> + 'static, C1: Command<S> + 'static, C0::Error: CmdError, C1::Error: CmdError,

Source§

impl<D, T, S> DomainChain<D, T, S>
where D: Clone + Send + Sync + 'static, T: Send + 'static, S: Clone + Send + 'static,

Source

pub fn exec_parallel_3<C0, S0, C1, S1, C2, S2>( self, C0: (C0, S0), C1: (C1, S1), C2: (C2, S2), ) -> DomainChain<D, (), S>
where C0: Command<S> + 'static, C1: Command<S> + 'static, C2: Command<S> + 'static, C0::Output: Clone + Send + 'static, C1::Output: Clone + Send + 'static, C2::Output: Clone + Send + 'static, C0::Error: CmdError, C1::Error: CmdError, C2::Error: CmdError, S0: Fn(&mut D, &C0::Output) + Send + Sync + 'static, S1: Fn(&mut D, &C1::Output) + Send + Sync + 'static, S2: Fn(&mut D, &C2::Output) + Send + Sync + 'static,

Source§

impl<D, T, S> DomainChain<D, T, S>
where D: Clone + Send + Sync + 'static, T: Send + 'static, S: Clone + Send + 'static,

Source

pub fn exec_parallel_discard_3<C0, C1, C2>( self, C0: C0, C1: C1, C2: C2, ) -> DomainChain<D, (), S>
where C0: Command<S> + 'static, C1: Command<S> + 'static, C2: Command<S> + 'static, C0::Error: CmdError, C1::Error: CmdError, C2::Error: CmdError,

Source§

impl<D, T, S> DomainChain<D, T, S>
where D: Clone + Send + Sync + 'static, T: Send + 'static, S: Clone + Send + 'static,

Source

pub fn exec_parallel_4<C0, S0, C1, S1, C2, S2, C3, S3>( self, C0: (C0, S0), C1: (C1, S1), C2: (C2, S2), C3: (C3, S3), ) -> DomainChain<D, (), S>
where C0: Command<S> + 'static, C1: Command<S> + 'static, C2: Command<S> + 'static, C3: Command<S> + 'static, C0::Output: Clone + Send + 'static, C1::Output: Clone + Send + 'static, C2::Output: Clone + Send + 'static, C3::Output: Clone + Send + 'static, C0::Error: CmdError, C1::Error: CmdError, C2::Error: CmdError, C3::Error: CmdError, S0: Fn(&mut D, &C0::Output) + Send + Sync + 'static, S1: Fn(&mut D, &C1::Output) + Send + Sync + 'static, S2: Fn(&mut D, &C2::Output) + Send + Sync + 'static, S3: Fn(&mut D, &C3::Output) + Send + Sync + 'static,

Source§

impl<D, T, S> DomainChain<D, T, S>
where D: Clone + Send + Sync + 'static, T: Send + 'static, S: Clone + Send + 'static,

Source

pub fn exec_parallel_discard_4<C0, C1, C2, C3>( self, C0: C0, C1: C1, C2: C2, C3: C3, ) -> DomainChain<D, (), S>
where C0: Command<S> + 'static, C1: Command<S> + 'static, C2: Command<S> + 'static, C3: Command<S> + 'static, C0::Error: CmdError, C1::Error: CmdError, C2::Error: CmdError, C3::Error: CmdError,

Source§

impl<D, T, S> DomainChain<D, T, S>
where D: Clone + Send + Sync + 'static, T: Send + 'static, S: Clone + Send + 'static,

Source

pub fn exec_parallel_5<C0, S0, C1, S1, C2, S2, C3, S3, C4, S4>( self, C0: (C0, S0), C1: (C1, S1), C2: (C2, S2), C3: (C3, S3), C4: (C4, S4), ) -> DomainChain<D, (), S>
where C0: Command<S> + 'static, C1: Command<S> + 'static, C2: Command<S> + 'static, C3: Command<S> + 'static, C4: Command<S> + 'static, C0::Output: Clone + Send + 'static, C1::Output: Clone + Send + 'static, C2::Output: Clone + Send + 'static, C3::Output: Clone + Send + 'static, C4::Output: Clone + Send + 'static, C0::Error: CmdError, C1::Error: CmdError, C2::Error: CmdError, C3::Error: CmdError, C4::Error: CmdError, S0: Fn(&mut D, &C0::Output) + Send + Sync + 'static, S1: Fn(&mut D, &C1::Output) + Send + Sync + 'static, S2: Fn(&mut D, &C2::Output) + Send + Sync + 'static, S3: Fn(&mut D, &C3::Output) + Send + Sync + 'static, S4: Fn(&mut D, &C4::Output) + Send + Sync + 'static,

Source§

impl<D, T, S> DomainChain<D, T, S>
where D: Clone + Send + Sync + 'static, T: Send + 'static, S: Clone + Send + 'static,

Source

pub fn exec_parallel_discard_5<C0, C1, C2, C3, C4>( self, C0: C0, C1: C1, C2: C2, C3: C3, C4: C4, ) -> DomainChain<D, (), S>
where C0: Command<S> + 'static, C1: Command<S> + 'static, C2: Command<S> + 'static, C3: Command<S> + 'static, C4: Command<S> + 'static, C0::Error: CmdError, C1::Error: CmdError, C2::Error: CmdError, C3::Error: CmdError, C4::Error: CmdError,

Auto Trait Implementations§

§

impl<D, T, S> Freeze for DomainChain<D, T, S>
where S: Freeze,

§

impl<D, T, S> !RefUnwindSafe for DomainChain<D, T, S>

§

impl<D, T, S> Send for DomainChain<D, T, S>
where S: Send, D: Sync + Send,

§

impl<D, T, S> !Sync for DomainChain<D, T, S>

§

impl<D, T, S> Unpin for DomainChain<D, T, S>
where S: Unpin,

§

impl<D, T, S> UnsafeUnpin for DomainChain<D, T, S>
where S: UnsafeUnpin,

§

impl<D, T, S> !UnwindSafe for DomainChain<D, T, S>

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.