devela 0.28.0

A development substrate of coherence.
Documentation
Each named constant represents one or more bits.

Constants may be defined from single bit indices,
inclusive bit ranges, or comma-separated mixtures of both.

# Generated type surface

## Traits and operators

The generated struct always derives `Clone` and `Copy`.

By default, the macro also implements common value traits:
`Debug`, `DebugExt`, `Default`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash`.

- `DebugExt` is generated with a `Self: Debug` bound, so suppressing the generated
  `Debug` implementation still works when `Debug` is provided by the caller.

It also implements formatting traits for viewing the raw set bits:
`Display`, `Binary`, `Octal`, `LowerHex` and `UpperHex`.

Selected generated trait implementations may be suppressed with a
`traits(!Trait, ...)` section after the declarations:

`traits(!Debug, !DebugExt, !Default);`

This is useful when the caller wants to provide a custom implementation,
derive the trait externally, or keep the generated type surface smaller.

The macro also implements the standard bitwise/set operators and their
assignment variants: `BitOr`, `BitOrAssign`, `BitAnd`, `BitAndAssign`,
`BitXor`, `BitXorAssign`, `Sub`, `SubAssign` and `Not`.

These operators form the canonical algebraic surface of the set and cannot be
suppressed with `traits(...)`.

## Custom impl blocks

One or more custom `impl { ... }` blocks may be provided after the declarations
and optional `traits(...)` section.

Custom impl blocks are emitted before all generated associated constants and
methods, and may still refer to them through `Self`.

# Generated methods

For a generated set type `Set`, the macro defines the following methods.

## Core construction and access
- `new()`
- `from_bits(bits)`
- `bits()`
- `all()`

## Core predicates
- `is_empty()`
- `is_full()`
- `contains(other)`
- `has(other)`
- `intersects(other)`
- `is_subset(other)`
- `is_superset(other)`

`contains` and `has` return whether all bits in `other` are present.
`has` is a shorter alias intended for flag-like use.

## By-value modification
- `with(other)`
- `without(other)`
- `toggled(other)`
- `with_if(condition, other)`

## Set algebra
- `union(other)`
- `intersection(other)`
- `difference(other)`
- `symmetric_difference(other)`

## In-place modification
- `clear()`
- `insert(other)`
- `remove(other)`
- `toggle(other)`

## Per-constant methods

For each named constant `NAME`, the macro generates:
- `contains_name()`
- `intersects_name()`
- `with_name()`
- `with_name_if(condition)`
- `without_name()`
- `set_name()`
- `set_name_if(condition)`
- `unset_name()`

For constants declared as a single bit, it also generates:
- `has_name()`

For grouped constants, use `contains_name()` for "all bits are present"
and `intersects_name()` for "at least one bit is present".

## Reserved set names

Some set names are reserved because their generated methods
would collide with common methods. Avoid:
- `IF`

The names `EMPTY`, `FULL`, `SUBSET`, and `SUPERSET` are discouraged
because their generated `is_*` methods conflict with methods provided by the set API.

# Examples
```
# use devela::set;
set! {
    /// A small set example.
    pub struct SmallSet(u16) {
        /// A single bit.
        A = 0;

        /// Another single bit.
        B = 1;

        /// A grouped constant from explicit bits.
        AB = 0, 1;

        /// A grouped constant from an inclusive range.
        BC = 1..=2;

        /// A grouped constant from mixed bits and ranges.
        MIXED = 0, 3..=5, 7;
    }

    // Suppresses selected generated trait implementations.
    traits(!Default, !Hash);

    /// Custom semantic helpers emitted before generated methods.
    impl {
        /// A custom named combination.
        pub const ABC: Self = Self::AB.with_bc();

        pub const fn contains_abc(self) -> bool { self.contains(Self::ABC) }
    }
}

let mut s = SmallSet::new()
    .with_a()
    .with_mixed_if(true);

assert!(s.has_a());
assert!(s.contains_mixed());
assert!(s.intersects_ab());

s.unset_a();
assert!(!s.has_a());
```

- Some examples of structs defined with the `set!` macro are:
  [`AsciiSet`], [`EventButtons`], [`RunCapInput`].
- Another macro that leverages `set!` is: [`enumset!`].
- See also the [`bitfield!`] macro.

[`AsciiSet`]: crate::AsciiSet
[`EventButtons`]: crate::EventButtons
[`RunCapInput`]: crate::RunCapInput
[`enumset!`]: crate::enumset
[`bitfield!`]: crate::bitfield