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}