Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Stage 1 — TreeishPipeline

#![allow(unused)]
fn main() {
/// Stage-1 typestate pipeline with two base slots: `treeish`
/// (graph) and `fold`. Used when children are directly enumerable
/// from nodes of the same type (`N → N*`).
#[must_use]
pub struct TreeishPipeline<D, N, H, R>
where D: Domain<N>,
      N: 'static, H: 'static, R: 'static,
{
    pub(crate) treeish: <D as Domain<N>>::Graph<N>,
    pub(crate) fold:    <D as Domain<N>>::Fold<H, R>,
}
}

Two slots:

  • treeish: <D as Domain<N>>::Graph<N> — direct child enumeration, N → N*.
  • fold: <D as Domain<N>>::Fold<H, R> — the algebra over N.

No grow step, no entry seeds. Execution starts from a &N root supplied to the executor.

Constructors

#![allow(unused)]
fn main() {
// Shared domain.
TreeishPipeline::<Shared, _, _, _>::new(
    treeish_arc,         // hylic::graph::Treeish<N>
    &fold,               // &shared::Fold<N, H, R>
);

// Local domain — note the `_local` suffix; Rust's inherent-method
// resolution can't disambiguate two `new`s on the same struct that
// differ only in the domain marker.
TreeishPipeline::<Local, _, _, _>::new_local(
    treeish_local,       // local::Edgy<N, N>
    fold_local,          // local::Fold<N, H, R>
);

// Domain-generic.
TreeishPipeline::<D, _, _, _>::from_slots(treeish, fold);
}

Stage-1 reshape

One sugar — there’s no grow axis to reshape and no seeds to filter:

methodoutput
map_node_bi(co, contra)TreeishPipeline<D, N2, H, R>

Provided by TreeishSugarsShared (Local mirror: TreeishSugarsLocal); see Sugars.

Stage 2

Two ways to enter:

  • Explicit: tree_pipeline.lift() returns Stage2Pipeline<TreeishPipeline<D, N, H, R>, IdentityLift>.
  • Auto-lift: every Stage-2 sugar is also callable directly on TreeishPipeline. tree_pipeline.wrap_init(w) is shorthand for tree_pipeline.lift().wrap_init(w).
#![allow(unused)]
fn main() {
    #[test]
    fn treeish_pipeline_chain() {
        use hylic_pipeline::prelude::*;

        #[derive(Clone)]
        struct Node { value: u64, children: Vec<Node> }
        let root = Node {
            value: 1,
            children: vec![
                Node { value: 2, children: vec![] },
                Node { value: 3, children: vec![] },
            ],
        };

        let tp: TreeishPipeline<Shared, Node, u64, u64> = TreeishPipeline::new(
            treeish(|n: &Node| n.children.clone()),
            &fold(|n: &Node| n.value, |h: &mut u64, c: &u64| *h += c, |h: &u64| *h),
        );

        let r: (u64, bool) = tp
            .wrap_init(|n: &Node, orig: &dyn Fn(&Node) -> u64| orig(n) + 1)
            .zipmap(|r: &u64| *r > 5)
            .run_from_node(&FUSED, &root);
        assert_eq!(r, (9, true));
    }
}

The chain’s input N stays at the user’s N (no wrap layer); the Wrap impl is Identity.

Running

#![allow(unused)]
fn main() {
let r = pipeline.run_from_node(&FUSED, &root);
}

PipelineExec::run_from_node(&exec, &root) is a blanket method on every TreeishSource. The first init runs on the supplied root. Returns the chain-tip R — the base fold’s R when no Stage-2 sugars are composed, otherwise whatever the rightmost lift produces.

Stage2Pipeline<TreeishPipeline<…>, L> inherits the same method through its TreeishSource impl; the call shape is identical.

Worked example

#![allow(unused)]
fn main() {
    #[test]
    fn treeish_pipeline_ctor() {
        use hylic_pipeline::prelude::*;

        #[derive(Clone)]
        struct Node { value: u64, children: Vec<Node> }
        let root = Node { value: 7, children: vec![] };

        let tp: TreeishPipeline<Shared, Node, u64, u64> = TreeishPipeline::new(
            treeish(|n: &Node| n.children.clone()),
            &fold(
                |n: &Node| n.value,
                |h: &mut u64, c: &u64| *h += c,
                |h: &u64| *h,
            ),
        );
        assert_eq!(tp.run_from_node(&FUSED, &root), 7);
    }
}