summaryrefslogtreecommitdiffstats
path: root/extra/bitflags/spec.md
blob: 43dae1d79d367020430732fb9e8fedfa7c07b746 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
# Bitflags

`bitflags` generates flags enums with well-defined semantics and ergonomic end-user APIs.

You can use `bitflags` to:

- provide more user-friendly bindings to C APIs where flags may or may not be fully known in advance.
- generate efficient options types with string parsing and formatting support.

You can't use `bitflags` to:

- guarantee only bits corresponding to defined flags will ever be set. `bitflags` allows access to the underlying bits type so arbitrary bits may be set.
- define bitfields. `bitflags` only generates types where set bits denote the presence of some combination of flags.

## Definitions

This section formally defines the terminology and semantics of `bitflags`. It's organized so more fundamental concepts are introduced before those that build on them. It may be helpful to start from the bottom of the section and refer back up to concepts defined earlier.

Examples use `bitflags` syntax with `u8` as the bits type.

### Bits type

A type that defines a fixed number of bits at specific locations.

----

Bits types are typically fixed-width unsigned integers. For example, `u8` is a bits type that defines 8 bits; bit-0 through bit-7.

### Bits value

An instance of a bits type where each bit may be set (`1`) or unset (`0`).

----

Some examples of bits values for the bits type `u8` are:

```rust
0b0000_0000
0b1111_1111
0b1010_0101
```

#### Equality

Two bits values are equal if their bits are in the same configuration; set bits in one are set in the other, and unset bits in one are unset in the other.

#### Operations

Bits values define the bitwise operators and (`&`), or (`|`), exclusive-or (`^`), and negation (`!`) that apply to each of their bits.

### Flag

A set of bits in a bits type that may have a unique name.

----

Bits are not required to be exclusive to a flag. Bits are not required to be contiguous.

The following is a flag for `u8` with the name `A` that includes bit-0:

```rust
const A = 0b0000_0001;
```

The following is a flag for `u8` with the name `B` that includes bit-0, and bit-5:

```rust
const B = 0b0010_0001;
```

#### Named flag

A flag with a name.

----

The following is a named flag, where the name is `A`:

```rust
const A = 0b0000_0001;
```

#### Unnamed flag

A flag without a name.

----

The following is an unnamed flag:

```rust
const _ = 0b0000_0001;
```

#### Zero-bit flag

A flag with a set of zero bits.

----

The following is a zero-bit flag:

```rust
const ZERO = 0b0000_0000;
```

#### Single-bit flag

A flag with a set of one bit.

----

The following are single-bit flags:

```rust
const A = 0b0000_0001;
const B = 0b0000_0010;
```

#### Multi-bit flag

A flag with a set of more than one bit.

----

The following are multi-bit flags:

```rust
const A = 0b0000_0011;
const B = 0b1111_1111;
```

### Flags type

A set of defined flags over a specific bits type.

#### Known bit

A bit in any defined flag.

----

In the following flags type:

```rust
struct Flags {
    const A = 0b0000_0001;
    const B = 0b0000_0010;
    const C = 0b0000_0100;
}
```

the known bits are:

```rust
0b0000_0111
```

#### Unknown bit

A bit not in any defined flag.

----

In the following flags type:

```rust
struct Flags {
    const A = 0b0000_0001;
    const B = 0b0000_0010;
    const C = 0b0000_0100;
}
```

the unknown bits are:

```rust
0b1111_1000
```

### Flags value

An instance of a flags type using its specific bits value for storage.

The flags value of a flag is one where each of its bits is set, and all others are unset.

#### Contains

Whether all set bits in a source flags value are also set in a target flags value.

----

Given the flags value:

```rust
0b0000_0011
```

the following flags values are contained:

```rust
0b0000_0000
0b0000_0010
0b0000_0001
0b0000_0011
```

but the following flags values are not contained:

```rust
0b0000_1000
0b0000_0110
```

#### Intersects

Whether any set bits in a source flags value are also set in a target flags value.

----

Given the flags value:

```rust
0b0000_0011
```

the following flags intersect:

```rust
0b0000_0010
0b0000_0001
0b1111_1111
```

but the following flags values do not intersect:

```rust
0b0000_0000
0b1111_0000
```

#### Empty

Whether all bits in a flags value are unset.

----

The following flags value is empty:

```rust
0b0000_0000
```

The following flags values are not empty:

```rust
0b0000_0001
0b0110_0000
```

#### All

Whether all defined flags are contained in a flags value.

----

Given a flags type:

```rust
struct Flags {
    const A   = 0b0000_0001;
    const B   = 0b0000_0010;
}
```

the following flags values all satisfy all:

```rust
0b0000_0011
0b1000_0011
0b1111_1111
```

### Operations

Examples in this section all use the given flags type:

```rust
struct Flags {
    const A = 0b0000_0001;
    const B = 0b0000_0010;
    const C = 0b0000_1100;
}
```

#### Truncate

Unset all unknown bits in a flags value.

----

Given the flags value:

```rust
0b1111_1111
```

the result of truncation will be:

```rust
0b0000_1111
```

----

Truncating doesn't guarantee that a non-empty result will contain any defined flags. Given the following flags type:

```rust
struct Flags {
    const A = 0b0000_0101;
}
```

and the following flags value:

```rust
0b0000_1110;
```

The result of truncation will be:

```rust
0b0000_0100;
```

which intersects the flag `A`, but doesn't contain it.

This behavior is possible even when only operating with flags values containing defined flags. Given the following flags type:

```rust
struct Flags {
    const A = 0b0000_0101;
    const B = 0b0000_0001;
}
```

The result of `A ^ B` is `0b0000_0100`, which also doesn't contain any defined flag.

----

If all known bits are in the set of at least one defined single-bit flag, then all operations that produce non-empty results will always contain defined flags.

#### Union

The bitwise or (`|`) of the bits in two flags values.

----

The following are examples of the result of unioning flags values:

```rust
0b0000_0001 | 0b0000_0010 = 0b0000_0011
0b0000_0000 | 0b1111_1111 = 0b1111_1111
```

#### Intersection

The bitwise and (`&`) of the bits in two flags values.

----

The following are examples of the result of intersecting flags values:

```rust
0b0000_0001 & 0b0000_0010 = 0b0000_0000
0b1111_1100 & 0b1111_0111 = 0b1111_0100
0b1111_1111 & 0b1111_1111 = 0b1111_1111
```

#### Symmetric difference

The bitwise exclusive-or (`^`) of the bits in two flags values.

----

The following are examples of the symmetric difference between two flags values:

```rust
0b0000_0001 ^ 0b0000_0010 = 0b0000_0011
0b0000_1111 ^ 0b0000_0011 = 0b0000_1100
0b1100_0000 ^ 0b0011_0000 = 0b1111_0000
```

#### Complement

The bitwise negation (`!`) of the bits in a flags value, truncating the result.

----

The following are examples of the complement of a flags value:

```rust
!0b0000_0000 = 0b0000_1111
!0b0000_1111 = 0b0000_0000
!0b1111_1000 = 0b0000_0111
```

#### Difference

The bitwise union (`|`) of the bits in one flags value and the bitwise negation (`!`) of the bits in another.

----

This operation is not equivalent to the intersection of one flags value with the complement of another (`&!`).
The former will truncate the result, where difference will not.

----

The following are examples of the difference between two flags values:

```rust
0b0000_0001 & !0b0000_0010 = 0b0000_0001
0b0000_1101 & !0b0000_0011 = 0b0000_1100
0b1111_1111 & !0b0000_0001 = 0b1111_1110
```

### Iteration

Yield the bits of a source flags value in a set of contained flags values.

----

To be most useful, each yielded flags value should set exactly the bits of a defined flag contained in the source. Any known bits that aren't in the set of any contained flag should be yielded together as a final flags value.

----

Given the following flags type:

```rust
struct Flags {
    const A  = 0b0000_0001;
    const B  = 0b0000_0010;
    const AB = 0b0000_0011;
}
```

and the following flags value:

```rust
0b0000_1111
```

When iterated it may yield a flags value for `A` and `B`, then a final flag with the unknown bits:

```rust
0b0000_0001
0b0000_0010
0b0000_1100
```

It may also yield a flags value for `AB`, then a final flag with the unknown bits:

```rust
0b0000_0011
0b0000_1100
```

----

Given the following flags type:

```rust
struct Flags {
    const A = 0b0000_0011;
}
```

and the following flags value:

```rust
0b0000_0001
```

When iterated it will still yield a flags value for the known bit `0b0000_0001` even though it doesn't contain a flag.

### Formatting

Format and parse a flags value as text using the following grammar:

- _Flags:_ (_Whitespace_ _Flag_ _Whitespace_)`|`*
- _Flag:_ _Name_ | _Hex Number_
- _Name:_ The name of any defined flag
- _Hex Number_: `0x`([0-9a-fA-F])*
- _Whitespace_: (\s)*

Flags values can be formatted as _Flags_ by iterating over them, formatting each yielded flags value as a _Flag_. Any yielded flags value that sets exactly the bits of a defined flag with a name should be formatted as a _Name_. Otherwise it must be formatted as a _Hex Number_.

Formatting and parsing supports three modes:

- **Retain**: Formatting and parsing roundtrips exactly the bits of the source flags value. This is the default behavior.
- **Truncate**: Flags values are truncated before formatting, and truncated after parsing.
- **Strict**: A _Flag_ may only be formatted and parsed as a _Name_. _Hex numbers_ are not allowed. A consequence of this is that unknown bits and any bits that aren't in a contained named flag will be ignored. This is recommended for flags values serialized across API boundaries, like web services.

Text that is empty or whitespace is an empty flags value.

----

Given the following flags type:

```rust
struct Flags {
    const A  = 0b0000_0001;
    const B  = 0b0000_0010;
    const AB = 0b0000_0011;
    const C  = 0b0000_1100;
}
```

The following are examples of how flags values can be formatted using any mode:

```rust
0b0000_0000 = ""
0b0000_0001 = "A"
0b0000_0010 = "B"
0b0000_0011 = "A | B"
0b0000_0011 = "AB"
0b0000_1111 = "A | B | C"
```

Truncate mode will unset any unknown bits:

```rust
0b1000_0000 = ""
0b1111_1111 = "A | B | C"
0b0000_1000 = "0x8"
```

Retain mode will include any unknown bits as a final _Flag_:

```rust
0b1000_0000 = "0x80"
0b1111_1111 = "A | B | C | 0xf0"
0b0000_1000 = "0x8"
```

Strict mode will unset any unknown bits, as well as bits not contained in any defined named flags:

```rust
0b1000_0000 = ""
0b1111_1111 = "A | B | C"
0b0000_1000 = ""
```