1use crate::{ConfigErr, ConfigResult};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum ConfigType {
6 Bool,
8 Int,
10 Uint,
12 String,
14 Tuple(Vec<ConfigType>),
16 Array(Box<ConfigType>),
18 Unknown,
22}
23
24impl ConfigType {
25 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 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}