cao_lang/vm/runtime/
cao_lang_table.rs

1use 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}