yui-link 0.5.0

Knots & Links Library for YUI
Documentation
//! [`BraidGen`]: a signed Artin generator `σ_i^{±1}`, stored as a single `i8`
//! whose absolute value is the 1-based strand index.

use derive_more::{Display, Debug};
use num_traits::Zero;
use yui_core::num::{GetSign, Sign};

#[derive(Clone, Copy, PartialEq, Eq, Display, Debug)]
#[display("{}", _0)]
#[  debug("{}", _0)]
pub struct BraidGen(i8);

impl BraidGen {
    pub fn new(val: i8) -> Self {
        Self::from(val)
    }

    pub fn index(&self) -> usize {
        self.0.unsigned_abs() as usize
    }

    pub fn sign(&self) -> Sign {
        self.0.sign()
    }

    pub fn inv(&self) -> Self {
        Self(-self.0)
    }
}

macro_rules! impl_from_int {
    ($($t:ty),* $(,)?) => {
        $(
            impl From<$t> for BraidGen {
                fn from(value: $t) -> Self {
                    assert!(!value.is_zero());
                    let v = i8::try_from(value).expect("BraidGen value must fit in i8");
                    Self(v)
                }
            }
        )*
    };
}

impl_from_int!(i8, i16, i32, i64);

pub(super) fn from_raw(value: i8) -> BraidGen {
    BraidGen(value)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn new_pos() {
        let g = BraidGen::new(1);
        assert_eq!(g.index(), 1);
        assert!(g.sign().is_positive());
    }

    #[test]
    fn new_neg() {
        let g = BraidGen::new(-2);
        assert_eq!(g.index(), 2);
        assert!(g.sign().is_negative());
    }

    #[test]
    #[should_panic]
    fn new_zero_panics() {
        BraidGen::new(0);
    }

    #[test]
    fn from_i32() {
        let g = BraidGen::from(3);
        assert_eq!(g.index(), 3);
        assert!(g.sign().is_positive());

        let g = BraidGen::from(-3);
        assert_eq!(g.index(), 3);
        assert!(g.sign().is_negative());
    }

    #[test]
    #[should_panic]
    fn from_zero_panics() {
        let _ = BraidGen::from(0);
    }

    #[test]
    fn inv() {
        let g = BraidGen::from(2);
        let h = g.inv();
        assert_eq!(h.index(), 2);
        assert!(h.sign().is_negative());
        assert_eq!(h.inv(), g);
    }

    #[test]
    fn to_string() {
        assert_eq!(BraidGen::from(3).to_string(), "3");
        assert_eq!(BraidGen::from(-3).to_string(), "-3");
    }
}