5 个版本

0.2.1 2020 年 12 月 29 日
0.2.0 2020 年 12 月 29 日
0.1.2 2020 年 12 月 29 日
0.1.1 2020 年 12 月 29 日
0.1.0 2020 年 12 月 29 日

#1433 in Rust 模式


用于 termorrow

MIT/Apache

5KB
88

flag-mast

人体工程学 Rust 位标志

Crates.io Docs.rs GitHub top language

用法

flag-mast 包提供了一个 derive 宏,帮助创建符合人体工程学的 C 兼容位标志。

示例

use flag_mast::*;

#[derive(Flags, Default)]
#[flag(name = "BARKS", method_name = "can_bark", value = 0x1)]
#[flag(name = "SITS", method_name = "can_sit", value = 0x2)]
#[flag(name = "BROWN", method_name = "is_brown", value = 0x4)]
struct Dog(#[flag_backing_field] u32);

fn foo() {
  let mut dog = Dog::default();
  dog.set_can_bark(true)
     .set_can_sit(false)
     .set_is_brown(true);
	 
  if dog.is_brown() {
    println!("Cute doggo!");
  } else {
    println!("Doggo is not brown, but is cute anyway");
  }
}

derive 宏不会改变结构体的底层布局,甚至可以是 repr(C)!。

name 参数是标志的规范名称,它不需要是一个有效的 Rust 标识符或遵循 Rust 命名惯例。

如果 name 参数 作为 Rust 标识符适当的(并且你不想自定义或前缀它),则可以省略 method_name 参数。

value 参数可以是整数字面量或包含求解标志值的表达式的字符串。

value 不必与支持字段具有相同的精确类型,只需可转换为该类型。

flag_backing_field 属性指定结构体中用于存储位标志的字段。

这意味着我们也可以有

use flag_mast::*;

const BLUE: u8 = 0x1;
const RED: u8 = 0x2;

mod secondary_colours {
  pub const YELLOW: u16 = 0x4;
}


#[derive(Flags, Default)]
#[flag(name = "blue", value = "BLUE")]
#[flag(name = "red", value = "RED")]
#[flag(name = "yellow", value = "secondary_colours::YELLOW")]
#[flag(name = "purple", value = "BLUE & RED")]
#[flag(name = "black", value = 0x8)]
#[repr(C)]
struct Colour{
  is_useful: bool,
  #[flag_backing_field] 
  flags: u32
}

fn bar() {
  let mut colour = Colour::default();
  colour.set_blue(true);
  colour.set_red(true);
  
  if colour.purple() {
    println("That's red AND blue!");
  }
}

自动 Debug 实现

derive 宏还可以自动为你生成一个符合你标志的 Debug 实现。这种行为由一个额外的属性控制。

use flag_mast::*;

#[derive(Flags, Default)]
#[flag_debug]
#[flag(name = "one", value = 4)]
#[flag(name = "second", method_name = "two", value = 8)]
#[flag(name = "three", value = 16)]
struct Buttons(#[flag_backing_field] u16)

fn baz() {
  let mut buttons = Buttons::default();
  buttons.set_one(true);
  
  println!("{:?}", buttons);
  println!("---");
  println!("{:#?}", buttons);
}

这将打印(注意使用的是 方法名称

Buttons { one: true, two: false, three: true }
---
Buttons {
    one: true,
    two: false,
    three: false
}

你也可以通过指定 flag_debug 属性的 compact 参数来选择(可能)更紧凑的调试格式。此格式仅显示已设置的标志。

use flag_mast::*;

#[derive(Flags, Default)]
#[flag_debug(compact)]
#[flag(name = "one", value = 4)]
#[flag(name = "second", method_name = "two", value = 8)]
#[flag(name = "three", value = 16)]
struct Buttons(#[flag_backing_field] u16)

fn baz() {
  let mut buttons = Buttons::default();
  buttons.set_one(true);
  buttons.set_two(true);
  
  println!("{:?}", buttons);
  println!("---");
  println!("{:#?}", buttons);
}

这将打印(注意使用的是 名称

Buttons { "one", "second" }
---
Buttons {
    "one",
    "second",
}

许可证

flag-mast 在 MIT 许可证和 Apache 2.0 许可证下双许可。你可以选择你喜欢的任何一个。

依赖项

~1.5MB
~36K SLoC