fray 0.1.2

A type-safe and ergonomic Rust library for working with bitfields.
Documentation
/*!
A type-safe and ergonomic library for working with bitfields.

A bitfield is defined using the [`#[bitfield]`](crate::bitfield) attribute macro and must specify either
`repr(primitive)`, where `primitive` is an unsigned integer type, or `container(T)`, where `T`
implements the [`BitContainer`] trait.

The generated bitfield struct provides access to its fields through the methods of the [`BitField`] trait.

Each field type must implement [`FieldType`], which defines its default size and the type used
for storage. The default size can be overridden with the `#[bits(N)]` attribute on individual fields.

The macro also allows customizing the generated struct: any trait can be forwarded via `derives`,
while only certain common traits can be requested via `impls`.

See the [`#[bitfield]`](crate::bitfield) documentation for all available macro arguments and options.

## Example: basic usage
```
use fray::{bitfield, BitField};

#[bitfield(repr(u8), impls(debug), derives(Clone, Copy))]
pub struct DeviceFlags {
    powered_on: bool,
    error: bool,
    tx_enabled: bool,
    rx_enabled: bool,
    #[bits(3)]
    priority: u8,
    #[bits(1)]
    reserved: (),
}

fn main() {
    let mut flags = DeviceFlags::new();

    flags
        .with::<powered_on>(true)
        .with::<tx_enabled>(true)
        .with::<priority>(5);

    assert!(flags.get::<powered_on>());
    assert!(flags.get::<tx_enabled>());
    assert_eq!(flags.get::<priority>(), 5);

    assert!(!flags.get::<error>());
    flags.set::<error>(true);
    assert!(flags.get::<error>());

    let debug_fmt = format!("{:?}", flags);
    let expected = "DeviceFlags { powered_on: true, error: true, tx_enabled: true, rx_enabled: false, priority: 5, reserved: () }";
    assert_eq!(debug_fmt, expected);

    let flags_copy = flags;

    // DeviceFlags use LSB0 ordering, so the literal is written
    // with the least-significant bit on the right.
    assert_eq!(flags.into_inner(), 0b0_101_0_1_1_1);
    //                               | |   | | | |
    //                               | |   | | | powered_on
    //                               | |   | | error
    //                               | |   | tx_enabled
    //                               | |   rx_enabled
    //                               | priority
    //                               reserved
}
```
## Example: custom field type
```
use fray::{bitfield, BitField, FieldType};

#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PriorityLevel {
    Low = 0,
    Medium = 1,
    High = 2,
    Critical = 3,
}

// Requiered for try_get
impl TryFrom<u8> for PriorityLevel {
    type Error = u8;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        Ok(match value {
            0 => Self::Low,
            1 => Self::Medium,
            2 => Self::High,
            3 => Self::Critical,
            value => return Err(value)
        })
    }
}

// Requiered for set/with
impl From<PriorityLevel> for u8 {
    fn from(value: PriorityLevel) -> Self {
        value as u8
    }
}

// Requiered for being accepted as field type in struct declaration
impl FieldType for PriorityLevel {
    const SIZE: usize = 3;
    type BitsType = u8;
}

#[bitfield(repr(u8))]
pub struct DeviceFlags {
    powered_on: bool,
    error: bool,
    tx_enabled: bool,
    rx_enabled: bool,
    priority: PriorityLevel,
    #[bits(1)]
    reserved: (),
}

fn main() {
    let mut flags = DeviceFlags::new();

    flags.with::<powered_on>(true)
        .with::<priority>(PriorityLevel::High)
        .with::<error>(true);

    assert!(flags.get::<powered_on>());
    assert!(flags.get::<error>());
    assert_eq!(flags.try_get::<priority>(), Ok(PriorityLevel::High));
}
```

## Example: nested
```
use fray::{BitFieldImpl, BitField, FieldType, bitfield};

// https://datatracker.ietf.org/doc/html/rfc9293#name-header-format
#[bitfield(repr(u16), bitorder(msb0))]
pub struct TcpHeader {
    #[bits(4)]
    DOffset: u8,
    #[bits(4)]
    Rsrvd: (),
    flags: ControlBits,
}

#[bitfield(repr(u8), bitorder(msb0))]
pub struct ControlBits {
    CWR: bool,
    ECE: bool,
    URG: bool,
    ACK: bool,
    PSH: bool,
    RST: bool,
    SYN: bool,
    FIN: bool,
}

impl FieldType for ControlBits {
    const SIZE: usize = 8;

    type BitsType = u8;
}

impl From<ControlBits> for u8 {
    fn from(value: ControlBits) -> Self {
        value.into_inner()
    }
}

impl From<u8> for ControlBits {
    fn from(value: u8) -> Self {
        <Self as BitFieldImpl>::Container::from(value).into()
    }
}

fn main() {
    let mut control_bits = ControlBits::new();
    control_bits.with::<FIN>(true).with::<ACK>(true);
    let mut tcp_header = TcpHeader::new();
    tcp_header.set::<flags>(control_bits);
    tcp_header.set::<DOffset>(8);

    let flags = tcp_header.get::<flags>();
    assert!(flags.get::<FIN>());
    assert!(flags.get::<ACK>());

    assert_eq!(tcp_header.get::<DOffset>(), 8);

    assert_eq!(tcp_header.into_inner(), 0x8011)
}
```

# How It Works

A [`BitField`] is essentially a wrapper around a [`BitContainer`]. The [`BitField`] trait provides
high-level methods for interacting with the bitfield, while the underlying [`BitContainer`] defines
how values are stored and retrieved at a low level.

To interact with individual fields, each field must also be defined and implement the
[`Field<T>`](crate::Field) trait (where T is the type of the bitfield).

The [`BitField`] trait is **sealed** and is automatically implemented for all types that implement
[`BitFieldImpl`].

The [`#[bitfield]`](crate::bitfield) attribute macro generates a struct that implements [`BitField`],
as well as structs implementing [`Field`] for each of its fields.
*/

#![allow(clippy::needless_doctest_main)]
#![no_std]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]

#[cfg(test)]
extern crate std;

mod bitcontainers;
pub use bitcontainers::{BitContainer, BitContainerFor, iterable};
mod bitfields;
pub use bitfields::{BitField, BitFieldImpl, Field, FieldType, bitorder};
pub mod debug;

/// Attribute macro for defining bitfield structures.
///
/// Applying `#[bitfield]` to a struct:
/// - Generates a new wrapper struct around the chosen [`BitContainer`],
/// - Implements [`BitField`] for this wrapper,
/// - Generates a zero-sized [`Field`] type for each field,
///   which provides metadata such as offset and size.
///
/// The macro also determines field offsets according to the selected bit order.
/// When the [`bitorder`](#-bitorderorder) argument is used, it controls how
/// bit positions are assigned (`lsb0` by default, or `msb0` if specified).
/// The chosen order is reflected in [`BitFieldImpl::BitOrder`],
/// which serves purely as a marker and has no functional impact.
///
/// This macro is the primary way end-users create bitfield types.
///
/// # Arguments
///
/// The attribute accepts a comma-separated list of options:
///
/// - **`container(<Type>)`**
///   Specifies a custom container type to hold the bitfield data.
///   - **Mandatory** unless `repr` is specified.
///   - Mutually exclusive with `repr`.
///   - The type must implement the [`BitContainer`] trait,
///     which defines how bits are accessed and modified.
///   - Example: `container(Foobar<u8>)`, where `Foobar<u8>` implement [`BitContainer`].
///
/// - **`repr(<primitive>)`**
///   Shorthand for using [`BitIterableContainer<primitive>`](crate::iterable::BitIterableContainer)
///   as the underlying bitfield container.
///   - **Mandatory** unless `container` is specified.
///   - Mutually exclusive with `container`.
///   - Allowed primitives: `u8`, `u16`, `u32`, `u64`.
///
/// - **`impls(<trait>)`**
///   Requests generation of custom `impl` blocks for specific traits.
///   Unlike `derives`, this is restricted to a predefined set of
///   implementations provided by the macro itself.
///   - Currently supported values:
///     - `debug`: generates a custom [`Debug`] implementation
///       that prints the bitfield fields and their values.
///
///       ```
///       use fray::{bitfield, BitField};
///
///       #[bitfield(repr(u8), impls(debug))]
///       pub struct MyFlags {
///           a: bool,
///           #[bits(7)]
///           b: u8,
///       }
///
///       fn main() {
///           let mut flags = MyFlags::new();
///           flags.with::<a>(true).with::<b>(53);
///           // Custom Debug output (example):
///           // MyFlags { a: true, b: 53 }
///           let fmt_debug = format!("{:?}", flags);
///           assert_eq!(fmt_debug, "MyFlags { a: true, b: 53 }");
///       }
///       ```
///   - Optional.
///   - Can be repeated (once multiple traits are available).
///
/// - **`derives(<traits...>)`**
///   Adds `#[derive(...)]` to the generated bitfield struct.
///   - Optional.
///
/// - **`bitorder(<order>)`**
///   Defines the bit numbering order within the container.
///   - Supported values:
///     - `lsb0`: Least Significant Bit first (default).
///     - `msb0`: Most Significant Bit first.
///   - Sets [`BitFieldImpl::BitOrder`] to [`LSB0`](crate::bitorder::LSB0) or [`MSB0`](crate::bitorder::MSB0).
///   - Optional.
///
///   ```
///   use fray::bitfield;
///
///   #[bitfield(repr(u8), bitorder(msb0))]
///   pub struct Flags {
///       a: bool,
///       #[bits(3)]
///       b: u8,
///       #[bits(4)]
///       c: u8,
///   }
///   // Bit index:  7   6   5   4   3   2   1   0
///   //             │   │   │   │   │   │   │   │
///   // Binary:    [c0][c1][c2][c3][b0][b1][b2][a]   <- bitorder(lsb0)
///   // Binary:    [a] [b2][b1][b0][c3][c2][c1][c0]  <- bitorder(msb0)
///   ```
///
///   > **Note:**
///   > The `bitorder` option changes how field offsets are assigned within the bitfield,
///   > but it does **not** alter the internal bit layout or significance of the underlying
///   > type.
///
pub use fray_macro::bitfield;

#[doc = include_str!("../../README.md")]
#[cfg(doctest)]
struct ReadmeDoctests;