Skip to content

Commit

Permalink
add nested function
Browse files Browse the repository at this point in the history
  • Loading branch information
TOwInOK committed Oct 26, 2024
1 parent 48a50dc commit 40e4f88
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 31 deletions.
115 changes: 85 additions & 30 deletions src/gen_enum.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,79 @@
/// A macro for generating enums with a string representation of their variants.
/// A macro for generating enums with string representation capabilities.
///
/// This macro provides a convenient way to define enums with a specified set of variants.
/// It automatically implements the `Debug` trait and provides a conversion from a reference
/// of the enum to a string slice that contains the variant name.
/// # Description
/// This macro creates an enum with specified variants and implements conversion
/// from a reference of the enum to a string slice (`&str`). It also provides
/// methods to get string representations of nested enum variants.
///
/// There are two forms of the macro:
/// # Generated Methods
/// - `From<&T> for &str`: returns current variant name
/// - `nested_str()`: returns string representation one level down
/// - `deepest_str()`: recursively gets the deepest nested variant name
///
/// 1. **Without nested types:**
/// ```rust
/// use anime_grubber::gen_enum;
/// # Examples
///
/// gen_enum!(MyEnum, [VariantA, VariantB, VariantC]);
/// ```
/// This will generate an enum `MyEnum` with variants `VariantA`, `VariantB`, and `VariantC`.
/// 1. Simple variants without associated data:
/// ```rust
/// use anime_grubber::gen_enum;
///
/// 2. **With nested types:**
/// ```rust
/// use anime_grubber::gen_enum;
/// gen_enum!(SimpleEnum, [First, Second, Third]);
///
/// gen_enum!(MyEnumWithData, [VariantA(u32), VariantB(String)]);
/// ```
/// This will generate an enum `MyEnumWithData` with variants `VariantA` that holds a `u32`
/// and `VariantB` that holds a `String`.
/// let variant = SimpleEnum::First;
/// assert_eq!(<&str>::from(&variant), "First");
/// assert_eq!(variant.deepest_str(), "First");
/// ```
///
/// # Examples
/// 2. Simple nested enum:
/// ```rust
/// use anime_grubber::gen_enum;
///
/// gen_enum!(Inner, [One, Two]);
/// gen_enum!(Outer, [Value(Inner)]);
///
/// let nested = Outer::Value(Inner::One);
/// assert_eq!(<&str>::from(&nested), "Value"); // Current variant
/// assert_eq!(nested.nested_str(), "One"); // One level down
/// assert_eq!(nested.deepest_str(), "One"); // Deepest level
/// ```
///
/// 3. Deep nested example (5 levels):
/// ```rust
/// use anime_grubber::gen_enum;
/// // Generating a simple enum
/// gen_enum!(SimpleEnum, [VariantOne, VariantTwo, VariantThree]);
///
/// let variant = SimpleEnum::VariantOne;
/// let converted: &str = (&variant).into();
/// assert_eq!(converted, "VariantOne");
/// gen_enum!(Level5, [Five, Six]);
/// gen_enum!(Level4, [Fourth(Level5)]);
/// gen_enum!(Level3, [Third(Level4)]);
/// gen_enum!(Level2, [Second(Level3)]);
/// gen_enum!(Level1, [First(Level2)]);
///
/// let deep = Level1::First(
/// Level2::Second(
/// Level3::Third(
/// Level4::Fourth(
/// Level5::Five
/// )
/// )
/// )
/// );
///
/// // Get current level variant name
/// assert_eq!(<&str>::from(&deep), "First");
///
/// // Get the deepest nested value
/// assert_eq!(deep.deepest_str(), "Five");
///
/// // Generating an enum with nested types
/// gen_enum!(DataEnum, [ValueA(u32), ValueB(String)]);
/// // Access intermediate levels through destructuring
/// let Level1::First(level2) = deep;
/// assert_eq!(<&str>::from(&level2), "Second");
///
/// let variant_with_data = DataEnum::ValueA(10);
/// let converted: &str = (&variant_with_data).into();
/// assert_eq!(converted, "ValueA");
/// let Level2::Second(level3) = level2;
/// assert_eq!(<&str>::from(&level3), "Third");
///
/// let Level3::Third(level4) = level3;
/// assert_eq!(<&str>::from(&level4), "Fourth");
///
/// let Level4::Fourth(level5) = level4;
/// assert_eq!(<&str>::from(&level5), "Five");
/// ```
#[macro_export]
macro_rules! gen_enum {
Expand All @@ -59,6 +93,11 @@ macro_rules! gen_enum {
}
}
}
impl $name {
pub fn deepest_str(&self) -> &str {
<&str>::from(self)
}
}
};
($name:tt, [ $($variant:ident($nested:ty)),* $(,)? ]) => {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
Expand All @@ -71,7 +110,23 @@ macro_rules! gen_enum {
fn from(value: &$name) -> Self {
match value {
$(
$name::$variant(value) => value.into(),
$name::$variant(_) => stringify!($variant),
)*
}
}
}
impl $name {
pub fn nested_str(&self) -> &str {
match self {
$(
$name::$variant(inner) => <&str>::from(inner),
)*
}
}
pub fn deepest_str(&self) -> &str {
match self {
$(
$name::$variant(inner) => inner.deepest_str(),
)*
}
}
Expand Down
31 changes: 30 additions & 1 deletion tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mod test {
use anime_grubber::{
agent::Agent,
agents::waifu_pics::{Categories, Waifu, SFW},
url,
gen_enum, url,
};
use std::sync::LazyLock;
use tracing::info;
Expand Down Expand Up @@ -48,4 +48,33 @@ mod test {
assert_eq!(&url, expected);
Ok(())
}
#[test]
fn deep_nested_enum() {
gen_enum!(Level5, [Five, Six]);
gen_enum!(Level4, [Fourth(Level5)]);
gen_enum!(Level3, [Third(Level4)]);
gen_enum!(Level2, [Second(Level3)]);
gen_enum!(Level1, [First(Level2)]);

let deep = Level1::First(Level2::Second(Level3::Third(Level4::Fourth(Level5::Five))));

// Проверяем прямое преобразование каждого уровня
assert_eq!(<&str>::from(&deep), "First");

// Проверяем получение самого глубокого значения
assert_eq!(deep.deepest_str(), "Five");

// Проверяем каждый уровень через деструктуризацию
let Level1::First(level2) = deep;
assert_eq!(<&str>::from(&level2), "Second");

let Level2::Second(level3) = level2;
assert_eq!(<&str>::from(&level3), "Third");

let Level3::Third(level4) = level3;
assert_eq!(<&str>::from(&level4), "Fourth");

let Level4::Fourth(level5) = level4;
assert_eq!(<&str>::from(&level5), "Five");
}
}

0 comments on commit 40e4f88

Please sign in to comment.