microcad_lang/value/
array.rs

1// Copyright © 2024-2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Typed list of values evaluation entity
5
6use crate::{ty::*, value::*};
7use derive_more::{Deref, DerefMut};
8
9/// Collection of values of the same type.
10#[derive(Clone, Deref, DerefMut)]
11pub struct Array {
12    /// List of values
13    #[deref]
14    #[deref_mut]
15    items: ValueList,
16    /// Element type.
17    ty: Type,
18}
19
20impl Array {
21    /// Create new list
22    pub fn new(ty: Type) -> Self {
23        Self {
24            items: ValueList::default(),
25            ty,
26        }
27    }
28
29    /// Create new list from `ValueList`.
30    pub fn from_values(items: ValueList, ty: Type) -> Self {
31        Self { items, ty }
32    }
33
34    /// Fetch all values as `Vec<Value>`
35    pub fn fetch(&self) -> Vec<Value> {
36        self.items.iter().cloned().collect::<Vec<_>>()
37    }
38
39    /// Get the first element, or None
40    pub fn head(&self) -> Value {
41        self.items.iter().next().cloned().unwrap_or(Value::None)
42    }
43
44    /// Get all elements but the first
45    pub fn tail(&self) -> Array {
46        Array::from_values(
47            self.items.iter().skip(1).cloned().collect(),
48            self.ty.clone(),
49        )
50    }
51}
52
53impl PartialEq for Array {
54    fn eq(&self, other: &Self) -> bool {
55        self.ty == other.ty && self.items == other.items
56    }
57}
58
59impl IntoIterator for Array {
60    type Item = Value;
61    type IntoIter = std::vec::IntoIter<Self::Item>;
62
63    fn into_iter(self) -> Self::IntoIter {
64        self.items.into_iter()
65    }
66}
67
68impl TryFrom<ValueList> for Array {
69    type Error = ValueError;
70    fn try_from(items: ValueList) -> ValueResult<Array> {
71        match items.types().common_type() {
72            Some(ty) => Ok(Array::from_values(items, ty)),
73            None => Err(ValueError::CommonTypeExpected),
74        }
75    }
76}
77
78impl FromIterator<Value> for Array {
79    fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
80        let items: ValueList = iter.into_iter().collect();
81        let ty = items.types().common_type().expect("Common type");
82        Self { ty, items }
83    }
84}
85
86impl std::fmt::Display for Array {
87    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
88        write!(
89            f,
90            "[{items}]",
91            items = self
92                .items
93                .iter()
94                .map(|v| v.to_string())
95                .collect::<Vec<_>>()
96                .join(", ")
97        )
98    }
99}
100
101impl std::fmt::Debug for Array {
102    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
103        write!(
104            f,
105            "[{items}]",
106            items = self
107                .items
108                .iter()
109                .map(|v| format!("{v:?}"))
110                .collect::<Vec<_>>()
111                .join(", ")
112        )
113    }
114}
115
116impl crate::ty::Ty for Array {
117    fn ty(&self) -> Type {
118        Type::Array(Box::new(self.ty.clone()))
119    }
120}
121
122/// + operator. Adds a value to an array, e.g.: `[1,2] + 1 == [2,3]`.
123impl std::ops::Add<Value> for Array {
124    type Output = ValueResult;
125
126    fn add(self, rhs: Value) -> Self::Output {
127        if self.ty.is_compatible_to(&rhs.ty()) {
128            Ok(Value::Array(Self::from_values(
129                ValueList::new(
130                    self.items
131                        .iter()
132                        .map(|value| value.clone() + rhs.clone())
133                        .collect::<Result<Vec<_>, _>>()?,
134                ),
135                self.ty,
136            )))
137        } else {
138            Err(ValueError::InvalidOperator("+".into()))
139        }
140    }
141}
142
143/// - operator. Subtracts a value from an array, e.g.: `[1,2] - 1 == [0,1]`.
144impl std::ops::Sub<Value> for Array {
145    type Output = ValueResult;
146
147    fn sub(self, rhs: Value) -> Self::Output {
148        if self.ty.is_compatible_to(&rhs.ty()) {
149            Ok(Value::Array(Self::from_values(
150                ValueList::new(
151                    self.items
152                        .iter()
153                        .map(|value| value.clone() - rhs.clone())
154                        .collect::<Result<Vec<_>, _>>()?,
155                ),
156                self.ty,
157            )))
158        } else {
159            Err(ValueError::InvalidOperator("-".into()))
160        }
161    }
162}
163
164/// * operator. Multiply a value from an array, e.g.: `[1,2] * 2 == [2,4]`.
165impl std::ops::Mul<Value> for Array {
166    type Output = ValueResult;
167
168    fn mul(self, rhs: Value) -> Self::Output {
169        match self.ty {
170            // List * Scalar or List * Integer
171            Type::Quantity(_) | Type::Integer => Ok(Value::Array(Array::from_values(
172                ValueList::new({
173                    self.iter()
174                        .map(|value| value.clone() * rhs.clone())
175                        .collect::<Result<Vec<_>, _>>()?
176                }),
177                self.ty * rhs.ty().clone(),
178            ))),
179            _ => Err(ValueError::InvalidOperator("*".into())),
180        }
181    }
182}
183
184/// / operator. Divide an array by value, e.g.: `[2,4] / 2 == [1,2]`.
185impl std::ops::Div<Value> for Array {
186    type Output = ValueResult;
187
188    fn div(self, rhs: Value) -> Self::Output {
189        let values = ValueList::new(
190            self.iter()
191                .map(|value| value.clone() / rhs.clone())
192                .collect::<Result<Vec<_>, _>>()?,
193        );
194
195        match (&self.ty, rhs.ty()) {
196            // Integer / Integer => Scalar
197            (Type::Integer, Type::Integer) => Ok(Value::Array(Array::from_values(
198                values,
199                self.ty / rhs.ty().clone(),
200            ))),
201            (Type::Quantity(_), _) => Ok(Value::Array(values.try_into()?)),
202            _ => Err(ValueError::InvalidOperator("/".into())),
203        }
204    }
205}
206
207impl std::ops::Neg for Array {
208    type Output = ValueResult;
209
210    fn neg(self) -> Self::Output {
211        let items: ValueList = self
212            .iter()
213            .map(|value| -value.clone())
214            .collect::<Result<Vec<_>, _>>()?
215            .into_iter()
216            .collect();
217        Ok(Value::Array(items.try_into()?))
218    }
219}
220
221#[test]
222fn test_array_debug() {
223    let val1 = Value::Target(Target::new("my::name1".into(), Some("my::target1".into())));
224    let val2 = Value::Target(Target::new("my::name2".into(), None));
225
226    let mut array = Array::new(Type::Target);
227    array.push(val1);
228    array.push(val2);
229
230    log::info!("{array}");
231    log::info!("{array:?}");
232}