1mod argument_value;
10mod argument_value_list;
11mod array;
12mod matrix;
13mod parameter_value;
14mod parameter_value_list;
15mod quantity;
16mod target;
17mod tuple;
18mod value_access;
19mod value_error;
20mod value_list;
21
22pub use argument_value::*;
23pub use argument_value_list::*;
24pub use array::*;
25pub use matrix::*;
26pub use parameter_value::*;
27pub use parameter_value_list::*;
28pub use quantity::*;
29pub use target::*;
30pub use tuple::*;
31pub use value_access::*;
32pub use value_error::*;
33pub use value_list::*;
34
35use crate::{model::*, rc::*, src_ref::SrcRef, syntax::*, ty::*};
36use microcad_core::*;
37
38pub(crate) type ValueResult<Type = Value> = std::result::Result<Type, ValueError>;
39
40#[derive(Clone, Default, PartialEq)]
42pub enum Value {
43 #[default]
45 None,
46 Quantity(Quantity),
48 Bool(bool),
50 Integer(Integer),
52 String(String),
54 Array(Array),
56 Tuple(Box<Tuple>),
58 Matrix(Box<Matrix>),
60 Model(Model),
62 Return(Box<Value>),
64 ConstExpression(Rc<Expression>),
66 Target(Target),
68}
69
70impl Value {
71 pub fn is_invalid(&self) -> bool {
73 matches!(self, Value::None)
74 }
75
76 pub fn pow(&self, rhs: &Value) -> ValueResult {
78 match (&self, rhs) {
79 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity(lhs.pow(rhs))),
80 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity(lhs.pow_int(rhs))),
81 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs.pow(*rhs as u32))),
82 _ => Err(ValueError::InvalidOperator("^".to_string())),
83 }
84 }
85
86 pub fn binary_op(lhs: Value, rhs: Value, op: &str) -> ValueResult {
88 match op {
89 "+" => lhs + rhs,
90 "-" => lhs - rhs,
91 "*" => lhs * rhs,
92 "/" => lhs / rhs,
93 "^" => lhs.pow(&rhs),
94 "&" => lhs & rhs,
95 "|" => lhs | rhs,
96 ">" => Ok(Value::Bool(lhs > rhs)),
97 "<" => Ok(Value::Bool(lhs < rhs)),
98 "≤" => Ok(Value::Bool(lhs <= rhs)),
99 "≥" => Ok(Value::Bool(lhs >= rhs)),
100 "~" => todo!("implement near ~="),
101 "==" => Ok(Value::Bool(lhs == rhs)),
102 "!=" => Ok(Value::Bool(lhs != rhs)),
103 _ => unimplemented!("{op:?}"),
104 }
105 }
106
107 pub fn unary_op(self, op: &str) -> ValueResult {
109 match op {
110 "-" => -self,
111 _ => unimplemented!(),
112 }
113 }
114
115 pub fn try_bool(&self) -> Result<bool, ValueError> {
119 match self {
120 Value::Bool(b) => Ok(*b),
121 Value::None => Ok(false),
122 value => Err(ValueError::CannotConvertToBool(value.to_string())),
123 }
124 }
125
126 pub fn try_string(&self) -> Result<String, ValueError> {
128 match self {
129 Value::String(s) => return Ok(s.clone()),
130 Value::Integer(i) => return Ok(i.to_string()),
131 _ => {}
132 }
133
134 Err(ValueError::CannotConvert(self.to_string(), "String".into()))
135 }
136
137 pub fn try_scalar(&self) -> Result<Scalar, ValueError> {
139 match self {
140 Value::Quantity(q) => return Ok(q.value),
141 Value::Integer(i) => return Ok((*i) as f64),
142 _ => {}
143 }
144
145 Err(ValueError::CannotConvert(self.to_string(), "Scalar".into()))
146 }
147
148 pub fn un_return(&self) -> Value {
150 match self {
151 Value::Return(value) => value.as_ref().clone(),
152 value => value.clone(),
153 }
154 }
155}
156
157impl PartialOrd for Value {
158 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
159 match (self, other) {
160 (Value::Integer(lhs), Value::Integer(rhs)) => lhs.partial_cmp(rhs),
162 (Value::Quantity(lhs), Value::Quantity(rhs)) => lhs.partial_cmp(rhs),
163 (
164 Value::Quantity(Quantity {
165 value,
166 quantity_type: QuantityType::Scalar,
167 }),
168 Value::Integer(rhs),
169 ) => value.partial_cmp(&(*rhs as Scalar)),
170 _ => {
171 log::warn!("unhandled type mismatch between {self} and {other}");
172 None
173 }
174 }
175 }
176}
177
178impl crate::ty::Ty for Value {
179 fn ty(&self) -> Type {
180 match self {
181 Value::None | Value::ConstExpression(_) => Type::Invalid,
182 Value::Integer(_) => Type::Integer,
183 Value::Quantity(q) => q.ty(),
184 Value::Bool(_) => Type::Bool,
185 Value::String(_) => Type::String,
186 Value::Array(list) => list.ty(),
187 Value::Tuple(tuple) => tuple.ty(),
188 Value::Matrix(matrix) => matrix.ty(),
189 Value::Model(_) => Type::Models,
190 Value::Return(r) => r.ty(),
191 Value::Target(..) => Type::Target,
192 }
193 }
194}
195
196impl std::ops::Neg for Value {
197 type Output = ValueResult;
198
199 fn neg(self) -> Self::Output {
200 match self {
201 Value::Integer(n) => Ok(Value::Integer(-n)),
202 Value::Quantity(q) => Ok(Value::Quantity(q.neg())),
203 Value::Array(a) => -a,
204 Value::Tuple(t) => -t.as_ref().clone(),
205 _ => Err(ValueError::InvalidOperator("-".into())),
206 }
207 }
208}
209
210impl std::ops::Add for Value {
212 type Output = ValueResult;
213
214 fn add(self, rhs: Self) -> Self::Output {
215 match (self, rhs) {
216 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs + rhs)),
218 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
220 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
222 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
224 (Value::String(lhs), Value::String(rhs)) => Ok(Value::String(lhs + &rhs)),
226 (Value::Array(lhs), Value::Array(rhs)) => {
228 if lhs.ty() != rhs.ty() {
229 return Err(ValueError::CannotCombineVecOfDifferentType(
230 lhs.ty(),
231 rhs.ty(),
232 ));
233 }
234
235 Ok(Value::Array(Array::from_values(
236 lhs.iter().chain(rhs.iter()).cloned().collect(),
237 lhs.ty(),
238 )))
239 }
240 (Value::Array(lhs), rhs) => Ok((lhs + rhs)?),
242 (Value::Tuple(lhs), Value::Tuple(rhs)) => Ok((*lhs + *rhs)?.into()),
244 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} + {rhs}"))),
245 }
246 }
247}
248
249impl std::ops::Sub for Value {
251 type Output = ValueResult;
252
253 fn sub(self, rhs: Self) -> Self::Output {
254 match (self, rhs) {
255 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs - rhs)),
257 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
259 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
261 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
263 (Value::Array(lhs), rhs) => Ok((lhs - rhs)?),
265 (Value::Tuple(lhs), Value::Tuple(rhs)) => Ok((*lhs - *rhs)?.into()),
267
268 (Value::Model(lhs), Value::Model(rhs)) => Ok(Value::Model(
270 lhs.boolean_op(microcad_core::BooleanOp::Subtract, rhs),
271 )),
272 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} - {rhs}"))),
273 }
274 }
275}
276
277impl std::ops::Mul for Value {
279 type Output = ValueResult;
280
281 fn mul(self, rhs: Self) -> Self::Output {
282 match (self, rhs) {
283 (Value::Integer(lhs), Value::Model(rhs)) => Ok(Value::Model(
284 Models::from(rhs.multiply(lhs)).to_multiplicity(SrcRef(None)),
285 )),
286 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs * rhs)),
288 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
290 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
292 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
294 (Value::Array(array), value) | (value, Value::Array(array)) => Ok((array * value)?),
295
296 (Value::Tuple(tuple), value) | (value, Value::Tuple(tuple)) => {
297 Ok((tuple.as_ref().clone() * value)?.into())
298 }
299 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} * {rhs}"))),
300 }
301 }
302}
303
304impl std::ops::Mul<Unit> for Value {
308 type Output = ValueResult;
309
310 fn mul(self, unit: Unit) -> Self::Output {
311 match (self, unit.ty()) {
312 (value, Type::Quantity(QuantityType::Scalar)) | (value, Type::Integer) => Ok(value),
313 (Value::Integer(i), Type::Quantity(quantity_type)) => Ok(Value::Quantity(
314 Quantity::new(unit.normalize(i as Scalar), quantity_type),
315 )),
316 (Value::Quantity(quantity), Type::Quantity(quantity_type)) => Ok(Value::Quantity(
317 (quantity * Quantity::new(unit.normalize(1.0), quantity_type))?,
318 )),
319 (Value::Array(array), Type::Quantity(quantity_type)) => {
320 Ok((array * Value::Quantity(Quantity::new(unit.normalize(1.0), quantity_type)))?)
321 }
322 (value, _) => Err(ValueError::CannotAddUnitToValueWithUnit(value.to_string())),
323 }
324 }
325}
326
327impl std::ops::Div for Value {
329 type Output = ValueResult;
330
331 fn div(self, rhs: Self) -> Self::Output {
332 match (self, rhs) {
333 (Value::Integer(lhs), Value::Integer(rhs)) => {
335 Ok(Value::Quantity((lhs as Scalar / rhs as Scalar).into()))
336 }
337 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
338 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
339 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
340 (Value::Array(array), value) => Ok((array / value)?),
341 (Value::Tuple(tuple), value) => Ok((tuple.as_ref().clone() / value)?.into()),
342 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} / {rhs}"))),
343 }
344 }
345}
346
347impl std::ops::BitOr for Value {
349 type Output = ValueResult;
350
351 fn bitor(self, rhs: Self) -> Self::Output {
352 match (self, rhs) {
353 (Value::Model(lhs), Value::Model(rhs)) => Ok(Value::Model(
354 lhs.boolean_op(microcad_core::BooleanOp::Union, rhs),
355 )),
356 (Value::Bool(lhs), Value::Bool(rhs)) => Ok(Value::Bool(lhs | rhs)),
357 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} | {rhs}"))),
358 }
359 }
360}
361
362impl std::ops::BitAnd for Value {
364 type Output = ValueResult;
365
366 fn bitand(self, rhs: Self) -> Self::Output {
367 match (self, rhs) {
368 (Value::Model(lhs), Value::Model(rhs)) => {
369 Ok(Value::Model(lhs.boolean_op(BooleanOp::Intersect, rhs)))
370 }
371 (Value::Bool(lhs), Value::Bool(rhs)) => Ok(Value::Bool(lhs & rhs)),
372 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} & {rhs}"))),
373 }
374 }
375}
376
377impl std::fmt::Display for Value {
378 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
379 match self {
380 Value::None => write!(f, crate::invalid_no_ansi!(VALUE)),
381 Value::Integer(n) => write!(f, "{n}"),
382 Value::Quantity(q) => write!(f, "{q}"),
383 Value::Bool(b) => write!(f, "{b}"),
384 Value::String(s) => write!(f, "{s}"),
385 Value::Array(l) => write!(f, "{l}"),
386 Value::Tuple(t) => write!(f, "{t}"),
387 Value::Matrix(m) => write!(f, "{m}"),
388 Value::Model(n) => write!(f, "{n}"),
389 Value::Return(r) => write!(f, "{r}"),
390 Value::ConstExpression(e) => write!(f, "{e}"),
391 Value::Target(target) => write!(f, "{target}"),
392 }
393 }
394}
395
396impl std::fmt::Debug for Value {
397 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
398 match self {
399 Value::None => write!(f, crate::invalid!(VALUE)),
400 Value::Integer(n) => write!(f, "{n}"),
401 Value::Quantity(q) => write!(f, "{q:?}"),
402 Value::Bool(b) => write!(f, "{b}"),
403 Value::String(s) => write!(f, "{s:?}"),
404 Value::Array(l) => write!(f, "{l:?}"),
405 Value::Tuple(t) => write!(f, "{t:?}"),
406 Value::Matrix(m) => write!(f, "{m:?}"),
407 Value::Model(n) => write!(f, "\n {n:?}"),
408 Value::Return(r) => write!(f, "->{r:?}"),
409 Value::ConstExpression(e) => write!(f, "{e:?}"),
410 Value::Target(target) => write!(f, "{target:?}"),
411 }
412 }
413}
414
415impl std::hash::Hash for Value {
416 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
417 match self {
418 Value::None => std::mem::discriminant(&Value::None).hash(state),
419 Value::Quantity(quantity) => quantity.hash(state),
420 Value::Bool(b) => b.hash(state),
421 Value::Integer(i) => i.hash(state),
422 Value::String(s) => s.hash(state),
423 Value::Array(array) => array.hash(state),
424 Value::Tuple(tuple) => tuple.hash(state),
425 Value::Matrix(matrix) => matrix.hash(state),
426 Value::Model(model) => model.hash(state),
427 Value::Return(value) => value.hash(state),
428 Value::ConstExpression(expression) => expression.to_string().hash(state), Value::Target(target) => target.hash(state),
430 }
431 }
432}
433
434macro_rules! impl_try_from {
435 ($($variant:ident),+ => $ty:ty ) => {
436 impl TryFrom<Value> for $ty {
437 type Error = ValueError;
438
439 fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
440 match value {
441 $(Value::$variant(v) => Ok(v),)*
442 value => Err(ValueError::CannotConvert(value.to_string(), stringify!($ty).into())),
443 }
444 }
445 }
446
447 impl TryFrom<&Value> for $ty {
448 type Error = ValueError;
449
450 fn try_from(value: &Value) -> std::result::Result<Self, Self::Error> {
451 match value {
452 $(Value::$variant(v) => Ok(v.clone().into()),)*
453 value => Err(ValueError::CannotConvert(value.to_string(), stringify!($ty).into())),
454 }
455 }
456 }
457 };
458}
459
460impl_try_from!(Integer => i64);
461impl_try_from!(Bool => bool);
462impl_try_from!(String => String);
463
464impl TryFrom<&Value> for Scalar {
465 type Error = ValueError;
466
467 fn try_from(value: &Value) -> Result<Self, Self::Error> {
468 match value {
469 Value::Integer(i) => Ok(*i as Scalar),
470 Value::Quantity(Quantity {
471 value,
472 quantity_type: QuantityType::Scalar,
473 }) => Ok(*value),
474 _ => Err(ValueError::CannotConvert(
475 value.to_string(),
476 "Scalar".into(),
477 )),
478 }
479 }
480}
481
482impl TryFrom<Value> for Scalar {
483 type Error = ValueError;
484
485 fn try_from(value: Value) -> Result<Self, Self::Error> {
486 match value {
487 Value::Integer(i) => Ok(i as Scalar),
488 Value::Quantity(Quantity {
489 value,
490 quantity_type: QuantityType::Scalar,
491 }) => Ok(value),
492 _ => Err(ValueError::CannotConvert(
493 value.to_string(),
494 "Scalar".into(),
495 )),
496 }
497 }
498}
499
500impl TryFrom<&Value> for Angle {
501 type Error = ValueError;
502
503 fn try_from(value: &Value) -> Result<Self, Self::Error> {
504 match value {
505 Value::Quantity(Quantity {
506 value,
507 quantity_type: QuantityType::Angle,
508 }) => Ok(cgmath::Rad(*value)),
509 _ => Err(ValueError::CannotConvert(value.to_string(), "Angle".into())),
510 }
511 }
512}
513
514impl TryFrom<&Value> for Length {
515 type Error = ValueError;
516
517 fn try_from(value: &Value) -> Result<Self, Self::Error> {
518 match value {
519 Value::Quantity(Quantity {
520 value,
521 quantity_type: QuantityType::Length,
522 }) => Ok(Length(*value)),
523 _ => Err(ValueError::CannotConvert(
524 value.to_string(),
525 "Length".into(),
526 )),
527 }
528 }
529}
530
531impl TryFrom<&Value> for Size2 {
532 type Error = ValueError;
533
534 fn try_from(value: &Value) -> Result<Self, Self::Error> {
535 match value {
536 Value::Tuple(tuple) => Ok(tuple.as_ref().try_into()?),
537 _ => Err(ValueError::CannotConvert(value.to_string(), "Size2".into())),
538 }
539 }
540}
541
542impl TryFrom<&Value> for Mat3 {
543 type Error = ValueError;
544
545 fn try_from(value: &Value) -> Result<Self, Self::Error> {
546 if let Value::Matrix(m) = value {
547 if let Matrix::Matrix3(matrix3) = m.as_ref() {
548 return Ok(*matrix3);
549 }
550 }
551
552 Err(ValueError::CannotConvert(
553 value.to_string(),
554 "Matrix3".into(),
555 ))
556 }
557}
558
559impl From<f32> for Value {
560 fn from(f: f32) -> Self {
561 Value::Quantity((f as Scalar).into())
562 }
563}
564
565impl From<Scalar> for Value {
566 fn from(scalar: Scalar) -> Self {
567 Value::Quantity(scalar.into())
568 }
569}
570
571impl From<Length> for Value {
572 fn from(length: Length) -> Self {
573 Value::Quantity(length.into())
574 }
575}
576
577impl From<Size2> for Value {
578 fn from(value: Size2) -> Self {
579 Self::Tuple(Box::new(value.into()))
580 }
581}
582
583impl From<Quantity> for Value {
584 fn from(qty: Quantity) -> Self {
585 Self::Quantity(qty)
586 }
587}
588
589impl From<String> for Value {
590 fn from(value: String) -> Self {
591 Self::String(value)
592 }
593}
594
595impl From<Color> for Value {
596 fn from(color: Color) -> Self {
597 Self::Tuple(Box::new(color.into()))
598 }
599}
600
601impl FromIterator<Value> for Value {
602 fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
603 Self::Array(iter.into_iter().collect())
604 }
605}
606
607impl From<Model> for Value {
608 fn from(model: Model) -> Self {
609 Self::Model(model)
610 }
611}
612
613impl AttributesAccess for Value {
614 fn get_attributes_by_id(&self, id: &Identifier) -> Vec<crate::model::Attribute> {
615 match self {
616 Value::Model(model) => model.get_attributes_by_id(id),
617 _ => Vec::default(),
618 }
619 }
620}
621
622#[cfg(test)]
623fn integer(value: i64) -> Value {
624 Value::Integer(value)
625}
626
627#[cfg(test)]
628fn scalar(value: f64) -> Value {
629 Value::Quantity(Quantity::new(value, QuantityType::Scalar))
630}
631
632#[cfg(test)]
633fn check(result: ValueResult, value: Value) {
634 let result = result.expect("error result");
635 assert_eq!(result, value);
636}
637
638#[test]
639fn test_value_integer() {
640 let u = || integer(2);
641 let v = || integer(5);
642 let w = || scalar(5.0);
643
644 check(u() + v(), integer(2 + 5));
646 check(u() - v(), integer(2 - 5));
647 check(u() * v(), integer(2 * 5));
648 check(u() / v(), scalar(2.0 / 5.0));
649 check(-u(), integer(-2));
650
651 check(u() + w(), scalar(2 as Scalar + 5.0));
653 check(u() - w(), scalar(2 as Scalar - 5.0));
654 check(u() * w(), scalar(2 as Scalar * 5.0));
655 check(u() / w(), scalar(2.0 / 5.0));
656}
657
658#[test]
659fn test_value_scalar() {
660 let u = || scalar(2.0);
661 let v = || scalar(5.0);
662 let w = || integer(5);
663
664 check(u() + v(), scalar(2.0 + 5.0));
666 check(u() - v(), scalar(2.0 - 5.0));
667 check(u() * v(), scalar(2.0 * 5.0));
668 check(u() / v(), scalar(2.0 / 5.0));
669 check(-u(), scalar(-2.0));
670
671 check(u() + w(), scalar(2.0 + 5.0));
673 check(u() - w(), scalar(2.0 - 5.0));
674 check(u() * w(), scalar(2.0 * 5.0));
675 check(u() / w(), scalar(2.0 / 5.0));
676}