use crate::list::List;
use crate::{any::Any, k::K};
use crate::{k_type::MIXED_LIST, kapi, type_traits::KObject};
use crate::{
k_type::{KTypeCode, DICT},
kbox::KBox,
type_traits::KTyped,
};
use std::{mem, ops::Index};
#[repr(transparent)]
pub struct Dictionary {
k: K,
}
impl Dictionary {
fn key_list_mut(&mut self) -> &mut KBox<List<Any>> {
unsafe { &mut *(&mut self.k.union.dict.k as *mut _ as *mut KBox<List<Any>>) }
}
fn value_list_mut(&mut self) -> &mut KBox<List<Any>> {
unsafe { &mut *(&mut self.k.union.dict.v as *mut _ as *mut KBox<List<Any>>) }
}
fn key_list(&self) -> &KBox<List<Any>> {
unsafe { &*(&self.k.union.dict.k as *const _ as *const KBox<List<Any>>) }
}
fn value_list(&self) -> &KBox<List<Any>> {
unsafe { &*(&self.k.union.dict.v as *const _ as *const KBox<List<Any>>) }
}
#[inline]
pub fn len(&self) -> usize {
self.key_list().len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn keys(&self) -> &[KBox<Any>] {
&self.key_list()[..]
}
#[inline]
pub fn values(&self) -> &[KBox<Any>] {
&self.value_list()[..]
}
#[inline]
pub fn insert(&mut self, key: impl Into<KBox<Any>>, value: impl Into<KBox<Any>>) {
self.key_list_mut().push(key.into());
self.value_list_mut().push(value.into());
}
#[inline]
pub fn get<T: Into<KBox<Any>>>(&self, key: T) -> Option<&KBox<Any>> {
let key = key.into();
let index = self
.keys()
.iter()
.enumerate()
.find(|(_, k2)| unsafe { *k2.k.as_ptr() == *key.k.as_ptr() })
.map(|(i, _)| i)?;
self.values().get(index)
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (&KBox<Any>, &KBox<Any>)> {
self.keys().iter().zip(self.values().iter())
}
}
impl<T> Index<T> for Dictionary
where
for<'a> T: Into<KBox<Any>>,
{
type Output = Any;
fn index(&self, index: T) -> &Self::Output {
self.get(index).unwrap()
}
}
impl KObject for Dictionary {
#[inline]
fn k_ptr(&self) -> *const K {
&self.k
}
#[inline]
fn k_ptr_mut(&mut self) -> *mut K {
&mut self.k
}
}
impl KTyped for Dictionary {
const K_TYPE: KTypeCode = DICT;
}
impl KBox<Dictionary> {
pub fn new_dict() -> Self {
unsafe {
let keys = kapi::ktn(MIXED_LIST.into(), 0) as *mut K;
let values = kapi::ktn(MIXED_LIST.into(), 0) as *mut K;
mem::transmute(kapi::xD(keys, values))
}
}
}
#[cfg(test)]
mod tests {
use crate::symbol;
use super::*;
#[test]
fn insert_appends_items_to_dictionary() {
let mut dict = KBox::new_dict();
dict.insert(symbol("Hello"), symbol("World"));
assert_eq!(dict.len(), 1);
}
#[test]
fn get_retrieves_items_by_key() {
let mut dict = KBox::new_dict();
dict.insert(symbol("Hello"), symbol("World"));
let val = dict.get(symbol("Hello")).unwrap();
assert_eq!(*val.as_ref(), *KBox::<Any>::from(symbol("World")).as_ref());
}
}