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
//! # `pack_bools`: an easy way to pack all bools in your struct
//!
//! [](https://crates.io/crates/pack_bools)
//! [](https://docs.rs/pack_bools)
//! [](https://opensource.org/licenses/MIT)
//!
//! `pack_bools` transforms structs with boolean fields into a struct containing an integer with bit flags for each boolean
//! value:
//!
//! ```rust
//! 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
//! }
//! ```
//!
//! gets transformed into something like this:
//!
//! ```rust
//! #[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 */
//! }
//! ```
//!
//! ## Usage
//!
//! Simply run `cargo add pack_bools` in your project directory, `use pack_bools::pack_bools;` and add the `#[pack_bools]`
//! macro on top of your struct. By default, this will behave as the example above: it will replace all fields of type
//! `bool` with a single numeric field `packed_bools` and add getters and setters for each field. By default, both the
//! getter and setter will inherit their visibility from the field, so if the field is declared `pub(super)`, the getters
//! and setters will too.
//!
//! By adding options to the `#[pack_bools(..)]` attribute, you can configure options for the entire struct, using
//! *global options*. Additionally, you can add `#[pack_bools(..)]` to `boolean` fields to configure options for just that
//! field, using *local options*.
//!
//! ### Global options
//!
//! Global options available when using `#[pack_bools(..)]` on a struct:
//!
//! * `#[pack_bools(getters = [vis] [name])]` changes the name and visibility of the getters.
//! * Use `%` as a substitution for the field name.
//! * If the name is skipped, the default name template will be used.
//! * `vis` is a Rust visibility modifier (such as `pub`, `pub(super)` etc.). Use `self` to reference the visibility of
//! the field (leaving `vis` empty otherwise implies private visibility, as in Rust).
//! * Example: Using `#[pack_bools(getters = pub get_field_%)]` will make all getters public named
//! `get_field_` followed by the field name. A field named `foo` will thus get a getter with the signature
//! `pub fn get_field_foo(&self) -> bool`.
//! * Example: Using `#[pack_bools(getters = self %)]` will make all getters have the same name as the field, with the
//! same visibility as the field.
//! * As a consequence of an empty template leaving the field name unchanged together with Rust using no modifier for
//! private items, just `#[pack_bools(getters = )]` will make all getters private named `get_` followed by the field
//! name (the default template). For clarity purposes, consider using `#[pack_bools(getters = get_%)]`
//! * Aliased as `get`/`getter`. For setters, use `#[pack_bools(set/setter/setters)]`.
//! * Default values are `#[pack_bools(get = self get_%, set = self set_%)]`.
//! * `#[pack_bools(no_getters)]` will not generate getters (aliased as `no_get`/`no_getter`)
//! * Similarly `#[pack_bools(no_set/no_setter/no_setters)]` will not generate setters.
//! * `#[pack_bools(type = u16)]` will use `u16` as the data type for the bit flags. Available options are `u8`/`u16`/`u32`/
//! `u64`/`u128`/`auto`, where `auto` (the default option) automatically use the smallest of those types that can fit all
//! the bools in the struct.
//! * `#[pack_bools(field = <name>)]` will set the name of the field containing the bitflags, by default `packed_bools`.
//! * `#[pack_bools(inline)]` will use the inline pattern for the bitflag field, i.e. create fields of the pattern
//! `packed_bools: u8`. This is the default option. Compare to `newtype` below.
//! * `#[pack_bools(newtype [= name])]` will make a new single-valued tuple struct for holding the bitflags, similar to
//! `struct MyStructPackedBools(u8);`. If a name is specified, the newtype struct will be defined with that name,
//! otherwise `PackedBools` will be suffixed to the name of the struct. The example at the top of this document,
//! with `#[pack_bools(newtype)]` will be compiled into:
//!
//! ```rust
//! #[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 */
//! }
//! ```
//!
//! ### Local options
//!
//! You may add the `#[pack_bools(..)]` attribute on fields of type `bool` to configure the output of that specific field.
//! Available options are:
//!
//! * `#[pack_bools(skip)]` excludes that field from being packed with the other bools.
//! * `#[pack_bools(getter = [vis] [name])` changes the name (and possibly visibility) of the getter to that field.
//! * This uses a concrete name instead of a template, otherwise it has the same syntax as the global
//! `#[pack_bools(getter = ..)]` attribute, see above.
//! * `#[pack_bools(getter = pub debug_mode)]` added to a field `debug: bool` will create a getter like
//! `pub fn debug_mode(&self) -> bool { .. }`. Aliased as `get`.
//! * For setters, use `#[pack_bools(set/setter = [vis] [name])]`.
//! * `#[pack_bools(no_getter)]` skips generating a getter for that field. Aliased as `no_get`. For setters, use
//! `#[pack_bools(no_set/no_setter)]`.
//! * `#[pack_bools(default = <true/false>)]` sets the default value for the field. If set to `true`, the `newtype` pattern
//! must be used, but then a `impl Default` will be generated for that newtype with this field set to `true`. If all other
//! fields of the struct has appropriate default values, this will allow you to use `#[derive(Default)]` on the struct,
//! while having some boolean values set to `true`. Defaults to `false`.
use TokenStream;
use ;
use GlobalConfig;
/// Packs the bools in this struct into one numeric field