noterm 0.2.3

noterm, a no_std terminal handler.
Documentation
//! Attributes.

use core::fmt;
use core::ops::{BitAnd, BitOr, BitXor};

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Attribute {
    #[default]
    Reset = 0,

    Bold = 1,
    Dimmed = 2,
    Italic = 3,
    Underlined = 4,
    Striked = 9,

    SlowBlink = 5,
    RapidBlink = 6,

    Reversed = 7,

    NotBoldOrDimmed = 22,
    NotItalic = 23,
    NotUnderlined = 24,
    NotStriked = 29,
    NotBlinking = 25,
    NotReversed = 27,
}

impl Attribute {
    pub fn bits(&self) -> u32 {
        if Attribute::Reset == *self {
            0
        } else {
            1u32 << self.index()
        }
    }

    pub(crate) fn index(&self) -> usize {
        ATTRIBUTE_LOOKUP_TABLE
            .iter()
            .position(|x| self == x)
            .expect("predifined attribute set")
    }
}

impl fmt::Display for Attribute {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", *self as u8)
    }
}

static ATTRIBUTE_LOOKUP_TABLE: &[Attribute] = &[
    Attribute::Bold,
    Attribute::Dimmed,
    Attribute::Italic,
    Attribute::Underlined,
    Attribute::Striked,
    Attribute::SlowBlink,
    Attribute::RapidBlink,
    Attribute::Reversed,
    Attribute::NotBoldOrDimmed,
    Attribute::NotItalic,
    Attribute::NotUnderlined,
    Attribute::NotStriked,
    Attribute::NotReversed,
];

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct AttributeSet {
    mask: u32,
}

impl AttributeSet {
    pub fn is_empty(&self) -> bool {
        self.mask == 0
    }

    pub fn reset(&mut self) -> &mut Self {
        self.mask = 0;
        self
    }

    pub fn insert(&mut self, attribute: Attribute) -> &mut Self {
        self.mask |= attribute.bits();
        self
    }

    pub fn remove(&mut self, attribute: Attribute) -> &mut Self {
        self.mask &= !attribute.bits();
        self
    }

    pub fn extend(&mut self, other: AttributeSet) -> &mut Self {
        self.mask |= other.mask;
        self
    }

    pub fn contains(&self, attribute: &Attribute) -> bool {
        (attribute.bits() & self.mask) != 0
    }

    pub fn intersection(&self, other: &AttributeSet) -> AttributeSet {
        AttributeSet {
            mask: self.mask & other.mask,
        }
    }

    pub fn union(&self, other: &AttributeSet) -> AttributeSet {
        AttributeSet {
            mask: self.mask | other.mask,
        }
    }

    pub fn difference(&self, other: &AttributeSet) -> AttributeSet {
        AttributeSet {
            mask: self.mask ^ other.mask,
        }
    }

    pub fn iter(&self) -> impl Iterator<Item = Attribute> {
        ATTRIBUTE_LOOKUP_TABLE
            .iter()
            .copied()
            .filter(|attr| self.contains(attr))
    }
}

impl From<Attribute> for AttributeSet {
    fn from(value: Attribute) -> Self {
        *AttributeSet::default().insert(value)
    }
}

impl From<(Attribute, Attribute)> for AttributeSet {
    fn from(value: (Attribute, Attribute)) -> Self {
        *AttributeSet::from(value.0).insert(value.1)
    }
}

impl From<(Attribute, Attribute, Attribute)> for AttributeSet {
    fn from(value: (Attribute, Attribute, Attribute)) -> Self {
        *AttributeSet::from(value.0).insert(value.1).insert(value.2)
    }
}

impl From<(Attribute, Attribute, Attribute, Attribute)> for AttributeSet {
    fn from(value: (Attribute, Attribute, Attribute, Attribute)) -> Self {
        *AttributeSet::from(value.0)
            .insert(value.1)
            .insert(value.2)
            .insert(value.3)
    }
}

impl From<(Attribute, Attribute, Attribute, Attribute, Attribute)> for AttributeSet {
    fn from(value: (Attribute, Attribute, Attribute, Attribute, Attribute)) -> Self {
        *AttributeSet::from(value.0)
            .insert(value.1)
            .insert(value.2)
            .insert(value.3)
            .insert(value.4)
    }
}

impl
    From<(
        Attribute,
        Attribute,
        Attribute,
        Attribute,
        Attribute,
        Attribute,
    )> for AttributeSet
{
    fn from(
        value: (
            Attribute,
            Attribute,
            Attribute,
            Attribute,
            Attribute,
            Attribute,
        ),
    ) -> Self {
        *AttributeSet::from(value.0)
            .insert(value.1)
            .insert(value.2)
            .insert(value.3)
            .insert(value.4)
            .insert(value.5)
    }
}

impl BitAnd<Attribute> for Attribute {
    type Output = AttributeSet;

    fn bitand(self, rhs: Attribute) -> Self::Output {
        AttributeSet::from(self).intersection(&rhs.into())
    }
}

impl BitOr<Attribute> for Attribute {
    type Output = AttributeSet;

    fn bitor(self, rhs: Attribute) -> Self::Output {
        AttributeSet::from(self).union(&rhs.into())
    }
}

impl BitXor<Attribute> for Attribute {
    type Output = AttributeSet;

    fn bitxor(self, rhs: Attribute) -> Self::Output {
        AttributeSet::from(self).difference(&rhs.into())
    }
}

impl BitAnd<Attribute> for AttributeSet {
    type Output = AttributeSet;

    fn bitand(self, rhs: Attribute) -> Self::Output {
        self.intersection(&rhs.into())
    }
}

impl BitOr<Attribute> for AttributeSet {
    type Output = AttributeSet;

    fn bitor(self, rhs: Attribute) -> Self::Output {
        self.union(&rhs.into())
    }
}

impl BitXor<Attribute> for AttributeSet {
    type Output = AttributeSet;

    fn bitxor(self, rhs: Attribute) -> Self::Output {
        self.difference(&rhs.into())
    }
}

impl BitAnd<AttributeSet> for Attribute {
    type Output = AttributeSet;

    fn bitand(self, rhs: AttributeSet) -> Self::Output {
        AttributeSet::from(self).intersection(&rhs)
    }
}

impl BitOr<AttributeSet> for Attribute {
    type Output = AttributeSet;

    fn bitor(self, rhs: AttributeSet) -> Self::Output {
        AttributeSet::from(self).union(&rhs)
    }
}

impl BitXor<AttributeSet> for Attribute {
    type Output = AttributeSet;

    fn bitxor(self, rhs: AttributeSet) -> Self::Output {
        AttributeSet::from(self).difference(&rhs)
    }
}

impl BitAnd<AttributeSet> for AttributeSet {
    type Output = AttributeSet;

    fn bitand(self, rhs: AttributeSet) -> Self::Output {
        self.intersection(&rhs)
    }
}

impl BitOr<AttributeSet> for AttributeSet {
    type Output = AttributeSet;

    fn bitor(self, rhs: AttributeSet) -> Self::Output {
        self.union(&rhs)
    }
}

impl BitXor<AttributeSet> for AttributeSet {
    type Output = AttributeSet;

    fn bitxor(self, rhs: AttributeSet) -> Self::Output {
        self.difference(&rhs)
    }
}