Skip to main content

dfir_rs/util/
demux_enum.rs

1//! Trait for the `demux_enum` derive and operator.
2
3use std::task::{Context, Poll};
4
5pub use dfir_macro::DemuxEnum;
6use dfir_pipes::Toggle;
7use dfir_pipes::push::PushStep;
8
9/// Trait for use with the `demux_enum` operator (Sink-based version).
10///
11/// This trait is meant to be derived: `#[derive(DemuxEnum)]`.
12///
13/// The derive will implement this such that `Outputs` can be any tuple where each item is a
14/// `Sink` that corresponds to each of the variants of the tuple, in alphabetic order.
15#[diagnostic::on_unimplemented(
16    note = "ensure there is exactly one output for each enum variant.",
17    note = "ensure that the type for each output is a tuple of the field for the variant: `()`, `(a,)`, or `(a, b, ...)`."
18)]
19pub trait DemuxEnumSink<Outputs>: DemuxEnumBase {
20    /// The error type for pushing self into the `Outputs` `Sink`s.
21    type Error;
22
23    /// Call `poll_ready` on all `Outputs`.
24    fn poll_ready(outputs: &mut Outputs, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
25
26    /// Pushes `self` into the corresponding output sink in `outputs`.
27    fn start_send(self, outputs: &mut Outputs) -> Result<(), Self::Error>;
28
29    /// Call `poll_flush` on all `Outputs`.
30    fn poll_flush(outputs: &mut Outputs, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
31
32    /// Call `poll_close` on all `Outputs`.
33    fn poll_close(outputs: &mut Outputs, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
34}
35
36/// Trait for use with the `demux_enum` operator (Push-based version).
37///
38/// This trait is meant to be derived: `#[derive(DemuxEnum)]`.
39///
40/// The derive will implement this such that `Outputs` can be any tuple where each item is a
41/// `Push` that corresponds to each of the variants of the tuple, in alphabetic order.
42#[diagnostic::on_unimplemented(
43    note = "ensure there is exactly one output for each enum variant.",
44    note = "ensure that the type for each output is a tuple of the field for the variant: `()`, `(a,)`, or `(a, b, ...)`."
45)]
46pub trait DemuxEnumPush<Outputs, Meta: Copy>: DemuxEnumBase {
47    /// The context type, inherited from the downstream pushes.
48    type Ctx<'ctx>: dfir_pipes::Context<'ctx>;
49
50    /// Whether this push can return [`PushStep::Pending`], inherited from the
51    /// downstream pushes.
52    type CanPend: Toggle;
53
54    /// Poll readiness of all output pushes.
55    fn poll_ready(outputs: &mut Outputs, ctx: &mut Self::Ctx<'_>) -> PushStep<Self::CanPend>;
56
57    /// Pushes `self` into the corresponding output push in `outputs`.
58    fn start_send(self, meta: Meta, outputs: &mut Outputs);
59
60    /// Flushes all output pushes.
61    fn poll_flush(outputs: &mut Outputs, ctx: &mut Self::Ctx<'_>) -> PushStep<Self::CanPend>;
62}
63/// Special case of [`DemuxEnum`] for when there is only one variant.
64#[diagnostic::on_unimplemented(
65    note = "requires that the enum have only one variant.",
66    note = "ensure there are no missing outputs; there must be exactly one output for each enum variant."
67)]
68pub trait SingleVariant: DemuxEnumBase {
69    /// Output tuple type.
70    type Output;
71    /// Convert self into it's single variant tuple Output.
72    fn single_variant(self) -> Self::Output;
73}
74
75/// Base implementation to constrain that [`DemuxEnum<SOMETHING>`] is implemented.
76#[diagnostic::on_unimplemented(note = "use `#[derive(dfir_rs::DemuxEnum)]`")]
77pub trait DemuxEnumBase {}