Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/toshokan/flag-mast
Ergonomic Rust bit flags
https://github.com/toshokan/flag-mast
bitflags ffi proc-macro rust
Last synced: about 20 hours ago
JSON representation
Ergonomic Rust bit flags
- Host: GitHub
- URL: https://github.com/toshokan/flag-mast
- Owner: toshokan
- Created: 2020-12-29T06:56:58.000Z (about 4 years ago)
- Default Branch: master
- Last Pushed: 2020-12-29T18:24:00.000Z (about 4 years ago)
- Last Synced: 2024-12-15T04:48:18.915Z (26 days ago)
- Topics: bitflags, ffi, proc-macro, rust
- Language: Rust
- Homepage:
- Size: 33.2 KB
- Stars: 0
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# flag-mast
Ergonomic Rust bit flags
[![Crates.io](https://img.shields.io/crates/v/flag-mast)](https://crates.io/crates/flag-mast)
[![Docs.rs](https://docs.rs/flag-mast/badge.svg)](https://docs.rs/flag-mast)
[![GitHub top language](https://img.shields.io/github/languages/top/toshokan/flag-mast)](https://github.com/toshokan/flag-mast)## Usage
The `flag-mast` crate provides a derive macro to help create ergonomic C-compatible bit flags.### Example
```rust
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");
}
}
```The derive macro does not change the underlying layout of the struct, it can even be `repr(C)`!.
The `name` argument is the canonical name of the flag, which need not be a valid Rust identifier or follow idiomatic Rust naming conventions.
If the `name` argument _is_ appropriate as a Rust identifier (and you don't want to customize or prefix it), the `method_name` argument can be ommitted.
The `value` argument can either be an integer literal or a string containing an expression which resolves to the value for the flag.
The `value` needn't have to have the same exact type as the backing field, it only has to be castable to that type.
The `flag_backing_field` attribute specifies which field of the struct is used to hold the bit flags.
This means we can also have
```rust
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!");
}
}
```### Automatic Debug Implementation
The derive macro can also automatically generate a `Debug` implementation for you in a way that makes sense for your flags.
This behaviour is controlled by an additional attribute.```rust
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);
}
```This will print (note that the _method name_ is used)
```
Buttons { one: true, two: false, three: true }
---
Buttons {
one: true,
two: false,
three: false
}
```You can also choose a (potentially) more compact debug format by specifying the `compact` argument to the `flag_debug` attribute.
This format only displays the flags that are set.```rust
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);
}
```This will print (note that the _name_ is used)
```
Buttons { "one", "second" }
---
Buttons {
"one",
"second",
}
```## License
`flag-mast` is dual licensed under the MIT license and the Apache 2.0 license. You may choose whichever one you prefer.