microcad_lang/ty/
tuple_type.rs1use crate::{syntax::*, ty::*};
7
8#[derive(Debug, Clone, Default, PartialEq, Eq)]
10pub struct TupleType {
11 pub(crate) named: std::collections::HashMap<Identifier, Type>,
12 pub(crate) unnamed: std::collections::HashSet<Type>,
13}
14impl TupleType {
15 pub fn new_vec2() -> Self {
17 [("x", Type::scalar()), ("y", Type::scalar())]
18 .into_iter()
19 .collect()
20 }
21
22 pub fn new_vec3() -> Self {
24 [
25 ("x", Type::scalar()),
26 ("y", Type::scalar()),
27 ("z", Type::scalar()),
28 ]
29 .into_iter()
30 .collect()
31 }
32
33 pub fn new_color() -> Self {
35 [
36 ("r", Type::scalar()),
37 ("g", Type::scalar()),
38 ("b", Type::scalar()),
39 ("a", Type::scalar()),
40 ]
41 .into_iter()
42 .collect()
43 }
44
45 pub fn new_size2() -> Self {
47 [("width", Type::length()), ("height", Type::length())]
48 .into_iter()
49 .collect()
50 }
51
52 fn matches(&self, keys: &[&str]) -> bool {
54 if !self.unnamed.is_empty() || self.named.len() != keys.len() {
55 return false;
56 }
57 keys.iter()
58 .all(|k| self.named.contains_key(&Identifier::no_ref(k)))
59 }
60
61 fn is_scalar_only(&self) -> bool {
63 self.common_type().is_some_and(|ty| *ty == Type::scalar())
64 }
65
66 fn is_length_only(&self) -> bool {
68 self.common_type().is_some_and(|ty| *ty == Type::length())
69 }
70
71 pub(crate) fn common_type(&self) -> Option<&Type> {
73 let mut iter = self.unnamed.iter().chain(self.named.values());
74 if let Some(first) = iter.next() {
75 if iter.all(|x| x == first) {
76 return Some(first);
77 }
78 }
79 None
80 }
81
82 pub(crate) fn is_color(&self) -> bool {
84 self.is_scalar_only() && self.matches(&["r", "g", "b", "a"])
85 }
86
87 pub(crate) fn is_vec2(&self) -> bool {
89 self.is_scalar_only() && self.matches(&["x", "y"])
90 }
91
92 pub(crate) fn is_vec3(&self) -> bool {
94 self.is_scalar_only() && self.matches(&["x", "y", "z"])
95 }
96
97 pub(crate) fn is_size2(&self) -> bool {
99 self.is_length_only() && self.matches(&["width", "height"])
100 }
101}
102
103impl std::hash::Hash for TupleType {
104 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
105 self.named.iter().for_each(|(id, ty)| {
106 id.hash(state);
107 ty.hash(state)
108 });
109 self.unnamed.iter().for_each(|ty| ty.hash(state));
110 }
111}
112
113impl FromIterator<(Identifier, Type)> for TupleType {
114 fn from_iter<T: IntoIterator<Item = (Identifier, Type)>>(iter: T) -> Self {
115 let (unnamed, named) = iter.into_iter().partition(|(id, _)| id.is_empty());
116 Self {
117 named,
118 unnamed: unnamed.into_values().collect(),
119 }
120 }
121}
122
123impl<'a> FromIterator<(&'a str, Type)> for TupleType {
124 fn from_iter<T: IntoIterator<Item = (&'a str, Type)>>(iter: T) -> Self {
125 let (unnamed, named) = iter
126 .into_iter()
127 .map(|(id, ty)| (Identifier::no_ref(id), ty))
128 .partition(|(id, _)| id.is_empty());
129 Self {
130 named,
131 unnamed: unnamed.into_values().collect(),
132 }
133 }
134}
135
136impl std::fmt::Display for TupleType {
137 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
138 if self.is_color() {
139 return write!(f, "Color");
140 }
141 if self.is_vec2() {
142 return write!(f, "Vec2");
143 }
144 if self.is_vec3() {
145 return write!(f, "Vec3");
146 }
147 if self.is_size2() {
148 return write!(f, "Size2");
149 }
150
151 write!(f, "({})", {
152 let mut types = self
153 .named
154 .iter()
155 .map(|(id, ty)| format!("{id}: {ty}"))
156 .chain(self.unnamed.iter().map(|ty| ty.to_string()))
157 .collect::<Vec<_>>();
158
159 types.sort();
160 types.join(", ")
161 })
162 }
163}