1use std::cmp::Ordering;
2use std::convert::TryFrom;
3use std::fmt;
4use std::str::FromStr;
5use std::sync::Arc;
6
7use async_trait::async_trait;
8use bytes::Bytes;
9use destream::de::Error as DestreamError;
10use destream::de::Visitor as DestreamVisitor;
11use destream::{de, en};
12use email_address_parser::EmailAddress;
13use log::debug;
14use safecast::{TryCastFrom, TryCastInto};
15
16use tc_error::*;
17use tcgeneric::*;
18
19use super::number::{ComplexType, FloatType, IntType, NumberClass, NumberType, UIntType};
20use super::value::Value;
21use super::version::Version;
22
23pub const PREFIX: PathLabel = path_label(&["state", "scalar", "value"]);
25
26#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28pub enum ValueType {
29 Bytes,
30 Email,
31 Id,
32 Link,
33 None,
34 Number(NumberType),
35 String,
36 Tuple,
37 Value,
38 Version,
39}
40
41impl ValueType {
42 pub fn from_suffix(suffix: &[PathSegment]) -> Option<Self> {
44 debug!("ValueType::from_suffix {}", TCPath::from(suffix));
45
46 use ComplexType as CT;
47 use FloatType as FT;
48 use IntType as IT;
49 use NumberType as NT;
50 use UIntType as UT;
51
52 if suffix.is_empty() {
53 Some(Self::default())
54 } else if suffix.len() == 1 {
55 match suffix[0].as_str() {
56 "bytes" => Some(Self::Bytes),
57 "email" => Some(Self::Email),
58 "id" => Some(Self::Id),
59 "link" => Some(Self::Link),
60 "number" => Some(Self::Number(NT::Number)),
61 "none" => Some(Self::None),
62 "string" => Some(Self::String),
63 "tuple" => Some(Self::Tuple),
64 "version" => Some(Self::Version),
65 _ => None,
66 }
67 } else if suffix.len() == 2 && &suffix[0] == "number" {
68 match suffix[1].as_str() {
69 "bool" => Some(Self::Number(NT::Bool)),
70 "complex" => Some(Self::Number(NT::Complex(CT::Complex))),
71 "float" => Some(Self::Number(NT::Float(FT::Float))),
72 "int" => Some(Self::Number(NT::Int(IT::Int))),
73 "uint" => Some(Self::Number(NT::UInt(UT::UInt))),
74 _ => None,
75 }
76 } else if suffix.len() == 3 && &suffix[0] == "number" {
77 match suffix[1].as_str() {
78 "complex" => match suffix[2].as_str() {
79 "32" => Some(Self::Number(NT::Complex(CT::C32))),
80 "64" => Some(Self::Number(NT::Complex(CT::C64))),
81 _ => None,
82 },
83 "float" => match suffix[2].as_str() {
84 "32" => Some(Self::Number(NT::Float(FT::F32))),
85 "64" => Some(Self::Number(NT::Float(FT::F64))),
86 _ => None,
87 },
88 "int" => match suffix[2].as_str() {
89 "16" => Some(Self::Number(NT::Int(IT::I16))),
90 "32" => Some(Self::Number(NT::Int(IT::I32))),
91 "64" => Some(Self::Number(NT::Int(IT::I64))),
92 _ => None,
93 },
94 "uint" => match suffix[2].as_str() {
95 "8" => Some(Self::Number(NT::UInt(UT::U8))),
96 "16" => Some(Self::Number(NT::UInt(UT::U16))),
97 "32" => Some(Self::Number(NT::UInt(UT::U32))),
98 "64" => Some(Self::Number(NT::UInt(UT::U64))),
99 _ => None,
100 },
101 _ => None,
102 }
103 } else {
104 None
105 }
106 }
107
108 pub fn size(&self) -> Option<usize> {
110 match self {
111 Self::Number(nt) => Some(nt.size()),
112 _ => None,
113 }
114 }
115
116 pub fn try_cast<V>(&self, value: V) -> TCResult<Value>
118 where
119 Value: From<V>,
120 {
121 let on_err = |v: &Value| bad_request!("cannot cast into {self:?} from {v:?}");
122 let value = Value::from(value);
123
124 match self {
125 Self::Bytes => match value {
126 Value::Bytes(bytes) => Ok(Value::Bytes(bytes)),
127 Value::Number(_) => Err(not_implemented!("cast into Bytes from Number")),
128 Value::String(s) => {
129 Bytes::try_cast_from(s, |s| bad_request!("cannot cast into Bytes from {s}"))
130 .map(Vec::from)
131 .map(Arc::from)
132 .map(Value::Bytes)
133 }
134 other => Err(bad_request!("cannot cast into Bytes from {other:?}")),
135 },
136 Self::Email => match value {
137 Value::Email(email) => Ok(Value::Email(email)),
138
139 Value::Id(id) => parse_email(id.as_str())
140 .map(Arc::new)
141 .map(Value::Email)
142 .ok_or_else(|| bad_request!("cannot cast into an email address from {}", id)),
143
144 Value::String(s) => parse_email(s.as_str())
145 .map(Arc::new)
146 .map(Value::Email)
147 .ok_or_else(|| bad_request!("cannot cast into an email address from {}", s)),
148
149 other => Err(bad_request!(
150 "cannot cast into an email address from {other:?}"
151 )),
152 },
153 Self::Id => value.try_cast_into(on_err).map(Value::Id),
154 Self::Link => value.try_cast_into(on_err).map(Value::String),
155 Self::None => Ok(Value::None),
156 Self::Number(nt) => value
157 .try_cast_into(|v| bad_request!("cannot cast into Number from {v:?}"))
158 .map(|n| nt.cast(n))
159 .map(Value::Number),
160
161 Self::String => value.try_cast_into(on_err).map(Value::String),
162 Self::Tuple => value.try_cast_into(on_err).map(Value::Tuple),
163 Self::Value => Ok(value),
164 Self::Version => match value {
165 Value::Id(id) => id.as_str().parse().map(Value::Version),
166 Value::String(s) => s.as_str().parse().map(Value::Version),
167 Value::Tuple(t) => {
168 let (maj, min, rev) =
169 t.try_cast_into(|t| bad_request!("invalid semantic version {t:?}"))?;
170
171 Ok(Value::Version(Version::from((maj, min, rev))))
172 }
173 Value::Version(v) => Ok(Value::Version(v)),
174 other => Err(bad_request!("cannot cast into Version from {other:?}")),
175 },
176 }
177 }
178}
179
180impl Default for ValueType {
181 fn default() -> Self {
182 Self::Value
183 }
184}
185
186impl Class for ValueType {}
187
188impl NativeClass for ValueType {
189 fn from_path(path: &[PathSegment]) -> Option<Self> {
190 debug!("ValueType::from_path {}", TCPath::from(path));
191
192 if path.len() >= 3 && &path[..3] == &PREFIX[..] {
193 Self::from_suffix(&path[3..])
194 } else {
195 None
196 }
197 }
198
199 fn path(&self) -> TCPathBuf {
200 let prefix = TCPathBuf::from(PREFIX);
201
202 match self {
203 Self::Bytes => prefix.append(label("bytes")),
204 Self::Email => prefix.append(label("email")),
205 Self::Id => prefix.append(label("id")),
206 Self::Link => prefix.append(label("link")),
207 Self::None => prefix.append(label("none")),
208 Self::Number(nt) => {
209 const N8: Label = label("8");
210 const N16: Label = label("16");
211 const N32: Label = label("32");
212 const N64: Label = label("64");
213
214 let prefix = prefix.append(label("number"));
215 use NumberType as NT;
216 match nt {
217 NT::Bool => prefix.append(label("bool")),
218 NT::Complex(ct) => {
219 let prefix = prefix.append(label("complex"));
220 use ComplexType as CT;
221 match ct {
222 CT::C32 => prefix.append(N32),
223 CT::C64 => prefix.append(N64),
224 CT::Complex => prefix,
225 }
226 }
227 NT::Float(ft) => {
228 let prefix = prefix.append(label("float"));
229 use FloatType as FT;
230 match ft {
231 FT::F32 => prefix.append(N32),
232 FT::F64 => prefix.append(N64),
233 FT::Float => prefix,
234 }
235 }
236 NT::Int(it) => {
237 let prefix = prefix.append(label("int"));
238 use IntType as IT;
239 match it {
240 IT::I8 => prefix.append(N16),
241 IT::I16 => prefix.append(N16),
242 IT::I32 => prefix.append(N32),
243 IT::I64 => prefix.append(N64),
244 IT::Int => prefix,
245 }
246 }
247 NT::UInt(ut) => {
248 let prefix = prefix.append(label("uint"));
249 use UIntType as UT;
250 match ut {
251 UT::U8 => prefix.append(N8),
252 UT::U16 => prefix.append(N16),
253 UT::U32 => prefix.append(N32),
254 UT::U64 => prefix.append(N64),
255 UT::UInt => prefix,
256 }
257 }
258 NT::Number => prefix,
259 }
260 }
261 Self::String => prefix.append(label("string")),
262 Self::Tuple => prefix.append(label("tuple")),
263 Self::Value => prefix,
264 Self::Version => prefix.append(label("version")),
265 }
266 }
267}
268
269impl Ord for ValueType {
270 fn cmp(&self, other: &Self) -> Ordering {
271 use Ordering::*;
272
273 match (self, other) {
274 (Self::Number(l), Self::Number(r)) => l.cmp(r),
275 (l, r) if l == r => Equal,
276
277 (Self::Value, _) => Greater,
278 (_, Self::Value) => Less,
279
280 (Self::Tuple, _) => Greater,
281 (_, Self::Tuple) => Less,
282
283 (Self::Link, _) => Greater,
284 (_, Self::Link) => Less,
285
286 (Self::String, _) => Greater,
287 (_, Self::String) => Less,
288
289 (Self::Email, _) => Greater,
290 (_, Self::Email) => Less,
291
292 (Self::Id, _) => Greater,
293 (_, Self::Id) => Less,
294
295 (Self::Bytes, _) => Greater,
296 (_, Self::Bytes) => Less,
297
298 (Self::Number(_), _) => Greater,
299 (_, Self::Number(_)) => Less,
300
301 (Self::Version, _) => Greater,
302 (_, Self::Version) => Less,
303
304 (Self::None, Self::None) => Equal,
305 }
306 }
307}
308
309impl PartialOrd for ValueType {
310 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
311 Some(self.cmp(other))
312 }
313}
314
315impl From<NumberType> for ValueType {
316 fn from(nt: NumberType) -> ValueType {
317 ValueType::Number(nt)
318 }
319}
320
321impl TryCastFrom<Value> for ValueType {
322 fn can_cast_from(value: &Value) -> bool {
323 match value {
324 Value::Link(l) if l.host().is_none() => Self::from_path(l.path()).is_some(),
325 Value::String(s) => {
326 if let Ok(path) = TCPathBuf::from_str(s.as_str()) {
327 Self::from_path(&path).is_some()
328 } else {
329 false
330 }
331 }
332 _ => false,
333 }
334 }
335
336 fn opt_cast_from(value: Value) -> Option<Self> {
337 if let Some(path) = TCPathBuf::opt_cast_from(value) {
338 Self::from_path(&path)
339 } else {
340 None
341 }
342 }
343}
344
345impl TryFrom<ValueType> for NumberType {
346 type Error = TCError;
347
348 fn try_from(vt: ValueType) -> TCResult<NumberType> {
349 match vt {
350 ValueType::Number(nt) => Ok(nt),
351 other => Err(TCError::unexpected(other, "a Number class")),
352 }
353 }
354}
355
356#[async_trait]
357impl de::FromStream for ValueType {
358 type Context = ();
359
360 async fn from_stream<D: de::Decoder>(_: (), decoder: &mut D) -> Result<Self, D::Error> {
361 debug!("ValueType::from_stream");
362 decoder.decode_any(ValueTypeVisitor).await
363 }
364}
365
366impl<'en> en::IntoStream<'en> for ValueType {
367 fn into_stream<E: en::Encoder<'en>>(self, encoder: E) -> Result<E::Ok, E::Error> {
368 use en::EncodeMap;
369 let mut map = encoder.encode_map(Some(1))?;
370 map.encode_entry(self.path(), Map::<Value>::default())?;
371 map.end()
372 }
373}
374
375impl<'en> en::ToStream<'en> for ValueType {
376 fn to_stream<E: en::Encoder<'en>>(&'en self, encoder: E) -> Result<E::Ok, E::Error> {
377 use en::EncodeMap;
378 let mut map = encoder.encode_map(Some(1))?;
379 map.encode_entry(self.path(), Map::<Value>::default())?;
380 map.end()
381 }
382}
383
384impl fmt::Display for ValueType {
385 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
386 match self {
387 Self::Bytes => f.write_str("type Bytes"),
388 Self::Email => f.write_str("type Email"),
389 Self::Id => f.write_str("type Id"),
390 Self::Link => f.write_str("type Link"),
391 Self::None => f.write_str("type None"),
392 Self::Number(nt) => write!(f, "type {}", nt),
393 Self::String => f.write_str("type String"),
394 Self::Tuple => f.write_str("type Tuple<Value>"),
395 Self::Value => f.write_str("type Value"),
396 Self::Version => f.write_str("type Version"),
397 }
398 }
399}
400
401struct ValueTypeVisitor;
402
403impl ValueTypeVisitor {
404 fn visit_path<E: DestreamError>(self, path: TCPathBuf) -> Result<ValueType, E> {
405 ValueType::from_path(&path)
406 .ok_or_else(|| DestreamError::invalid_value(path, Self::expecting()))
407 }
408}
409
410#[async_trait]
411impl DestreamVisitor for ValueTypeVisitor {
412 type Value = ValueType;
413
414 fn expecting() -> &'static str {
415 "a Value type"
416 }
417
418 fn visit_string<E: DestreamError>(self, v: String) -> Result<Self::Value, E> {
419 let path: TCPathBuf = v.parse().map_err(DestreamError::custom)?;
420 self.visit_path(path)
421 }
422
423 async fn visit_map<A: de::MapAccess>(self, mut access: A) -> Result<Self::Value, A::Error> {
424 if let Some(path) = access.next_key::<TCPathBuf>(()).await? {
425 if let Ok(map) = access.next_value::<Map<Value>>(()).await {
426 if map.is_empty() {
427 self.visit_path(path)
428 } else {
429 Err(de::Error::custom(format!(
430 "invalid specification {:?} for Value class {}",
431 map, path
432 )))
433 }
434 } else if let Ok(list) = access.next_value::<Tuple<Value>>(()).await {
435 if list.is_empty() {
436 self.visit_path(path)
437 } else {
438 Err(de::Error::custom(format!(
439 "invalid specification {:?} for Value class {}",
440 list, path
441 )))
442 }
443 } else {
444 Err(de::Error::custom(format!(
445 "invalid specification for Value class {}",
446 path
447 )))
448 }
449 } else {
450 Err(DestreamError::invalid_length(0, Self::expecting()))
451 }
452 }
453}
454
455fn parse_email(s: &str) -> Option<EmailAddress> {
456 EmailAddress::parse(s.as_ref(), None)
457}