#枚举 #过程宏 # #判别式 #程序性的

enum_ext

增强枚举类型的方法和转换的过程宏

5个版本

0.2.2 2024年5月26日
0.2.1 2024年5月19日
0.1.3 2024年5月18日

#644 in Rust模式

MIT/Apache

48KB
713

枚举扩展库

Rust Dependency Review Crate API

此Rust包提供了proceduralattribute宏,用于增强Rust枚举类型的方法和转换。它通过自动生成常见任务的实用方法(如获取所有变体列表、计数变体以及在不同判别式和整型类型之间转换)来简化枚举的使用。

请参阅下面的enum_ext!#[enum_extend]宏示例,获取更多信息。

这两个宏生成相同的实用方法,因此您可以选择最适合您编码风格的宏。

实用函数

  • list():返回包含枚举所有变体的数组。
  • count():返回枚举中的变体数量。
  • ordinal():返回变体的序号(索引)。
  • from_ordinal(ordinal: usize):返回与给定序号对应的变体。
  • ref_from_ordinal(ordinal: usize):返回指向与给定序号对应的变体的引用。
  • valid_ordinal(ordinal: usize):检查给定的序号是否对枚举有效。
  • iter():返回枚举所有变体的迭代器。
  • from_<IntType>(value: <IntType>)as_<IntType>(&self):将指定整数类型进行转换,如果在该属性中定义了。
    • 例如,如果 IntType = "i32",则 from_i32(10)as_i32(),或者如果 IntType = "u32",则 from_u32(10)as_u32(),等等。
  • pascal_spaced(&self):将变体名称转换为空格分隔的 PascalCase。例如,InQA 变为 "In QA"
  • from_pascal_spaced(name: &str):返回对应于空格分隔的 PascalCase 名称的变体。例如,"In QA" 变为 InQA
  • pretty_print():返回一个格式化的字符串,显示枚举及其所有变体,以漂亮的打印格式。
  • 更多内容即将到来...:请继续关注其他实用函数和特性。

请查看示例存储库中获取更多信息属性.

属性是可选的,用于自定义生成的函数。

IntType 目前是唯一支持的属性,用于指定转换方法的判别类型。生成的函数允许将此类型转换为枚举变体,反之亦然。支持的类型包括标准 Rust 整数类型,如 i32u32i64 等。如果没有指定此属性,则使用 usize 作为默认值。

  • 注意:如果枚举有判别值,则向枚举中添加 #[derive(Clone)](如果尚未存在)。
    • 属性分配略有不同,取决于使用的宏。

使用 enum_extend 时,属性直接应用于标签

使用 enum_ext! 时,属性应用于宏的 enum_def 参数

use enum_ext::enum_extend;

// example with no attribute
#[enum_extend]
#[derive(Debug, Clone, PartialEq)]
pub enum Discr1 {
    A = 10,
    B = 20,
    C = 30,
}

// example with an attribute
#[enum_extend(IntType = "i32")]  // <- `IntType` is the discriminant type for conversion methods
#[derive(Debug, Clone, PartialEq)]
pub enum Discr2 {
    A = 10,
    B = 20,
    C = 30,
}

使用

use enum_ext::enum_ext;

enum_ext!(
    #[enum_def(IntType = "i32")]  // <- `IntType` is the discriminant type. 
    #[derive(Debug, Clone, PartialEq)]
    pub enum AdvancedEnum {
        A = 10,  
        B = 20,
        C = 30,
    }
);

用法

使用 #[enum_extend] 属性宏

要使用 enum_extend 属性宏,只需将其包含在你的 Rust 项目中,并将其应用于你的枚举定义。以下是一个示例:

fn main() {
    use enum_ext::enum_extend;

    #[enum_extend(IntType = "i32")]
    #[derive(Debug, Default, Clone, PartialEq)]
    pub enum AdvancedEnum {
        #[default]
        A = 10,
        B = 20,
        C = 30,
    }

    for x in AdvancedEnum::iter() {
        let i = x.as_i32();
        let v = AdvancedEnum::from_i32(i).unwrap();
        assert_eq!(i, v.as_i32());
        assert_eq!(*x, v); // This comparison requires that PartialEq be derived
    }

    let v = AdvancedEnum::from_i32(20).unwrap();
    assert_eq!(v, AdvancedEnum::B);
}

使用 enum_ext! 过程宏

要使用 enum_ext! 宏,只需将其包含在你的 Rust 项目中,并将其应用于你的枚举定义。以下是一个示例:

fn main() {
    use enum_ext::enum_ext;

    enum_ext!(
        #[derive(Debug, Clone, PartialEq)]
        pub enum SimpleEnum {
            A,
            B,
            C,
        }
    );
    // With this, you can now use the generated methods on SimpleEnum:
    let x = SimpleEnum::B;
    assert_eq!(x.ordinal(), 1); // B is the second variant, so its ordinal is 1

    let mut count = 0;

    // enum_ext gives enums an iterator and variants can be iterated over
    for x in SimpleEnum::iter() {
        // The ordinal of the variant can be retrieved
        let i = x.ordinal();
        assert_eq!(i, count);
        count += 1;
    }

    // enums also get a list method that returns an array of all variants
    let list = SimpleEnum::list();
    assert_eq!(list, [SimpleEnum::A, SimpleEnum::B, SimpleEnum::C]);

    enum_ext!(
        #[derive(Debug, Clone, Default, PartialEq)]
        pub enum TicketStatus {
            #[default]
            Open,
            InDev,
            Completed,
            InQA,
            CodeReview,
            FinalQA,
            FinalCodeReview,
            Accepted,
            Closed,
        }
    );

    // enums now have a pascal_spaced method that returns the variant name in spaced PascalCase.
    // This is useful for displaying enum variants in a user-friendly format (e.g., in a UI).
    // One example usage is converting InQA to "In QA" for display on a web page.
    let status = TicketStatus::InQA;
    assert_eq!(status.pascal_spaced(), "In QA");

    // enums also get a from_pascal_spaced method that returns the variant from the spaced PascalCase name.
    // This is useful for converting user-friendly format back to an enum variant.
    // This is the reverse of the example above, converting "In QA" back to an enum.
    let status2 = TicketStatus::from_pascal_spaced("In QA").unwrap();
    assert_eq!(status2, TicketStatus::InQA);
}

为枚举变体生成了额外的实用方法

use enum_ext::enum_extend;

#[enum_extend(IntType = "i32")]
#[derive(Debug, PartialEq)]
pub enum DevelopmentStatus {
    InDev = 10,
    InQA = 20,
    CodeReview = 30,
    FinalQA = 40,
    FinalCodeReview = 50,
    Accepted = 60,
    Closed = 70,
}

fn main() {
    // Using list()
    let variants = DevelopmentStatus::list();
    assert_eq!(variants,
               [DevelopmentStatus::InDev,
                   DevelopmentStatus::InQA,
                   DevelopmentStatus::CodeReview,
                   DevelopmentStatus::FinalQA,
                   DevelopmentStatus::FinalCodeReview,
                   DevelopmentStatus::Accepted,
                   DevelopmentStatus::Closed]);

    // Using count()
    let count = DevelopmentStatus::count();
    assert_eq!(count, 7);

    // Using ordinal()
    let ordinal = DevelopmentStatus::CodeReview.ordinal();
    assert_eq!(ordinal, 2);  // CodeReview is the third variant, so its ordinal is 2
    assert_eq!(DevelopmentStatus::from_ordinal(2), Some(DevelopmentStatus::CodeReview));

    // Using iter()
    for (i, variant) in DevelopmentStatus::iter().enumerate() {
        assert_eq!(i, variant.ordinal());
    }

    // Using from_i32() and as_i32()
    let variant = DevelopmentStatus::from_i32(20).unwrap();
    assert_eq!(variant, DevelopmentStatus::InQA);
    assert_eq!(variant.as_i32(), 20);

    // Using pascal_spaced() method that returns the variant name in spaced PascalCase.
    // This is useful for displaying enum variants in a user-friendly format (e.g., in a UI).
    // One example usage is converting InQA to "In QA" for display on a web page.
    let status = DevelopmentStatus::InQA;
    assert_eq!(status.pascal_spaced(), "In QA");

    // Using from_pascal_spaced() method that returns the variant from the spaced PascalCase name.
    // This is useful for converting user-friendly format back to an enum variant.
    // This is the reverse of the example above, converting "In QA" back to an enum.
    let status2 = DevelopmentStatus::from_pascal_spaced("In QA").unwrap();
    assert_eq!(status2, DevelopmentStatus::InQA);
}

入门指南

将以下内容添加到你的 Cargo.toml 文件中

[dependencies]
enum_ext = "0.2.2"

依赖项

~250–690KB
~17K SLoC