#位字段 #打包 #

pack_bools

将结构体中所有布尔字段打包到位字段中的属性宏

3个版本

0.1.2 2024年5月19日
0.1.1 2024年5月18日
0.1.0 2024年5月18日

#193过程宏

Download history 367/week @ 2024-05-15 52/week @ 2024-05-22

每月 74 次下载

MIT 协议

44KB
838

pack_bools:一种简单的方法将结构体中的所有bool字段打包

Crates.io Docs.rs License: MIT

pack_bools将具有布尔字段的struct转换为包含整数和位标志的结构体,每个布尔值一个位标志

use pack_bools::pack_bools;

#[pack_bools]
#[derive(Debug, Clone)]
struct Config<'a> {
    output_name: &'a str,
    verbose: bool,
    pub use_colors: bool,
    original_file: &'a std::path::Path,
    legacy_mode: bool
}

转换为如下内容

#[derive(Debug, Clone)]
struct Config<'a> {
    output_name: &'a str,
    original_file: &'a std::path::Path,
    packed_bools: u8
}

impl<'a> Config<'a> {
    fn get_verbose(&self) -> bool {
        self.packed_bools & 1 << 0 != 0
    }

    fn set_verbose(&mut self, value: bool) {
        if value {
            self.packed_bools |= 1 << 0;
        } else {
            self.packed_bools &= !(1 << 0);
        }
    }

    pub fn get_use_colors(&self) -> bool {
        self.packed_bools & 1 << 1 != 0
    }

    pub fn set_use_colors(&mut self, value: bool) {
        if value {
            self.packed_bools |= 1 << 1;
        } else {
            self.packed_bools &= !(1 << 1);
        }
    }

    /* getters and setters for legacy_mode omitted */
}

用法

只需在您的项目目录中运行 cargo add pack_bools,然后 use pack_bools::pack_bools; 并在您的结构体顶部添加 #[pack_bools] 宏。默认情况下,这将像上面的示例那样操作:将所有类型为 bool 的字段替换为单个数值字段 packed_bools,并为每个字段添加获取器和设置器。默认情况下,获取器和设置器的可见性将继承自字段,因此如果字段声明为 pub(super),则获取器和设置器也将是公开的。

通过向 #[pack_bools(..)] 属性添加选项,您可以配置整个结构体的选项,使用 全局选项。此外,您还可以将 #[pack_bools(..)] 添加到 boolean 字段,以使用 局部选项 配置该字段的选项。

全局选项

当在结构体上使用 #[pack_bools(..)] 时,可用的全局选项

  • #[pack_bools(getters = [vis] [name])] 修改了获取器的名称和可见性。
    • 使用 % 作为字段名称的替换。
    • 如果省略名称,则将使用默认名称模板。
    • vis 是 Rust 的可见性修饰符(如 pubpub(super) 等)。使用 self 来引用字段的可见性(否则 vis 为空意味着私有可见性,如 Rust 中所示)。
    • 示例:使用 #[pack_bools(getters = pub get_field_%)] 将所有获取器设置为公共,名称为 get_field_ 后跟字段名称。一个名为 foo 的字段将因此获得一个签名 pub fn get_field_foo(&self) -> bool 的获取器。
    • 示例:使用 #[pack_bools(getters = self%)] 将所有获取器的名称与字段名称相同,具有与字段相同的可见性。
    • 由于模板为空而字段名称保持不变,并且 Rust 使用无修饰符的私有项,因此仅使用 #[pack_bools(getters = )] 将所有获取器设置为私有,名称为 get_ 后跟字段名称(默认模板)。为了清晰起见,建议使用 #[pack_bools(getters = get_%)]
    • 别名为 get/getter。对于设置器,使用 #[pack_bools(set/setter/setters)]
    • 默认值是 #[pack_bools(get = self get_%, set = self set_%)]
  • #[pack_bools(no_getters)] 将不会生成获取器(别名为 no_getno_getter
  • 类似地,#[pack_bools(no_set/no_setter/no_setters)] 也不会生成设置器。
  • #[pack_bools(type = u16)] 将使用 u16 作为位标志的数据类型。可用选项有 u8 / u16 / u32 / u64 / u128 / auto(默认选项),其中 auto 会自动使用可以容纳所有布尔值的这些类型中最小的一个。
  • #[pack_bools(field = <name>)] 将设置包含位标志的字段名称,默认为 packed_bools
  • #[pack_bools(inline)] 将使用内联模式为位标志字段,即创建 packed_bools: u8 模式的字段。这是默认选项。与下面的 newtype 相比。
  • #[pack_bools(newtype [= name])] 将创建一个新的单值元组结构体来存储位标志,类似于 struct MyStructPackedBools(u8);。如果指定了名称,则新类型结构体将以该名称定义,否则将在结构体名称后添加 PackedBools。本文档顶部的示例,带有 #[pack_bools(newtype)],将被编译为
#[derive(Debug, Clone)]
struct Config<'a> {
    output_name: &'a str,
    original_file: &'a std::path::Path,
    packed_bools: ConfigPackedBools
}

#[derive(Copy, Clone, Debug)]
#[repr(transparent)]
struct ConfigPackedBools(u8);

impl<'a> Config<'a> {
    fn get_verbose(&self) -> bool {
        self.packed_bools.0 & 1 << 0 != 0
    }

    fn set_verbose(&mut self, value: bool) {
        if value {
            self.packed_bools.0 |= 1 << 0;
        } else {
            self.packed_bools.0 &= !(1 << 0);
        }
    }

    /* additional getters and setters omitted */
}

局部选项

您可以在 bool 类型的字段上添加 #[pack_bools(..)] 属性来配置该特定字段的输出。可用选项有

  • #[pack_bools(skip)] 将该字段排除,使其不与其他布尔值一起打包。
  • #[pack_bools(getter = [vis] [name]) 更改getter的名称(以及可能的可视性),使其与该字段对应。
    • 这使用了一个具体名称而不是模板,否则它的语法与全局的#[pack_bools(getter = ..)] 属性相同,见上文。
    • #[pack_bools(getter = pub debug_mode)] 添加到字段 debug: bool 将创建一个类似 pub fn debug_mode(&self) -> bool { .. } 的getter。别名 get
    • 对于setter,使用#[pack_bools(set/setter = [vis] [name])]
  • #[pack_bools(no_getter)] 跳过为该字段生成getter。别名 no_get。对于setter,使用 #[pack_bools(no_set/no_setter)]
  • #[pack_bools(默认 = <true/false>)] 用于设置字段的默认值。如果设置为 true,则必须使用 newtype 模式,但此时将为该 newtype 生成一个 impl Default,该字段被设置为 true。如果结构体中其他所有字段都有合适的默认值,这将允许你在结构体上使用 #[derive(Default)],同时将某些布尔值设置为 true。默认为 false

更新日志

0.1.0

  • 首次提交

0.1.1

  • 修复了一些小的文档错误

0.1.2

  • self 添加为继承可见性修饰符。
  • #[pack_bools(获取 = ..)] 中将名称设置为可选,适用于全局和本地配置

依赖项

~265–710KB
~17K SLoC