ted: add num module
2 files changed, 186 insertions(+), 0 deletions(-)

M src/lib.rs
A => src/num.rs
M src/lib.rs +1 -0
@@ 9,6 9,7 @@ pub mod trie;
 pub mod plugin;
 pub mod command;
 pub mod cache;
+pub mod num;
 
 pub(crate) trait Ropey {
     fn starts_with(&self, prefix: &str) -> bool;

          
A => src/num.rs +185 -0
@@ 0,0 1,185 @@ 
+macro_rules! ints {
+    ($mac:ident) => {
+        $mac!(u8);
+        $mac!(i8);
+        $mac!(u16);
+        $mac!(i16);
+        $mac!(u32);
+        $mac!(i32);
+        $mac!(u64);
+        $mac!(i64);
+        #[cfg(has_u128)]
+        $mac!(u128);
+        #[cfg(has_i128)]
+        $mac!(i128);
+        $mac!(usize);
+        $mac!(isize);
+    }
+}
+
+pub trait NumDigits {
+    type Output;
+
+    fn num_digits(&self) -> Self::Output;
+}
+
+macro_rules! impl_numdigits {
+    ($ty:ty) => {
+        impl NumDigits for $ty {
+            type Output = u8;
+
+            fn num_digits(&self) -> Self::Output {
+                let mut digits = 1;
+                let mut num = *self;
+                while num >= 10 {
+                    num /= 10;
+                    digits += 1;
+                }
+                digits
+            }
+        }
+    }
+}
+ints!(impl_numdigits);
+
+pub trait Digits: Sized {
+    fn digits(&self) -> DigitIter<Self>;
+}
+
+impl<T> Digits for T where T: Clone {
+    fn digits(&self) -> DigitIter<T> {
+        DigitIter(self.clone())
+    }
+}
+
+pub struct DigitIter<T>(T);
+
+impl<T> DigitIter<T> {
+    pub fn str(self) -> DigitStrIter<T> {
+        DigitStrIter(self)
+    }
+}
+
+macro_rules! impl_digititer {
+    ($ty:ty) => {
+        impl Iterator for DigitIter<$ty> {
+            type Item = u8;
+
+            fn next(&mut self) -> Option<Self::Item> {
+                if self.0 == 0 { return None }
+
+                let digit = self.0 % 10;
+                self.0 /= 10;
+
+                Some(digit as u8)
+            }
+
+            fn size_hint(&self) -> (usize, Option<usize>) {
+                let num_digits = self.0.num_digits().into();
+                (num_digits, Some(num_digits))
+            }
+        }
+    }
+}
+ints!(impl_digititer);
+
+impl<T> ExactSizeIterator for DigitIter<T> where
+    T: NumDigits<Output=u8>,
+    DigitIter<T>: Iterator<Item=u8>
+{
+    fn len(&self) -> usize {
+        self.0.num_digits().into()
+    }
+}
+
+pub struct DigitStrIter<T>(DigitIter<T>);
+
+impl<T> Iterator for DigitStrIter<T> where DigitIter<T>: Iterator<Item=u8> {
+    type Item = &'static str;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.0.next().map(|digit| match &digit {
+            0 => "0",
+            1 => "1",
+            2 => "2",
+            3 => "3",
+            4 => "4",
+            5 => "5",
+            6 => "6",
+            7 => "7",
+            8 => "8",
+            9 => "9",
+            _ => unreachable!()
+        })
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.0.size_hint()
+    }
+}
+
+impl<T> ExactSizeIterator for DigitStrIter<T> where
+    T: NumDigits<Output=u8>,
+    DigitIter<T>: ExactSizeIterator,
+    DigitStrIter<T>: Iterator<Item=&'static str>
+{
+    fn len(&self) -> usize {
+        self.0.len()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn num_digits() {
+        assert_eq!(0u8.num_digits(), 1);
+        assert_eq!(1u8.num_digits(), 1);
+        assert_eq!(12i8.num_digits(), 2);
+        assert_eq!(123u16.num_digits(), 3);
+        assert_eq!(1234i16.num_digits(), 4);
+        assert_eq!(12345u32.num_digits(), 5);
+        assert_eq!(123456i32.num_digits(), 6);
+        assert_eq!(1234567u64.num_digits(), 7);
+        assert_eq!(12345678i64.num_digits(), 8);
+        #[cfg(has_u128)]
+        assert_eq!(123456789u128.num_digits(), 9);
+        #[cfg(has_i128)]
+        assert_eq!(1234567890i128.num_digits(), 10);
+    }
+
+    #[test]
+    fn digits() {
+        macro_rules! test {
+            ($ty:ty) => {
+                let num: $ty = 123;
+                let mut iter = num.digits();
+                assert_eq!(iter.len(), 3);
+                assert_eq!(iter.size_hint(), (3, Some(3)));
+                assert_eq!(iter.next(), Some(3));
+                assert_eq!(iter.next(), Some(2));
+                assert_eq!(iter.next(), Some(1));
+                assert_eq!(iter.next(), None);
+            }
+        }
+        ints!(test);
+    }
+
+    #[test]
+    fn digits_str() {
+        macro_rules! test {
+            ($ty:ty) => {
+                let num: $ty = 123;
+                let mut iter = num.digits().str();
+                assert_eq!(iter.len(), 3);
+                assert_eq!(iter.size_hint(), (3, Some(3)));
+                assert_eq!(iter.next(), Some("3"));
+                assert_eq!(iter.next(), Some("2"));
+                assert_eq!(iter.next(), Some("1"));
+                assert_eq!(iter.next(), None);
+            }
+        }
+        ints!(test);
+    }
+}