Skip to content

Commit

Permalink
refactor: simplify demux_enum(), somewhat improves error messages #…
Browse files Browse the repository at this point in the history
  • Loading branch information
MingweiSamuel committed May 20, 2024
1 parent 041bcf9 commit 826dbd9
Show file tree
Hide file tree
Showing 18 changed files with 289 additions and 181 deletions.
49 changes: 14 additions & 35 deletions hydroflow/src/util/demux_enum.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,22 @@
//! Traits for the `demux_enum` derive and operator.
//! Trait for the `demux_enum` derive and operator.

pub use hydroflow_macro::DemuxEnum;
use pusherator::demux::PusheratorList;
use pusherator::Pusherator;
use variadics::Variadic;

/// Trait for use with the `demux_enum` operator.
///
/// This trait is meant to be derived: `#[derive(DemuEnum)]`.
pub trait DemuxEnum<Nexts>: DemuxEnumItems
where
Nexts: PusheratorListForItems<Self::Items>,
{
/// Pushes self into the corresponding output pusherator.
fn demux_enum(self, outputs: &mut Nexts);
}

/// Fixed output item list for [`DemuxEnum`].
/// This trait is meant to be derived: `#[derive(DemuxEnum)]`.
///
/// This trait is meant to be derived: `#[derive(DemuEnum)]`.
pub trait DemuxEnumItems {
/// A `var_type!(...)` list of items corresponding to each variant's output type.
type Items: Variadic;
/// The derive will implement this such that `Outputs` can be any tuple where each item is a
/// `Pusherator` that corresponds to each of the variants of the tuple, in alphabetic order.
#[diagnostic::on_unimplemented(
note = "Ensure there is exactly one output for each enum variant.",
note = "Ensure that the type for each output is a tuple of the field for the variant: `()`, `(a,)`, or `(a, b, ...)`."
)]
pub trait DemuxEnum<Outputs>: DemuxEnumBase {
/// Pushes self into the corresponding output pusherator in `outputs`.
fn demux_enum(self, outputs: &mut Outputs);
}

/// Helper trait to bound a [`PusheratorList`] variadic to some coresponding item list variadic.
///
/// A pusherator list `var_type!(PushA, PushB, PushC)` implements `PusheratorListForItems<var_type!(ItemA, ItemB, ItemC)>`,
/// where `PushA: Pusherator<Item = ItemA>`, etc.
pub trait PusheratorListForItems<Items>: PusheratorList
where
Items: Variadic,
{
}
impl<HeadPush, RestPush, Head, Rest> PusheratorListForItems<(Head, Rest)> for (HeadPush, RestPush)
where
HeadPush: Pusherator<Item = Head>,
RestPush: PusheratorListForItems<Rest>,
Rest: Variadic,
{
}
impl PusheratorListForItems<()> for () {}
/// Base implementation to constrain that `DemuxEnum<SOMETHING>` is implemented.
#[diagnostic::on_unimplemented(note = "Use `#[derive(hydroflow::DemuxEnum)]`")]
pub trait DemuxEnumBase {}
69 changes: 9 additions & 60 deletions hydroflow/tests/compile-fail/surface_demuxenum_notenum.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
error[E0277]: the trait bound `Shape: DemuxEnumItems` is not satisfied
error[E0277]: the trait bound `Shape: DemuxEnumBase` is not satisfied
--> tests/compile-fail/surface_demuxenum_notenum.rs:12:28
|
12 | ]) -> demux_enum::<Shape>();
| ^^^^^ the trait `DemuxEnumItems` is not implemented for `Shape`
| ^^^^^ the trait `DemuxEnumBase` is not implemented for `Shape`
|
= note: Use `#[derive(hydroflow::DemuxEnum)]`
note: required by a bound in `check_impl_demux_enum`
--> tests/compile-fail/surface_demuxenum_notenum.rs:8:18
|
Expand Down Expand Up @@ -62,72 +63,20 @@ help: if there were a trait named `Example` with associated type `Square` implem
15 | my_demux[<Shape as Example>::Square] -> for_each(std::mem::drop);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0277]: the trait bound `Shape: DemuxEnumItems` is not satisfied
--> tests/compile-fail/surface_demuxenum_notenum.rs:12:15
|
12 | ]) -> demux_enum::<Shape>();
| ^^^^^^^^^^^^^^^^^^^^^ the trait `DemuxEnumItems` is not implemented for `Shape`

error[E0277]: the trait bound `Shape: DemuxEnum<_>` is not satisfied
--> tests/compile-fail/surface_demuxenum_notenum.rs:12:28
|
12 | ]) -> demux_enum::<Shape>();
| ^^^^^ the trait `DemuxEnum<_>` is not implemented for `Shape`
|
note: required by a bound in `__typeguard_demux_enum_fn`
--> tests/compile-fail/surface_demuxenum_notenum.rs:8:18
|
8 | let mut df = hydroflow_syntax! {
| __________________^
9 | | my_demux = source_iter([
10 | | Shape { area: 10.0 },
11 | | Shape { area: 9.0 },
... |
16 | | my_demux[Ellipse] -> for_each(std::mem::drop);
17 | | };
| |_____^ required by this bound in `__typeguard_demux_enum_fn`
= note: this error originates in the macro `hydroflow_syntax` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Shape: DemuxEnum<(impl Pusherator<Item = _>, (impl Pusherator<Item = _>, (impl Pusherator<Item = _>, (impl Pusherator<Item = _>, ()))))>` is not satisfied
--> tests/compile-fail/surface_demuxenum_notenum.rs:12:15
|
12 | ]) -> demux_enum::<Shape>();
| ^^^^^^^^^^^^^^^^^^^^^ the trait `DemuxEnum<(impl Pusherator<Item = _>, (impl Pusherator<Item = _>, (impl Pusherator<Item = _>, (impl Pusherator<Item = _>, ()))))>` is not implemented for `Shape`
|
note: required by a bound in `__typeguard_demux_enum_fn`
--> tests/compile-fail/surface_demuxenum_notenum.rs:8:18
|
8 | let mut df = hydroflow_syntax! {
| __________________^
| __________________-
9 | | my_demux = source_iter([
10 | | Shape { area: 10.0 },
11 | | Shape { area: 9.0 },
... |
16 | | my_demux[Ellipse] -> for_each(std::mem::drop);
17 | | };
| |_____^ required by this bound in `__typeguard_demux_enum_fn`
= note: this error originates in the macro `hydroflow_syntax` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Shape: DemuxEnum<(impl Pusherator<Item = _>, (impl Pusherator<Item = _>, (impl Pusherator<Item = _>, (impl Pusherator<Item = _>, ()))))>` is not satisfied
--> tests/compile-fail/surface_demuxenum_notenum.rs:9:20
|
9 | my_demux = source_iter([
| ____________________^
10 | | Shape { area: 10.0 },
11 | | Shape { area: 9.0 },
12 | | ]) -> demux_enum::<Shape>();
| |___________________________________^ the trait `DemuxEnum<(impl Pusherator<Item = _>, (impl Pusherator<Item = _>, (impl Pusherator<Item = _>, (impl Pusherator<Item = _>, ()))))>` is not implemented for `Shape`
|
note: required by a bound in `__typeguard_demux_enum_fn`
--> tests/compile-fail/surface_demuxenum_notenum.rs:8:18
|
8 | let mut df = hydroflow_syntax! {
| __________________^
9 | | my_demux = source_iter([
10 | | Shape { area: 10.0 },
11 | | Shape { area: 9.0 },
| | ^^^^^^^^^^^^^^^^^^^^^ the trait `DemuxEnum<_>` is not implemented for `Shape`
... |
16 | | my_demux[Ellipse] -> for_each(std::mem::drop);
17 | | };
| |_____^ required by this bound in `__typeguard_demux_enum_fn`
= note: this error originates in the macro `hydroflow_syntax` (in Nightly builds, run with -Z macro-backtrace for more info)
| |_____- required by a bound introduced by this call
|
= note: Ensure there is exactly one output for each enum variant.
= note: Ensure that the type for each output is a tuple of the field for the variant: `()`, `(a,)`, or `(a, b, ...)`.
27 changes: 19 additions & 8 deletions hydroflow/tests/compile-fail/surface_demuxenum_port_extra.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,31 @@ error[E0599]: no variant named `Ellipse` found for enum `Shape`
| ^^^^^^^ variant not found in `Shape`

error[E0308]: mismatched types
--> tests/compile-fail/surface_demuxenum_port_extra.rs:12:18
--> tests/compile-fail/surface_demuxenum_port_extra.rs:17:15
|
12 | let mut df = hydroflow_syntax! {
| __________________^
| __________________-
13 | | my_demux = source_iter([
14 | | Shape::Rectangle { w: 10.0, h: 8.0 },
15 | | Shape::Square(9.0),
... |
16 | | Shape::Circle { r: 5.0 },
17 | | ]) -> demux_enum::<Shape>();
| | ^^^^^^^^^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements
18 | | my_demux[Rectangle] -> for_each(std::mem::drop);
| | ------------------------ one of the found opaque types
19 | | my_demux[Circle] -> for_each(std::mem::drop);
| | ------------------------ one of the found opaque types
20 | | my_demux[Square] -> for_each(std::mem::drop);
| | ------------------------ the found opaque type
| | ------------------------ one of the found opaque types
21 | | my_demux[Ellipse] -> for_each(std::mem::drop);
| | ------------------------ one of the found opaque types
22 | | };
| |_____^ expected `()`, found `(impl Pusherator<Item = _>, ())`
| |_____- arguments to this function are incorrect
|
= note: expected unit type `()`
found tuple `(impl Pusherator<Item = _>, ())`
= note: this error originates in the macro `$crate::var_expr` which comes from the expansion of the macro `hydroflow_syntax` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: expected mutable reference `&mut (_, _, _)`
found mutable reference `&mut (impl Pusherator<Item = _>, impl Pusherator<Item = _>, impl Pusherator<Item = _>, impl Pusherator<Item = _>)`
note: method defined here
--> src/util/demux_enum.rs
|
| fn demux_enum(self, outputs: &mut Outputs);
| ^^^^^^^^^^
23 changes: 16 additions & 7 deletions hydroflow/tests/compile-fail/surface_demuxenum_port_missing.stderr
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
error[E0308]: mismatched types
--> tests/compile-fail/surface_demuxenum_port_missing.rs:12:18
--> tests/compile-fail/surface_demuxenum_port_missing.rs:17:15
|
12 | let mut df = hydroflow_syntax! {
| __________________^
| __________________-
13 | | my_demux = source_iter([
14 | | Shape::Rectangle { w: 10.0, h: 8.0 },
15 | | Shape::Square(9.0),
... |
16 | | Shape::Circle { r: 5.0 },
17 | | ]) -> demux_enum::<Shape>();
| | ^^^^^^^^^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 2 elements
18 | | my_demux[Rectangle] -> for_each(std::mem::drop);
| | ------------------------ one of the found opaque types
19 | | my_demux[Circle] -> for_each(std::mem::drop);
| | ------------------------ one of the found opaque types
20 | | };
| |_____^ expected `(_, ())`, found `()`
| |_____- arguments to this function are incorrect
|
= note: expected tuple `(_, ())`
found unit type `()`
= note: this error originates in the macro `$crate::var_expr` which comes from the expansion of the macro `hydroflow_syntax` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: expected mutable reference `&mut (_, _, _)`
found mutable reference `&mut (impl Pusherator<Item = _>, impl Pusherator<Item = _>)`
note: method defined here
--> src/util/demux_enum.rs
|
| fn demux_enum(self, outputs: &mut Outputs);
| ^^^^^^^^^^
3 changes: 1 addition & 2 deletions hydroflow/tests/compile-fail/surface_demuxenum_wrongenum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ fn main() {
Shape::Rectangle { w: 10.0, h: 8.0 },
Shape::Square(9.0),
Shape::Circle { r: 5.0 },
]) -> demux_enum::<Option>();
]) -> demux_enum::<Option<()>>();
my_demux[Rectangle] -> for_each(std::mem::drop);
my_demux[Circle] -> for_each(std::mem::drop);
my_demux[Square] -> for_each(std::mem::drop);
my_demux[Square] -> for_each(std::mem::drop);
};
df.run_available();
}
87 changes: 81 additions & 6 deletions hydroflow/tests/compile-fail/surface_demuxenum_wrongenum.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,86 @@
error: Output connection conflicts with below ($DIR/tests/compile-fail/surface_demuxenum_wrongenum.rs:21:18) (1/2)
error[E0277]: the trait bound `std::option::Option<()>: DemuxEnumBase` is not satisfied
--> tests/compile-fail/surface_demuxenum_wrongenum.rs:17:28
|
17 | ]) -> demux_enum::<Option<()>>();
| ^^^^^^^^^^ the trait `DemuxEnumBase` is not implemented for `std::option::Option<()>`
|
= note: Use `#[derive(hydroflow::DemuxEnum)]`
= help: the trait `DemuxEnumBase` is implemented for `Shape`
note: required by a bound in `check_impl_demux_enum`
--> tests/compile-fail/surface_demuxenum_wrongenum.rs:12:18
|
12 | let mut df = hydroflow_syntax! {
| __________________^
13 | | my_demux = source_iter([
14 | | Shape::Rectangle { w: 10.0, h: 8.0 },
15 | | Shape::Square(9.0),
... |
20 | | my_demux[Square] -> for_each(std::mem::drop);
21 | | };
| |_____^ required by this bound in `check_impl_demux_enum`
= note: this error originates in the macro `hydroflow_syntax` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: no variant named `Circle` found for enum `std::option::Option<()>`
--> tests/compile-fail/surface_demuxenum_wrongenum.rs:19:18
|
19 | my_demux[Circle] -> for_each(std::mem::drop);
| ^^^^^^ variant not found in `std::option::Option<()>`

error[E0599]: no variant named `Rectangle` found for enum `std::option::Option<()>`
--> tests/compile-fail/surface_demuxenum_wrongenum.rs:18:18
|
18 | my_demux[Rectangle] -> for_each(std::mem::drop);
| ^^^^^^^^^ variant not found in `std::option::Option<()>`

error[E0599]: no variant named `Square` found for enum `std::option::Option<()>`
--> tests/compile-fail/surface_demuxenum_wrongenum.rs:20:18
|
20 | my_demux[Square] -> for_each(std::mem::drop);
| ^^^^^^
| ^^^^^^ variant not found in `std::option::Option<()>`

error[E0277]: the trait bound `std::option::Option<()>: DemuxEnum<_>` is not satisfied
--> tests/compile-fail/surface_demuxenum_wrongenum.rs:17:15
|
12 | let mut df = hydroflow_syntax! {
| __________________-
13 | | my_demux = source_iter([
14 | | Shape::Rectangle { w: 10.0, h: 8.0 },
15 | | Shape::Square(9.0),
16 | | Shape::Circle { r: 5.0 },
17 | | ]) -> demux_enum::<Option<()>>();
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `DemuxEnum<_>` is not implemented for `std::option::Option<()>`
... |
20 | | my_demux[Square] -> for_each(std::mem::drop);
21 | | };
| |_____- required by a bound introduced by this call
|
= note: Ensure there is exactly one output for each enum variant.
= note: Ensure that the type for each output is a tuple of the field for the variant: `()`, `(a,)`, or `(a, b, ...)`.
= help: the trait `DemuxEnum<(__PusheratorCircle, __PusheratorRectangle, __PusheratorSquare)>` is implemented for `Shape`

error: Output connection conflicts with above ($DIR/tests/compile-fail/surface_demuxenum_wrongenum.rs:20:18) (2/2)
--> tests/compile-fail/surface_demuxenum_wrongenum.rs:21:18
error[E0271]: type mismatch resolving `<impl Pusherator<Item = Option<()>> as Pusherator>::Item == Shape`
--> tests/compile-fail/surface_demuxenum_wrongenum.rs:17:15
|
13 | my_demux = source_iter([
| ____________________-
14 | | Shape::Rectangle { w: 10.0, h: 8.0 },
15 | | Shape::Square(9.0),
16 | | Shape::Circle { r: 5.0 },
17 | | ]) -> demux_enum::<Option<()>>();
| | ^^^^^^^^^^^^^^^^^^^^^^^^^-
| |_______________|________________________|
| | required by a bound introduced by this call
| expected `Shape`, found `Option<()>`
|
= note: expected enum `Shape`
found enum `std::option::Option<()>`
note: required by a bound in `pivot_run_sg_1v1`
--> tests/compile-fail/surface_demuxenum_wrongenum.rs:13:20
|
21 | my_demux[Square] -> for_each(std::mem::drop);
| ^^^^^^
13 | my_demux = source_iter([
| ____________________^
14 | | Shape::Rectangle { w: 10.0, h: 8.0 },
15 | | Shape::Square(9.0),
16 | | Shape::Circle { r: 5.0 },
17 | | ]) -> demux_enum::<Option<()>>();
| |________________________________________^ required by this bound in `pivot_run_sg_1v1`
23 changes: 23 additions & 0 deletions hydroflow/tests/compile-fail/surface_demuxenum_wrongfields_1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use hydroflow::util::demux_enum::DemuxEnum;
use hydroflow::hydroflow_syntax;

fn main() {
#[derive(DemuxEnum)]
enum Shape {
Square(f64),
Rectangle { w: f64, h: f64 },
Circle { r: f64 },
}

let mut df = hydroflow_syntax! {
my_demux = source_iter([
Shape::Rectangle { w: 10.0, h: 8.0 },
Shape::Square(9.0),
Shape::Circle { r: 5.0 },
]) -> demux_enum::<Shape>();
my_demux[Rectangle] -> for_each(std::mem::drop);
my_demux[Circle] -> for_each(std::mem::drop);
my_demux[Square] -> for_each(|side: u32| ());
};
df.run_available();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
error[E0271]: type mismatch resolving `<impl Pusherator<Item = u32> as Pusherator>::Item == (f64,)`
--> tests/compile-fail/surface_demuxenum_wrongfields_1.rs:17:15
|
12 | let mut df = hydroflow_syntax! {
| __________________-
13 | | my_demux = source_iter([
14 | | Shape::Rectangle { w: 10.0, h: 8.0 },
15 | | Shape::Square(9.0),
16 | | Shape::Circle { r: 5.0 },
17 | | ]) -> demux_enum::<Shape>();
| | ^^^^^^^^^^^^^^^^^^^^^ expected `(f64,)`, found `u32`
... |
20 | | my_demux[Square] -> for_each(|side: u32| ());
21 | | };
| |_____- required by a bound introduced by this call
|
= note: expected tuple `(f64,)`
found type `u32`
note: required for `Shape` to implement `DemuxEnum<(impl Pusherator<Item = (f64,)>, impl Pusherator<Item = (f64, f64)>, impl Pusherator<Item = u32>)>`
--> tests/compile-fail/surface_demuxenum_wrongfields_1.rs:5:14
|
5 | #[derive(DemuxEnum)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
6 | enum Shape {
| ^^^^^
= note: associated types for the current `impl` cannot be restricted in `where` clauses
= note: associated types for the current `impl` cannot be restricted in `where` clauses
= note: associated types for the current `impl` cannot be restricted in `where` clauses
= note: this error originates in the derive macro `DemuxEnum` (in Nightly builds, run with -Z macro-backtrace for more info)
Loading

0 comments on commit 826dbd9

Please sign in to comment.