wick_packet/
wrapped_type.rs

1use serde_json::Value;
2use wick_interface_types::Type;
3
4use crate::Error;
5
6#[derive(Debug, Clone)]
7#[must_use]
8pub struct TypeWrapper(Type, Value);
9
10impl TypeWrapper {
11  /// Create a new TypeWrapper.
12  pub const fn new(ty: Type, val: Value) -> Self {
13    Self(ty, val)
14  }
15
16  pub const fn type_signature(&self) -> &Type {
17    &self.0
18  }
19
20  #[must_use]
21  #[allow(clippy::missing_const_for_fn)]
22  pub fn into_inner(self) -> Value {
23    self.1
24  }
25
26  #[must_use]
27  pub const fn inner(&self) -> &Value {
28    &self.1
29  }
30}
31
32macro_rules! coersion_err {
33  ($val:expr, $ty:expr) => {
34    return Err(Error::Coersion {
35      value: $val,
36      desired: $ty,
37    })
38  };
39}
40
41pub(crate) fn coerce(val: Value, ty: &Type) -> Result<Value, Error> {
42  let val = match ty {
43    Type::I8
44    | Type::I16
45    | Type::I32
46    | Type::I64
47    | Type::U8
48    | Type::U16
49    | Type::U32
50    | Type::U64
51    | Type::F32
52    | Type::F64 => match &val {
53      Value::Number(_) => val,
54      Value::String(v) => Value::Number(v.parse().map_err(|_| Error::Coersion {
55        value: val,
56        desired: ty.clone(),
57      })?),
58      _ => coersion_err!(val, ty.clone()),
59    },
60    Type::Bool => match &val {
61      Value::Bool(_) => val,
62      _ => coersion_err!(val, ty.clone()), // Todo: Coerce truthiness?
63    },
64    Type::String => {
65      let string = match val {
66        Value::Null => String::new(),
67        Value::Bool(v) => v.to_string(),
68        Value::Number(v) => v.to_string(),
69        Value::String(v) => v,
70        _ => coersion_err!(val, ty.clone()),
71      };
72
73      Value::String(string)
74    }
75    Type::Datetime => match &val {
76      Value::Number(_) => val,
77      Value::String(_) => val,
78      _ => coersion_err!(val, ty.clone()),
79    },
80    Type::Bytes => match &val {
81      Value::String(_) => val,
82      _ => coersion_err!(val, ty.clone()), // Todo: Coerce a [u8] to Base64Bytes?
83    },
84    Type::Named(_) => unimplemented!("named types"),
85    Type::List { ty: inner_ty } => {
86      let Value::Array(val) = val else {
87        coersion_err!(val, ty.clone())
88      };
89
90      let mut out = Vec::with_capacity(val.len());
91      for v in val {
92        out.push(coerce(v, inner_ty)?);
93      }
94
95      Value::Array(out)
96    }
97    Type::Optional { ty: inner_ty } => {
98      if val.is_null() {
99        Value::Null
100      } else {
101        coerce(val, inner_ty)?
102      }
103    }
104    Type::Map {
105      value: inner_value_ty, ..
106    } => {
107      let Value::Object(obj) = val else {
108        coersion_err!(val, ty.clone())
109      };
110
111      let mut out = serde_json::Map::with_capacity(obj.len());
112      for (k, v) in obj {
113        out.insert(k, coerce(v, inner_value_ty)?);
114      }
115
116      Value::Object(out)
117    }
118    #[allow(deprecated)]
119    Type::Link { .. } => match &val {
120      Value::String(_) => val,
121      _ => coersion_err!(val, ty.clone()),
122    },
123    Type::Object => val,
124    Type::AnonymousStruct(_) => unimplemented!(),
125  };
126  Ok(val)
127}