1mod argument_value;
10mod argument_value_list;
11mod array;
12mod matrix;
13mod parameter_value;
14mod parameter_value_list;
15mod quantity;
16mod tuple;
17mod value_access;
18mod value_error;
19mod value_list;
20
21pub use argument_value::*;
22pub use argument_value_list::*;
23pub use array::*;
24pub use matrix::*;
25pub use parameter_value::*;
26pub use parameter_value_list::*;
27pub use quantity::*;
28pub use tuple::*;
29pub use value_access::*;
30pub use value_error::*;
31pub use value_list::*;
32
33use crate::{model::*, syntax::*, ty::*, *};
34use microcad_core::*;
35
36pub(crate) type ValueResult<Type = Value> = std::result::Result<Type, ValueError>;
37
38#[derive(Clone, Default, PartialEq)]
40pub enum Value {
41 #[default]
43 None,
44 Quantity(Quantity),
46 Bool(bool),
48 Integer(Integer),
50 String(String),
52 Array(Array),
54 Tuple(Box<Tuple>),
56 Matrix(Box<Matrix>),
58 Model(Model),
60 Return(Box<Value>),
62}
63
64impl Value {
65 pub fn is_invalid(&self) -> bool {
67 matches!(self, Value::None)
68 }
69
70 pub fn pow(&self, rhs: &Value) -> ValueResult {
72 match (&self, rhs) {
73 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity(lhs.pow(rhs))),
74 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity(lhs.pow_int(rhs))),
75 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs.pow(*rhs as u32))),
76 _ => Err(ValueError::InvalidOperator("^".to_string())),
77 }
78 }
79
80 pub fn binary_op(lhs: Value, rhs: Value, op: &str) -> ValueResult {
82 match op {
83 "+" => lhs + rhs,
84 "-" => lhs - rhs,
85 "*" => lhs * rhs,
86 "/" => lhs / rhs,
87 "^" => lhs.pow(&rhs),
88 "&" => lhs & rhs,
89 "|" => lhs | rhs,
90 ">" => Ok(Value::Bool(lhs > rhs)),
91 "<" => Ok(Value::Bool(lhs < rhs)),
92 "≤" => Ok(Value::Bool(lhs <= rhs)),
93 "≥" => Ok(Value::Bool(lhs >= rhs)),
94 "~" => todo!("implement near ~="),
95 "==" => Ok(Value::Bool(lhs == rhs)),
96 "!=" => Ok(Value::Bool(lhs != rhs)),
97 _ => unimplemented!("{op:?}"),
98 }
99 }
100
101 pub fn unary_op(self, op: &str) -> ValueResult {
103 match op {
104 "-" => -self,
105 _ => unimplemented!(),
106 }
107 }
108
109 pub fn try_bool(&self) -> Result<bool, ValueError> {
113 match self {
114 Value::Bool(b) => Ok(*b),
115 Value::None => Ok(false),
116 value => Err(ValueError::CannotConvertToBool(value.clone())),
117 }
118 }
119
120 pub fn try_string(&self) -> Result<String, ValueError> {
122 match self {
123 Value::String(s) => return Ok(s.clone()),
124 Value::Integer(i) => return Ok(i.to_string()),
125 _ => {}
126 }
127
128 Err(ValueError::CannotConvert(self.clone(), "String".into()))
129 }
130
131 pub fn try_scalar(&self) -> Result<Scalar, ValueError> {
133 match self {
134 Value::Quantity(q) => return Ok(q.value),
135 Value::Integer(i) => return Ok((*i) as f64),
136 _ => {}
137 }
138
139 Err(ValueError::CannotConvert(self.clone(), "Scalar".into()))
140 }
141}
142
143impl PartialOrd for Value {
144 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
145 match (self, other) {
146 (Value::Integer(lhs), Value::Integer(rhs)) => lhs.partial_cmp(rhs),
148 (Value::Quantity(lhs), Value::Quantity(rhs)) => lhs.partial_cmp(rhs),
149 (
150 Value::Quantity(Quantity {
151 value,
152 quantity_type: QuantityType::Scalar,
153 }),
154 Value::Integer(rhs),
155 ) => value.partial_cmp(&(*rhs as Scalar)),
156 _ => {
157 log::warn!("unhandled type mismatch between {self} and {other}");
158 None
159 }
160 }
161 }
162}
163
164impl crate::ty::Ty for Value {
165 fn ty(&self) -> Type {
166 match self {
167 Value::None => Type::Invalid,
168 Value::Integer(_) => Type::Integer,
169 Value::Quantity(q) => q.ty(),
170 Value::Bool(_) => Type::Bool,
171 Value::String(_) => Type::String,
172 Value::Array(list) => list.ty(),
173 Value::Tuple(tuple) => tuple.ty(),
174 Value::Matrix(matrix) => matrix.ty(),
175 Value::Model(_) => Type::Models,
176 Value::Return(r) => r.ty(),
177 }
178 }
179}
180
181impl std::ops::Neg for Value {
182 type Output = ValueResult;
183
184 fn neg(self) -> Self::Output {
185 match self {
186 Value::Integer(n) => Ok(Value::Integer(-n)),
187 Value::Quantity(q) => Ok(Value::Quantity(q.neg())),
188 Value::Array(a) => -a,
189 Value::Tuple(t) => -t.as_ref().clone(),
190 _ => Err(ValueError::InvalidOperator("-".into())),
191 }
192 }
193}
194
195impl std::ops::Add for Value {
197 type Output = ValueResult;
198
199 fn add(self, rhs: Self) -> Self::Output {
200 match (self, rhs) {
201 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs + rhs)),
203 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
205 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
207 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
209 (Value::String(lhs), Value::String(rhs)) => Ok(Value::String(lhs + &rhs)),
211 (Value::Array(lhs), Value::Array(rhs)) => {
213 if lhs.ty() != rhs.ty() {
214 return Err(ValueError::CannotCombineVecOfDifferentType(
215 lhs.ty(),
216 rhs.ty(),
217 ));
218 }
219
220 Ok(Value::Array(Array::new(
221 lhs.iter().chain(rhs.iter()).cloned().collect(),
222 lhs.ty(),
223 )))
224 }
225 (Value::Array(lhs), rhs) => Ok((lhs + rhs)?),
227 (Value::Tuple(lhs), Value::Tuple(rhs)) => Ok((*lhs + *rhs)?.into()),
229 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} + {rhs}"))),
230 }
231 }
232}
233
234impl std::ops::Sub for Value {
236 type Output = ValueResult;
237
238 fn sub(self, rhs: Self) -> Self::Output {
239 match (self, rhs) {
240 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs - rhs)),
242 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
244 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
246 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
248 (Value::Array(lhs), rhs) => Ok((lhs - rhs)?),
250 (Value::Tuple(lhs), Value::Tuple(rhs)) => Ok((*lhs - *rhs)?.into()),
252
253 (Value::Model(lhs), Value::Model(rhs)) => Ok(Value::Model(
255 lhs.boolean_op(microcad_core::BooleanOp::Subtract, rhs),
256 )),
257 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} - {rhs}"))),
258 }
259 }
260}
261
262impl std::ops::Mul for Value {
264 type Output = ValueResult;
265
266 fn mul(self, rhs: Self) -> Self::Output {
267 match (self, rhs) {
268 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs * rhs)),
270 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
272 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
274 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
276 (Value::Array(array), value) | (value, Value::Array(array)) => Ok((array * value)?),
277 (Value::Tuple(tuple), value) | (value, Value::Tuple(tuple)) => {
278 Ok((tuple.as_ref().clone() * value)?.into())
279 }
280 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} * {rhs}"))),
281 }
282 }
283}
284
285impl std::ops::Mul<Unit> for Value {
289 type Output = ValueResult;
290
291 fn mul(self, unit: Unit) -> Self::Output {
292 match (self, unit.ty()) {
293 (value, Type::Quantity(QuantityType::Scalar)) | (value, Type::Integer) => Ok(value),
294 (Value::Integer(i), Type::Quantity(quantity_type)) => Ok(Value::Quantity(
295 Quantity::new(unit.normalize(i as Scalar), quantity_type),
296 )),
297 (Value::Quantity(quantity), Type::Quantity(quantity_type)) => Ok(Value::Quantity(
298 (quantity * Quantity::new(unit.normalize(1.0), quantity_type))?,
299 )),
300 (Value::Array(array), Type::Quantity(quantity_type)) => {
301 Ok((array * Value::Quantity(Quantity::new(unit.normalize(1.0), quantity_type)))?)
302 }
303 (value, _) => Err(ValueError::CannotAddUnitToValueWithUnit(value.clone())),
304 }
305 }
306}
307
308impl std::ops::Div for Value {
310 type Output = ValueResult;
311
312 fn div(self, rhs: Self) -> Self::Output {
313 match (self, rhs) {
314 (Value::Integer(lhs), Value::Integer(rhs)) => {
316 Ok(Value::Quantity((lhs as Scalar / rhs as Scalar).into()))
317 }
318 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
319 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
320 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
321 (Value::Array(array), value) => Ok((array / value)?),
322 (Value::Tuple(tuple), value) => Ok((tuple.as_ref().clone() / value)?.into()),
323 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} / {rhs}"))),
324 }
325 }
326}
327
328impl std::ops::BitOr for Value {
330 type Output = ValueResult;
331
332 fn bitor(self, rhs: Self) -> Self::Output {
333 match (self, rhs) {
334 (Value::Model(lhs), Value::Model(rhs)) => Ok(Value::Model(
335 lhs.boolean_op(microcad_core::BooleanOp::Union, rhs),
336 )),
337 (Value::Bool(lhs), Value::Bool(rhs)) => Ok(Value::Bool(lhs | rhs)),
338 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} | {rhs}"))),
339 }
340 }
341}
342
343impl std::ops::BitAnd for Value {
345 type Output = ValueResult;
346
347 fn bitand(self, rhs: Self) -> Self::Output {
348 match (self, rhs) {
349 (Value::Model(lhs), Value::Model(rhs)) => {
350 Ok(Value::Model(lhs.boolean_op(BooleanOp::Intersect, rhs)))
351 }
352 (Value::Bool(lhs), Value::Bool(rhs)) => Ok(Value::Bool(lhs & rhs)),
353 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} & {rhs}"))),
354 }
355 }
356}
357
358impl std::fmt::Display for Value {
359 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
360 match self {
361 Value::None => write!(f, crate::invalid_no_ansi!(VALUE)),
362 Value::Integer(n) => write!(f, "{n}"),
363 Value::Quantity(q) => write!(f, "{q}"),
364 Value::Bool(b) => write!(f, "{b}"),
365 Value::String(s) => write!(f, "{s}"),
366 Value::Array(l) => write!(f, "{l}"),
367 Value::Tuple(t) => write!(f, "{t}"),
368 Value::Matrix(m) => write!(f, "{m}"),
369 Value::Model(n) => write!(f, "{n}"),
370 Value::Return(r) => write!(f, "{r}"),
371 }
372 }
373}
374
375impl std::fmt::Debug for Value {
376 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
377 match self {
378 Value::None => write!(f, crate::invalid!(VALUE)),
379 Value::Integer(n) => write!(f, "{n}"),
380 Value::Quantity(q) => write!(f, "{q}"),
381 Value::Bool(b) => write!(f, "{b}"),
382 Value::String(s) => write!(f, "\"{s}\""),
383 Value::Array(l) => write!(f, "{l}"),
384 Value::Tuple(t) => write!(f, "{t}"),
385 Value::Matrix(m) => write!(f, "{m}"),
386 Value::Model(n) => write!(f, "Models:\n {n}"),
387 Value::Return(r) => write!(f, "Return: {r}"),
388 }
389 }
390}
391
392macro_rules! impl_try_from {
393 ($($variant:ident),+ => $ty:ty ) => {
394 impl TryFrom<Value> for $ty {
395 type Error = ValueError;
396
397 fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
398 match value {
399 $(Value::$variant(v) => Ok(v),)*
400 value => Err(ValueError::CannotConvert(value, stringify!($ty).into())),
401 }
402 }
403 }
404
405 impl TryFrom<&Value> for $ty {
406 type Error = ValueError;
407
408 fn try_from(value: &Value) -> std::result::Result<Self, Self::Error> {
409 match value {
410 $(Value::$variant(v) => Ok(v.clone().into()),)*
411 value => Err(ValueError::CannotConvert(value.clone(), stringify!($ty).into())),
412 }
413 }
414 }
415 };
416}
417
418impl_try_from!(Integer => i64);
419impl_try_from!(Bool => bool);
420impl_try_from!(String => String);
421
422impl TryFrom<&Value> for Scalar {
423 type Error = ValueError;
424
425 fn try_from(value: &Value) -> Result<Self, Self::Error> {
426 match value {
427 Value::Integer(i) => Ok(*i as Scalar),
428 Value::Quantity(Quantity {
429 value,
430 quantity_type: QuantityType::Scalar,
431 }) => Ok(*value),
432 _ => Err(ValueError::CannotConvert(value.clone(), "Scalar".into())),
433 }
434 }
435}
436
437impl TryFrom<Value> for Scalar {
438 type Error = ValueError;
439
440 fn try_from(value: Value) -> Result<Self, Self::Error> {
441 match value {
442 Value::Integer(i) => Ok(i as Scalar),
443 Value::Quantity(Quantity {
444 value,
445 quantity_type: QuantityType::Scalar,
446 }) => Ok(value),
447 _ => Err(ValueError::CannotConvert(value.clone(), "Scalar".into())),
448 }
449 }
450}
451
452impl TryFrom<&Value> for Size2 {
453 type Error = ValueError;
454
455 fn try_from(value: &Value) -> Result<Self, Self::Error> {
456 match value {
457 Value::Tuple(tuple) => Ok(tuple.as_ref().try_into()?),
458 _ => Err(ValueError::CannotConvert(value.clone(), "Size2".into())),
459 }
460 }
461}
462
463impl TryFrom<&Value> for Mat3 {
464 type Error = ValueError;
465
466 fn try_from(value: &Value) -> Result<Self, Self::Error> {
467 if let Value::Matrix(m) = value {
468 if let Matrix::Matrix3(matrix3) = m.as_ref() {
469 return Ok(*matrix3);
470 }
471 }
472
473 Err(ValueError::CannotConvert(value.clone(), "Matrix3".into()))
474 }
475}
476
477impl From<f32> for Value {
478 fn from(f: f32) -> Self {
479 Value::Quantity((f as Scalar).into())
480 }
481}
482
483impl From<Scalar> for Value {
484 fn from(scalar: Scalar) -> Self {
485 Value::Quantity(scalar.into())
486 }
487}
488
489impl From<Size2> for Value {
490 fn from(value: Size2) -> Self {
491 Value::Tuple(Box::new(value.into()))
492 }
493}
494
495impl From<Quantity> for Value {
496 fn from(qty: Quantity) -> Self {
497 Value::Quantity(qty)
498 }
499}
500
501impl From<String> for Value {
502 fn from(value: String) -> Self {
503 Value::String(value)
504 }
505}
506
507impl FromIterator<Value> for Value {
508 fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
509 Self::Array(iter.into_iter().collect())
510 }
511}
512
513impl From<Model> for Value {
514 fn from(model: Model) -> Self {
515 Self::Model(model)
516 }
517}
518
519impl AttributesAccess for Value {
520 fn get_attributes_by_id(&self, id: &Identifier) -> Vec<crate::model::Attribute> {
521 match self {
522 Value::Model(model) => model.get_attributes_by_id(id),
523 _ => Vec::default(),
524 }
525 }
526}
527
528#[cfg(test)]
529fn integer(value: i64) -> Value {
530 Value::Integer(value)
531}
532
533#[cfg(test)]
534fn scalar(value: f64) -> Value {
535 Value::Quantity(Quantity::new(value, QuantityType::Scalar))
536}
537
538#[cfg(test)]
539fn check(result: ValueResult, value: Value) {
540 let result = result.expect("error result");
541 assert_eq!(result, value);
542}
543
544#[test]
545fn test_value_integer() {
546 let u = || integer(2);
547 let v = || integer(5);
548 let w = || scalar(5.0);
549
550 check(u() + v(), integer(2 + 5));
552 check(u() - v(), integer(2 - 5));
553 check(u() * v(), integer(2 * 5));
554 check(u() / v(), scalar(2.0 / 5.0));
555 check(-u(), integer(-2));
556
557 check(u() + w(), scalar(2 as Scalar + 5.0));
559 check(u() - w(), scalar(2 as Scalar - 5.0));
560 check(u() * w(), scalar(2 as Scalar * 5.0));
561 check(u() / w(), scalar(2.0 / 5.0));
562}
563
564#[test]
565fn test_value_scalar() {
566 let u = || scalar(2.0);
567 let v = || scalar(5.0);
568 let w = || integer(5);
569
570 check(u() + v(), scalar(2.0 + 5.0));
572 check(u() - v(), scalar(2.0 - 5.0));
573 check(u() * v(), scalar(2.0 * 5.0));
574 check(u() / v(), scalar(2.0 / 5.0));
575 check(-u(), scalar(-2.0));
576
577 check(u() + w(), scalar(2.0 + 5.0));
579 check(u() - w(), scalar(2.0 - 5.0));
580 check(u() * w(), scalar(2.0 * 5.0));
581 check(u() / w(), scalar(2.0 / 5.0));
582}