1use std::collections::HashMap;
7
8use crate::{src_ref::*, ty::*, value::*};
9
10#[derive(Clone, Default, Debug, 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.clone(),
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(Box::new(tuple.clone()))),
435 }
436 }
437}
438
439impl TryFrom<Color> for Value {
440 type Error = ValueError;
441
442 fn try_from(c: Color) -> Result<Self, Self::Error> {
443 Ok(crate::create_tuple_value!(
444 r = c.r,
445 g = c.g,
446 b = c.b,
447 a = c.a
448 ))
449 }
450}
451
452impl TryFrom<&Tuple> for Size2 {
453 type Error = ValueError;
454
455 fn try_from(tuple: &Tuple) -> Result<Self, Self::Error> {
456 let (width, height) = (
457 tuple.by_id(&Identifier::no_ref("width")),
458 tuple.by_id(&Identifier::no_ref("height")),
459 );
460
461 match (width, height) {
462 (
463 Some(Value::Quantity(Quantity {
464 value: width,
465 quantity_type: QuantityType::Length,
466 })),
467 Some(Value::Quantity(Quantity {
468 value: height,
469 quantity_type: QuantityType::Length,
470 })),
471 ) => Ok(Size2 {
472 width: *width,
473 height: *height,
474 }),
475 _ => Err(ValueError::CannotConvert(
476 tuple.clone().into(),
477 "Size2".into(),
478 )),
479 }
480 }
481}
482
483impl std::fmt::Display for Tuple {
484 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
485 write!(
486 f,
487 "({items})",
488 items = {
489 let mut items = self
490 .named
491 .iter()
492 .map(|(id, v)| format!("{id}={v}"))
493 .chain(self.unnamed.values().map(|v| format!("{v}")))
494 .collect::<Vec<String>>();
495 items.sort();
496 items.join(", ")
497 }
498 )
499 }
500}
501
502impl std::ops::Add<Tuple> for Tuple {
503 type Output = ValueResult<Tuple>;
504
505 fn add(self, rhs: Tuple) -> Self::Output {
506 self.combine(rhs, |lhs, rhs| lhs.clone() + rhs.clone())
507 }
508}
509
510impl std::ops::Sub<Tuple> for Tuple {
511 type Output = ValueResult<Tuple>;
512
513 fn sub(self, rhs: Tuple) -> Self::Output {
514 self.combine(rhs, |lhs, rhs| lhs.clone() - rhs.clone())
515 }
516}
517
518impl std::ops::Mul<Value> for Tuple {
519 type Output = ValueResult<Tuple>;
520
521 fn mul(self, rhs: Value) -> Self::Output {
522 self.apply(rhs, |lhs, rhs| lhs * rhs)
523 }
524}
525
526impl std::ops::Div<Value> for Tuple {
527 type Output = ValueResult<Tuple>;
528
529 fn div(self, rhs: Value) -> Self::Output {
530 self.apply(rhs, |lhs, rhs| lhs / rhs)
531 }
532}
533
534impl std::ops::Neg for Tuple {
535 type Output = ValueResult;
536
537 fn neg(self) -> Self::Output {
538 Ok(Value::Tuple(Box::new(self.transform(|value| -value)?)))
539 }
540}
541
542impl Ty for Tuple {
543 fn ty(&self) -> Type {
544 Type::Tuple(Box::new(self.tuple_type()))
545 }
546}
547
548#[test]
549fn tuple_equal() {
550 assert_eq!(
551 tuple!("(v=1.0m³, l=1.0m, a=1.0m²)"),
552 tuple!("(l=1.0m, a=1.0m², v=1.0m³)")
553 );
554}
555
556#[test]
557fn tuple_not_equal() {
558 assert_ne!(
559 tuple!("(d=1.0g/mm³, l=1.0m, a=1.0m²)"),
560 tuple!("(l=1.0m, a=1.0m², v=1.0m³)")
561 );
562 assert_ne!(
563 tuple!("(l=1.0m, a=1.0m²)"),
564 tuple!("(l=1.0m, a=1.0m², v=1.0m³)")
565 );
566}
567
568#[test]
569fn multiplicity_check() {
570 let tuple = tuple!("(x = [1, 2, 3], y = [1, 2], z = 1)");
571
572 let ids: IdentifierList = ["x".into(), "y".into()].into_iter().collect();
573 tuple.multiplicity(ids, |tuple| println!("{tuple}"));
574}