1use core::num::ParseIntError;
2
3use super::tokenizer::Tokenizer;
4
5#[derive(Debug)]
6#[allow(dead_code)]
7pub enum ParseErrorKind<'a> {
8 Unexpected { need: &'a str, got: Option<&'a str> },
9 ParseIntError(ParseIntError),
10 UnexpectedId(&'a str),
11}
12
13#[derive(Debug)]
14#[allow(dead_code)]
15pub struct ParseError<'a> {
16 kind: ParseErrorKind<'a>,
17 loc: usize,
18}
19
20impl<'a> ParseError<'a> {
21 pub fn new(kind: ParseErrorKind<'a>, loc: usize) -> Self {
22 Self { kind, loc }
23 }
24}
25
26pub type Result<'a, T> = core::result::Result<T, ParseError<'a>>;
27
28pub trait CmdlineParse<'a>
29where
30 Self: Sized,
31{
32 fn parse_cmdline(tokenizer: &mut Tokenizer<'a>) -> Result<'a, Self>;
33}
34
35impl<'a> CmdlineParse<'a> for bool {
36 fn parse_cmdline(tokenizer: &mut Tokenizer<'a>) -> Result<'a, Self> {
37 let (loc, value) = tokenizer.next_value().ok_or_else(|| {
38 ParseError::new(
39 ParseErrorKind::Unexpected {
40 need: "true/false",
41 got: None,
42 },
43 tokenizer.current_index(),
44 )
45 })?;
46
47 match value {
48 "true" => Ok(true),
49 "false" => Ok(false),
50 _ => Err(ParseError::new(
51 ParseErrorKind::Unexpected {
52 need: "true/false",
53 got: Some(value),
54 },
55 loc,
56 )),
57 }
58 }
59}
60
61impl<'a> CmdlineParse<'a> for u32 {
62 fn parse_cmdline(tokenizer: &mut Tokenizer<'a>) -> Result<'a, Self> {
63 let (loc, value) = tokenizer.next_value().ok_or_else(|| {
64 ParseError::new(
65 ParseErrorKind::Unexpected {
66 need: "<number>",
67 got: None,
68 },
69 tokenizer.current_index(),
70 )
71 })?;
72
73 value
74 .parse()
75 .map_err(|e| ParseError::new(ParseErrorKind::ParseIntError(e), loc))
76 }
77}
78
79impl<'a> CmdlineParse<'a> for &'a str {
80 fn parse_cmdline(tokenizer: &mut Tokenizer<'a>) -> Result<'a, Self> {
81 let (_loc, value) = tokenizer.next_value().ok_or_else(|| {
82 ParseError::new(
83 ParseErrorKind::Unexpected {
84 need: "<str>",
85 got: None,
86 },
87 tokenizer.current_index(),
88 )
89 })?;
90
91 Ok(value)
92 }
93}