cao_lang/vm/runtime/
cao_lang_table.rs1use crate::{
2 alloc::AllocProxy,
3 collections::hash_map::{CaoHashMap, MapError},
4 prelude::*,
5 value::Value,
6};
7
8pub struct CaoLangTable {
9 map: CaoHashMap<Value, Value, AllocProxy>,
10 keys: Vec<Value>,
11 alloc: AllocProxy,
12}
13
14impl Clone for CaoLangTable {
15 fn clone(&self) -> Self {
16 Self::from_iter(self.iter().map(|(k, v)| (*k, *v)), self.alloc.clone()).unwrap()
17 }
18}
19
20impl std::fmt::Debug for CaoLangTable {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 f.debug_map()
23 .entries(self.keys.iter().map(|k| (k, self.map.get(k))))
24 .finish()
25 }
26}
27
28impl CaoLangTable {
29 pub fn with_capacity(size: usize, proxy: AllocProxy) -> Result<Self, MapError> {
30 let res = Self {
31 map: CaoHashMap::with_capacity_in(size, proxy.clone())?,
32 keys: Vec::default(),
33 alloc: proxy,
34 };
35 Ok(res)
36 }
37
38 pub fn len(&self) -> usize {
39 self.keys.len()
40 }
41
42 pub fn is_empty(&self) -> bool {
43 self.len() == 0
44 }
45
46 pub fn from_iter(
47 it: impl Iterator<Item = (Value, Value)>,
48 alloc: AllocProxy,
49 ) -> Result<Self, ExecutionErrorPayload> {
50 let mut result = Self::with_capacity(it.size_hint().0, alloc)
51 .map_err(|_err| ExecutionErrorPayload::OutOfMemory)?;
52
53 for (key, value) in it {
54 result.insert(key, value)?;
55 }
56
57 Ok(result)
58 }
59
60 pub fn insert(
61 &mut self,
62 key: impl Into<Value>,
63 value: impl Into<Value>,
64 ) -> Result<(), ExecutionErrorPayload> {
65 fn _insert(
66 this: &mut CaoLangTable,
67 key: Value,
68 value: Value,
69 ) -> Result<(), ExecutionErrorPayload> {
70 match this.map.get_mut(&key) {
71 Some(r) => {
72 *r = value;
73 }
74 None => {
75 this.map
76 .insert(key, value)
77 .map_err(|_| ExecutionErrorPayload::OutOfMemory)?;
78 this.keys.push(key);
79 }
80 }
81
82 Ok(())
83 }
84
85 _insert(self, key.into(), value.into())
86 }
87
88 pub fn remove(&mut self, key: Value) -> Result<(), ExecutionErrorPayload> {
89 self.keys.retain(|k| {
90 let retain = k != &key;
91 if !retain {
92 self.map.remove(k);
93 }
94 retain
95 });
96 Ok(())
97 }
98
99 pub fn append(&mut self, value: Value) -> Result<(), ExecutionErrorPayload> {
100 let mut index = self.keys.len() as i64;
101 while self.map.contains(&Value::Integer(index)) {
102 index += 1;
103 }
104 self.insert(Value::Integer(index), value)
105 }
106
107 pub fn pop(&mut self) -> Result<Value, ExecutionErrorPayload> {
108 match self.keys.pop() {
109 Some(key) => {
110 let res = self.get(&key).copied().unwrap_or(Value::Nil);
111 self.remove(key)?;
112 Ok(res)
113 }
114 None => Ok(Value::Nil),
115 }
116 }
117
118 pub fn nth_key(&self, i: usize) -> Value {
119 if i >= self.keys.len() {
120 return Value::Nil;
121 }
122 self.keys[i]
123 }
124
125 pub fn iter(&self) -> impl Iterator<Item = (&Value, &Value)> + '_ {
126 self.keys
127 .iter()
128 .filter_map(|k| self.map.get(k).map(|v| (k, v)))
129 }
130
131 pub fn keys(&self) -> &[Value] {
132 &self.keys
133 }
134
135 pub fn keys_mut(&mut self) -> &mut [Value] {
136 &mut self.keys
137 }
138}
139
140impl std::ops::Deref for CaoLangTable {
141 type Target = CaoHashMap<Value, Value, AllocProxy>;
142
143 fn deref(&self) -> &Self::Target {
144 &self.map
145 }
146}