summaryrefslogtreecommitdiff
path: root/src/eval/array.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-06-06 21:13:59 +0200
committerLaurenz <laurmaedje@gmail.com>2023-06-06 22:06:16 +0200
commitfd417da04f7ca4b995de7f6510abafd3e9c31307 (patch)
tree3675529c75ca7363701ac8ea306de2cc1d3cbcb3 /src/eval/array.rs
parent168bdf35bd773e67343c965cb473492cc5cae9e7 (diff)
Improve value casting infrastructure
Diffstat (limited to 'src/eval/array.rs')
-rw-r--r--src/eval/array.rs95
1 files changed, 63 insertions, 32 deletions
diff --git a/src/eval/array.rs b/src/eval/array.rs
index d0b63b35..a7a1387b 100644
--- a/src/eval/array.rs
+++ b/src/eval/array.rs
@@ -4,7 +4,7 @@ use std::ops::{Add, AddAssign};
use ecow::{eco_format, EcoString, EcoVec};
-use super::{ops, Args, Func, Value, Vm};
+use super::{ops, Args, CastInfo, FromValue, Func, IntoValue, Reflect, Value, Vm};
use crate::diag::{At, SourceResult, StrResult};
use crate::syntax::Span;
use crate::util::pretty_array_like;
@@ -14,11 +14,16 @@ use crate::util::pretty_array_like;
#[doc(hidden)]
macro_rules! __array {
($value:expr; $count:expr) => {
- $crate::eval::Array::from_vec($crate::eval::eco_vec![$value.into(); $count])
+ $crate::eval::Array::from($crate::eval::eco_vec![
+ $crate::eval::IntoValue::into_value($value);
+ $count
+ ])
};
($($value:expr),* $(,)?) => {
- $crate::eval::Array::from_vec($crate::eval::eco_vec![$($value.into()),*])
+ $crate::eval::Array::from($crate::eval::eco_vec![$(
+ $crate::eval::IntoValue::into_value($value)
+ ),*])
};
}
@@ -38,19 +43,14 @@ impl Array {
Self::default()
}
- /// Create a new array from an eco vector of values.
- pub fn from_vec(vec: EcoVec<Value>) -> Self {
- Self(vec)
- }
-
/// Return `true` if the length is 0.
pub fn is_empty(&self) -> bool {
self.0.len() == 0
}
/// The length of the array.
- pub fn len(&self) -> i64 {
- self.0.len() as i64
+ pub fn len(&self) -> usize {
+ self.0.len()
}
/// The first value in the array.
@@ -134,14 +134,14 @@ impl Array {
.filter(|&start| start <= self.0.len())
.ok_or_else(|| out_of_bounds(start, len))?;
- let end = end.unwrap_or(self.len());
+ let end = end.unwrap_or(self.len() as i64);
let end = self
.locate(end)
.filter(|&end| end <= self.0.len())
.ok_or_else(|| out_of_bounds(end, len))?
.max(start);
- Ok(Self::from_vec(self.0[start..end].into()))
+ Ok(self.0[start..end].into())
}
/// Whether the array contains a specific value.
@@ -182,7 +182,7 @@ impl Array {
kept.push(item.clone())
}
}
- Ok(Self::from_vec(kept))
+ Ok(kept.into())
}
/// Transform each item in the array with a function.
@@ -273,7 +273,7 @@ impl Array {
flat.push(item.clone());
}
}
- Self::from_vec(flat)
+ flat.into()
}
/// Returns a new array with reversed order.
@@ -317,9 +317,7 @@ impl Array {
pub fn zip(&self, other: Array) -> Array {
self.iter()
.zip(other)
- .map(|(first, second)| {
- Value::Array(Array::from_vec(eco_vec![first.clone(), second]))
- })
+ .map(|(first, second)| array![first.clone(), second].into_value())
.collect()
}
@@ -360,7 +358,7 @@ impl Array {
}
}
});
- result.map(|_| Self::from_vec(vec))
+ result.map(|_| vec.into())
}
/// Repeat this array `n` times.
@@ -385,19 +383,20 @@ impl Array {
/// Resolve an index.
fn locate(&self, index: i64) -> Option<usize> {
- usize::try_from(if index >= 0 { index } else { self.len().checked_add(index)? })
- .ok()
+ usize::try_from(if index >= 0 {
+ index
+ } else {
+ (self.len() as i64).checked_add(index)?
+ })
+ .ok()
}
/// Enumerate all items in the array.
pub fn enumerate(&self) -> Self {
- let v = self
- .iter()
+ self.iter()
.enumerate()
- .map(|(i, value)| array![i, value.clone()])
- .map(Value::Array)
- .collect();
- Self::from_vec(v)
+ .map(|(i, value)| array![i, value.clone()].into_value())
+ .collect()
}
}
@@ -453,6 +452,40 @@ impl<'a> IntoIterator for &'a Array {
}
}
+impl From<EcoVec<Value>> for Array {
+ fn from(v: EcoVec<Value>) -> Self {
+ Array(v)
+ }
+}
+
+impl From<&[Value]> for Array {
+ fn from(v: &[Value]) -> Self {
+ Array(v.into())
+ }
+}
+
+impl<T> Reflect for Vec<T> {
+ fn describe() -> CastInfo {
+ Array::describe()
+ }
+
+ fn castable(value: &Value) -> bool {
+ Array::castable(value)
+ }
+}
+
+impl<T: IntoValue> IntoValue for Vec<T> {
+ fn into_value(self) -> Value {
+ Value::Array(self.into_iter().map(IntoValue::into_value).collect())
+ }
+}
+
+impl<T: FromValue> FromValue for Vec<T> {
+ fn from_value(value: Value) -> StrResult<Self> {
+ value.cast::<Array>()?.into_iter().map(Value::cast).collect()
+ }
+}
+
/// The error message when the array is empty.
#[cold]
fn array_is_empty() -> EcoString {
@@ -461,17 +494,15 @@ fn array_is_empty() -> EcoString {
/// The out of bounds access error message.
#[cold]
-fn out_of_bounds(index: i64, len: i64) -> EcoString {
- eco_format!("array index out of bounds (index: {}, len: {})", index, len)
+fn out_of_bounds(index: i64, len: usize) -> EcoString {
+ eco_format!("array index out of bounds (index: {index}, len: {len})")
}
/// The out of bounds access error message when no default value was given.
#[cold]
-fn out_of_bounds_no_default(index: i64, len: i64) -> EcoString {
+fn out_of_bounds_no_default(index: i64, len: usize) -> EcoString {
eco_format!(
- "array index out of bounds (index: {}, len: {}) \
+ "array index out of bounds (index: {index}, len: {len}) \
and no default value was specified",
- index,
- len
)
}