tytanic_filter/ast/
num.rs

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