use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum TypeSig {
Any,
Null,
Bool,
Int,
Float,
String,
Bytes,
List(Box<TypeSig>),
Map(Box<TypeSig>),
Named(std::string::String),
}
impl TypeSig {
pub fn is_compatible_with(&self, other: &TypeSig) -> bool {
match (self, other) {
(TypeSig::Any, _) | (_, TypeSig::Any) => true,
(TypeSig::List(a), TypeSig::List(b)) => a.is_compatible_with(b),
(TypeSig::Map(a), TypeSig::Map(b)) => a.is_compatible_with(b),
(TypeSig::Named(a), TypeSig::Named(b)) => a == b,
_ => self == other,
}
}
}
impl std::fmt::Display for TypeSig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TypeSig::Any => write!(f, "Any"),
TypeSig::Null => write!(f, "Null"),
TypeSig::Bool => write!(f, "Bool"),
TypeSig::Int => write!(f, "Int"),
TypeSig::Float => write!(f, "Float"),
TypeSig::String => write!(f, "String"),
TypeSig::Bytes => write!(f, "Bytes"),
TypeSig::List(inner) => write!(f, "List<{}>", inner),
TypeSig::Map(inner) => write!(f, "Map<{}>", inner),
TypeSig::Named(name) => write!(f, "{}", name),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum LayerTag {
Core,
Domain,
Integration,
Custom(std::string::String),
}
impl std::fmt::Display for LayerTag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LayerTag::Core => write!(f, "Core"),
LayerTag::Domain => write!(f, "Domain"),
LayerTag::Integration => write!(f, "Integration"),
LayerTag::Custom(s) => write!(f, "Custom({})", s),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn any_is_compatible_with_everything() {
assert!(TypeSig::Any.is_compatible_with(&TypeSig::Int));
assert!(TypeSig::Int.is_compatible_with(&TypeSig::Any));
assert!(TypeSig::Any.is_compatible_with(&TypeSig::Any));
}
#[test]
fn exact_match_compatible() {
assert!(TypeSig::Int.is_compatible_with(&TypeSig::Int));
assert!(TypeSig::Bool.is_compatible_with(&TypeSig::Bool));
}
#[test]
fn mismatched_primitives_incompatible() {
assert!(!TypeSig::Int.is_compatible_with(&TypeSig::Float));
assert!(!TypeSig::Bool.is_compatible_with(&TypeSig::String));
}
#[test]
fn named_compatible_same() {
assert!(TypeSig::Named("Foo".into()).is_compatible_with(&TypeSig::Named("Foo".into())));
}
#[test]
fn named_incompatible_different() {
assert!(!TypeSig::Named("Foo".into()).is_compatible_with(&TypeSig::Named("Bar".into())));
}
#[test]
fn list_compatibility_recursive() {
let list_int = TypeSig::List(Box::new(TypeSig::Int));
let list_any = TypeSig::List(Box::new(TypeSig::Any));
assert!(list_int.is_compatible_with(&list_any));
assert!(!list_int.is_compatible_with(&TypeSig::List(Box::new(TypeSig::Bool))));
}
}