use std::{
cmp::Ordering,
collections::{HashMap, BTreeMap},
hash::{Hash, Hasher},
ops::Deref,
};
use gc::{Gc, GcCell, GcCellRef, GcCellRefMut, Finalize, Trace};
use super::{IndexOutOfBounds, Value};
pub mod keys {
use super::Value;
thread_local! {
pub static FINISHED: Value = "finished".into();
pub static KEY: Value = "key".into();
pub static VALUE: Value = "value".into();
}
}
#[derive(Debug, Default, PartialEq, Eq)]
#[derive(Trace, Finalize)]
pub struct Dict(Gc<GcCell<HashMap<Value, Value>>>);
impl Dict {
pub fn new(dict: HashMap<Value, Value>) -> Self {
Self(Gc::new(GcCell::new(dict)))
}
pub fn copy(&self) -> Self {
Self(self.0.clone())
}
pub fn borrow(&self) -> GcCellRef<HashMap<Value, Value>> {
self.0.deref().borrow()
}
pub fn borrow_mut(&self) -> GcCellRefMut<HashMap<Value, Value>> {
self.0.deref().borrow_mut()
}
pub fn insert(&self, key: Value, value: Value) {
self.borrow_mut().insert(key, value);
}
pub fn get(&self, key: &Value) -> Result<Value, IndexOutOfBounds> {
self
.borrow()
.get(key)
.map(Value::copy)
.ok_or(IndexOutOfBounds)
}
pub fn contains(&self, key: &Value) -> bool {
self
.borrow()
.contains_key(key)
}
pub fn len(&self) -> i64 {
self.borrow().len() as i64
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl PartialOrd for Dict {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Dict {
fn cmp(&self, other: &Self) -> Ordering {
let _self = self.borrow();
let _self: BTreeMap<&Value, &Value> = _self.iter().collect();
let _other = other.borrow();
let _other: BTreeMap<&Value, &Value> = _other.iter().collect();
_self.cmp(&_other)
}
}
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for Dict {
fn hash<H: Hasher>(&self, state: &mut H) {
let _self = self.borrow();
let _self: BTreeMap<&Value, &Value> = _self.iter().collect();
_self.hash(state)
}
}