superbitty 0.3.2

A bitfields crate.
Documentation
use std::cmp::Ordering;
use std::hash::Hash;

use superbitty::{bitfields, BitFieldCompatible};

#[derive(BitFieldCompatible, Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum EnumA {
    #[default]
    A,
    B,
}
#[derive(BitFieldCompatible, Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EnumB {
    A,
    B,
    #[default]
    C,
}

bitfields! {
    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct Bitfields : u8 {
        enum_a: EnumA,
        pub enum_b: EnumB,
    }
    construct = fn new();
}

#[test]
fn new_and_set() {
    let mut instance = Bitfields::new(EnumA::B, EnumB::A);
    assert_eq!(instance.enum_a(), EnumA::B);
    assert_eq!(instance.enum_b(), EnumB::A);

    instance.set_enum_b(EnumB::C);
    assert_eq!(instance.enum_a(), EnumA::B);
    assert_eq!(instance.enum_b(), EnumB::C);

    instance.set_enum_a(EnumA::A);
    assert_eq!(instance.enum_a(), EnumA::A);
    assert_eq!(instance.enum_b(), EnumB::C);
}

#[test]
fn default() {
    let instance = Bitfields::default();
    assert_eq!(instance.enum_a(), EnumA::default());
    assert_eq!(instance.enum_b(), EnumB::default());
}

#[test]
fn debug() {
    let debug_str = format!("{:?}", Bitfields::new(EnumA::B, EnumB::B));
    assert_eq!(debug_str, "Bitfields { enum_a: B, enum_b: B }");
}

#[test]
fn clone_copy() {
    let original = Bitfields::new(EnumA::A, EnumB::C);
    let clone = original.clone();
    assert_eq!(original.enum_a(), clone.enum_a());
    assert_eq!(original.enum_b(), clone.enum_b());
    let copy = original;
    assert_eq!(original.enum_a(), copy.enum_a());
    assert_eq!(original.enum_b(), copy.enum_b());
}

#[test]
fn equality() {
    fn assert_eq<T: Eq>() {}
    assert_eq::<Bitfields>();

    for a1 in [EnumA::A, EnumA::B] {
        for b1 in [EnumB::A, EnumB::B, EnumB::C] {
            for a2 in [EnumA::A, EnumA::B] {
                for b2 in [EnumB::A, EnumB::B, EnumB::C] {
                    let one = Bitfields::new(a1, b1);
                    let two = Bitfields::new(a2, b2);
                    assert_eq!(one == two, a1 == a2 && b1 == b2);
                }
            }
        }
    }
}

#[test]
fn comparison() {
    for a1 in [EnumA::A, EnumA::B] {
        for b1 in [EnumB::A, EnumB::B, EnumB::C] {
            for a2 in [EnumA::A, EnumA::B] {
                for b2 in [EnumB::A, EnumB::B, EnumB::C] {
                    let one = Bitfields::new(a1, b1);
                    let two = Bitfields::new(a2, b2);
                    assert_eq!(one.cmp(&two), a1.cmp(&a2).then(b1.cmp(&b2)));
                    assert_eq!(one.partial_cmp(&two), Some(a1.cmp(&a2).then(b1.cmp(&b2))));
                }
            }
        }
    }
}

#[test]
fn hash() {
    for a in [EnumA::A, EnumA::B] {
        for b in [EnumB::A, EnumB::B, EnumB::C] {
            let bitfields = Bitfields::new(a, b);

            #[derive(Debug, Default, PartialEq, Eq)]
            struct VecHasher(Vec<u8>);
            impl std::hash::Hasher for VecHasher {
                fn finish(&self) -> u64 {
                    0
                }
                fn write(&mut self, bytes: &[u8]) {
                    self.0.extend_from_slice(bytes);
                }
            }

            let mut bitfields_hasher = VecHasher::default();
            bitfields.hash(&mut bitfields_hasher);
            let mut individual_hasher = VecHasher::default();
            a.hash(&mut individual_hasher);
            b.hash(&mut individual_hasher);

            assert_eq!(bitfields_hasher, individual_hasher);
        }
    }
}

bitfields! {
    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub(crate) struct Empty : u32 {}
}

#[test]
fn empty() {
    _ = Empty::new().clone();
    _ = Empty::default();
    assert_eq!(Empty::default(), Empty::new());
    assert!(!(Empty::default() != Empty::new()));
    assert!(Empty::default() >= Empty::new());
    assert_eq!(Empty::new().partial_cmp(&Empty::new()), Some(Ordering::Equal));
}