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
}
) => { ... };
}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 (extrabuildparameters become parameters ofnew; aself_idsection adds a leadingself_idparameter).- one accessor per input / network-in / membership entry returning
&InputBuffer<_>, topushitems 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_withpanic 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
floworrun;buildparameters must not be namedself_id,membership,inputs,network_in,outputs, ornetwork_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).