castle_types/
inputs.rs

1use std::{collections::HashMap, fmt::Display};
2
3use crate::{Primitive, CastleError};
4
5// (ident: primitive, ident2: primitive)
6// (ident: { ident: value, ident2: value })
7// (ident: [ value, value ])
8// (ident: Variant { // this is a map variant
9//   ident: value
10// })
11// (ident: Variant (value, value), ident_2: Primitive) // this is a tuple variant
12// (ident: Variant, ident_2: primitive) // is a unit variant
13
14#[derive(Debug, PartialEq, Clone)]
15pub enum Input {
16    Primitive(Primitive),
17    Variant(Variant),
18    Map(HashMap<Box<str>, Input>),
19    List(Vec<Input>),
20}
21
22pub type Inputs = HashMap<Box<str>, Input>;
23
24impl Input {
25    pub fn as_str(&self) -> Option<&str> {
26        match self {
27            Input::Primitive(Primitive::String(str)) => return Some(&**str),
28            _ => None,
29        }
30    }
31    pub fn as_map(&self) -> Option<&HashMap<Box<str>, Input>> {
32        match self {
33            Input::Map(map) => return Some(map),
34            _ => None,
35        }
36    }
37    pub fn as_list(&self) -> Option<&Vec<Input>> {
38        match self {
39            Input::List(list) => return Some(list),
40            _ => None,
41        }
42    }
43    pub fn as_variant(&self) -> Option<&Variant> {
44        match self {
45            Input::Variant(variant) => return Some(variant),
46            _ => None,
47        }
48    }
49}
50
51impl TryFrom<&Input> for Option<String> {
52    type Error = CastleError;
53
54    fn try_from(input: &Input) -> Result<Self, Self::Error> {
55        match input {
56            Input::Variant(Variant { ident, value: VariantType::Tuple(tuple)}) if &**ident == "Some" => {
57                match tuple.first() {
58                    Some(item) => Ok(Some(item.try_into()?)),
59                    _ => Err(CastleError::Validation("Expected value in tuple".into())),
60                }
61            },
62            Input::Variant(Variant { ident, value: VariantType::Unit}) if &**ident == "None" => Ok(None),
63            _ => Err(CastleError::Validation("Expected variant 'Some(..)' or 'None'".into())),
64        }
65    }
66}
67
68impl TryFrom<&Input> for String {
69    type Error = CastleError;
70
71    fn try_from(input: &Input) -> Result<Self, Self::Error> {
72        match input {
73            Input::Primitive(Primitive::String(str)) => Ok(str.to_string()),
74            _ => Err(CastleError::Validation("Expected string".into())),
75        }
76    }
77}
78
79impl<'a> TryFrom<&'a Input> for Option<&'a str> {
80    type Error = CastleError;
81
82    fn try_from(input: &'a Input) -> Result<Self, Self::Error> {
83        match input {
84            Input::Variant(Variant { ident, value: VariantType::Tuple(tuple)}) if &**ident == "Some" => {
85                match tuple.first() {
86                    Some(item) => Ok(Some(item.try_into()?)),
87                    _ => Err(CastleError::Validation("Expected value in tuple".into())),
88                }
89            }
90            Input::Variant(Variant { ident, value: VariantType::Unit}) if &**ident == "None" => Ok(None),
91            _ => Err(CastleError::Validation("Expected variant 'Some(..)' or 'None'".into())),
92        }
93    }
94}
95
96impl<'a> TryFrom<&'a Input> for &'a str {
97    type Error = CastleError;
98
99    fn try_from(input: &'a Input) -> Result<Self, Self::Error> {
100        match input {
101            Input::Primitive(Primitive::String(str)) => Ok(&**str),
102            _ => Err(CastleError::Validation("Expected string".into())),
103        }
104    }
105}
106
107impl TryFrom<&Input> for bool {
108    type Error = CastleError;
109
110    fn try_from(input: &Input) -> Result<Self, Self::Error> {
111        match input {
112            Input::Primitive(Primitive::Boolean(bool)) => Ok(*bool),
113            _ => Err(CastleError::Validation("Expected boolean".into())),
114        }
115    }
116}
117
118impl TryFrom<&Input> for Option<bool> {
119    type Error = CastleError;
120
121    fn try_from(input: &Input) -> Result<Self, Self::Error> {
122        match input {
123            Input::Variant(Variant { ident, value: VariantType::Tuple(tuple)}) if &**ident == "Some" => {
124                match tuple.first() {
125                    Some(item) => Ok(Some(item.try_into()?)),
126                    _ => panic!("Expected value in tuple"),
127                }
128            }
129            Input::Variant(Variant { ident, value: VariantType::Unit}) if &**ident == "None" => Ok(None),
130            _ => Err(CastleError::Validation("Expected variant 'Some(..)' or 'None'".into())),
131        }
132    }
133}
134
135impl<'a, T: TryFrom<&'a Input, Error = CastleError>> TryFrom<&'a Input> for Vec<T> {
136    type Error = CastleError;
137    fn try_from(input: &'a Input) -> Result<Self, Self::Error> {
138        match input {
139            Input::List(list) => list.iter().map(|input| T::try_from(input)).collect(),
140            _ => Ok(vec![]),
141        }
142    }
143}
144
145// Implement From for all the primitive numeric types
146macro_rules! impl_from_input {
147    ($($t:ty),*) => {
148        $(
149            impl TryFrom<&Input> for Option<$t> {
150                type Error = CastleError;
151
152                fn try_from(input: &Input) -> Result<Self, Self::Error> {
153                    match input {
154                        Input::Variant(Variant { ident, value: VariantType::Tuple(tuple)}) if &**ident == "Some" => {
155                            match tuple.first() {
156                                Some(item) => Ok(Some(item.try_into()?)),
157                                _ => Err(CastleError::Validation("Expected value in tuple".into())),
158                            }
159                        }
160                        Input::Variant(Variant { ident, value: VariantType::Unit}) if &**ident == "None" => Ok(None),
161                        _ => Err(CastleError::Validation("Expected variant 'Some(..)' or 'None'".into())),
162                    }
163                }
164            }
165
166            impl TryFrom<&Input> for $t {
167                type Error = CastleError;
168
169                fn try_from(input: &Input) -> Result<Self, Self::Error> {
170                    match input {
171                        Input::Primitive(Primitive::Number(number)) => Ok(number.clone().into()),
172                        _ => Err(CastleError::Validation("Expected number".into())),
173                    }
174                }
175            }
176        )*
177    };
178}
179
180impl_from_input!(i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, usize, isize);
181
182#[derive(Debug, PartialEq, Clone)]
183pub struct Variant {
184    pub ident: Box<str>,
185    pub value: VariantType,
186}
187
188#[derive(Debug, PartialEq, Clone)]
189pub enum VariantType {
190    Unit,
191    Tuple(Vec<Input>),
192    Map(HashMap<Box<str>, Input>),
193}
194
195impl Display for Input {
196    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
197        match self {
198            Input::Primitive(primitive) => write!(f, "{}", primitive),
199            Input::Variant(variant) => write!(f, "{}", variant),
200            Input::Map(map) => write!(f, "{:#?}", map),
201            Input::List(list) => write!(
202                f,
203                "{}",
204                list.iter()
205                    .map(|item| format!("{}", item))
206                    .collect::<Vec<String>>()
207                    .join(", ")
208            ),
209        }
210    }
211}
212
213impl Display for Variant {
214    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215        write!(f, "{}", self.ident)?;
216        match &self.value {
217            VariantType::Unit => write!(f, "()"),
218            VariantType::Tuple(tuple) => write!(
219                f,
220                "({})",
221                tuple
222                    .iter()
223                    .map(|val| format!("{}", val))
224                    .collect::<Vec<String>>()
225                    .join(", ")
226            ),
227            VariantType::Map(map) => write!(f, "{:#?}", map),
228        }
229    }
230}