• Home
Name Date Size #Lines LOC

..--

patches/03-May-2024-1513

src/03-May-2024-1,291389

.cargo_vcs_info.jsonD03-May-202494 66

Android.bpD03-May-2024776 3127

Cargo.tomlD03-May-20241.1 KiB3532

Cargo.toml.origD03-May-2024662 2822

LICENSED03-May-202411.1 KiB203169

METADATAD03-May-2024401 2019

MODULE_LICENSE_APACHE2D03-May-20240

OWNERSD03-May-202447 21

README.mdD03-May-20246.5 KiB228180

cargo2android.jsonD03-May-2024129 98

README.md

1[![Build Status](https://github.com/enarx/flagset/workflows/test/badge.svg)](https://github.com/enarx/flagset/actions)
2![Rust Version 1.36+](https://img.shields.io/badge/rustc-v1.36%2B-blue.svg)
3[![Crate](https://img.shields.io/crates/v/flagset.svg)](https://crates.io/crates/flagset)
4[![Docs](https://docs.rs/flagset/badge.svg)](https://docs.rs/flagset)
5![License](https://img.shields.io/crates/l/flagset.svg?style=popout)
6
7# Welcome to FlagSet!
8
9FlagSet is a new, ergonomic approach to handling flags that combines the
10best of existing crates like `bitflags` and `enumflags` without their
11downsides.
12
13## Existing Implementations
14
15The `bitflags` crate has long been part of the Rust ecosystem.
16Unfortunately, it doesn't feel like natural Rust. The `bitflags` crate
17uses a wierd struct format to define flags. Flags themselves are just
18integers constants, so there is little type-safety involved. But it doesn't
19have any dependencies. It also allows you to define implied flags (otherwise
20known as overlapping flags).
21
22The `enumflags` crate tried to improve on `bitflags` by using enumerations
23to define flags. This was a big improvement to the natural feel of the code.
24Unfortunately, there are some design flaws. To generate the flags,
25procedural macros were used. This implied two separate crates plus
26additional dependencies. Further, `enumflags` specifies the size of the
27flags using a `repr($size)` attribute. Unfortunately, this attribute
28cannot resolve type aliases, such as `c_int`. This makes `enumflags` a
29poor fit for FFI, which is the most important place for a flags library.
30The `enumflags` crate also disallows overlapping flags and is not
31maintained.
32
33FlagSet improves on both of these by adopting the `enumflags` natural feel
34and the `bitflags` mode of flag generation; as well as additional API usage
35niceties. FlagSet has no dependencies and is extensively documented and
36tested. It also tries very hard to prevent you from making mistakes by
37avoiding external usage of the integer types. FlagSet is also a zero-cost
38abstraction: all functions are inlineable and should reduce to the core
39integer operations. FlagSet also does not depend on stdlib, so it can be
40used in `no_std` libraries and applications.
41
42## Defining Flags
43
44Flags are defined using the `flags!` macro:
45
46```rust
47use flagset::{FlagSet, flags};
48use std::os::raw::c_int;
49
50flags! {
51    enum FlagsA: u8 {
52        Foo,
53        Bar,
54        Baz,
55    }
56
57    enum FlagsB: c_int {
58        Foo,
59        Bar,
60        Baz,
61    }
62}
63```
64
65Notice that a flag definition looks just like a regular enumeration, with
66the addition of the field-size type. The field-size type is required and
67can be either a type or a type alias. Both examples are given above.
68
69Also note that the field-size type specifies the size of the corresponding
70`FlagSet` type, not size of the enumeration itself. To specify the size of
71the enumeration, use the `repr($size)` attribute as specified below.
72
73## Flag Values
74
75Flags often need values assigned to them. This can be done implicitly,
76where the value depends on the order of the flags:
77
78```rust
79use flagset::{FlagSet, flags};
80
81flags! {
82    enum Flags: u16 {
83        Foo, // Implicit Value: 0b0001
84        Bar, // Implicit Value: 0b0010
85        Baz, // Implicit Value: 0b0100
86    }
87}
88```
89
90Alternatively, flag values can be defined explicitly, by specifying any
91`const` expression:
92
93```rust
94use flagset::{FlagSet, flags};
95
96flags! {
97    enum Flags: u16 {
98        Foo = 0x01,   // Explicit Value: 0b0001
99        Bar = 2,      // Explicit Value: 0b0010
100        Baz = 0b0100, // Explicit Value: 0b0100
101    }
102}
103```
104
105Flags can also overlap or "imply" other flags:
106
107```rust
108use flagset::{FlagSet, flags};
109
110flags! {
111    enum Flags: u16 {
112        Foo = 0b0001,
113        Bar = 0b0010,
114        Baz = 0b0110, // Implies Bar
115        All = (Flags::Foo | Flags::Bar | Flags::Baz).bits(),
116    }
117}
118```
119
120## Specifying Attributes
121
122Attributes can be used on the enumeration itself or any of the values:
123
124```rust
125use flagset::{FlagSet, flags};
126
127flags! {
128    #[derive(PartialOrd, Ord)]
129    enum Flags: u8 {
130        Foo,
131        #[deprecated]
132        Bar,
133        Baz,
134    }
135}
136```
137
138## Collections of Flags
139
140A collection of flags is a `FlagSet<T>`. If you are storing the flags in
141memory, the raw `FlagSet<T>` type should be used. However, if you want to
142receive flags as an input to a function, you should use
143`impl Into<FlagSet<T>>`. This allows for very ergonomic APIs:
144
145```rust
146use flagset::{FlagSet, flags};
147
148flags! {
149    enum Flags: u8 {
150        Foo,
151        Bar,
152        Baz,
153    }
154}
155
156struct Container(FlagSet<Flags>);
157
158impl Container {
159    fn new(flags: impl Into<FlagSet<Flags>>) -> Container {
160        Container(flags.into())
161    }
162}
163
164assert_eq!(Container::new(Flags::Foo | Flags::Bar).0.bits(), 0b011);
165assert_eq!(Container::new(Flags::Foo).0.bits(), 0b001);
166assert_eq!(Container::new(None).0.bits(), 0b000);
167```
168
169## Operations
170
171Operations can be performed on a `FlagSet<F>` or on individual flags:
172
173| Operator | Assignment Operator | Meaning                |
174|----------|---------------------|------------------------|
175| \|       | \|=                 | Union                  |
176| &        | &=                  | Intersection           |
177| ^        | ^=                  | Toggle specified flags |
178| -        | -=                  | Difference             |
179| %        | %=                  | Symmetric difference   |
180| !        |                     | Toggle all flags       |
181
182## Optional Serde support
183
184[Serde] support can be enabled with the 'serde' feature flag. You can then serialize and
185deserialize `FlagSet<T>` to and from any of the [supported formats]:
186
187 ```rust
188 use flagset::{FlagSet, flags};
189
190 flags! {
191     enum Flags: u8 {
192         Foo,
193         Bar,
194     }
195 }
196
197 let flagset = Flags::Foo | Flags::Bar;
198 let json = serde_json::to_string(&flagset).unwrap();
199 let flagset: FlagSet<Flags> = serde_json::from_str(&json).unwrap();
200 assert_eq!(flagset.bits(), 0b011);
201 ```
202
203For serialization and deserialization of flags enum itself, you can use the [`serde_repr`] crate
204(or implement `serde::ser::Serialize` and `serde:de::Deserialize` manually), combined with the
205appropriate `repr` attribute:
206
207 ```rust
208 use flagset::{FlagSet, flags};
209 use serde_repr::{Serialize_repr, Deserialize_repr};
210
211 flags! {
212    #[repr(u8)]
213    #[derive(Deserialize_repr, Serialize_repr)]
214    enum Flags: u8 {
215         Foo,
216         Bar,
217    }
218 }
219
220 let json = serde_json::to_string(&Flags::Foo).unwrap();
221 let flag: Flags = serde_json::from_str(&json).unwrap();
222 assert_eq!(flag, Flags::Foo);
223 ```
224
225[Serde]: https://serde.rs/
226[supported formats]: https://serde.rs/#data-formats
227[`serde_repr`]: https://crates.io/crates/serde_repr
228