protospec-build 0.3.0

One binary format language to rule them all, One binary format language to find them, One binary format language to bring them all and in the darkness bind them.
Documentation
use super::*;

#[derive(Clone, Debug)]
pub enum PartialType {
    Type(Type),
    Scalar(PartialScalarType),
    Array(Option<Box<PartialType>>),
    Any,
}

#[derive(Clone, Copy, Debug)]
pub enum PartialScalarType {
    Some(ScalarType),
    Defaults(ScalarType),
    None,
}

impl PartialType {
    pub fn assignable_from(&self, other: &Type) -> bool {
        match (self, other.resolved().as_ref()) {
            (t1, Type::Foreign(f2)) => f2.obj.assignable_to_partial(t1),
            (PartialType::Type(x), other) => x.assignable_from(other),
            (PartialType::Scalar(PartialScalarType::Some(x)), other) => Type::Scalar(*x).assignable_from(other),
            (PartialType::Scalar(PartialScalarType::Defaults(x)), other) => Type::Scalar(*x).assignable_from(other),
            (PartialType::Scalar(PartialScalarType::None), _) => true,
            (PartialType::Array(None), Type::Array(_)) => true,
            (PartialType::Array(Some(element)), Type::Array(array_type)) => {
                element.assignable_from(&array_type.element.type_.borrow())
            }
            (PartialType::Any, _) => true,
            _ => false,
        }
    }

    pub fn coercable_from(&self, other: &Type) -> bool {
        match (self, other.resolved().as_ref()) {
            (PartialType::Scalar(PartialScalarType::Some(scalar_type)), Type::Enum(e1))
                if e1.rep.can_implicit_cast_to(scalar_type) =>
            {
                true
            }
            (PartialType::Scalar(PartialScalarType::Defaults(scalar_type)), Type::Enum(e1))
                if e1.rep.can_implicit_cast_to(scalar_type) =>
            {
                true
            }
            (PartialType::Scalar(PartialScalarType::Some(x)), other) => other.can_coerce_to(&Type::Scalar(*x)),
            (PartialType::Scalar(PartialScalarType::Defaults(x)), other) => other.can_coerce_to(&Type::Scalar(*x)),
            (PartialType::Type(x), other) => other.can_coerce_to(x),
            (_, _) => false,
        }
    }

    pub fn into_type(&self) -> Option<Type> {
        Some(match self {
            PartialType::Type(t) => t.clone(),
            PartialType::Scalar(PartialScalarType::Some(s)) => Type::Scalar(*s),
            PartialType::Scalar(PartialScalarType::Defaults(s)) => Type::Scalar(*s),
            _ => return None,
        })
    }
}

impl fmt::Display for PartialType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            PartialType::Type(t) => t.fmt(f),
            PartialType::Scalar(PartialScalarType::Some(s)) => s.fmt(f),
            PartialType::Scalar(PartialScalarType::Defaults(s)) => write!(f, "{}?", s),
            PartialType::Scalar(PartialScalarType::None) => write!(f, "integer"),
            PartialType::Array(None) => write!(f, "array"),
            PartialType::Array(Some(inner)) => write!(f, "{}[]", inner),
            PartialType::Any => write!(f, "any"),
        }
    }
}

impl Into<PartialType> for Type {
    fn into(self) -> PartialType {
        match self {
            Type::Ref(x) => x.target.type_.borrow().clone().into(),
            Type::Scalar(x) => PartialType::Scalar(PartialScalarType::Some(x)),
            Type::Array(x) => {
                PartialType::Array(Some(Box::new(x.element.type_.borrow().clone().into())))
            }
            x => PartialType::Type(x),
        }
    }
}