Skip to main content

embedded_flow

Macro embedded_flow 

Source
macro_rules! embedded_flow {
    (
        $(#[$struct_meta:meta])*
        $vis:vis struct $name:ident {
            $( self_id($self_ref:ident : $self_ty:ty); )?
            $( membership($mem_path:path as $membership_ref:ident) {
                $($mem_name:ident),* $(,)?
            } )?
            $( inputs { $($in_name:ident : $in_ty:ty),* $(,)? } )?
            $( network_in($nin_path:path as $network_in_ref:ident) {
                $($nin_name:ident : $nin_ty:ty),* $(,)?
            } )?
            $( outputs($outputs_path:path as $outputs_ref:ident) {
                $($out_name:ident : $out_ty:ty),* $(,)?
            } )?
            $( network_out($nout_path:path as $network_out_ref:ident) {
                $($nout_name:ident : $nout_ty:ty),* $(,)?
            } )?
            build($($param:ident : $param_ty:ty),* $(,)?) $build_body:block
        }
    ) => { ... };
}
Available on crate feature embedded_runtime only.
Expand description

Declares a holder struct that owns a generated embedded DFIR flow (see hydro_lang::compile::embedded) together with the input buffers and output callback slots it borrows from, exposing an entirely safe API.

The generated struct has:

  • fn new(...) — constructs the buffers/slots and the flow (extra build parameters become parameters of new; a self_id section adds a leading self_id parameter).
  • one accessor per input / network-in / membership entry returning &InputBuffer<_>, to push items into;
  • one accessor per output / network-out entry returning &CallbackSlot<_>;
  • fn run(&self) — runs the flow until no more work is available (outputs emitted with no callback installed are dropped);
  • fn run_with(&self, ...) — runs the flow with a &mut dyn FnMut(_) callback installed for each output, then each network-out, in declaration order.

§Sections

All sections are optional except build, but must appear in the order shown. Each Path as binder clause names a struct generated by the embedded backend (e.g. my_fn::EmbeddedOutputs) and binds the value passed to the generated function to a local usable inside build. Input names are bound directly as stream locals.

hydro_lang::embedded_flow! {
    /// Holder for my flow.
    pub struct MyFlow {
        // For cluster locations: the member id of this instance.
        self_id(my_id: TaglessMemberId);
        // Cluster membership streams; field names are the cluster fn names.
        membership(my_fn::EmbeddedMembershipStreams as memberships) { other_cluster }
        inputs { events: MyEvent }
        network_in(my_fn::EmbeddedNetworkIn as net_in) {
            requests: Result<BytesMut, std::io::Error>,
        }
        outputs(my_fn::EmbeddedOutputs as outputs) { results: MyResult }
        network_out(my_fn::EmbeddedNetworkOut as net_out) { responses: Bytes }
        build(some_config: usize) {
            my_module::my_fn(my_id, memberships, events, outputs, net_in, net_out)
        }
    }
}

let flow = MyFlow::new(member_id, 42);
flow.events().push(event);
flow.run_with(
    &mut |result| println!("{result:?}"),
    &mut |response| network.send(response),
);

Item types must match the generated function’s parameter types exactly: network_in items are Result<BytesMut, io::Error> (tagged: Result<(TaglessMemberId, BytesMut), io::Error>) unless the channel uses external serialization, network_out items are Bytes (tagged: (TaglessMemberId, Bytes)), and membership items are always (TaglessMemberId, MembershipEvent).

§Caveats

  • The holder is single-threaded (!Send); construct and run it on one thread.
  • run / run_with panic if called re-entrantly from within an output callback (output callbacks may push new inputs, which are processed later in the same run).
  • Entry names are used as field and accessor names, so they must be distinct and must not be named flow or run; build parameters must not be named self_id, membership, inputs, network_in, outputs, or network_out.
  • The fields of the generated struct are self-referential; code in the defining module must never mutate or replace them (use the generated accessors instead).