tytanic_filter/ast/
num.rs1use 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#[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 num *= 10;
71 num += (d - b'0') as usize;
72 }
73
74 Ok(Self(num))
75 }
76}