1use crate::list::List;
2use crate::{any::Any, k::K};
3use crate::{k_type::MIXED_LIST, kapi, type_traits::KObject};
4use crate::{
5 k_type::{KTypeCode, DICT},
6 kbox::KBox,
7 type_traits::KTyped,
8};
9use std::{mem, ops::Index};
10
11#[repr(transparent)]
13pub struct Dictionary {
14 k: K,
15}
16
17impl Dictionary {
18 fn key_list_mut(&mut self) -> &mut KBox<List<Any>> {
19 unsafe { &mut *(&mut self.k.union.dict.k as *mut _ as *mut KBox<List<Any>>) }
20 }
21
22 fn value_list_mut(&mut self) -> &mut KBox<List<Any>> {
23 unsafe { &mut *(&mut self.k.union.dict.v as *mut _ as *mut KBox<List<Any>>) }
24 }
25
26 fn key_list(&self) -> &KBox<List<Any>> {
27 unsafe { &*(&self.k.union.dict.k as *const _ as *const KBox<List<Any>>) }
28 }
29
30 fn value_list(&self) -> &KBox<List<Any>> {
31 unsafe { &*(&self.k.union.dict.v as *const _ as *const KBox<List<Any>>) }
32 }
33
34 #[inline]
36 pub fn len(&self) -> usize {
37 self.key_list().len()
38 }
39
40 #[inline]
42 pub fn is_empty(&self) -> bool {
43 self.len() == 0
44 }
45
46 #[inline]
48 pub fn keys(&self) -> &[KBox<Any>] {
49 &self.key_list()[..]
50 }
51
52 #[inline]
54 pub fn values(&self) -> &[KBox<Any>] {
55 &self.value_list()[..]
56 }
57
58 #[inline]
61 pub fn insert(&mut self, key: impl Into<KBox<Any>>, value: impl Into<KBox<Any>>) {
62 self.key_list_mut().push(key.into());
63 self.value_list_mut().push(value.into());
64 }
65
66 #[inline]
68 pub fn get<T: Into<KBox<Any>>>(&self, key: T) -> Option<&KBox<Any>> {
69 let key = key.into();
70 let index = self
71 .keys()
72 .iter()
73 .enumerate()
74 .find(|(_, k2)| unsafe { *k2.k.as_ptr() == *key.k.as_ptr() })
75 .map(|(i, _)| i)?;
76 self.values().get(index)
77 }
78
79 #[inline]
81 pub fn iter(&self) -> impl Iterator<Item = (&KBox<Any>, &KBox<Any>)> {
82 self.keys().iter().zip(self.values().iter())
83 }
84}
85
86impl<T> Index<T> for Dictionary
87where
88 for<'a> T: Into<KBox<Any>>,
89{
90 type Output = Any;
91
92 fn index(&self, index: T) -> &Self::Output {
93 self.get(index).unwrap()
94 }
95}
96
97impl KObject for Dictionary {
98 #[inline]
99 fn k_ptr(&self) -> *const K {
100 &self.k
101 }
102
103 #[inline]
104 fn k_ptr_mut(&mut self) -> *mut K {
105 &mut self.k
106 }
107}
108
109impl KTyped for Dictionary {
110 const K_TYPE: KTypeCode = DICT;
111}
112
113impl KBox<Dictionary> {
114 pub fn new_dict() -> Self {
116 unsafe {
117 let keys = kapi::ktn(MIXED_LIST.into(), 0) as *mut K;
118 let values = kapi::ktn(MIXED_LIST.into(), 0) as *mut K;
119 mem::transmute(kapi::xD(keys, values))
120 }
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use crate::symbol;
127
128 use super::*;
129
130 #[test]
131 fn insert_appends_items_to_dictionary() {
132 let mut dict = KBox::new_dict();
133 dict.insert(symbol("Hello"), symbol("World"));
134
135 assert_eq!(dict.len(), 1);
136 }
137
138 #[test]
139 fn get_retrieves_items_by_key() {
140 let mut dict = KBox::new_dict();
141 dict.insert(symbol("Hello"), symbol("World"));
142
143 let val = dict.get(symbol("Hello")).unwrap();
144
145 assert_eq!(*val.as_ref(), *KBox::<Any>::from(symbol("World")).as_ref());
146 }
147}