3 releases
0.1.2 | May 19, 2024 |
---|---|
0.1.1 | May 18, 2024 |
0.1.0 | May 18, 2024 |
#218 in Procedural macros
74 downloads per month
44KB
838 lines
pack_bools
: an easy way to pack all bools in your struct
pack_bools
transforms structs with boolean fields into a struct containing an integer with bit flags for each boolean
value:
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:
#[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 aspub
,pub(super)
etc.). Useself
to reference the visibility of the field (leavingvis
empty otherwise implies private visibility, as in Rust).- Example: Using
#[pack_bools(getters = pub get_field_%)]
will make all getters public namedget_field_
followed by the field name. A field namedfoo
will thus get a getter with the signaturepub 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 namedget_
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_%)]
.
- Use
#[pack_bools(no_getters)]
will not generate getters (aliased asno_get
/no_getter
)- Similarly
#[pack_bools(no_set/no_setter/no_setters)]
will not generate setters. #[pack_bools(type = u16)]
will useu16
as the data type for the bit flags. Available options areu8
/u16
/u32
/u64
/u128
/auto
, whereauto
(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 defaultpacked_bools
.#[pack_bools(inline)]
will use the inline pattern for the bitflag field, i.e. create fields of the patternpacked_bools: u8
. This is the default option. Compare tonewtype
below.#[pack_bools(newtype [= name])]
will make a new single-valued tuple struct for holding the bitflags, similar tostruct MyStructPackedBools(u8);
. If a name is specified, the newtype struct will be defined with that name, otherwisePackedBools
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:
#[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 fielddebug: bool
will create a getter likepub fn debug_mode(&self) -> bool { .. }
. Aliased asget
.- For setters, use
#[pack_bools(set/setter = [vis] [name])]
.
- This uses a concrete name instead of a template, otherwise it has the same syntax as the global
#[pack_bools(no_getter)]
skips generating a getter for that field. Aliased asno_get
. For setters, use#[pack_bools(no_set/no_setter)]
.#[pack_bools(default = <true/false>)]
sets the default value for the field. If set totrue
, thenewtype
pattern must be used, but then aimpl Default
will be generated for that newtype with this field set totrue
. 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 totrue
. Defaults tofalse
.
Changelog
0.1.0
- Initial commit
0.1.1
- Fix some small documentation mistakes
0.1.2
- Add
self
as an inheriting visibility modifier. - Made name optional in
#[pack_bools(get = ..)]
for both global and local config
Dependencies
~235–680KB
~16K SLoC