valitron/register/
field_name.rs

1use std::{
2    convert::Infallible,
3    fmt::Display,
4    hash::{Hash, Hasher},
5};
6
7use serde::Serialize;
8
9use super::{
10    lexer::{Cursor, Token, TokenKind},
11    MessageKey,
12};
13
14#[derive(Debug, PartialEq, Eq, Hash, Clone)]
15pub enum FieldName {
16    Literal(String),
17    Array(usize),
18    Tuple(u8),
19    Option,
20
21    /// get `g` on enum A { Color{ r:u8, g:u8, b:u8}}
22    StructVariant(String),
23}
24
25impl FieldName {
26    pub fn as_str(&self) -> &str {
27        match self {
28            FieldName::Literal(s) => s.as_str(),
29            FieldName::StructVariant(s) => s.as_str(),
30            _ => "",
31        }
32    }
33}
34
35impl Display for FieldName {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        match self {
38            FieldName::Literal(s) => s.fmt(f),
39            FieldName::Array(n) => n.fmt(f),
40            FieldName::Tuple(n) => n.fmt(f),
41            FieldName::Option => "?".fmt(f),
42            FieldName::StructVariant(s) => s.fmt(f),
43        }
44    }
45}
46
47fn names_to_string(vec: &[FieldName]) -> String {
48    let mut string = String::new();
49    for item in vec.iter() {
50        match item {
51            FieldName::Literal(s) => {
52                if !string.is_empty() {
53                    string.push('.');
54                }
55                string.push_str(s);
56            }
57            FieldName::Array(n) => {
58                string.push('[');
59                string.push_str(&n.to_string());
60                string.push(']');
61            }
62            FieldName::Tuple(n) => {
63                if !string.is_empty() {
64                    string.push('.');
65                }
66                string.push_str(&n.to_string());
67            }
68            FieldName::Option => string.push('?'),
69            FieldName::StructVariant(s) => {
70                string.push('[');
71                string.push_str(s);
72                string.push(']');
73            }
74        }
75    }
76    string
77}
78
79#[derive(Debug, PartialEq, Eq, Clone, Default)]
80pub struct FieldNames {
81    string: String,
82}
83
84impl Serialize for FieldNames {
85    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
86    where
87        S: serde::Serializer,
88    {
89        serializer.serialize_str(&self.string)
90    }
91}
92
93impl Hash for FieldNames {
94    fn hash<H: Hasher>(&self, state: &mut H) {
95        self.string.hash(state)
96    }
97}
98
99impl FieldNames {
100    pub(crate) fn new(string: String) -> Self {
101        Self { string }
102    }
103
104    // pub fn iter(&self) -> Iter<'_, FieldName> {
105    //     self.vec.iter()
106    // }
107    pub fn as_str(&self) -> &str {
108        &self.string
109    }
110}
111
112impl From<Vec<FieldName>> for FieldNames {
113    fn from(value: Vec<FieldName>) -> Self {
114        Self {
115            string: names_to_string(&value),
116        }
117    }
118}
119impl From<FieldName> for FieldNames {
120    fn from(value: FieldName) -> Self {
121        let vec = vec![value];
122        Self {
123            string: names_to_string(&vec),
124        }
125    }
126}
127impl<const N: usize> From<[FieldName; N]> for FieldNames {
128    fn from(value: [FieldName; N]) -> Self {
129        let vec: Vec<_> = value.into_iter().collect();
130        Self::from(vec)
131    }
132}
133
134impl From<String> for FieldNames {
135    fn from(string: String) -> Self {
136        Self { string }
137    }
138}
139impl From<&str> for FieldNames {
140    fn from(string: &str) -> Self {
141        Self {
142            string: string.to_owned(),
143        }
144    }
145}
146
147/// Convert to FieldName trait
148pub trait IntoFieldName {
149    type Error: std::fmt::Display;
150    fn into_field(self) -> Result<FieldNames, Self::Error>;
151}
152
153impl IntoFieldName for &str {
154    type Error = Infallible;
155    fn into_field(self) -> Result<FieldNames, Self::Error> {
156        Ok(FieldNames {
157            string: self.to_string(),
158        })
159    }
160}
161impl IntoFieldName for u8 {
162    type Error = Infallible;
163    fn into_field(self) -> Result<FieldNames, Self::Error> {
164        Ok(FieldNames {
165            string: self.to_string(),
166        })
167    }
168}
169impl IntoFieldName for (u8, u8) {
170    type Error = Infallible;
171    fn into_field(self) -> Result<FieldNames, Self::Error> {
172        Ok(FieldNames {
173            string: format!("{}.{}", self.0, self.1),
174        })
175    }
176}
177impl IntoFieldName for (u8, u8, u8) {
178    type Error = Infallible;
179    fn into_field(self) -> Result<FieldNames, Self::Error> {
180        Ok(FieldNames {
181            string: format!("{}.{}.{}", self.0, self.1, self.2),
182        })
183    }
184}
185impl IntoFieldName for [usize; 1] {
186    type Error = Infallible;
187    fn into_field(self) -> Result<FieldNames, Self::Error> {
188        Ok(FieldNames {
189            string: format!("[{}]", self[0]),
190        })
191    }
192}
193// impl IntoFieldName for [&str; 1] {
194//     type Error = String;
195//     fn into_field(self) -> Result<Vec<FieldName>, Self::Error> {
196//         self[0].chars()
197//         Ok(vec![FieldName::StructVariant(self[0].to_string())])
198//     }
199// }
200impl<T> IntoFieldName for &'_ T
201where
202    T: IntoFieldName + Copy,
203{
204    type Error = T::Error;
205
206    fn into_field(self) -> Result<FieldNames, Self::Error> {
207        T::into_field(*self)
208    }
209}
210
211pub(crate) struct Parser<'a> {
212    source: &'a str,
213    token: Cursor<'a>,
214}
215
216impl<'a> Parser<'a> {
217    pub(crate) fn new(source: &'a str) -> Self {
218        let token = Cursor::new(source);
219        Self { source, token }
220    }
221
222    pub fn next_name(&mut self) -> Result<Option<FieldName>, ParserError> {
223        let token = self.token.advance();
224        match token.kind() {
225            TokenKind::Ident => {
226                //self.current_pos += 1;
227                let ident;
228                (ident, self.source) = self.source.split_at(token.len);
229                let res = FieldName::Literal(ident.to_owned());
230                self.eat_dot()?;
231                Ok(Some(res))
232            }
233            TokenKind::Dot => Err(ParserError::DotStart),
234            TokenKind::LeftBracket => {
235                self.source = &self.source[token.len..];
236                self.parse_bracket().map(Some)
237            }
238            TokenKind::Option => {
239                self.source = &self.source[token.len..];
240                let res = FieldName::Option;
241                self.eat_dot()?;
242                Ok(Some(res))
243            }
244            TokenKind::RightBracket => Err(ParserError::BracketRight),
245            TokenKind::Index => {
246                let index_str;
247                (index_str, self.source) = self.source.split_at(token.len);
248                let res = FieldName::Tuple(
249                    index_str
250                        .parse()
251                        .map_err(|_| ParserError::ParseTupleIndex)?,
252                );
253                if !(self.expect(TokenKind::Dot)
254                    || self.expect(TokenKind::LeftBracket)
255                    || self.expect(TokenKind::Eof))
256                {
257                    return Err(ParserError::TupleClose);
258                }
259
260                self.eat_dot()?;
261                Ok(Some(res))
262            }
263            TokenKind::Undefined => Err(ParserError::Undefined),
264            TokenKind::Eof => Ok(None),
265        }
266    }
267
268    /// parse `[0]` or `[abc]`
269    fn parse_bracket(&mut self) -> Result<FieldName, ParserError> {
270        let mut peek = self.token.clone();
271        let t = peek.advance();
272        match t.kind() {
273            TokenKind::Index => {
274                if let Token {
275                    kind: TokenKind::RightBracket,
276                    ..
277                } = peek.advance()
278                {
279                    let name = FieldName::Array(
280                        (self.source[..t.len])
281                            .parse()
282                            .map_err(|_| ParserError::ParseArrayIndex)?,
283                    );
284                    // eat index
285                    self.token.advance();
286                    self.source = &self.source[t.len..];
287                    // eat `]`
288                    self.token.advance();
289                    self.source = &self.source[1..];
290
291                    if !(self.expect(TokenKind::Dot)
292                        || self.expect(TokenKind::LeftBracket)
293                        || self.expect(TokenKind::Eof)
294                        || self.expect(TokenKind::Option))
295                    {
296                        return Err(ParserError::ArrayClose);
297                    }
298                    self.eat_dot()?;
299                    return Ok(name);
300                }
301            }
302            TokenKind::Ident => {
303                if let Token {
304                    kind: TokenKind::RightBracket,
305                    ..
306                } = peek.advance()
307                {
308                    let str;
309                    (str, self.source) = self.source.split_at(t.len);
310                    let name = FieldName::StructVariant(str.to_owned());
311
312                    // eat ident
313                    self.token.advance();
314                    // eat `]`
315                    self.token.advance();
316                    self.source = &self.source[1..];
317
318                    if !(self.expect(TokenKind::Dot)
319                        || self.expect(TokenKind::LeftBracket)
320                        || self.expect(TokenKind::Eof)
321                        || self.expect(TokenKind::Option))
322                    {
323                        return Err(ParserError::ArrayClose);
324                    }
325
326                    self.eat_dot()?;
327                    return Ok(name);
328                }
329            }
330            _ => return Err(ParserError::BracketSyntaxError),
331        }
332
333        Err(ParserError::BracketSyntaxError)
334    }
335
336    fn expect(&self, token: TokenKind) -> bool {
337        let peek = self.token.clone().advance();
338        token == peek.kind
339    }
340
341    fn eat_dot(&mut self) -> Result<(), ParserError> {
342        let mut peek = self.token.clone();
343        if let Token {
344            kind: TokenKind::Dot,
345            ..
346        } = peek.advance()
347        {
348            let Token { kind, .. } = peek.advance();
349            match kind {
350                TokenKind::Eof => return Err(ParserError::DotIsLast),
351                TokenKind::LeftBracket => return Err(ParserError::DotTieLeftBracket),
352                _ => (),
353            }
354            self.token.advance();
355            self.source = &self.source[1..];
356        }
357
358        Ok(())
359    }
360}
361
362#[cfg(test)]
363pub(crate) fn parse(source: &str) -> Result<Vec<FieldName>, ParserError> {
364    let mut parser = Parser::new(source);
365
366    let mut vec = Vec::new();
367    loop {
368        match parser.next_name()? {
369            Some(name) => vec.push(name),
370            None => break Ok(vec),
371        }
372    }
373}
374
375pub fn parse_message(source: &str) -> Result<MessageKey, String> {
376    let (name_str, string) = source
377        .rsplit_once('.')
378        .ok_or("not found message".to_owned())?;
379
380    Ok(MessageKey::new(
381        FieldNames::new(name_str.to_string()),
382        string,
383    ))
384}
385
386#[derive(Debug)]
387pub(crate) enum ParserError {
388    DotStart,
389    BracketRight,
390    ParseTupleIndex,
391    TupleClose,
392    Undefined,
393    ParseArrayIndex,
394    ArrayClose,
395    BracketSyntaxError,
396    DotIsLast,
397    DotTieLeftBracket,
398}
399
400impl Display for ParserError {
401    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
402        use ParserError::*;
403        match self {
404            DotStart => "`.` can not be start".fmt(f),
405            BracketRight => "`]` should to stay behind `[`".fmt(f),
406            ParseTupleIndex => "tuple index is not u8 type".fmt(f),
407            TupleClose => "after tuple index must be `.` or `[` or eof".fmt(f),
408            Undefined => "undefined character".fmt(f),
409            ParseArrayIndex => "array index is not usize type".fmt(f),
410            ArrayClose => "after `]` must be `.` or `[` or eof".fmt(f),
411            BracketSyntaxError => "bracket syntax error".fmt(f),
412            DotIsLast => "`.` can not be end".fmt(f),
413            DotTieLeftBracket => "after `.` can not be `[`".fmt(f),
414        }
415    }
416}
417
418#[test]
419fn test_parse() {
420    let names = parse("abc").unwrap();
421    assert_eq!(names, vec![FieldName::Literal("abc".into())]);
422
423    let names = parse("name.full_name").unwrap();
424    assert_eq!(
425        names,
426        vec![
427            FieldName::Literal("name".into()),
428            FieldName::Literal("full_name".into())
429        ]
430    );
431
432    let names = parse("name.1").unwrap();
433    assert_eq!(
434        names,
435        vec![FieldName::Literal("name".into()), FieldName::Tuple(1)]
436    );
437
438    let names = parse("name[511]").unwrap();
439    assert_eq!(
440        names,
441        vec![FieldName::Literal("name".into()), FieldName::Array(511)]
442    );
443
444    let names = parse("name[age]").unwrap();
445    assert_eq!(
446        names,
447        vec![
448            FieldName::Literal("name".into()),
449            FieldName::StructVariant("age".into())
450        ]
451    );
452
453    let names = parse("5").unwrap();
454    assert_eq!(names, vec![FieldName::Tuple(5)]);
455
456    parse("511").unwrap_err();
457    parse("5age").unwrap_err();
458    parse("[5]age").unwrap_err();
459    parse(".age").unwrap_err();
460
461    let names = parse("name.age[foo]?[0]?.color.0").unwrap();
462    assert_eq!(
463        names,
464        vec![
465            FieldName::Literal("name".into()),
466            FieldName::Literal("age".into()),
467            FieldName::StructVariant("foo".into()),
468            FieldName::Option,
469            FieldName::Array(0),
470            FieldName::Option,
471            FieldName::Literal("color".into()),
472            FieldName::Tuple(0),
473        ]
474    );
475}