#枚举 #变体 #常量 #关联 # #结构体类型

const-table

将结构体类型常量与枚举变体关联

1 个不稳定版本

0.1.0 2020年8月22日

91#常量

34 每月下载量
用于 simple-irc-server

MIT/Apache

18KB
163

#[const_table]

此crate提供了一种属性宏,用于将结构体类型的常量与枚举变体关联。

[dependencies]
const-table = "0.1"

语法

在至少有两个变体的枚举上放置 #[const_table],其中

  • 第一个变体具有命名字段并定义了相关常量的类型,
  • 所有后续变体都有该类型的区分表达式
#[const_table]
pub enum Planet {
    PlanetInfo {
        pub mass: f32,
        pub radius: f32,
    },

    Mercury = PlanetInfo { mass: 3.303e+23, radius: 2.4397e6 },
    Venus = PlanetInfo { mass: 4.869e+24, radius: 6.0518e6 },
    Earth = PlanetInfo { mass: 5.976e+24, radius: 6.37814e6 },
    Mars = PlanetInfo { mass: 6.421e+23, radius: 3.3972e6 },
    Jupiter = PlanetInfo { mass: 1.9e+27, radius: 7.1492e7 },
    Saturn = PlanetInfo { mass: 5.688e+26, radius: 6.0268e7 },
    Uranus = PlanetInfo { mass: 8.686e+25, radius: 2.5559e7 },
    Neptune = PlanetInfo { mass: 1.024e+26, radius: 2.4746e7 },
}

这将扩展为以下内容

#[repr(u32)]
#[derive(core::marker::Copy, core::clone::Clone, core::fmt::Debug, core::hash::Hash, core::cmp::PartialEq, core::cmp::Eq)]
pub enum Planet {
    Mercury,
    Venus,
    Earth,
    Mars,
    Jupiter,
    Saturn,
    Uranus,
    Neptune,
}

pub struct PlanetInfo {
    pub mass: f32,
    pub radius: f32,
}

impl Planet {
    const COUNT: usize = 8;
    pub fn iter() -> impl core::iter::DoubleEndedIterator<Item = Self> {
        // transmuting here is fine because... (see try_from)
        (0..Self::COUNT).map(|i| unsafe { core::mem::transmute(i as u32) })
    }
}

impl core::ops::Deref for Planet {
    type Target = PlanetInfo;
    fn deref(&self) -> &Self::Target {
        use Planet::*;
        const TABLE: [PlanetInfo; 8] = [
            PlanetInfo { mass: 3.303e+23, radius: 2.4397e6 },
            PlanetInfo { mass: 4.869e+24, radius: 6.0518e6 },
            PlanetInfo { mass: 5.976e+24, radius: 6.37814e6 },
            PlanetInfo { mass: 6.421e+23, radius: 3.3972e6 },
            PlanetInfo { mass: 1.9e+27, radius: 7.1492e7 },
            PlanetInfo { mass: 5.688e+26, radius: 6.0268e7 },
            PlanetInfo { mass: 8.686e+25, radius: 2.5559e7 },
            PlanetInfo { mass: 1.024e+26, radius: 2.4746e7 },
        ];

        &TABLE[*self as usize]
    }
}

impl core::convert::TryFrom<u32> for Planet {
    type Error = u32;
    fn try_from(i: u32) -> Result<Self, Self::Error> {
        if (i as usize) < Self::COUNT {
            // transmuting here is fine because all values in range are valid, since
            // discriminants are assigned linearly starting at 0.
            Ok(unsafe { core::mem::transmute(i) })
        } else {
            Err(i)
        }
    }
}

注意自动插入的 reprderive 属性。您可以像通常一样放置不同的 repr 属性,尽管只支持 u8u16u32u64;提供了一个 TryFrom<T> 实现,其中 T 是选择的 repr 类型。您还可以在枚举上派生额外的特质。

放置在第一个变体上的任何属性都将放置在展开代码中对应的结构体上。

此外,请注意,该宏将区分表达式放置在一个导入您枚举所有变体的作用域内。这使得使值相互引用变得方便,例如在类似图的结构中。

由于该宏为您枚举实现了 Deref,您可以通过 Planet::Earth.mass 这样的方式访问目标类型的字段。

最后,Planet::iter() 提供了按声明顺序遍历所有变体的 DoubleEndedIterator,而 Planet::COUNT 是变体的总数。

许可证

本软件许可协议适用于以下任一:Apache License, Version 2.0MIT 协议,具体取决于您的要求。

除非您明确表示,否则根据 Apache-2.0 许可证的定义,您有意提交并包含在此软件包中的任何贡献,都将如上所述双许可,不附加任何额外的条款或条件。

依赖关系

~1.5MB
~36K SLoC