dfir_lang/graph/ops/
cross_singleton.rs
1use quote::{ToTokens, quote_spanned};
2use syn::parse_quote;
3
4use super::{
5 DelayType, OperatorCategory, OperatorConstraints, OperatorWriteOutput, RANGE_0, RANGE_1,
6 WriteContextArgs,
7};
8use crate::graph::PortIndexValue;
9
10pub const CROSS_SINGLETON: OperatorConstraints = OperatorConstraints {
31 name: "cross_singleton",
32 categories: &[OperatorCategory::MultiIn],
33 persistence_args: RANGE_0,
34 type_args: RANGE_0,
35 hard_range_inn: &(2..=2),
36 soft_range_inn: &(2..=2),
37 hard_range_out: RANGE_1,
38 soft_range_out: RANGE_1,
39 num_args: 0,
40 is_external_input: false,
41 has_singleton_output: false,
42 flo_type: None,
43 ports_inn: Some(|| super::PortListSpec::Fixed(parse_quote! { input, single })),
44 ports_out: None,
45 input_delaytype_fn: |idx| match idx {
46 PortIndexValue::Path(path) if "single" == path.to_token_stream().to_string() => {
47 Some(DelayType::Stratum)
48 }
49 _else => None,
50 },
51 write_fn: |wc @ &WriteContextArgs {
52 context,
53 df_ident,
54 ident,
55 op_span,
56 inputs,
57 is_pull,
58 work_fn,
59 ..
60 },
61 _diagnostics| {
62 assert!(is_pull);
63
64 let stream_input = &inputs[0];
65 let singleton_input = &inputs[1];
66 let singleton_handle_ident = wc.make_ident("singleton_handle");
67
68 let write_prologue = quote_spanned! {op_span=>
69 let #singleton_handle_ident = #df_ident.add_state(
70 ::std::cell::RefCell::new(::std::option::Option::None)
71 );
72 #df_ident.set_state_tick_hook(#singleton_handle_ident, |rcell| { rcell.take(); });
74 };
75
76 let write_iterator = quote_spanned! {op_span=>
77 let #ident = {
78 #[inline(always)]
79 fn cross_singleton_guard<Singleton, Item, SingletonIter, Stream>(
80 mut singleton_state_mut: std::cell::RefMut<'_, Option<Singleton>>,
81 mut singleton_input: SingletonIter,
82 stream_input: Stream,
83 ) -> impl use<Item, Singleton, Stream, SingletonIter> + Iterator<Item = (Item, Singleton)>
84 where
85 Singleton: ::std::clone::Clone,
86 SingletonIter: Iterator<Item = Singleton>,
87 Stream: Iterator<Item = Item>,
88 {
89 let singleton_value_opt = #work_fn(|| match &*singleton_state_mut {
90 ::std::option::Option::Some(singleton_value) => Some(singleton_value.clone()),
91 ::std::option::Option::None => {
92 let singleton_value_opt = singleton_input.next();
93 *singleton_state_mut = singleton_value_opt.clone();
94 singleton_value_opt
95 }
96 });
97 singleton_value_opt
98 .map(|singleton_value| {
99 stream_input.map(move |item| (item, ::std::clone::Clone::clone(&singleton_value)))
100 })
101 .into_iter()
102 .flatten()
103 }
104 cross_singleton_guard(
105 unsafe {
106 #context.state_ref_unchecked(#singleton_handle_ident)
108 }.borrow_mut(),
109 #singleton_input,
110 #stream_input,
111 )
112 };
113 };
114
115 Ok(OperatorWriteOutput {
116 write_prologue,
117 write_iterator,
118 ..Default::default()
119 })
120 },
121};