dfir_lang/graph/ops/
difference.rs

1use quote::{quote_spanned, ToTokens};
2use syn::parse_quote;
3
4use super::{
5    DelayType, OperatorCategory, OperatorConstraints, OperatorInstance,
6    OperatorWriteOutput, PortIndexValue, WriteContextArgs, RANGE_0, RANGE_1,
7};
8
9/// > 2 input streams of the same type T, 1 output stream of type T
10///
11/// Forms the set difference of the items in the input
12/// streams, returning items in the `pos` input that are not found in the
13/// `neg` input.
14///
15/// `difference` can be provided with one or two generic lifetime persistence arguments
16/// in the same way as [`join`](#join), see [`join`'s documentation](#join) for more info.
17///
18/// Note set semantics only for the `neg` input.
19///
20/// ```dfir
21/// source_iter(vec!["dog", "cat", "elephant"]) -> [pos]diff;
22/// source_iter(vec!["dog", "cat", "gorilla"]) -> [neg]diff;
23/// diff = difference() -> assert_eq(["elephant"]);
24/// ```
25pub const DIFFERENCE: OperatorConstraints = OperatorConstraints {
26    name: "difference",
27    categories: &[OperatorCategory::MultiIn],
28    hard_range_inn: &(2..=2),
29    soft_range_inn: &(2..=2),
30    hard_range_out: RANGE_1,
31    soft_range_out: RANGE_1,
32    num_args: 0,
33    persistence_args: &(0..=2),
34    type_args: RANGE_0,
35    is_external_input: false,
36    has_singleton_output: false,
37    flo_type: None,
38    ports_inn: Some(|| super::PortListSpec::Fixed(parse_quote! { pos, neg })),
39    ports_out: None,
40    input_delaytype_fn: |idx| match idx {
41        PortIndexValue::Path(path) if "neg" == path.to_token_stream().to_string() => {
42            Some(DelayType::Stratum)
43        }
44        _else => None,
45    },
46    write_fn: |wc @ &WriteContextArgs {
47                   op_span,
48                   ident,
49                   inputs,
50                   op_inst: OperatorInstance { .. },
51                   ..
52               },
53               diagnostics| {
54        let OperatorWriteOutput {
55            write_prologue,
56            write_iterator,
57            write_iterator_after,
58        } = (super::anti_join::ANTI_JOIN.write_fn)(wc, diagnostics)?;
59
60        let pos = &inputs[1];
61        let write_iterator = quote_spanned! {op_span=>
62            let #pos = #pos.map(|k| (k, ()));
63            #write_iterator
64            let #ident = #ident.map(|(k, ())| k);
65        };
66
67        Ok(OperatorWriteOutput {
68            write_prologue,
69            write_iterator,
70            write_iterator_after,
71        })
72    },
73};