1use microcad_core::hash::HashMap;
7
8use microcad_lang_base::{Identifier, SrcReferrer};
9use microcad_lang_proc_macros::SrcReferrer;
10
11use crate::{ty::*, value::*};
12
13#[derive(Clone, Debug, Default, PartialEq, SrcReferrer)]
17pub struct Tuple {
18 pub(crate) named: HashMap<ir::Identifier, Value>,
19 pub(crate) unnamed: HashMap<Type, Value>,
20 pub(crate) src_ref: SrcRef,
21}
22
23#[macro_export]
25macro_rules! create_tuple_value {
26 ($($key:ident = $value:expr),*) => {
27 Value::Tuple(Box::new($crate::create_tuple!($( $key = $value ),*)))
28 };
29}
30
31#[macro_export]
33macro_rules! create_tuple {
34 ($($key:ident = $value:expr),*) => {
35 [$( (stringify!($key), $crate::value::Value::try_from($value).expect("Valid value")) ),* ]
36 .iter()
37 .into()
38 };
39}
40
41impl Tuple {
42 pub fn new_named(
44 named: microcad_core::hash::HashMap<ir::Identifier, Value>,
45 src_ref: SrcRef,
46 ) -> Self {
47 Self {
48 named,
49 unnamed: HashMap::default(),
50 src_ref,
51 }
52 }
53
54 pub fn insert(&mut self, id: ir::Identifier, value: Value) {
56 if id.is_empty() {
57 self.unnamed.insert(value.ty(), value);
58 } else {
59 self.named.insert(id, value);
60 }
61 }
62
63 pub fn named_iter(&self) -> std::collections::hash_map::Iter<'_, ir::Identifier, Value> {
65 if !self.unnamed.is_empty() {
66 log::warn!("using named_iter() on a tuple which has unnamed items too")
67 }
68 self.named.iter()
69 }
70
71 pub fn tuple_type(&self) -> TupleType {
73 TupleType {
74 named: self
75 .named
76 .iter()
77 .map(|(id, v)| (id.clone(), v.ty()))
78 .collect(),
79 unnamed: self.unnamed.values().map(|v| v.ty()).collect(),
80 }
81 }
82
83 pub fn combine(
87 self,
88 rhs: Tuple,
89 op: impl Fn(Value, Value) -> ValueResult,
90 ) -> ValueResult<Self> {
91 if self.ty() == rhs.ty() {
92 let mut named = self.named;
93
94 for (key, rhs_val) in rhs.named {
95 named
96 .entry(key)
97 .and_modify(|lhs_val| {
98 *lhs_val = op(lhs_val.clone(), rhs_val.clone()).unwrap_or_default()
99 })
100 .or_insert(rhs_val);
101 }
102
103 let mut unnamed = self.unnamed;
104
105 for (key, rhs_val) in rhs.unnamed {
106 unnamed
107 .entry(key)
108 .and_modify(|lhs_val| {
109 *lhs_val = op(lhs_val.clone(), rhs_val.clone()).unwrap_or_default()
110 })
111 .or_insert(rhs_val);
112 }
113
114 Ok(Tuple {
115 named,
116 unnamed,
117 src_ref: self.src_ref,
118 })
119 } else {
120 Err(ValueError::TupleTypeMismatch {
121 lhs: self.ty(),
122 rhs: rhs.ty(),
123 })
124 }
125 }
126
127 pub fn apply(
131 self,
132 value: Value,
133 op: impl Fn(Value, Value) -> ValueResult,
134 ) -> ValueResult<Self> {
135 let mut named = HashMap::default();
136 for (key, lhs_val) in self.named {
137 named.insert(key, op(lhs_val, value.clone()).unwrap_or_default());
138 }
139
140 let mut unnamed = HashMap::default();
141 for (key, lhs_val) in self.unnamed {
142 unnamed.insert(key, op(lhs_val, value.clone()).unwrap_or_default());
143 }
144
145 Ok(Tuple {
146 named,
147 unnamed,
148 src_ref: self.src_ref,
149 })
150 }
151
152 pub fn transform(self, op: impl Fn(Value) -> ValueResult) -> ValueResult<Self> {
154 let mut named = HashMap::default();
155 for (key, value) in self.named {
156 named.insert(key, op(value).unwrap_or_default());
157 }
158
159 let mut unnamed = HashMap::default();
160 for (key, value) in self.unnamed {
161 unnamed.insert(key, op(value).unwrap_or_default());
162 }
163
164 Ok(Tuple {
165 named,
166 unnamed,
167 src_ref: self.src_ref,
168 })
169 }
170
171 pub fn ray(&mut self) {
180 self.unnamed.retain(|_, value| {
181 if let Value::Tuple(tuple) = value {
182 tuple.ray();
183 tuple.named.drain().for_each(|(k, v)| {
184 self.named.insert(k, v);
185 });
186 false
187 } else {
188 true
189 }
190 });
191 }
192
193 pub fn multiplicity<P: FnMut(Tuple)>(&self, mut ids: ir::IdentifierList, mut p: P) {
205 log::trace!("combining: {ids:?}:");
206
207 ids.sort();
209
210 let mut combinations = 1;
212 let mut counts: HashMap<Identifier, (_, _)> = ids
213 .into_iter()
214 .map(|id| {
215 let counter = if let Some(Value::Array(array)) = &self.named.get(&id) {
216 let len = array.len();
217 combinations *= len;
218 (0, len)
219 } else {
220 panic!("{id:?} found in tuple but no list:\n{self:#?}");
221 };
222 (id, counter)
223 })
224 .collect();
225
226 log::trace!("multiplicity: {combinations} combinations:");
227
228 for _ in 0..combinations {
230 let mut counted = false;
231
232 let mut named: Vec<_> = self.named.iter().collect();
234 named.sort_by(|lhs, rhs| lhs.0.cmp(rhs.0));
235
236 let tuple = named
237 .into_iter()
238 .map(|(id, v)| match v {
239 Value::Array(array) => {
240 if let Some((count, len)) = counts.get_mut(id) {
241 let item = (
242 id.clone(),
243 array.get(*count).expect("array index not found").clone(),
244 );
245 if !counted {
246 *count += 1;
247 if *count == *len {
248 *count = 0
249 } else {
250 counted = true;
251 }
252 }
253 item
254 } else {
255 panic!("{id:?} found in tuple but no list");
256 }
257 }
258 _ => (id.clone(), v.clone()),
259 })
260 .collect();
261 p(tuple);
262 }
263 }
264}
265
266impl ValueAccess for Tuple {
267 fn by_id(&self, id: &Identifier) -> Option<&Value> {
268 self.named.get(id)
269 }
270
271 fn by_ty(&self, ty: &Type) -> Option<&Value> {
272 self.unnamed.get(ty)
273 }
274}
275
276impl<T> From<std::slice::Iter<'_, (&'static str, T)>> for Tuple
278where
279 T: Into<Value> + Clone + std::fmt::Debug,
280{
281 fn from(iter: std::slice::Iter<'_, (&'static str, T)>) -> Self {
282 let (unnamed, named): (Vec<_>, _) = iter
283 .map(|(k, v)| (Identifier::no_ref(k), (*v).clone().into()))
284 .partition(|(k, _)| k.is_empty());
285 Self {
286 src_ref: SrcRef::none(),
287 named: named.into_iter().collect(),
288 unnamed: unnamed.into_iter().map(|(_, v)| (v.ty(), v)).collect(),
289 }
290 }
291}
292
293impl FromIterator<(Identifier, Value)> for Tuple {
294 fn from_iter<T: IntoIterator<Item = (Identifier, Value)>>(iter: T) -> Self {
295 let (unnamed, named): (Vec<_>, _) = iter
296 .into_iter()
297 .map(|(k, v)| (k, v.clone()))
298 .partition(|(k, _)| k.is_empty());
299 Self {
300 src_ref: SrcRef::merge_all(
301 named
302 .iter()
303 .map(|(id, _)| id.src_ref())
304 .chain(unnamed.iter().map(|(id, _)| id.src_ref())),
305 ),
306 named: named.into_iter().collect(),
307 unnamed: unnamed.into_iter().map(|(_, v)| (v.ty(), v)).collect(),
308 }
309 }
310}
311
312impl From<Vec2> for Tuple {
313 fn from(v: Vec2) -> Self {
314 create_tuple!(x = v.x, y = v.y)
315 }
316}
317
318impl From<Vec3> for Tuple {
319 fn from(v: Vec3) -> Self {
320 create_tuple!(x = v.x, y = v.y, z = v.z)
321 }
322}
323
324impl From<Color> for Tuple {
325 fn from(color: Color) -> Self {
326 create_tuple!(r = color.r, g = color.g, b = color.b, a = color.a)
327 }
328}
329
330impl From<Size2> for Tuple {
331 fn from(size: Size2) -> Self {
332 create_tuple!(
333 width = Value::from(Quantity::length(size.width)),
334 height = Value::from(Quantity::length(size.height))
335 )
336 }
337}
338
339impl From<Tuple> for Value {
340 fn from(tuple: Tuple) -> Self {
341 Value::Tuple(Box::new(tuple))
342 }
343}
344
345impl FromIterator<Tuple> for Tuple {
346 fn from_iter<T: IntoIterator<Item = Tuple>>(iter: T) -> Self {
347 let tuples: Vec<_> = iter.into_iter().collect();
348 Self {
349 src_ref: SrcRef::merge_all(tuples.iter().map(|t| t.src_ref())),
350 named: Default::default(),
351 unnamed: tuples
352 .into_iter()
353 .map(|t| (Type::Tuple(t.tuple_type().into()), Value::Tuple(t.into())))
354 .collect(),
355 }
356 }
357}
358
359impl IntoIterator for Tuple {
360 type Item = (Identifier, Value);
361 type IntoIter = std::collections::hash_map::IntoIter<Identifier, Value>;
362
363 fn into_iter(self) -> Self::IntoIter {
364 if !self.unnamed.is_empty() {
365 log::warn!("trying to iterate Tuple with unnamed items");
366 }
367 self.named.into_iter()
368 }
369}
370
371impl<'a> TryFrom<&'a Value> for &'a Tuple {
372 type Error = ValueError;
373
374 fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
375 match value {
376 Value::Tuple(tuple) => Ok(tuple),
377 _ => Err(ValueError::CannotConvert(
378 value.to_string(),
379 "Tuple".to_string(),
380 )),
381 }
382 }
383}
384
385impl TryFrom<&Tuple> for Color {
386 type Error = ValueError;
387
388 fn try_from(tuple: &Tuple) -> Result<Self, Self::Error> {
389 let (r, g, b, a) = (
390 tuple.by_id(&Identifier::no_ref("r")),
391 tuple.by_id(&Identifier::no_ref("g")),
392 tuple.by_id(&Identifier::no_ref("b")),
393 tuple
394 .by_id(&Identifier::no_ref("a"))
395 .unwrap_or(&Value::Quantity(Quantity::new(1.0, QuantityType::Scalar)))
396 .clone(),
397 );
398
399 match (r, g, b, a) {
400 (
401 Some(Value::Quantity(Quantity {
402 value: r,
403 quantity_type: QuantityType::Scalar,
404 ..
405 })),
406 Some(Value::Quantity(Quantity {
407 value: g,
408 quantity_type: QuantityType::Scalar,
409 ..
410 })),
411 Some(Value::Quantity(Quantity {
412 value: b,
413 quantity_type: QuantityType::Scalar,
414 ..
415 })),
416 Value::Quantity(Quantity {
417 value: a,
418 quantity_type: QuantityType::Scalar,
419 ..
420 }),
421 ) => Ok(Color::new(*r as f32, *g as f32, *b as f32, a as f32)),
422 _ => Err(ValueError::CannotConvertToColor(tuple.to_string())),
423 }
424 }
425}
426
427impl TryFrom<&Tuple> for Size2 {
428 type Error = ValueError;
429
430 fn try_from(tuple: &Tuple) -> Result<Self, Self::Error> {
431 let (width, height) = (
432 tuple.by_id(&Identifier::no_ref("width")),
433 tuple.by_id(&Identifier::no_ref("height")),
434 );
435
436 match (width, height) {
437 (
438 Some(Value::Quantity(Quantity {
439 value: width,
440 quantity_type: QuantityType::Length,
441 ..
442 })),
443 Some(Value::Quantity(Quantity {
444 value: height,
445 quantity_type: QuantityType::Length,
446 ..
447 })),
448 ) => Ok(Size2 {
449 width: *width,
450 height: *height,
451 }),
452 _ => Err(ValueError::CannotConvert(tuple.to_string(), "Size2".into())),
453 }
454 }
455}
456
457impl std::fmt::Display for Tuple {
458 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
459 write!(
460 f,
461 "({items})",
462 items = {
463 let mut items = self
464 .named
465 .iter()
466 .map(|(id, v)| format!("{id}={v}"))
467 .chain(self.unnamed.values().map(|v| format!("{v}")))
468 .collect::<Vec<String>>();
469 items.sort();
470 items.join(", ")
471 }
472 )
473 }
474}
475
476impl std::ops::Add<Tuple> for Tuple {
477 type Output = ValueResult<Tuple>;
478
479 fn add(self, rhs: Tuple) -> Self::Output {
480 self.combine(rhs, |lhs, rhs| lhs.clone() + rhs.clone())
481 }
482}
483
484impl std::ops::Sub<Tuple> for Tuple {
485 type Output = ValueResult<Tuple>;
486
487 fn sub(self, rhs: Tuple) -> Self::Output {
488 self.combine(rhs, |lhs, rhs| lhs.clone() - rhs.clone())
489 }
490}
491
492impl std::ops::Mul<Value> for Tuple {
493 type Output = ValueResult<Tuple>;
494
495 fn mul(self, rhs: Value) -> Self::Output {
496 self.apply(rhs, |lhs, rhs| lhs * rhs)
497 }
498}
499
500impl std::ops::Div<Value> for Tuple {
501 type Output = ValueResult<Tuple>;
502
503 fn div(self, rhs: Value) -> Self::Output {
504 self.apply(rhs, |lhs, rhs| lhs / rhs)
505 }
506}
507
508impl std::ops::Neg for Tuple {
509 type Output = ValueResult;
510
511 fn neg(self) -> Self::Output {
512 Ok(Value::Tuple(Box::new(self.transform(|value| -value)?)))
513 }
514}
515
516impl std::ops::Not for Tuple {
517 type Output = ValueResult;
518
519 fn not(self) -> Self::Output {
520 Ok(Value::Tuple(Box::new(self.transform(|value| !value)?)))
521 }
522}
523
524impl std::hash::Hash for Tuple {
525 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
526 self.unnamed.iter().for_each(|(ty, value)| {
527 ty.hash(state);
528 value.hash(state);
529 });
530 self.named.iter().for_each(|(id, value)| {
531 id.hash(state);
532 value.hash(state);
533 });
534 }
535}
536
537impl Ty for Tuple {
538 fn ty(&self) -> Type {
539 Type::Tuple(Box::new(self.tuple_type()))
540 }
541}