From 993517e7c2877618e137c12cf660a3337473ab4f Mon Sep 17 00:00:00 2001 From: Zettroke Date: Sun, 18 Aug 2024 07:11:51 +0300 Subject: [PATCH 1/2] support multiple enums --- examples/example.rs | 5 ++ src/lib.rs | 117 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 108 insertions(+), 14 deletions(-) diff --git a/examples/example.rs b/examples/example.rs index 751571e..4e34d03 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -31,6 +31,11 @@ enum_dispatch!( #[cfg(feature = "platform_specific")] Cube(Cube), } + + #[derive(Debug, Clone)] + pub enum AnotherShape { + Rect(Rect) + } ); #[derive(Debug, Clone)] diff --git a/src/lib.rs b/src/lib.rs index 1ccfccd..38bc42c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,11 @@ enum_dispatch!( #[cfg(feature = "platform_specific")] Cube(Cube) } + + #[derive(Debug, Clone)] + pub enum AnotherShape { + Rect(Rect) + } ); #[derive(Debug, Clone)] pub struct Rect{ w: i32, h: i32 } @@ -97,7 +102,8 @@ impl ShapeTrait for Circle { assert_eq!(Shape::Rect(Rect { w: 1, h: 1 }).name(), "Rect".to_string()); -assert_eq!(Shape::Circle(Circle { r: 1 }).name(), "Circle".to_string()); +assert_eq!(Shape::from(Circle { r: 1 }).name(), "Circle".to_string()); +assert_eq!(AnotherShape::Rect(Rect { w: 1, h: 1 }).area(), 1); ``` ## Macro expansion @@ -211,6 +217,61 @@ impl From for Shape { } } +#[derive(Debug, Clone)] +pub enum AnotherShape { + Rect(Rect) +} + +impl ShapeTrait for AnotherShape { + /// No return + default implementation + fn print_name(&self) { + match self { + AnotherShape::Rect(v) => v.print_name(), + } + } + /// Basic call without arguments + fn name(&self) -> String { + match self { + AnotherShape::Rect(v) => v.name(), + } + } + fn area(&self) -> i32 { + match self { + AnotherShape::Rect(v) => v.area(), + } + } + /// Mutable self + arguments + fn grow(&mut self, numerator: i32, denominator: i32) { + match self { + AnotherShape::Rect(v) => v.grow(numerator, denominator), + } + } + /// Kinda supports generics :) Bot not generic parameters, only `impl Trait` + fn greater(&self, other: &impl ShapeTrait) -> bool { + match self { + AnotherShape::Rect(v) => v.greater(other), + } + } + /// Supports async methods + async fn send(&self) { + match self { + AnotherShape::Rect(v) => v.send().await, + } + } + /// Works with attributes + #[cfg(feature = "platform_specific")] + fn platform_specific(self) { + match self { + AnotherShape::Rect(v) => v.platform_specific(), + } + } +} +impl From for AnotherShape { + fn from(value: Rect) -> AnotherShape { + AnotherShape::Rect(value) + } +} + # #[derive(Debug, Clone)] # pub struct Rect { # w: i32, @@ -327,22 +388,22 @@ macro_rules! __munch_methods { } #[macro_export] -macro_rules! enum_dispatch { +#[doc(hidden)] +macro_rules! __munch_enums { + + ($train_name:ident, { $($trait_body:tt)* }, { }) => {}; ( - $(#[$trait_attr:meta])* - $trait_vis:vis trait $train_name:ident $(: $lf:lifetime)? $(: $super_trait1:ident $(::$super_trait2:ident)* $(+ $super_trait3:ident $(::$super_trait4:ident)*)*)? $(+ $lf2:lifetime)? { - $($any:tt)* - } + $train_name:ident, + { $($trait_body:tt)* }, + { + $(#[$enum_attr:meta])* + $enum_vis:vis enum $enum_name:ident { + $($(#[$var_attr:meta])* $variant:ident($variant_type:ty)),+$(,)? + } - $(#[$enum_attr:meta])* - $enum_vis:vis enum $enum_name:ident { - $($(#[$var_attr:meta])* $variant:ident($variant_type:ty)),+$(,)? + $($rest:tt)* } ) => { - $(#[$trait_attr])* - $trait_vis trait $train_name $(: $lf)? $(: $super_trait1 $(::$super_trait2)* $(+ $super_trait3 $(::$super_trait4)*)*)? $(+ $lf2)? { - $($any)* - } $(#[$enum_attr])* $enum_vis enum $enum_name { @@ -350,7 +411,7 @@ macro_rules! enum_dispatch { } impl $train_name for $enum_name { - $crate::__munch_methods!({ $($any)* }; [$($(#[$var_attr])* $variant),+]; $enum_name); + $crate::__munch_methods!({ $($trait_body)* }; [$($(#[$var_attr])* $variant),+]; $enum_name); } $( @@ -361,5 +422,33 @@ macro_rules! enum_dispatch { } } )+ + + + $crate::__munch_enums!($train_name, {$($trait_body)*}, { $($rest)* }); + + }; +} + +#[macro_export] +macro_rules! enum_dispatch { + ( + $(#[$trait_attr:meta])* + $trait_vis:vis trait $train_name:ident $(: $lf:lifetime)? $(: $super_trait1:ident $(::$super_trait2:ident)* $(+ $super_trait3:ident $(::$super_trait4:ident)*)*)? $(+ $lf2:lifetime)? { + $($trait_body:tt)* + } + + $($enums:tt)+ + ) => { + $(#[$trait_attr])* + $trait_vis trait $train_name $(: $lf)? $(: $super_trait1 $(::$super_trait2)* $(+ $super_trait3 $(::$super_trait4)*)*)? $(+ $lf2)? { + $($trait_body)* + } + + $crate::__munch_enums!( + $train_name, + { $($trait_body)* }, + { $($enums)+ } + ); + }; } From d3ec794f253e32a29bcf886d2fef5b6fc46326ff Mon Sep 17 00:00:00 2001 From: Zettroke Date: Sun, 18 Aug 2024 08:55:11 +0300 Subject: [PATCH 2/2] simplify patterns a bit --- src/lib.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 38bc42c..3fa4c46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -391,18 +391,17 @@ macro_rules! __munch_methods { #[doc(hidden)] macro_rules! __munch_enums { - ($train_name:ident, { $($trait_body:tt)* }, { }) => {}; + ($train_name:ident; { $($trait_body:tt)* }; ) => {}; ( - $train_name:ident, - { $($trait_body:tt)* }, - { - $(#[$enum_attr:meta])* - $enum_vis:vis enum $enum_name:ident { - $($(#[$var_attr:meta])* $variant:ident($variant_type:ty)),+$(,)? - } - - $($rest:tt)* + $train_name:ident; + { $($trait_body:tt)* }; + $(#[$enum_attr:meta])* + $enum_vis:vis enum $enum_name:ident { + $($(#[$var_attr:meta])* $variant:ident($variant_type:ty)),+$(,)? } + + $($rest:tt)* + ) => { $(#[$enum_attr])* @@ -424,7 +423,7 @@ macro_rules! __munch_enums { )+ - $crate::__munch_enums!($train_name, {$($trait_body)*}, { $($rest)* }); + $crate::__munch_enums!($train_name; {$($trait_body)*}; $($rest)*); }; } @@ -445,9 +444,9 @@ macro_rules! enum_dispatch { } $crate::__munch_enums!( - $train_name, - { $($trait_body)* }, - { $($enums)+ } + $train_name; + { $($trait_body)* }; + $($enums)+ ); };