diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-07-10 20:01:18 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-07-10 23:10:17 +0200 |
| commit | 6a4823461f491aef63451f097ddfe5602e0b2157 (patch) | |
| tree | ad11b0ad169d030942d950573c729d50f7b3291b /src/eval/array.rs | |
| parent | 36b3067c19c8743032a44f888ee48702b88d135b (diff) | |
Reference-count complex values
Rename some nodes types
Diffstat (limited to 'src/eval/array.rs')
| -rw-r--r-- | src/eval/array.rs | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/src/eval/array.rs b/src/eval/array.rs new file mode 100644 index 00000000..f62bda9f --- /dev/null +++ b/src/eval/array.rs @@ -0,0 +1,148 @@ +use std::fmt::{self, Debug, Formatter}; +use std::iter::FromIterator; +use std::ops::{Add, AddAssign}; +use std::rc::Rc; + +use super::Value; + +/// Create a new [`Array`] from values. +#[macro_export] +macro_rules! array { + ($value:expr; $count:expr) => { + $crate::eval::Array::from_vec(vec![$crate::eval::Value::from($value); $count]) + }; + + ($($value:expr),* $(,)?) => { + $crate::eval::Array::from_vec(vec![$($crate::eval::Value::from($value)),*]) + }; +} + +/// A variably-typed array with clone-on-write value semantics. +#[derive(Clone, PartialEq)] +pub struct Array { + vec: Rc<Vec<Value>>, +} + +impl Array { + /// Create a new, empty array. + pub fn new() -> Self { + Self { vec: Rc::new(vec![]) } + } + + /// Create a new array from a vector of values. + pub fn from_vec(vec: Vec<Value>) -> Self { + Self { vec: Rc::new(vec) } + } + + /// Create a new, empty array with the given `capacity`. + pub fn with_capacity(capacity: usize) -> Self { + Self { + vec: Rc::new(Vec::with_capacity(capacity)), + } + } + + /// Whether the array is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// The length of the array. + pub fn len(&self) -> usize { + self.vec.len() + } + + /// Borrow the value at the given index. + pub fn get(&self, index: usize) -> Option<&Value> { + self.vec.get(index) + } + + /// Mutably borrow the value at the given index. + pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> { + Rc::make_mut(&mut self.vec).get_mut(index) + } + + /// Set the value at the given index. + /// + /// This panics the `index` is out of range. + pub fn set(&mut self, index: usize, value: Value) { + Rc::make_mut(&mut self.vec)[index] = value; + } + + /// Push a value to the end of the array. + pub fn push(&mut self, value: Value) { + Rc::make_mut(&mut self.vec).push(value); + } + + /// Extend the array with the values from another array. + pub fn extend(&mut self, other: &Array) { + Rc::make_mut(&mut self.vec).extend(other.into_iter()) + } + + /// Clear the array. + pub fn clear(&mut self) { + if Rc::strong_count(&mut self.vec) == 1 { + Rc::make_mut(&mut self.vec).clear(); + } else { + *self = Self::new(); + } + } + + /// Repeat this array `n` times. + pub fn repeat(&self, n: usize) -> Self { + let len = self.len().checked_mul(n).expect("capacity overflow"); + self.into_iter().cycle().take(len).collect() + } + + /// Iterate over references to the contained values. + pub fn iter(&self) -> std::slice::Iter<Value> { + self.vec.iter() + } + + /// Iterate over the contained values. + pub fn into_iter(&self) -> impl Iterator<Item = Value> + Clone + '_ { + // TODO: Actually consume the vector if the ref-count is 1? + self.iter().cloned() + } +} + +impl Default for Array { + fn default() -> Self { + Self::new() + } +} + +impl Debug for Array { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_list().entries(self.vec.iter()).finish() + } +} + +impl FromIterator<Value> for Array { + fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self { + Array { vec: Rc::new(iter.into_iter().collect()) } + } +} + +impl<'a> IntoIterator for &'a Array { + type Item = &'a Value; + type IntoIter = std::slice::Iter<'a, Value>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl Add<&Array> for Array { + type Output = Self; + + fn add(mut self, rhs: &Array) -> Self::Output { + self.extend(rhs); + self + } +} + +impl AddAssign<&Array> for Array { + fn add_assign(&mut self, rhs: &Array) { + self.extend(rhs); + } +} |
