ctcore 0.2.0

Precision tools for the CTfile family of file formats.
Documentation
use crate::text::{Digit, NonZeroDigit};

#[derive(Debug, PartialEq)]
pub struct Natural {
    head: NonZeroDigit,
    tail: Vec<Digit>,
}

impl Natural {
    pub fn new(head: NonZeroDigit) -> Self {
        Self {
            head,
            tail: Vec::new(),
        }
    }

    pub fn from_int(int: u32) -> Option<Self> {
        Self::from_digits(Digit::split(int))
    }

    pub fn from_digits(digits: Vec<Digit>) -> Option<Self> {
        let mut digits = digits.into_iter();
        let mut result = match digits.next()? {
            Digit::Zero => return None,
            Digit::NonZero(non_zero) => Self::new(non_zero),
        };

        for digit in digits {
            result.push(digit)
        }

        Some(result)
    }

    pub fn push(&mut self, digit: Digit) {
        self.tail.push(digit)
    }

    pub fn len(&self) -> usize {
        self.tail.len() + 1
    }
}

#[cfg(test)]
mod from_digits {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn empty() {
        assert_eq!(Natural::from_digits(vec![]), None)
    }

    #[test]
    fn leading_zero() {
        assert_eq!(Natural::from_digits(vec![Digit::d0(), Digit::d1()]), None)
    }

    #[test]
    fn leading_non_zero() {
        assert_eq!(
            Natural::from_digits(vec![Digit::d4(), Digit::d2()]),
            Some(Natural {
                head: NonZeroDigit::D4,
                tail: vec![Digit::d2()]
            })
        )
    }
}

#[cfg(test)]
mod from_int {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn zero() {
        assert_eq!(Natural::from_int(0), None)
    }

    #[test]
    fn one_digit() {
        assert_eq!(
            Natural::from_int(4),
            Some(Natural {
                head: NonZeroDigit::D4,
                tail: vec![]
            })
        )
    }

    #[test]
    fn two_digits() {
        assert_eq!(
            Natural::from_int(42),
            Some(Natural {
                head: NonZeroDigit::D4,
                tail: vec![Digit::d2()]
            })
        )
    }
}