use crate::{ty::*, value::*};
use derive_more::{Deref, DerefMut};
#[derive(Clone, Debug, Deref, DerefMut)]
pub struct Array {
#[deref]
#[deref_mut]
items: ValueList,
ty: Type,
}
impl Array {
pub fn new(ty: Type) -> Self {
Self {
items: ValueList::default(),
ty,
}
}
pub fn from_values(items: ValueList, ty: Type) -> Self {
Self { items, ty }
}
}
impl Array {
pub fn first(&self) -> Value {
self.items.first().cloned().unwrap_or_default()
}
pub fn last(&self) -> Value {
self.items.last().cloned().unwrap_or_default()
}
pub fn tail(&self) -> Array {
Array::from_values(
self.items.iter().skip(1).cloned().collect(),
self.ty.clone(),
)
}
pub fn rev(&self) -> Array {
Array::from_values(self.items.iter().rev().cloned().collect(), self.ty.clone())
}
pub fn sorted(&self) -> Array {
let mut items = self.items.clone();
match self.ty {
Type::Integer | Type::Quantity(..) | Type::String | Type::Bool => {
items.sort_by(|a, b| {
assert_eq!(a.ty(), b.ty());
match (a, b) {
(Value::Quantity(a), Value::Quantity(b)) => a.value.total_cmp(&b.value),
(Value::Integer(a), Value::Integer(b)) => a.cmp(b),
(Value::Bool(a), Value::Bool(b)) => a.cmp(b),
(Value::String(a), Value::String(b)) => a.cmp(b),
_ => unreachable!(),
}
})
}
_ => {}
};
Array::from_values(items, self.ty.clone())
}
pub fn all_equal(&self) -> bool {
match self.first() {
Value::None => true,
value => self[1..].iter().all(|x| *x == value),
}
}
pub fn is_ascending(&self) -> bool {
self.as_slice().windows(2).all(|w| w[0] <= w[1])
}
pub fn is_descending(&self) -> bool {
self.as_slice().windows(2).all(|w| w[0] >= w[1])
}
}
impl PartialEq for Array {
fn eq(&self, other: &Self) -> bool {
self.ty == other.ty && self.items == other.items
}
}
impl IntoIterator for Array {
type Item = Value;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
impl TryFrom<ValueList> for Array {
type Error = ValueError;
fn try_from(items: ValueList) -> ValueResult<Array> {
match items.types().common_type() {
Some(ty) => Ok(Array::from_values(items, ty)),
None => Err(ValueError::CommonTypeExpected),
}
}
}
impl FromIterator<Value> for Array {
fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
let items: ValueList = iter.into_iter().collect();
let ty = items.types().common_type().expect("Common type");
Self { ty, items }
}
}
impl std::fmt::Display for Array {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"[{items}]",
items = self
.items
.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ")
)
}
}
impl crate::ty::Ty for Array {
fn ty(&self) -> Type {
Type::Array(Box::new(self.ty.clone()))
}
}
impl std::ops::Add<Value> for Array {
type Output = ValueResult;
fn add(self, rhs: Value) -> Self::Output {
if self.ty.is_compatible_to(&rhs.ty()) {
Ok(Value::Array(Self::from_values(
ValueList::new(
self.items
.iter()
.map(|value| value.clone() + rhs.clone())
.collect::<Result<Vec<_>, _>>()?,
),
self.ty,
)))
} else {
Err(ValueError::InvalidOperator("+".into()))
}
}
}
impl std::ops::Sub<Value> for Array {
type Output = ValueResult;
fn sub(self, rhs: Value) -> Self::Output {
if self.ty.is_compatible_to(&rhs.ty()) {
Ok(Value::Array(Self::from_values(
ValueList::new(
self.items
.iter()
.map(|value| value.clone() - rhs.clone())
.collect::<Result<Vec<_>, _>>()?,
),
self.ty,
)))
} else {
Err(ValueError::InvalidOperator("-".into()))
}
}
}
impl std::ops::Mul<Value> for Array {
type Output = ValueResult;
fn mul(self, rhs: Value) -> Self::Output {
match self.ty {
Type::Quantity(_) | Type::Integer => Ok(Value::Array(Array::from_values(
ValueList::new({
self.iter()
.map(|value| value.clone() * rhs.clone())
.collect::<Result<Vec<_>, _>>()?
}),
self.ty * rhs.ty().clone(),
))),
_ => Err(ValueError::InvalidOperator("*".into())),
}
}
}
impl std::ops::Div<Value> for Array {
type Output = ValueResult;
fn div(self, rhs: Value) -> Self::Output {
let values = ValueList::new(
self.iter()
.map(|value| value.clone() / rhs.clone())
.collect::<Result<Vec<_>, _>>()?,
);
match (&self.ty, rhs.ty()) {
(Type::Integer, Type::Integer) => Ok(Value::Array(Array::from_values(
values,
self.ty / rhs.ty().clone(),
))),
(Type::Quantity(_), _) => Ok(Value::Array(values.try_into()?)),
_ => Err(ValueError::InvalidOperator("/".into())),
}
}
}
impl std::ops::Neg for Array {
type Output = ValueResult;
fn neg(self) -> Self::Output {
let items = ValueList::new(
self.iter()
.map(|value| -value.clone())
.collect::<Result<Vec<_>, _>>()?,
);
Ok(Value::Array(items.try_into()?))
}
}
impl std::ops::Not for Array {
type Output = ValueResult;
fn not(self) -> Self::Output {
let items = ValueList::new(
self.iter()
.map(|value| !value.clone())
.collect::<Result<Vec<_>, _>>()?,
);
Ok(Value::Array(items.try_into()?))
}
}