use crate::{
alloc::AllocProxy,
collections::hash_map::{CaoHashMap, MapError},
prelude::*,
value::Value,
};
pub struct CaoLangTable {
map: CaoHashMap<Value, Value, AllocProxy>,
keys: Vec<Value>,
alloc: AllocProxy,
}
impl Clone for CaoLangTable {
fn clone(&self) -> Self {
Self::from_iter(self.iter().map(|(k, v)| (*k, *v)), self.alloc.clone()).unwrap()
}
}
impl std::fmt::Debug for CaoLangTable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_map()
.entries(self.keys.iter().map(|k| (k, self.map.get(k))))
.finish()
}
}
impl CaoLangTable {
pub fn with_capacity(size: usize, proxy: AllocProxy) -> Result<Self, MapError> {
let res = Self {
map: CaoHashMap::with_capacity_in(size, proxy.clone())?,
keys: Vec::default(),
alloc: proxy,
};
Ok(res)
}
pub fn len(&self) -> usize {
self.keys.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn from_iter(
it: impl Iterator<Item = (Value, Value)>,
alloc: AllocProxy,
) -> Result<Self, ExecutionErrorPayload> {
let mut result = Self::with_capacity(it.size_hint().0, alloc)
.map_err(|_err| ExecutionErrorPayload::OutOfMemory)?;
for (key, value) in it {
result.insert(key, value)?;
}
Ok(result)
}
pub fn insert(
&mut self,
key: impl Into<Value>,
value: impl Into<Value>,
) -> Result<(), ExecutionErrorPayload> {
fn _insert(
this: &mut CaoLangTable,
key: Value,
value: Value,
) -> Result<(), ExecutionErrorPayload> {
match this.map.get_mut(&key) {
Some(r) => {
*r = value;
}
None => {
this.map
.insert(key, value)
.map_err(|_| ExecutionErrorPayload::OutOfMemory)?;
this.keys.push(key);
}
}
Ok(())
}
_insert(self, key.into(), value.into())
}
pub fn remove(&mut self, key: Value) -> Result<(), ExecutionErrorPayload> {
self.keys.retain(|k| {
let retain = k != &key;
if !retain {
self.map.remove(k);
}
retain
});
Ok(())
}
pub fn append(&mut self, value: Value) -> Result<(), ExecutionErrorPayload> {
let mut index = self.keys.len() as i64;
while self.map.contains(&Value::Integer(index)) {
index += 1;
}
self.insert(Value::Integer(index), value)
}
pub fn pop(&mut self) -> Result<Value, ExecutionErrorPayload> {
match self.keys.pop() {
Some(key) => {
let res = self.get(&key).copied().unwrap_or(Value::Nil);
self.remove(key)?;
Ok(res)
}
None => Ok(Value::Nil),
}
}
pub fn nth_key(&self, i: usize) -> Value {
if i >= self.keys.len() {
return Value::Nil;
}
self.keys[i]
}
pub fn iter(&self) -> impl Iterator<Item = (&Value, &Value)> + '_ {
self.keys
.iter()
.filter_map(|k| self.map.get(k).map(|v| (k, v)))
}
pub fn keys(&self) -> &[Value] {
&self.keys
}
pub fn keys_mut(&mut self) -> &mut [Value] {
&mut self.keys
}
}
impl std::ops::Deref for CaoLangTable {
type Target = CaoHashMap<Value, Value, AllocProxy>;
fn deref(&self) -> &Self::Target {
&self.map
}
}