entity/ent/value/
type.rs

1use super::{NumberType, PrimitiveType, Value};
2use strum::ParseError;
3
4/// Represents value types (primitive or complex). Assumes that complex
5/// types will contain the same inner type and does not vary
6#[derive(Clone, Debug, PartialEq, Eq)]
7#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
8pub enum ValueType {
9    List(Box<ValueType>),
10    Map(Box<ValueType>),
11    Optional(Box<ValueType>),
12    Primitive(PrimitiveType),
13    Text,
14    Custom,
15}
16
17impl ValueType {
18    pub fn is_primitive_type(&self) -> bool {
19        matches!(self, Self::Primitive(_))
20    }
21
22    pub fn to_primitive_type(&self) -> Option<PrimitiveType> {
23        match self {
24            Self::Primitive(x) => Some(*x),
25            _ => None,
26        }
27    }
28
29    /// Constructs a value type from a Rust-based type string similar to what
30    /// you would find from `std::any::type_name`
31    ///
32    /// ## Examples
33    ///
34    /// ```
35    /// use entity::{ValueType as VT, PrimitiveType as PVT, NumberType as NT};
36    ///
37    /// assert_eq!(
38    ///     VT::from_type_name("u8").expect("one"),
39    ///     VT::Primitive(PVT::Number(NT::U8)),
40    /// );
41    ///
42    /// assert_eq!(
43    ///     VT::from_type_name("std::vec::Vec<std::string::String>").expect("two"),
44    ///     VT::List(Box::from(VT::Text)),
45    /// );
46    ///
47    /// assert_eq!(
48    ///     VT::from_type_name("Vec<Option<u8>>").expect("three"),
49    ///     VT::List(Box::from(VT::Optional(Box::from(VT::Primitive(PVT::Number(NT::U8)))))),
50    /// );
51    ///
52    /// assert_eq!(
53    ///     VT::from_type_name("HashMap<String, u8>").expect("four"),
54    ///     VT::Map(Box::from(VT::Primitive(PVT::Number(NT::U8)))),
55    /// );
56    /// ```
57    pub fn from_type_name(name: &str) -> Result<Self, ParseError> {
58        if name.is_empty() {
59            return Err(ParseError::VariantNotFound);
60        }
61
62        // Split based on the start of a generic in the form of Outer<Inner>
63        let mut tokens = name.split(|c| c == '<');
64        let maybe_outer_str = tokens.next();
65        let inner_str = {
66            let mut x = tokens.collect::<Vec<&str>>().join("<");
67            if x.ends_with('>') {
68                x.pop();
69            }
70            x
71        };
72
73        // Get the outer type based on an equivalent rust type
74        //
75        // * HashMap | BTreeMap -> Map
76        // * Vec | VecDeque | LinkedList | HashSet | BTreeSet | BinaryHeap -> List
77        // * Option -> Optional
78        // * String -> Text
79        // * (anything else) -> Primitive
80        match maybe_outer_str
81            .unwrap()
82            .split(|c| c == ':')
83            .last()
84            .unwrap()
85            .to_lowercase()
86            .as_str()
87        {
88            // If a map, we expect the form to be ...<String, ...> and will
89            // verify that the first type paraemter is String
90            "hashmap" | "btreemap" => {
91                let mut items = inner_str.split(|c| c == ',');
92                if let Some(s) = items.next() {
93                    if s.trim().to_lowercase().as_str() != "string" {
94                        return Err(ParseError::VariantNotFound);
95                    }
96                }
97
98                let rest = items.collect::<String>();
99                Ok(ValueType::Map(Box::from(Self::from_type_name(
100                    &rest.trim(),
101                )?)))
102            }
103            "vec" | "vecdeque" | "linkedlist" | "hashset" | "btreeset" | "binaryheap" => Ok(
104                ValueType::List(Box::from(Self::from_type_name(&inner_str)?)),
105            ),
106            "option" => Ok(ValueType::Optional(Box::from(Self::from_type_name(
107                &inner_str,
108            )?))),
109            "string" => Ok(ValueType::Text),
110            x => Ok(ValueType::Primitive(PrimitiveType::from_type_name(x)?)),
111        }
112    }
113}
114
115impl Default for ValueType {
116    /// Returns default value type of primitive unit
117    fn default() -> Self {
118        Self::Primitive(Default::default())
119    }
120}
121
122impl std::str::FromStr for ValueType {
123    type Err = ParseError;
124
125    /// Parses a string delimited by colons into a nested value type
126    ///
127    /// ## Examples
128    ///
129    /// ```
130    /// use entity::{ValueType as VT, PrimitiveType as PVT, NumberType as NT};
131    /// use strum::ParseError;
132    /// use std::str::FromStr;
133    ///
134    /// assert_eq!(VT::from_str("char").unwrap(), VT::Primitive(PVT::Char));
135    /// assert_eq!(VT::from_str("u32").unwrap(), VT::Primitive(PVT::Number(NT::U32)));
136    /// assert_eq!(VT::from_str("number:u32").unwrap(), VT::Primitive(PVT::Number(NT::U32)));
137    /// assert_eq!(VT::from_str("primitive:number:u32").unwrap(), VT::Primitive(PVT::Number(NT::U32)));
138    /// assert_eq!(VT::from_str("list:u32").unwrap(), VT::List(Box::from(VT::Primitive(PVT::Number(NT::U32)))));
139    /// assert_eq!(VT::from_str("list:number:u32").unwrap(), VT::List(Box::from(VT::Primitive(PVT::Number(NT::U32)))));
140    /// assert_eq!(VT::from_str("list:primitive:number:u32").unwrap(), VT::List(Box::from(VT::Primitive(PVT::Number(NT::U32)))));
141    /// assert_eq!(VT::from_str("unknown").unwrap_err(), ParseError::VariantNotFound);
142    /// ```
143    fn from_str(s: &str) -> Result<Self, Self::Err> {
144        fn opt_to_err(maybe_type: Option<ValueType>) -> Result<ValueType, ParseError> {
145            match maybe_type {
146                Some(t) => Ok(t),
147                None => Err(ParseError::VariantNotFound),
148            }
149        }
150
151        fn from_tokens<'a>(
152            mut it: impl Iterator<Item = &'a str>,
153        ) -> Result<Option<ValueType>, ParseError> {
154            match it.next() {
155                // Special case where we cannot feed this directly into the
156                // primitive value type as it is the following type that is
157                // used instead, so we take the next value instead and use it
158                Some("number") => from_tokens(it),
159                Some(token) => {
160                    let maybe_inner = from_tokens(it)?;
161                    match token {
162                        "list" => Ok(Some(ValueType::List(Box::from(opt_to_err(maybe_inner)?)))),
163                        "map" => Ok(Some(ValueType::Map(Box::from(opt_to_err(maybe_inner)?)))),
164                        "optional" => Ok(Some(ValueType::Optional(Box::from(opt_to_err(
165                            maybe_inner,
166                        )?)))),
167                        "primitive" => Ok(Some(ValueType::Primitive(
168                            opt_to_err(maybe_inner)?
169                                .to_primitive_type()
170                                .ok_or(ParseError::VariantNotFound)?,
171                        ))),
172                        "text" => Ok(Some(ValueType::Text)),
173                        x => Ok(Some(ValueType::Primitive(PrimitiveType::from_str(x)?))),
174                    }
175                }
176                None => Ok(None),
177            }
178        }
179
180        match from_tokens(s.split(':')) {
181            Ok(Some(value_type)) => Ok(value_type),
182            Ok(None) => Err(ParseError::VariantNotFound),
183            Err(x) => Err(x),
184        }
185    }
186}
187
188impl std::fmt::Display for ValueType {
189    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190        match self {
191            Self::List(t) => write!(f, "list:{}", t),
192            Self::Map(t) => write!(f, "map:{}", t),
193            Self::Optional(t) => write!(f, "optional:{}", t),
194            Self::Primitive(t) => write!(f, "{}", t),
195            Self::Text => write!(f, "text"),
196            Self::Custom => write!(f, "custom"),
197        }
198    }
199}
200
201impl From<Value> for ValueType {
202    fn from(value: Value) -> Self {
203        Self::from(&value)
204    }
205}
206
207impl<'a> From<&'a Value> for ValueType {
208    /// Produces the type of the referenced value by recursively iterating
209    /// through complex types, assuming that the first value in types like
210    /// list represent the entire set, defaulting to a primitive unit if
211    /// a complex value does not have any items
212    fn from(v: &'a Value) -> Self {
213        match v {
214            Value::List(x) => Self::List(Box::from(
215                x.iter().next().map(ValueType::from).unwrap_or_default(),
216            )),
217            Value::Map(x) => Self::Map(Box::from(
218                x.values().next().map(ValueType::from).unwrap_or_default(),
219            )),
220            Value::Optional(x) => Self::Optional(Box::from(
221                x.as_ref()
222                    .map(Box::as_ref)
223                    .map(ValueType::from)
224                    .unwrap_or_default(),
225            )),
226            Value::Primitive(x) => Self::Primitive(PrimitiveType::from(x)),
227            Value::Text(_) => Self::Text,
228        }
229    }
230}
231
232impl From<PrimitiveType> for ValueType {
233    /// Converts primitive value type to a value type
234    fn from(t: PrimitiveType) -> Self {
235        Self::Primitive(t)
236    }
237}
238
239impl From<NumberType> for ValueType {
240    /// Converts number type (subclass of primitive type) to a value type
241    fn from(t: NumberType) -> Self {
242        Self::Primitive(PrimitiveType::Number(t))
243    }
244}