cmajor 0.7.0

Rust bindings for the Cmajor JIT engine.
Documentation
use {
    crate::value::types::{Array, Object, Primitive, Type},
    indexmap::IndexMap,
    serde::Deserialize,
    serde_json as json,
};

#[derive(Debug, Copy, Clone, Deserialize)]
enum TypeTag {
    #[serde(rename = "void")]
    Void,

    #[serde(rename = "bool")]
    Bool,

    #[serde(rename = "int32")]
    Int32,

    #[serde(rename = "int64")]
    Int64,

    #[serde(rename = "float32")]
    Float32,

    #[serde(rename = "float64")]
    Float64,

    #[serde(rename = "string")]
    String,

    #[serde(rename = "array")]
    Array,

    #[serde(rename = "object")]
    Object,

    #[serde(rename = "vector")]
    Vector,
}

#[derive(Debug, Clone, Deserialize)]
pub(crate) struct TypeDescription {
    #[serde(rename = "type")]
    type_tag: TypeTag,

    #[serde(rename = "class")]
    class: Option<String>,

    #[serde(rename = "members")]
    members: Option<IndexMap<String, Self>>,

    #[serde(rename = "element")]
    element: Option<Box<Self>>,

    #[serde(rename = "size")]
    size: Option<usize>,

    #[serde(flatten)]
    _extra: json::Map<String, json::Value>,
}

#[derive(Debug, thiserror::Error)]
pub(crate) enum TypeDescriptionError {
    #[error(transparent)]
    InvalidJson(#[from] json::Error),

    #[error("struct has no class")]
    StructHasNoClass,

    #[error("struct has no members")]
    StructHasNoMembers,

    #[error("array has no element")]
    ArrayHasNoElement,

    #[error("array has no size")]
    ArrayHasNoSize,

    #[error("endpoint has an unexpected number of types")]
    UnexpectedNumberOfTypes,
}

impl TryFrom<&TypeDescription> for Type {
    type Error = TypeDescriptionError;

    fn try_from(
        TypeDescription {
            type_tag,
            members,
            element,
            size,
            class,
            ..
        }: &TypeDescription,
    ) -> Result<Self, Self::Error> {
        match type_tag {
            TypeTag::Void => Ok(Type::Primitive(Primitive::Void)),
            TypeTag::Bool => Ok(Type::Primitive(Primitive::Bool)),
            TypeTag::Int32 => Ok(Type::Primitive(Primitive::Int32)),
            TypeTag::Int64 => Ok(Type::Primitive(Primitive::Int64)),
            TypeTag::Float32 => Ok(Type::Primitive(Primitive::Float32)),
            TypeTag::Float64 => Ok(Type::Primitive(Primitive::Float64)),
            TypeTag::Object => {
                let class = class.clone().ok_or(Self::Error::StructHasNoClass)?;

                let mut object = Object::new(class);
                for (name, type_description) in
                    members.as_ref().ok_or(Self::Error::StructHasNoMembers)?
                {
                    object.add_field(name, Type::try_from(type_description)?);
                }
                Ok(object.into())
            }
            TypeTag::Array | TypeTag::Vector => {
                let element_ty: Type = element
                    .as_ref()
                    .ok_or(TypeDescriptionError::ArrayHasNoElement)?
                    .as_ref()
                    .try_into()?;
                let size = size.ok_or(TypeDescriptionError::ArrayHasNoSize)?;

                Ok(Array::new(element_ty, size).into())
            }
            TypeTag::String => Ok(Type::String),
        }
    }
}