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