FlagsBuilder

Struct FlagsBuilder 

Source
pub struct FlagsBuilder { /* private fields */ }
Expand description

§(Bit)Flag/Enum Builder.

FlagsBuilder is a compile-time (build.rs) tool for generating small (single-byte) bitflag enums, with every flag — and combination — explicitly defined as its own unique variant.

It supports 1..=8 primary flags, zero, and a couple hundred combinations (that argyle will figure out for you).

The resulting code contains no unsafe blocks, no dependencies (other than std), and no runtime performance penalties, just the warmth and reassurance of a strictly-bound type.

§Examples

As the name suggests, FlagsBuilder employs builder-style configuration methods, allowing indefinite chaining, start to finish.

§build.rs

use argyle::FlagsBuilder;

FlagsBuilder::new("MyFlags") // Name of enum.
    .with_docs("# My Flags Are Awesome!") // Enum docs.
    .public() // Make it pub instead of pub(crate).
    .with_flag("FlagOne", None) // A primary flag.
    .with_flag("FlagTwo", Some("# Second Flag")) // A primary flag with docs.
    .with_alias("Both", ["FlagOne", "FlagTwo"], None) // A named combo.
    .with_defaults(["FlagOne", "FlagTwo"]) // MyFlags::default() == MyFlags::Both
    .save(std::env::var("OUT_DIR").unwrap().join("flags.rs")); // Save it!

§lib.rs

To use it, just import the build artifact into your library like:

// Generated by build.rs.
include!(concat!(env!("OUT_DIR"), "/flags.rs"));

// The type is "yours"; expand as needed!
impl From<MyFlags> for u8 {
    #[inline]
    fn from(src: MyFlags) -> Self { src as Self }
}

§Generated Structure.

Custom enums generated by FlagsBuilder implement the various bit-related traits — BitAnd/BitAndAssign, BitOr/BitOrAssign, and BitXor/BitXorAssign — so can be worked with in the usual manner.

A few additional helpers like contains and some basic unit tests are provided as well.

All told, you’ll wind up with something like this:

#[repr(u8)]
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
/// # My Awesome Enum.
pub(crate) enum AwesomeEnum {
    #[default]
    None = 0b0000_u8, // Zero is always called "None".
    A =    0b0001_u8,
    B =    0b0010_u8,
    C =    0b0100_u8,
    D =    0b1000_u8,
    // …
    Z =    0b1111_u8,
}

impl AwesomeEnum {
    /// # (Primary) Flags.
    pub(crate) const FLAGS: [Self; 4] = [
        Self::A, Self::B, Self::C, Self::D,
    ];

    #[must_use]
    /// # From `u8`.
    ///
    /// Find and return the flag corresponding to the `u8`. If out of range,
    /// `Self::None` is returned.
    pub(crate) const fn from_u8(num: u8) -> Self {
        // …
    }
}

impl AwesomeEnum {
    #[must_use]
    /// # Contains Flag?
    ///
    /// Returns `true` if `self` is or comprises `other`, `false` if not.
    pub(crate) const fn contains(self, other: Self) -> bool {
        // …
    }

    #[must_use]
    /// # Contains Any Part of Flag?
    ///
    /// Returns the bits common to `self` and `other`, if any.
    pub(crate) const fn contains_any(self, other: Self) -> Option<Self> {
        // …
    }

    #[must_use]
    /// # Is None?
    ///
    /// Returns `true` if [`AwesomeEnum::None`], meaning no bits are set.
    pub(crate) const fn is_none(self) -> bool {
        // …
    }

    /// # Set Flag Bits.
    ///
    /// Add any missing bits from `other` to `self`.
    ///
    /// This is equivalent to `self |= other`, but constant.
    pub(crate) const fn set(&mut self, other: Self) {
        // …
    }

    /// # Remove Flag Bits.
    ///
    /// Strip `other`'s bits from `self`.
    ///
    /// This is equivalent to `self &= ! other`, but constant.
    pub(crate) const fn unset(&mut self, other: Self) {
        // …
    }

    #[must_use]
    /// # With Flag Bits.
    ///
    /// Return the combination of `self` and `other`.
    ///
    /// This is equivalent to `self | other`, but constant.
    pub(crate) const fn with(self, other: Self) -> Self {
        // …
    }

    #[must_use]
    /// # Without Flag Bits.
    ///
    /// Remove `other` from `self`, returning the difference.
    ///
    /// This is equivalent to `self & ! other`, but constant.
    pub(crate) const fn without(self, other: Self) -> Self {
        // …
    }
}

If you’re having trouble visualizing it, clone the repository and check out the flags_builder example.

Implementations§

Source§

impl FlagsBuilder

Source

pub fn new<S: AsRef<str>>(name: S) -> Self

§New Instance.

Initialize a new builder for a custom enum named name.

As with flag/alias names, the enum name must be ASCII alphanumeric (alpha first), and PascalCase.

§Examples
use argyle::FlagsBuilder;

// Start a builder called Settings.
let mut builder = FlagsBuilder::new("Settings");
§Panics

This method will panic if the name is invalid.

Source

pub fn with_docs<S: AsRef<str>>(self, docs: S) -> Self

§With Documentation.

Customize the documentation that will wind up being attached to the enum definition.

§Examples
use argyle::FlagsBuilder;

FlagsBuilder::new("Settings")
    .with_docs("# App Settings
This enum holds the various boolean…");

Long write-ups can quickly get untidy with all the line breaks and whatnot. Storing the docs externally can be useful:

use argyle::FlagsBuilder;

FlagsBuilder::new("Settings")
    .with_docs(include_str!("../skel/settings.txt"));
Source

pub const fn private(self) -> Self

§Private Scope.

By default, the generated enum (and its members) are scoped to pub(crate) visibility; use this method to make them private instead.

§Examples
use argyle::FlagsBuilder;

FlagsBuilder::new("InternalFlags")
    .private();
Source

pub const fn public(self) -> Self

§Public Scope.

By default, the generated enum (and its members) are scoped to pub(crate) visibility; use this method to make them public instead.

§Examples
use argyle::FlagsBuilder;

FlagsBuilder::new("PeoplesFlags")
    .public();
Source

pub fn with_defaults<S, I>(self, flags: I) -> Self
where S: AsRef<str>, I: IntoIterator<Item = S>,

§With Default(s).

By default, the Default implementation for custom enums is None.

If you’d rather it start with one or more flags flipped on, use this method to specify them.

If you’d rather default to everything, use FlagsBuilder::with_default_all instead.

§Examples
use argyle::FlagsBuilder;

FlagsBuilder::new("Fruit")
    .with_flag("Apples", None)
    .with_flag("Bananas", None)
    .with_flag("Carrots", None)
    .with_flag("Dates", None)
    .with_defaults(["Apples", "Bananas", "Carrots"]);
§Panics

This method doesn’t check that the flags have been defined — that happens during save — but will panic if the names are invalid.

Source

pub const fn with_default_all(self) -> Self

§Default Everything!

By default, the Default implementation for custom enums is None.

Use this method to have it return all the bits (every flag) instead.

If you’d rather the default fall somewhere between the extremes, use FlagsBuilder::with_defaults instead.

§Examples
use argyle::FlagsBuilder;

FlagsBuilder::new("Fruit")
    .with_flag("Apples", None)
    .with_flag("Bananas", None)
    .with_flag("Carrots", None)
    .with_flag("Dates", None)
    .with_default_all();
Source§

impl FlagsBuilder

§Primary Flags.

Source

pub fn with_flag<S: AsRef<str>>(self, name: S, docs: Option<S>) -> Self

§With Flag.

Use this method to define a new primary flag with the given variant name and (optional) documentation.

As with the enum itself, names must be ASCII alphanumeric (alpha first), and PascalCase.

A given enum can have anywhere from 1..=8 primary flags.

§Examples
use argyle::FlagsBuilder;

FlagsBuilder::new("Animals")
    .with_flag("BullFrog", None);
§Panics

This method will panic if the flag name is invalid or has already been defined.

Source

pub fn with_complex_flag<S, I>(self, name: S, flags: I, docs: Option<S>) -> Self
where S: AsRef<str>, I: IntoIterator<Item = S>,

§With Complex Flag.

Like FlagsBuilder::with_flag, but for a flag that implies other flag(s), inheriting their bits (along with its own).

Implied flag names passed to this method must correspond to flags; aliases are not allowed.

§Examples
use argyle::FlagsBuilder;

FlagsBuilder::new("Animals")
    .with_flag("BullFrog", None)                   // 0b0001
    .with_flag("Bat", None)                        // 0b0010
    .with_complex_flag("Frog", ["BullFrog"], None) // 0b0101
    .with_alias("All", ["Bat", "Frog"], None);     // 0b0111
§Panics

This method will panic if any of the flag names are invalid, or the main name has already been defined.

Source

pub fn with_alias<S, I>(self, name: S, flags: I, docs: Option<S>) -> Self
where S: AsRef<str>, I: IntoIterator<Item = S>,

§With Alias.

Combinative aliases — the “AB” in A | B == AB — are automatically generated by FlagsBuilder, but can be selectively named if any of them hold special meaning for you.

As with the enum and primary flags, alias names must be ASCII alphanumeric (alpha first), and PascalCase.

§Examples
use argyle::FlagsBuilder;

FlagsBuilder::new("Compression")
    .with_flag("FmtAvif", None)
    .with_flag("FmtJpeg", None)
    .with_flag("FmtJxl", None)
    .with_flag("FmtPng", None)
    .with_flag("FmtWebP", None)
    .with_alias("FmtOld", ["FmtJpeg", "FmtPng"], None)
    .with_alias("FmtNew", ["FmtAvif", "FmtJxl", "FmtWebP"], None);
§Panics

This method will panic if the alias or flag names are invalid, if the alias has already been defined (including as a flag), or if it references fewer than two flags.

Source§

impl FlagsBuilder

Source

pub fn save<P: AsRef<Path>>(&self, file: P)

§Save it to a File!

Generate and save the custom flag enum to the specified file.

Note that many environments prohibit writes to arbitrary locations; for best results, your path should be somewhere under OUT_DIR.

§Examples
let out_dir: &Path = std::env::var("OUT_DIR").unwrap().as_ref();
flags.save(out_dir.join("flags.rs"));

If you’d prefer to handle the saving manually, the code can be obtained by simply calling FlagsBuilder::to_string instead.

use argyle::FlagsBuilder;

let out = FlagsBuilder::new("Names")
    .with_flag("John", None)
    .with_flag("Jane", None)
    .to_string();
§Panics

This method will panic if the write fails for any reason.

Trait Implementations§

Source§

impl Clone for FlagsBuilder

Source§

fn clone(&self) -> FlagsBuilder

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for FlagsBuilder

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for FlagsBuilder

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.