use std::{
convert::TryInto,
hash::{Hash, Hasher},
ops::Deref,
};
use gc::{Gc, GcCell, GcCellRef, GcCellRefMut, Finalize, Trace};
use super::{EmptyCollection, IndexOutOfBounds, Value};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Trace, Finalize)]
pub struct Array(Gc<GcCell<Vec<Value>>>);
impl Array {
pub fn new(vec: Vec<Value>) -> Self {
Self(Gc::new(GcCell::new(vec)))
}
pub fn copy(&self) -> Self {
Self(self.0.clone())
}
pub fn borrow(&self) -> GcCellRef<Vec<Value>> {
self.0.deref().borrow()
}
pub fn borrow_mut(&self) -> GcCellRefMut<Vec<Value>> {
self.0.deref().borrow_mut()
}
pub fn push(&mut self, value: Value) {
self.0.borrow_mut().push(value)
}
pub fn pop(&mut self) -> Result<Value, EmptyCollection> {
self.0
.borrow_mut()
.pop()
.ok_or(EmptyCollection)
}
pub fn index(&self, index: i64) -> Result<Value, IndexOutOfBounds> {
let index: usize = index
.try_into()
.map_err(|_| IndexOutOfBounds)?;
self
.borrow()
.get(index)
.map(Value::copy)
.ok_or(IndexOutOfBounds)
}
pub fn contains(&self, value: &Value) -> bool {
self
.borrow()
.contains(value)
}
pub fn set(&self, index: i64, value: Value) -> Result<(), IndexOutOfBounds> {
let index: usize = index
.try_into()
.map_err(|_| IndexOutOfBounds)?;
let mut array = self.borrow_mut();
let val = array
.get_mut(index)
.ok_or(IndexOutOfBounds)?;
*val = value;
Ok(())
}
pub fn len(&self) -> i64 {
self.borrow().len() as i64
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn sort(&mut self) {
self.borrow_mut().sort();
}
}
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for Array {
fn hash<H: Hasher>(&self, state: &mut H) {
self.borrow().hash(state)
}
}