collum 0.1.0

A crate for cleanly describing and parsing bit-wide data structures
Documentation
use crate::BitOffset;

pub(crate) const BITS_PER_BYTE: usize = 8;

/// Similarly to [`core::marker::Sized`] defines a type which can be said to have a given amount of
/// bits.
pub trait Sized {
    /// Returns the amount of bits needed for the type.
    fn bits() -> usize;

    /// Returns the size of the struct rounded up to the nearest byte alignment.
    ///
    /// ```
    /// # use collum::{Collum, Sized};
    /// # use collum_derive::{Collum, Sized};
    ///
    /// #[derive(Collum, Sized)]
    /// struct Data {
    ///     bit1: bool,
    ///     bit2: bool,
    /// }
    ///
    /// assert_eq!(<Data as Sized>::bits(), 2);
    /// assert_eq!(<Data as Sized>::bytes(), 1);
    /// ```
    fn bytes() -> usize {
        Self::bits().div_ceil(BITS_PER_BYTE)
    }

    /// Returns the size of the struct in the least amount of full bytes parsed. That is, if the
    /// parsed boundary lands in the middle of a byte, say the first 4 bits are parsed, then
    /// `least_bytes` does not count the last byte.
    ///
    /// ```
    /// # use collum::{Collum, Sized};
    /// # use collum_derive::{Collum, Sized};
    ///
    /// #[derive(Collum, Sized)]
    /// struct Data {
    ///     bit1: bool,
    ///     bit2: bool,
    /// }
    ///
    /// assert_eq!(<Data as Sized>::bits(), 2);
    /// assert_eq!(<Data as Sized>::least_bytes(), 0);
    /// ```
    fn least_bytes() -> usize {
        Self::bits() / BITS_PER_BYTE
    }

    /// Returns the byte count and additional bits needed for the type. In general it is the amount
    /// of full bytes, i.e. `Self::bits() / 8`, plus the extra bits, i.e. `Self::bits() % 8`.
    fn bytes_and_bits() -> (usize, BitOffset) {
        let bits = Self::bits();

        (bits / BITS_PER_BYTE, BitOffset::new_wrapped(bits))
    }
}

macro_rules! impl_sized_literal {
    ($(($type:ty, $size:expr)),*) => {
        $(
            impl self::Sized for $type {
                fn bits() -> usize {
                    $size
                }
            }
        )*
    };
}

impl_sized_literal! {
    ((), 0),
    (bool, 1),
    (u8, 8),
    (u16, 16),
    (u32, 32),
    (u64, 64),
    (u128, 128),
    (i8, 8),
    (i16, 16),
    (i32, 32),
    (i64, 64),
    (i128, 128),
    (f32, 32),
    (f64, 64),
    (char, 32),
    (core::net::Ipv4Addr, 32),
    (core::net::Ipv6Addr, 128)
}

impl<T, const N: usize> self::Sized for [T; N]
where
    T: self::Sized,
{
    fn bits() -> usize {
        T::bits() * N
    }
}