3个版本
0.1.2 | 2024年5月19日 |
---|---|
0.1.1 | 2024年5月18日 |
0.1.0 | 2024年5月18日 |
#193 在 过程宏
每月 74 次下载
44KB
838 行
pack_bools
:一种简单的方法将结构体中的所有bool字段打包
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 的可见性修饰符(如pub
,pub(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_get
或no_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