use serde_json::Value;
use wick_interface_types::Type;
use crate::Error;
#[derive(Debug, Clone)]
#[must_use]
pub struct TypeWrapper(Type, Value);
impl TypeWrapper {
pub const fn new(ty: Type, val: Value) -> Self {
Self(ty, val)
}
pub const fn type_signature(&self) -> &Type {
&self.0
}
#[must_use]
#[allow(clippy::missing_const_for_fn)]
pub fn into_inner(self) -> Value {
self.1
}
#[must_use]
pub const fn inner(&self) -> &Value {
&self.1
}
}
macro_rules! coersion_err {
($val:expr, $ty:expr) => {
return Err(Error::Coersion {
value: $val,
desired: $ty,
})
};
}
pub(crate) fn coerce(val: Value, ty: &Type) -> Result<Value, Error> {
let val = match ty {
Type::I8
| Type::I16
| Type::I32
| Type::I64
| Type::U8
| Type::U16
| Type::U32
| Type::U64
| Type::F32
| Type::F64 => match &val {
Value::Number(_) => val,
Value::String(v) => Value::Number(v.parse().map_err(|_| Error::Coersion {
value: val,
desired: ty.clone(),
})?),
_ => coersion_err!(val, ty.clone()),
},
Type::Bool => match &val {
Value::Bool(_) => val,
_ => coersion_err!(val, ty.clone()), },
Type::String => {
let string = match val {
Value::Null => String::new(),
Value::Bool(v) => v.to_string(),
Value::Number(v) => v.to_string(),
Value::String(v) => v,
_ => coersion_err!(val, ty.clone()),
};
Value::String(string)
}
Type::Datetime => match &val {
Value::Number(_) => val,
Value::String(_) => val,
_ => coersion_err!(val, ty.clone()),
},
Type::Bytes => match &val {
Value::String(_) => val,
_ => coersion_err!(val, ty.clone()), },
Type::Named(_) => unimplemented!("named types"),
Type::List { ty: inner_ty } => {
let Value::Array(val) = val else {
coersion_err!(val, ty.clone())
};
let mut out = Vec::with_capacity(val.len());
for v in val {
out.push(coerce(v, inner_ty)?);
}
Value::Array(out)
}
Type::Optional { ty: inner_ty } => {
if val.is_null() {
Value::Null
} else {
coerce(val, inner_ty)?
}
}
Type::Map {
value: inner_value_ty, ..
} => {
let Value::Object(obj) = val else {
coersion_err!(val, ty.clone())
};
let mut out = serde_json::Map::with_capacity(obj.len());
for (k, v) in obj {
out.insert(k, coerce(v, inner_value_ty)?);
}
Value::Object(out)
}
#[allow(deprecated)]
Type::Link { .. } => match &val {
Value::String(_) => val,
_ => coersion_err!(val, ty.clone()),
},
Type::Object => val,
Type::AnonymousStruct(_) => unimplemented!(),
};
Ok(val)
}