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
149impl PartialOrd for Value {
150 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
151 match (self, other) {
152 (Value::Integer(lhs), Value::Integer(rhs)) => lhs.partial_cmp(rhs),
154 (Value::Quantity(lhs), Value::Quantity(rhs)) => lhs.partial_cmp(rhs),
155 (
156 Value::Quantity(Quantity {
157 value,
158 quantity_type: QuantityType::Scalar,
159 }),
160 Value::Integer(rhs),
161 ) => value.partial_cmp(&(*rhs as Scalar)),
162 _ => {
163 log::warn!("unhandled type mismatch between {self} and {other}");
164 None
165 }
166 }
167 }
168}
169
170impl crate::ty::Ty for Value {
171 fn ty(&self) -> Type {
172 match self {
173 Value::None | Value::ConstExpression(_) => Type::Invalid,
174 Value::Integer(_) => Type::Integer,
175 Value::Quantity(q) => q.ty(),
176 Value::Bool(_) => Type::Bool,
177 Value::String(_) => Type::String,
178 Value::Array(list) => list.ty(),
179 Value::Tuple(tuple) => tuple.ty(),
180 Value::Matrix(matrix) => matrix.ty(),
181 Value::Model(_) => Type::Models,
182 Value::Return(r) => r.ty(),
183 Value::Target(..) => Type::Target,
184 }
185 }
186}
187
188impl std::ops::Neg for Value {
189 type Output = ValueResult;
190
191 fn neg(self) -> Self::Output {
192 match self {
193 Value::Integer(n) => Ok(Value::Integer(-n)),
194 Value::Quantity(q) => Ok(Value::Quantity(q.neg())),
195 Value::Array(a) => -a,
196 Value::Tuple(t) => -t.as_ref().clone(),
197 _ => Err(ValueError::InvalidOperator("-".into())),
198 }
199 }
200}
201
202impl std::ops::Add for Value {
204 type Output = ValueResult;
205
206 fn add(self, rhs: Self) -> Self::Output {
207 match (self, rhs) {
208 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs + rhs)),
210 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
212 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
214 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
216 (Value::String(lhs), Value::String(rhs)) => Ok(Value::String(lhs + &rhs)),
218 (Value::Array(lhs), Value::Array(rhs)) => {
220 if lhs.ty() != rhs.ty() {
221 return Err(ValueError::CannotCombineVecOfDifferentType(
222 lhs.ty(),
223 rhs.ty(),
224 ));
225 }
226
227 Ok(Value::Array(Array::from_values(
228 lhs.iter().chain(rhs.iter()).cloned().collect(),
229 lhs.ty(),
230 )))
231 }
232 (Value::Array(lhs), rhs) => Ok((lhs + rhs)?),
234 (Value::Tuple(lhs), Value::Tuple(rhs)) => Ok((*lhs + *rhs)?.into()),
236 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} + {rhs}"))),
237 }
238 }
239}
240
241impl std::ops::Sub for Value {
243 type Output = ValueResult;
244
245 fn sub(self, rhs: Self) -> Self::Output {
246 match (self, rhs) {
247 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs - rhs)),
249 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
251 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
253 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
255 (Value::Array(lhs), rhs) => Ok((lhs - rhs)?),
257 (Value::Tuple(lhs), Value::Tuple(rhs)) => Ok((*lhs - *rhs)?.into()),
259
260 (Value::Model(lhs), Value::Model(rhs)) => Ok(Value::Model(
262 lhs.boolean_op(microcad_core::BooleanOp::Subtract, rhs),
263 )),
264 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} - {rhs}"))),
265 }
266 }
267}
268
269impl std::ops::Mul for Value {
271 type Output = ValueResult;
272
273 fn mul(self, rhs: Self) -> Self::Output {
274 match (self, rhs) {
275 (Value::Integer(lhs), Value::Model(rhs)) => Ok(Value::Model(
276 Models::from(rhs.multiply(lhs)).to_multiplicity(SrcRef(None)),
277 )),
278 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs * rhs)),
280 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
282 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
284 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
286 (Value::Array(array), value) | (value, Value::Array(array)) => Ok((array * value)?),
287
288 (Value::Tuple(tuple), value) | (value, Value::Tuple(tuple)) => {
289 Ok((tuple.as_ref().clone() * value)?.into())
290 }
291 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} * {rhs}"))),
292 }
293 }
294}
295
296impl std::ops::Mul<Unit> for Value {
300 type Output = ValueResult;
301
302 fn mul(self, unit: Unit) -> Self::Output {
303 match (self, unit.ty()) {
304 (value, Type::Quantity(QuantityType::Scalar)) | (value, Type::Integer) => Ok(value),
305 (Value::Integer(i), Type::Quantity(quantity_type)) => Ok(Value::Quantity(
306 Quantity::new(unit.normalize(i as Scalar), quantity_type),
307 )),
308 (Value::Quantity(quantity), Type::Quantity(quantity_type)) => Ok(Value::Quantity(
309 (quantity * Quantity::new(unit.normalize(1.0), quantity_type))?,
310 )),
311 (Value::Array(array), Type::Quantity(quantity_type)) => {
312 Ok((array * Value::Quantity(Quantity::new(unit.normalize(1.0), quantity_type)))?)
313 }
314 (value, _) => Err(ValueError::CannotAddUnitToValueWithUnit(value.to_string())),
315 }
316 }
317}
318
319impl std::ops::Div for Value {
321 type Output = ValueResult;
322
323 fn div(self, rhs: Self) -> Self::Output {
324 match (self, rhs) {
325 (Value::Integer(lhs), Value::Integer(rhs)) => {
327 Ok(Value::Quantity((lhs as Scalar / rhs as Scalar).into()))
328 }
329 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
330 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
331 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
332 (Value::Array(array), value) => Ok((array / value)?),
333 (Value::Tuple(tuple), value) => Ok((tuple.as_ref().clone() / value)?.into()),
334 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} / {rhs}"))),
335 }
336 }
337}
338
339impl std::ops::BitOr for Value {
341 type Output = ValueResult;
342
343 fn bitor(self, rhs: Self) -> Self::Output {
344 match (self, rhs) {
345 (Value::Model(lhs), Value::Model(rhs)) => Ok(Value::Model(
346 lhs.boolean_op(microcad_core::BooleanOp::Union, rhs),
347 )),
348 (Value::Bool(lhs), Value::Bool(rhs)) => Ok(Value::Bool(lhs | rhs)),
349 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} | {rhs}"))),
350 }
351 }
352}
353
354impl std::ops::BitAnd for Value {
356 type Output = ValueResult;
357
358 fn bitand(self, rhs: Self) -> Self::Output {
359 match (self, rhs) {
360 (Value::Model(lhs), Value::Model(rhs)) => {
361 Ok(Value::Model(lhs.boolean_op(BooleanOp::Intersect, rhs)))
362 }
363 (Value::Bool(lhs), Value::Bool(rhs)) => Ok(Value::Bool(lhs & rhs)),
364 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} & {rhs}"))),
365 }
366 }
367}
368
369impl std::fmt::Display for Value {
370 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
371 match self {
372 Value::None => write!(f, crate::invalid_no_ansi!(VALUE)),
373 Value::Integer(n) => write!(f, "{n}"),
374 Value::Quantity(q) => write!(f, "{q}"),
375 Value::Bool(b) => write!(f, "{b}"),
376 Value::String(s) => write!(f, "{s}"),
377 Value::Array(l) => write!(f, "{l}"),
378 Value::Tuple(t) => write!(f, "{t}"),
379 Value::Matrix(m) => write!(f, "{m}"),
380 Value::Model(n) => write!(f, "{n}"),
381 Value::Return(r) => write!(f, "{r}"),
382 Value::ConstExpression(e) => write!(f, "{e}"),
383 Value::Target(target) => write!(f, "{target}"),
384 }
385 }
386}
387
388impl std::fmt::Debug for Value {
389 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
390 match self {
391 Value::None => write!(f, crate::invalid!(VALUE)),
392 Value::Integer(n) => write!(f, "{n}"),
393 Value::Quantity(q) => write!(f, "{q:?}"),
394 Value::Bool(b) => write!(f, "{b}"),
395 Value::String(s) => write!(f, "{s:?}"),
396 Value::Array(l) => write!(f, "{l:?}"),
397 Value::Tuple(t) => write!(f, "{t:?}"),
398 Value::Matrix(m) => write!(f, "{m:?}"),
399 Value::Model(n) => write!(f, "\n {n:?}"),
400 Value::Return(r) => write!(f, "->{r:?}"),
401 Value::ConstExpression(e) => write!(f, "{e:?}"),
402 Value::Target(target) => write!(f, "{target:?}"),
403 }
404 }
405}
406
407impl std::hash::Hash for Value {
408 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
409 match self {
410 Value::None => std::mem::discriminant(&Value::None).hash(state),
411 Value::Quantity(quantity) => quantity.hash(state),
412 Value::Bool(b) => b.hash(state),
413 Value::Integer(i) => i.hash(state),
414 Value::String(s) => s.hash(state),
415 Value::Array(array) => array.hash(state),
416 Value::Tuple(tuple) => tuple.hash(state),
417 Value::Matrix(matrix) => matrix.hash(state),
418 Value::Model(model) => model.hash(state),
419 Value::Return(value) => value.hash(state),
420 Value::ConstExpression(expression) => expression.to_string().hash(state), Value::Target(target) => target.hash(state),
422 }
423 }
424}
425
426macro_rules! impl_try_from {
427 ($($variant:ident),+ => $ty:ty ) => {
428 impl TryFrom<Value> for $ty {
429 type Error = ValueError;
430
431 fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
432 match value {
433 $(Value::$variant(v) => Ok(v),)*
434 value => Err(ValueError::CannotConvert(value.to_string(), stringify!($ty).into())),
435 }
436 }
437 }
438
439 impl TryFrom<&Value> for $ty {
440 type Error = ValueError;
441
442 fn try_from(value: &Value) -> std::result::Result<Self, Self::Error> {
443 match value {
444 $(Value::$variant(v) => Ok(v.clone().into()),)*
445 value => Err(ValueError::CannotConvert(value.to_string(), stringify!($ty).into())),
446 }
447 }
448 }
449 };
450}
451
452impl_try_from!(Integer => i64);
453impl_try_from!(Bool => bool);
454impl_try_from!(String => String);
455
456impl TryFrom<&Value> for Scalar {
457 type Error = ValueError;
458
459 fn try_from(value: &Value) -> Result<Self, Self::Error> {
460 match value {
461 Value::Integer(i) => Ok(*i as Scalar),
462 Value::Quantity(Quantity {
463 value,
464 quantity_type: QuantityType::Scalar,
465 }) => Ok(*value),
466 _ => Err(ValueError::CannotConvert(
467 value.to_string(),
468 "Scalar".into(),
469 )),
470 }
471 }
472}
473
474impl TryFrom<Value> for Scalar {
475 type Error = ValueError;
476
477 fn try_from(value: Value) -> Result<Self, Self::Error> {
478 match value {
479 Value::Integer(i) => Ok(i as Scalar),
480 Value::Quantity(Quantity {
481 value,
482 quantity_type: QuantityType::Scalar,
483 }) => Ok(value),
484 _ => Err(ValueError::CannotConvert(
485 value.to_string(),
486 "Scalar".into(),
487 )),
488 }
489 }
490}
491
492impl TryFrom<&Value> for Angle {
493 type Error = ValueError;
494
495 fn try_from(value: &Value) -> Result<Self, Self::Error> {
496 match value {
497 Value::Quantity(Quantity {
498 value,
499 quantity_type: QuantityType::Angle,
500 }) => Ok(cgmath::Rad(*value)),
501 _ => Err(ValueError::CannotConvert(value.to_string(), "Angle".into())),
502 }
503 }
504}
505
506impl TryFrom<&Value> for Length {
507 type Error = ValueError;
508
509 fn try_from(value: &Value) -> Result<Self, Self::Error> {
510 match value {
511 Value::Quantity(Quantity {
512 value,
513 quantity_type: QuantityType::Length,
514 }) => Ok(Length(*value)),
515 _ => Err(ValueError::CannotConvert(
516 value.to_string(),
517 "Length".into(),
518 )),
519 }
520 }
521}
522
523impl TryFrom<&Value> for Size2 {
524 type Error = ValueError;
525
526 fn try_from(value: &Value) -> Result<Self, Self::Error> {
527 match value {
528 Value::Tuple(tuple) => Ok(tuple.as_ref().try_into()?),
529 _ => Err(ValueError::CannotConvert(value.to_string(), "Size2".into())),
530 }
531 }
532}
533
534impl TryFrom<&Value> for Mat3 {
535 type Error = ValueError;
536
537 fn try_from(value: &Value) -> Result<Self, Self::Error> {
538 if let Value::Matrix(m) = value {
539 if let Matrix::Matrix3(matrix3) = m.as_ref() {
540 return Ok(*matrix3);
541 }
542 }
543
544 Err(ValueError::CannotConvert(
545 value.to_string(),
546 "Matrix3".into(),
547 ))
548 }
549}
550
551impl From<f32> for Value {
552 fn from(f: f32) -> Self {
553 Value::Quantity((f as Scalar).into())
554 }
555}
556
557impl From<Scalar> for Value {
558 fn from(scalar: Scalar) -> Self {
559 Value::Quantity(scalar.into())
560 }
561}
562
563impl From<Length> for Value {
564 fn from(length: Length) -> Self {
565 Value::Quantity(length.into())
566 }
567}
568
569impl From<Size2> for Value {
570 fn from(value: Size2) -> Self {
571 Self::Tuple(Box::new(value.into()))
572 }
573}
574
575impl From<Quantity> for Value {
576 fn from(qty: Quantity) -> Self {
577 Self::Quantity(qty)
578 }
579}
580
581impl From<String> for Value {
582 fn from(value: String) -> Self {
583 Self::String(value)
584 }
585}
586
587impl From<Color> for Value {
588 fn from(color: Color) -> Self {
589 Self::Tuple(Box::new(color.into()))
590 }
591}
592
593impl FromIterator<Value> for Value {
594 fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
595 Self::Array(iter.into_iter().collect())
596 }
597}
598
599impl From<Model> for Value {
600 fn from(model: Model) -> Self {
601 Self::Model(model)
602 }
603}
604
605impl AttributesAccess for Value {
606 fn get_attributes_by_id(&self, id: &Identifier) -> Vec<crate::model::Attribute> {
607 match self {
608 Value::Model(model) => model.get_attributes_by_id(id),
609 _ => Vec::default(),
610 }
611 }
612}
613
614#[cfg(test)]
615fn integer(value: i64) -> Value {
616 Value::Integer(value)
617}
618
619#[cfg(test)]
620fn scalar(value: f64) -> Value {
621 Value::Quantity(Quantity::new(value, QuantityType::Scalar))
622}
623
624#[cfg(test)]
625fn check(result: ValueResult, value: Value) {
626 let result = result.expect("error result");
627 assert_eq!(result, value);
628}
629
630#[test]
631fn test_value_integer() {
632 let u = || integer(2);
633 let v = || integer(5);
634 let w = || scalar(5.0);
635
636 check(u() + v(), integer(2 + 5));
638 check(u() - v(), integer(2 - 5));
639 check(u() * v(), integer(2 * 5));
640 check(u() / v(), scalar(2.0 / 5.0));
641 check(-u(), integer(-2));
642
643 check(u() + w(), scalar(2 as Scalar + 5.0));
645 check(u() - w(), scalar(2 as Scalar - 5.0));
646 check(u() * w(), scalar(2 as Scalar * 5.0));
647 check(u() / w(), scalar(2.0 / 5.0));
648}
649
650#[test]
651fn test_value_scalar() {
652 let u = || scalar(2.0);
653 let v = || scalar(5.0);
654 let w = || integer(5);
655
656 check(u() + v(), scalar(2.0 + 5.0));
658 check(u() - v(), scalar(2.0 - 5.0));
659 check(u() * v(), scalar(2.0 * 5.0));
660 check(u() / v(), scalar(2.0 / 5.0));
661 check(-u(), scalar(-2.0));
662
663 check(u() + w(), scalar(2.0 + 5.0));
665 check(u() - w(), scalar(2.0 - 5.0));
666 check(u() * w(), scalar(2.0 * 5.0));
667 check(u() / w(), scalar(2.0 / 5.0));
668}