interact 0.3.6

A framework for online program state introspection
Documentation
use crate::deser::{Deser, DeserError, Result, Tracker};
use crate::tokens::{Token, TokenKind};

macro_rules! impl_unsigned {
    ($a:tt) => {
        impl Deser for $a {
            fn deser<'a, 'b>(tracker: &mut Tracker<'a, 'b>) -> Result<Self> {
                if !tracker.has_remaining() {
                    return Err(DeserError::EndOfTokenList);
                }

                if let TokenKind::NonNegativeDecimal(nnd) = tracker.top_kind() {
                    let nnd = nnd.clone();
                    if nnd > u64::from(Self::max_value()) {
                        return Err(DeserError::NumberTooLarge);
                    }

                    tracker.step();
                    return Ok(nnd as Self);
                }
                if let TokenKind::Decimal(nnd) = tracker.top_kind() {
                    let nnd = nnd.clone();
                    if nnd < 0 {
                        return Err(DeserError::NumberTooSmall);
                    }
                    if nnd as u64 > u64::from(Self::max_value()) {
                        return Err(DeserError::NumberTooLarge);
                    }

                    tracker.step();
                    return Ok(nnd as Self);
                }

                Err(DeserError::UnexpectedToken)
            }
        }
    };
}

impl_unsigned!(u64);
impl_unsigned!(u32);
impl_unsigned!(u16);
impl_unsigned!(u8);

macro_rules! impl_signed {
    ($a:tt) => {
        impl Deser for $a {
            fn deser<'a, 'b>(tracker: &mut Tracker<'a, 'b>) -> Result<Self> {
                if !tracker.has_remaining() {
                    return Err(DeserError::EndOfTokenList);
                }

                if let TokenKind::NonNegativeDecimal(nnd) = tracker.top_kind() {
                    let nnd = nnd.clone();
                    if nnd >= Self::max_value() as u64 {
                        return Err(DeserError::NumberTooLarge);
                    }
                    tracker.step();
                    return Ok(nnd as Self);
                } else if let TokenKind::Decimal(dec) = tracker.top_kind() {
                    let dec = dec.clone();
                    if dec < Self::min_value() as i64 {
                        return Err(DeserError::NumberTooSmall);
                    }
                    if dec > Self::max_value() as i64 {
                        return Err(DeserError::NumberTooLarge);
                    }

                    tracker.step();
                    return Ok(dec as Self);
                }

                Err(DeserError::UnexpectedToken)
            }
        }
    };
}

impl_signed!(isize);
impl_signed!(i64);
impl_signed!(i32);
impl_signed!(i16);
impl_signed!(i8);

impl Deser for usize {
    fn deser<'a, 'b>(tracker: &mut Tracker<'a, 'b>) -> Result<Self> {
        if !tracker.has_remaining() {
            return Err(DeserError::EndOfTokenList);
        }

        if let TokenKind::NonNegativeDecimal(nnd) = tracker.top_kind() {
            let nnd = nnd.clone();
            if nnd > Self::max_value() as u64 {
                return Err(DeserError::NumberTooLarge);
            }

            tracker.step();
            return Ok(nnd as Self);
        }
        if let TokenKind::Decimal(nnd) = tracker.top_kind() {
            let nnd = nnd.clone();
            if nnd < 0 {
                return Err(DeserError::NumberTooSmall);
            }
            if nnd as u64 > Self::max_value() as u64 {
                return Err(DeserError::NumberTooLarge);
            }

            tracker.step();
            return Ok(nnd as Self);
        }

        Err(DeserError::UnexpectedToken)
    }
}

macro_rules! impl_simple {
    ($a:tt, $token:ident) => {
        impl Deser for $a {
            fn deser<'a, 'b>(tracker: &mut Tracker<'a, 'b>) -> Result<Self> {
                if !tracker.has_remaining() {
                    return Err(DeserError::EndOfTokenList);
                }

                if let TokenKind::$token(s) = tracker.top_kind() {
                    let s = s.clone();
                    tracker.step();
                    return Ok(s);
                }

                Err(DeserError::UnexpectedToken)
            }
        }
    };
}

impl_simple!(String, String);
impl_simple!(char, Char);

impl Deser for bool {
    fn deser<'a, 'b>(tracker: &mut Tracker<'a, 'b>) -> Result<Self> {
        let values = [("false", false), ("true", true)];

        if !tracker.has_remaining() {
            for (s, _) in values.iter() {
                tracker.possible_token(Token::new_borrowed(TokenKind::Ident, s));
            }
            return Err(DeserError::EndOfTokenList);
        }

        if let TokenKind::Ident = tracker.top_kind() {
            for (s, value) in values.iter() {
                if *s == tracker.top().text {
                    tracker.step();
                    return Ok(*value);
                }
            }

            for (s, _) in values.iter() {
                if s.starts_with(tracker.top().text.as_ref()) {
                    tracker.possible_token(Token::new_borrowed(TokenKind::Ident, s));
                }
            }
        }

        Err(DeserError::UnexpectedToken)
    }
}