wick_interface_types/
types.rs

1#![allow(deprecated)]
2#[cfg(feature = "typeid")]
3use std::any::TypeId;
4use std::error::Error;
5use std::str::FromStr;
6
7mod enum_def;
8mod struct_def;
9mod union_def;
10
11use serde::{Deserialize, Serialize};
12
13pub use self::enum_def::{EnumDefinition, EnumVariant};
14pub use self::struct_def::StructDefinition;
15pub use self::union_def::UnionDefinition;
16use crate::Field;
17
18#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
19#[must_use]
20/// A valid type definition.
21#[serde(tag = "type")]
22#[allow(clippy::exhaustive_enums)]
23pub enum TypeDefinition {
24  /// A struct definition.
25  #[serde(rename = "struct")]
26  Struct(StructDefinition),
27  /// An enum definition.
28  #[serde(rename = "enum")]
29  Enum(EnumDefinition),
30  /// An union definition.
31  #[serde(rename = "union")]
32  Union(UnionDefinition),
33}
34
35impl TypeDefinition {
36  /// Get the name of the type.
37  #[must_use]
38  pub fn name(&self) -> &str {
39    match self {
40      TypeDefinition::Struct(v) => &v.name,
41      TypeDefinition::Enum(v) => &v.name,
42      TypeDefinition::Union(v) => &v.name,
43    }
44  }
45}
46
47#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
48#[serde(rename_all = "lowercase")]
49#[must_use]
50#[allow(clippy::exhaustive_enums)]
51/// Enum of valid types.
52pub enum Type {
53  /// I8 type.
54  I8,
55  /// I16 type.
56  I16,
57  /// I32 type.
58  I32,
59  /// I64 type.
60  I64,
61  /// u8 type.
62  U8,
63  /// u16 type.
64  U16,
65  /// u32 type.
66  U32,
67  /// u64 type.
68  U64,
69  /// f32 type.
70  F32,
71  /// f64 type.
72  F64,
73  /// Boolean type.
74  Bool,
75  /// String type.
76  String,
77  /// Date type.
78  Datetime,
79  /// Raw bytes.
80  Bytes,
81  /// A reference to another type.
82  Named(String),
83  /// A list type
84  List {
85    /// The type of the list's elements
86    #[serde(rename = "type")]
87    #[cfg_attr(feature = "parser", serde(deserialize_with = "crate::types::box_type_signature"))]
88    #[cfg_attr(
89      feature = "yaml",
90      serde(serialize_with = "serde_yaml::with::singleton_map::serialize")
91    )]
92    ty: Box<Type>,
93  },
94  /// A type representing an optional value.
95  Optional {
96    /// The actual type that is optional.
97    #[serde(rename = "type")]
98    #[cfg_attr(feature = "parser", serde(deserialize_with = "crate::types::box_type_signature"))]
99    #[cfg_attr(
100      feature = "yaml",
101      serde(serialize_with = "serde_yaml::with::singleton_map::serialize")
102    )]
103    ty: Box<Type>,
104  },
105  /// A HashMap-like type.
106  Map {
107    /// The type of the map's keys.
108    #[cfg_attr(feature = "parser", serde(deserialize_with = "crate::types::box_type_signature"))]
109    #[cfg_attr(
110      feature = "yaml",
111      serde(serialize_with = "serde_yaml::with::singleton_map::serialize")
112    )]
113    key: Box<Type>,
114    /// The type of the map's values.
115    #[cfg_attr(feature = "parser", serde(deserialize_with = "crate::types::box_type_signature"))]
116    #[cfg_attr(
117      feature = "yaml",
118      serde(serialize_with = "serde_yaml::with::singleton_map::serialize")
119    )]
120    value: Box<Type>,
121  },
122  /// A type representing a link to another collection.
123  #[deprecated = "Links are deprecated, use the require/provides interface instead."]
124  Link {
125    /// The schemas that must be provided with the linked collection.
126    #[serde(default)]
127    schemas: Vec<String>,
128  },
129  /// A JSON-like key/value map.
130  Object,
131  /// An inline, anonymous struct interface.
132  AnonymousStruct(
133    /// A list of fields in the struct.
134    Vec<Field>,
135  ),
136}
137
138impl Type {
139  #[must_use]
140  #[cfg(feature = "typeid")]
141  pub fn to_type_id(&self) -> TypeId {
142    match self {
143      Type::I8 => TypeId::of::<i8>(),
144      Type::I16 => TypeId::of::<i16>(),
145      Type::I32 => TypeId::of::<i32>(),
146      Type::I64 => TypeId::of::<i64>(),
147      Type::U8 => TypeId::of::<u8>(),
148      Type::U16 => TypeId::of::<u16>(),
149      Type::U32 => TypeId::of::<u32>(),
150      Type::U64 => TypeId::of::<u64>(),
151      Type::F32 => TypeId::of::<f32>(),
152      Type::F64 => TypeId::of::<f64>(),
153      Type::Bool => TypeId::of::<bool>(),
154      Type::String => TypeId::of::<String>(),
155      Type::Datetime => TypeId::of::<String>(),
156      Type::Bytes => TypeId::of::<Vec<u8>>(),
157      Type::Named(_) => TypeId::of::<serde_json::Value>(),
158      Type::List { .. } => TypeId::of::<Vec<Box<dyn std::any::Any>>>(),
159      Type::Optional { .. } => TypeId::of::<Option<Box<dyn std::any::Any>>>(),
160      Type::Map { .. } => TypeId::of::<std::collections::HashMap<Box<dyn std::any::Any>, Box<dyn std::any::Any>>>(),
161      Type::Link { .. } => TypeId::of::<serde_json::Value>(),
162      Type::Object => TypeId::of::<serde_json::Value>(),
163      Type::AnonymousStruct(_) => unimplemented!(),
164    }
165  }
166
167  #[cfg(feature = "value")]
168  pub fn coerce_str<'a>(&self, value: &'a str) -> Result<serde_json::Value, &'a str> {
169    let val = match self {
170      Type::String => serde_json::Value::String(value.to_owned()),
171      Type::U8
172      | Type::U16
173      | Type::U32
174      | Type::U64
175      | Type::I8
176      | Type::I16
177      | Type::I32
178      | Type::I64
179      | Type::F32
180      | Type::F64 => serde_json::Value::Number(value.parse().map_err(|_| value)?),
181      Type::Bool => serde_json::Value::Bool(value.parse().map_err(|_| value)?),
182      Type::Object => match serde_json::from_str(value) {
183        Ok(v) => v,
184        Err(_) => serde_json::from_str(&format!("\"{}\"", value)).map_err(|_| value)?,
185      },
186      Type::List { ty } => {
187        let val: serde_json::Value = serde_json::from_str(value).map_err(|_| value)?;
188        if val.is_array() {
189          val
190        } else {
191          serde_json::Value::Array(vec![ty.coerce_str(value)?])
192        }
193      }
194      Type::Datetime => serde_json::Value::String(value.to_owned()),
195      Type::Bytes => serde_json::Value::String(value.to_owned()),
196      Type::Named(_) => serde_json::Value::Object(serde_json::from_str(value).map_err(|_| value)?),
197      Type::Optional { ty } => {
198        return Ok(ty.coerce_str(value).unwrap_or(serde_json::Value::Null));
199      }
200      Type::Map { .. } => serde_json::from_str(value).map_err(|_| value)?,
201      Type::Link { .. } => unimplemented!(),
202      Type::AnonymousStruct(_) => serde_json::Value::Object(serde_json::from_str(value).map_err(|_| value)?),
203    };
204    Ok(val)
205  }
206}
207
208impl std::fmt::Display for Type {
209  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210    match self {
211      Type::I8 => f.write_str("i8"),
212      Type::I16 => f.write_str("i16"),
213      Type::I32 => f.write_str("i32"),
214      Type::I64 => f.write_str("i64"),
215      Type::U8 => f.write_str("u8"),
216      Type::U16 => f.write_str("u16"),
217      Type::U32 => f.write_str("u32"),
218      Type::U64 => f.write_str("u64"),
219      Type::F32 => f.write_str("f32"),
220      Type::F64 => f.write_str("f64"),
221      Type::Bool => f.write_str("bool"),
222      Type::String => f.write_str("string"),
223      Type::Datetime => f.write_str("datetime"),
224      Type::Bytes => f.write_str("bytes"),
225      Type::Named(v) => f.write_str(v),
226      Type::List { ty } => write!(f, "{}[]", ty),
227      Type::Optional { ty } => write!(f, "{}?", ty),
228      Type::Map { key, value } => write!(f, "{{{}:{}}}", key, value),
229      Type::Link { .. } => todo!(),
230      Type::Object => f.write_str("object"),
231      Type::AnonymousStruct(_) => todo!(),
232    }
233  }
234}
235
236#[derive(Debug)]
237/// Error returned when attempting to convert an invalid source into a Wick type.
238pub struct ParseError(String);
239
240impl Error for ParseError {}
241
242impl std::fmt::Display for ParseError {
243  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244    write!(f, "Could not parse {} into a TypeSignature.", self.0)
245  }
246}
247
248#[cfg(feature = "parser")]
249impl FromStr for Type {
250  type Err = ParseError;
251
252  fn from_str(s: &str) -> Result<Self, Self::Err> {
253    crate::parser::parse(s).map_err(|_e| ParseError(s.to_owned()))
254  }
255}
256
257#[cfg(feature = "parser")]
258pub(crate) fn deserialize_type<'de, D>(deserializer: D) -> Result<Type, D::Error>
259where
260  D: serde::Deserializer<'de>,
261{
262  struct TypeSignatureVisitor;
263
264  impl<'de> serde::de::Visitor<'de> for TypeSignatureVisitor {
265    type Value = Type;
266
267    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
268      formatter.write_str("a TypeSignature definition")
269    }
270
271    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
272    where
273      E: serde::de::Error,
274    {
275      Type::from_str(s).map_err(|e| serde::de::Error::custom(e.to_string()))
276    }
277
278    fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
279    where
280      A: serde::de::MapAccess<'de>,
281    {
282      Type::deserialize(serde::de::value::MapAccessDeserializer::new(map))
283    }
284  }
285
286  deserializer.deserialize_any(TypeSignatureVisitor)
287}
288
289#[cfg(feature = "parser")]
290pub(crate) fn box_type_signature<'de, D>(deserializer: D) -> Result<Box<Type>, D::Error>
291where
292  D: serde::Deserializer<'de>,
293{
294  struct TypeVisitor;
295
296  impl<'de> serde::de::Visitor<'de> for TypeVisitor {
297    type Value = Box<Type>;
298
299    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
300      formatter.write_str("a TypeSignature definition")
301    }
302
303    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
304    where
305      E: serde::de::Error,
306    {
307      Type::from_str(s)
308        .map(Box::new)
309        .map_err(|e| serde::de::Error::custom(e.to_string()))
310    }
311
312    fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
313    where
314      A: serde::de::MapAccess<'de>,
315    {
316      Type::deserialize(serde::de::value::MapAccessDeserializer::new(map)).map(Box::new)
317    }
318  }
319
320  deserializer.deserialize_any(TypeVisitor)
321}
322
323#[cfg(test)]
324mod test {
325  use anyhow::Result;
326  use serde_json::json;
327
328  use super::{Type as TS, *};
329
330  fn b<T>(el: T) -> Box<T> {
331    Box::new(el)
332  }
333
334  #[test]
335  fn test_decode() -> Result<()> {
336    let ty: Type = serde_json::from_str(r#""object""#)?;
337    assert_eq!(ty, Type::Object);
338    let ty: Field = serde_json::from_str(r#"{"name": "foo", "type": "object"}"#)?;
339    assert_eq!(ty.name, "foo");
340    assert_eq!(ty.ty, Type::Object);
341    Ok(())
342  }
343
344  #[cfg(feature = "value")]
345  #[rstest::rstest]
346  #[case(TS::String, "foo", json!("foo"))]
347  #[case(TS::U32, "48", json!(48))]
348  #[case(TS::List{ty:b(TS::U32)}, "48", json!([48]))]
349  #[case(TS::List{ty:b(TS::String)}, "48", json!(["48"]))]
350  fn test_coerce(#[case] ty: Type, #[case] string: &str, #[case] json: serde_json::Value) -> Result<()> {
351    let val = ty.coerce_str(string).unwrap();
352
353    assert_eq!(val, json);
354    Ok(())
355  }
356}