tytanic_filter/ast/
num.rs

1use std::fmt::Debug;
2
3use ecow::eco_vec;
4use pest::iterators::Pair;
5
6use super::Error;
7use super::PairExt;
8use super::Rule;
9use crate::eval;
10use crate::eval::Context;
11use crate::eval::Eval;
12use crate::eval::Test;
13use crate::eval::TryFromValue;
14use crate::eval::Type;
15use crate::eval::Value;
16
17/// A number literal node.
18#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct Num(pub usize);
20
21impl Debug for Num {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        self.0.fmt(f)
24    }
25}
26
27impl From<usize> for Num {
28    fn from(value: usize) -> Self {
29        Self(value)
30    }
31}
32
33impl From<Num> for usize {
34    fn from(value: Num) -> Self {
35        value.0
36    }
37}
38
39impl<T: Test> Eval<T> for Num {
40    fn eval(&self, _ctx: &Context<T>) -> Result<Value<T>, eval::Error> {
41        Ok(Value::Num(*self))
42    }
43}
44
45impl<T> TryFromValue<T> for Num {
46    fn try_from_value(value: Value<T>) -> Result<Self, eval::Error> {
47        Ok(match value {
48            Value::Num(set) => set,
49            _ => {
50                return Err(eval::Error::TypeMismatch {
51                    expected: eco_vec![Type::Num],
52                    found: value.as_type(),
53                });
54            }
55        })
56    }
57}
58
59impl Num {
60    pub(super) fn parse(pair: Pair<'_, Rule>) -> Result<Self, Error> {
61        pair.expect_rules(&[Rule::num_inner])?;
62        let mut s = pair.as_str().as_bytes();
63        let mut num = 0;
64
65        while let Some((&d, rest)) = s.split_first() {
66            debug_assert!(
67                matches!(d, b'0'..=b'9' | b'_'),
68                "parser should ensure this is only digits and underscores",
69            );
70
71            s = rest;
72
73            if d == b'_' {
74                continue;
75            }
76
77            // Decimal equivalent of shift left and or LSB.
78            num *= 10;
79            num += (d - b'0') as usize;
80        }
81
82        Ok(Self(num))
83    }
84}