use std::collections::BTreeMap;
use brink_ir::{BaseType, SemanticTypeDef, TypeRef};
#[derive(Debug, Clone, Copy)]
pub(crate) enum TypeShape<'a> {
Unspecified,
Base(BaseType),
Registered(&'a SemanticTypeDef),
Unregistered,
}
pub(crate) fn classify<'a>(
t: &TypeRef,
types: &'a BTreeMap<String, SemanticTypeDef>,
) -> TypeShape<'a> {
if t.is_unspecified() {
return TypeShape::Unspecified;
}
if let Some(base) = t.as_base() {
return TypeShape::Base(base);
}
match types.get(t.0.trim()) {
Some(def) => TypeShape::Registered(def),
None => TypeShape::Unregistered,
}
}
#[cfg(test)]
mod tests {
use brink_ir::Constraint;
use super::*;
fn types_with(name: &str, base: BaseType) -> BTreeMap<String, SemanticTypeDef> {
let mut types = BTreeMap::new();
types.insert(
name.to_string(),
SemanticTypeDef {
name: name.to_string(),
base,
constraint: None,
values: None,
widget: None,
},
);
types
}
#[test]
fn unspecified_ref_classifies_as_unspecified() {
assert!(matches!(
classify(&TypeRef::default(), &BTreeMap::new()),
TypeShape::Unspecified
));
}
#[test]
fn base_keyword_never_consults_types() {
let types = types_with("int", BaseType::String);
assert!(matches!(
classify(&TypeRef("int".to_string()), &types),
TypeShape::Base(BaseType::Int)
));
}
#[test]
fn registered_name_resolves_through_its_def() {
let types = types_with("var_id", BaseType::Int);
let def = match classify(&TypeRef("var_id".to_string()), &types) {
TypeShape::Registered(def) => Some(def),
_ => None,
}
.expect("expected Registered");
assert_eq!(def.base, BaseType::Int);
}
#[test]
fn unregistered_name_classifies_as_unregistered() {
assert!(matches!(
classify(&TypeRef("var_id".to_string()), &BTreeMap::new()),
TypeShape::Unregistered
));
}
#[test]
fn unregistered_with_other_types_present_is_still_unregistered() {
let types = types_with("actor_id", BaseType::String);
assert!(matches!(
classify(&TypeRef("var_id".to_string()), &types),
TypeShape::Unregistered
));
}
#[test]
fn registered_carries_through_constraint() {
let mut types = BTreeMap::new();
types.insert(
"item_id".to_string(),
SemanticTypeDef {
name: "item_id".to_string(),
base: BaseType::String,
constraint: Some(Constraint::Enum {
values: vec!["sword".into()],
}),
values: None,
widget: None,
},
);
let def = match classify(&TypeRef("item_id".to_string()), &types) {
TypeShape::Registered(def) => Some(def),
_ => None,
}
.expect("expected Registered");
assert!(matches!(def.constraint, Some(Constraint::Enum { .. })));
}
}