tytanic_filter/ast/
num.rs1use 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#[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 num *= 10;
79 num += (d - b'0') as usize;
80 }
81
82 Ok(Self(num))
83 }
84}