1use std::fmt;
7
8use crate::value::Value;
9
10#[derive(Debug, Clone, PartialEq)]
12pub enum Type {
13 Null,
14 Number,
15 String,
16 Boolean,
17 Color,
18 Object,
19 Value,
21 Array(Box<Type>, Option<usize>),
23 ProjectionDefinition,
24 Collator,
25 Formatted,
26 Padding,
27 NumberArray,
28 ColorArray,
29 ResolvedImage,
30 VariableAnchorOffsetCollection,
31}
32
33impl Type {
34 pub fn array(item: Type, n: Option<usize>) -> Type {
36 Type::Array(Box::new(item), n)
37 }
38
39 pub fn kind(&self) -> &'static str {
41 match self {
42 Type::Null => "null",
43 Type::Number => "number",
44 Type::String => "string",
45 Type::Boolean => "boolean",
46 Type::Color => "color",
47 Type::Object => "object",
48 Type::Value => "value",
49 Type::Array(..) => "array",
50 Type::ProjectionDefinition => "projectionDefinition",
51 Type::Collator => "collator",
52 Type::Formatted => "formatted",
53 Type::Padding => "padding",
54 Type::NumberArray => "numberArray",
55 Type::ColorArray => "colorArray",
56 Type::ResolvedImage => "resolvedImage",
57 Type::VariableAnchorOffsetCollection => "variableAnchorOffsetCollection",
58 }
59 }
60
61 pub fn of_value(v: &Value) -> Type {
63 match v {
64 Value::Null => Type::Null,
65 Value::Bool(_) => Type::Boolean,
66 Value::Number(_) => Type::Number,
67 Value::String(_) => Type::String,
68 Value::Color(_) => Type::Color,
69 Value::Object(_) => Type::Object,
70 Value::Image { .. } => Type::ResolvedImage,
71 Value::Formatted(_) => Type::Formatted,
72 Value::NumberArray(_) => Type::NumberArray,
73 Value::ColorArray(_) => Type::ColorArray,
74 Value::Padding(_) => Type::Padding,
75 Value::Projection(_) => Type::ProjectionDefinition,
76 Value::Collator { .. } => Type::Collator,
77 Value::Array(items) => {
78 let mut item_type: Option<Type> = None;
79 for it in items {
80 let t = Type::of_value(it);
81 match &item_type {
82 None => item_type = Some(t),
83 Some(existing) if *existing == t => {}
84 Some(_) => {
85 item_type = Some(Type::Value);
86 break;
87 }
88 }
89 }
90 Type::array(item_type.unwrap_or(Type::Value), Some(items.len()))
91 }
92 }
93 }
94}
95
96impl fmt::Display for Type {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 match self {
99 Type::Array(item, Some(n)) => write!(f, "array<{item}, {n}>"),
100 Type::Array(item, None) => {
101 if matches!(**item, Type::Value) {
102 write!(f, "array")
103 } else {
104 write!(f, "array<{item}>")
105 }
106 }
107 other => write!(f, "{}", other.kind()),
108 }
109 }
110}
111
112pub fn is_subtype(expected: &Type, t: &Type) -> bool {
116 if let Type::Array(exp_item, exp_n) = expected {
117 if let Type::Array(t_item, t_n) = t {
118 let item_ok = (*t_n == Some(0) && matches!(**t_item, Type::Value))
119 || is_subtype(exp_item, t_item);
120 let n_ok = exp_n.is_none() || exp_n == t_n;
121 return item_ok && n_ok;
122 }
123 return false;
124 }
125 if expected.kind() == t.kind() {
126 return true;
127 }
128 if matches!(expected, Type::Value) {
129 return is_value_member(t);
130 }
131 false
132}
133
134fn is_value_member(t: &Type) -> bool {
137 !matches!(t, Type::Collator)
138}