axconfig_gen/
ty.rs

1use crate::{ConfigErr, ConfigResult};
2
3/// The supported types in the config file.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum ConfigType {
6    /// Boolean type (`bool`).
7    Bool,
8    /// Signed integer type (`int`).
9    Int,
10    /// Unsigned integer type (`uint`).
11    Uint,
12    /// String type (`str`).
13    String,
14    /// Tuple type (e.g., `(int, str)`).
15    Tuple(Vec<ConfigType>),
16    /// Array type (e.g., `[int]`).
17    Array(Box<ConfigType>),
18    /// Type is unknown.
19    ///
20    /// It is used for type inference.
21    Unknown,
22}
23
24impl ConfigType {
25    /// Parses a type string into a [`ConfigType`].
26    pub fn new(ty: &str) -> ConfigResult<Self> {
27        let ty = ty.trim();
28        #[cfg(test)]
29        if ty == "?" {
30            return Ok(Self::Unknown);
31        }
32        match ty {
33            "bool" => Ok(Self::Bool),
34            "int" => Ok(Self::Int),
35            "uint" => Ok(Self::Uint),
36            "str" => Ok(Self::String),
37            _ => {
38                if ty.starts_with("(") && ty.ends_with(")") {
39                    let tuple = ty[1..ty.len() - 1].trim();
40                    if tuple.is_empty() {
41                        return Ok(Self::Tuple(Vec::new()));
42                    }
43                    let items = split_tuple_items(tuple).ok_or(ConfigErr::InvalidType)?;
44                    let tuple_types = items
45                        .into_iter()
46                        .map(Self::new)
47                        .collect::<ConfigResult<Vec<_>>>()?;
48                    Ok(Self::Tuple(tuple_types))
49                } else if ty.starts_with('[') && ty.ends_with("]") {
50                    let element = ty[1..ty.len() - 1].trim();
51                    if element.is_empty() {
52                        return Err(ConfigErr::InvalidType);
53                    }
54                    Ok(Self::Array(Box::new(Self::new(element)?)))
55                } else {
56                    Err(ConfigErr::InvalidType)
57                }
58            }
59        }
60    }
61
62    /// Converts the type into a Rust type string.
63    pub fn to_rust_type(&self) -> String {
64        match self {
65            Self::Bool => "bool".into(),
66            Self::Int => "isize".into(),
67            Self::Uint => "usize".into(),
68            Self::String => "&str".into(),
69            Self::Tuple(items) => {
70                let items = items
71                    .iter()
72                    .map(Self::to_rust_type)
73                    .collect::<Vec<_>>()
74                    .join(", ");
75                format!("({})", items)
76            }
77            Self::Array(ty) => format!("&[{}]", ty.to_rust_type()),
78            _ => panic!("Unknown type"),
79        }
80    }
81}
82
83fn split_tuple_items(s: &str) -> Option<Vec<&str>> {
84    let mut items = Vec::new();
85    let mut start = 0;
86    let mut level = 0;
87    for (i, c) in s.char_indices() {
88        match c {
89            '(' => level += 1,
90            ')' => level -= 1,
91            ',' if level == 0 => {
92                if start < i {
93                    items.push(&s[start..i]);
94                } else {
95                    return None;
96                }
97                start = i + 1;
98            }
99            _ => {}
100        }
101        if level < 0 {
102            return None;
103        }
104    }
105    if level == 0 && start < s.len() {
106        items.push(&s[start..]);
107        Some(items)
108    } else {
109        None
110    }
111}
112
113impl std::fmt::Display for ConfigType {
114    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115        match self {
116            Self::Bool => write!(f, "bool"),
117            Self::Int => write!(f, "int"),
118            Self::Uint => write!(f, "uint"),
119            Self::String => write!(f, "str"),
120            Self::Tuple(items) => {
121                write!(f, "(")?;
122                for (i, item) in items.iter().enumerate() {
123                    if i > 0 {
124                        write!(f, ", ")?;
125                    }
126                    write!(f, "{}", item)?;
127                }
128                write!(f, ")")
129            }
130            Self::Array(ty) => write!(f, "[{}]", ty),
131            Self::Unknown => write!(f, "?"),
132        }
133    }
134}