1use std::cmp::Ordering;
2
3use kittycad_execution_plan_traits::{
4 events::{Event, EventWriter},
5 InMemory, ListHeader, MemoryError, NumericPrimitive, ObjectHeader, Primitive, ReadMemory, Value,
6};
7
8use crate::{Address, ExecutionError};
9
10pub struct StaticMemoryInitializer {
12 memory: Memory,
13 last: Address,
14}
15
16impl Default for StaticMemoryInitializer {
17 fn default() -> Self {
18 Self {
19 memory: Default::default(),
20 last: Address::ZERO,
21 }
22 }
23}
24
25impl StaticMemoryInitializer {
26 pub fn finish(self) -> Memory {
29 self.memory
30 }
31
32 pub fn push<T: Value>(&mut self, val: T) -> Address {
35 let addr_of_value = self.last;
36 let len = self.memory.set_composite(self.last, val);
37 self.last = self.last.offset(len);
38 addr_of_value
39 }
40}
41
42#[derive(Debug, Clone)]
44#[cfg_attr(test, derive(PartialEq))]
45pub struct Memory {
46 pub addresses: Vec<Option<Primitive>>,
48 pub stack: Stack<Vec<Primitive>>,
50 pub sketch_groups: Vec<crate::sketch_types::SketchGroup>,
52}
53
54impl Default for Memory {
55 fn default() -> Self {
56 Self {
57 addresses: vec![None; 1024],
58 stack: Stack::default(),
59 sketch_groups: Vec::new(),
60 }
61 }
62}
63
64impl kittycad_execution_plan_traits::ReadMemory for Memory {
65 fn get(&self, address: &Address) -> Option<&Primitive> {
67 self.addresses[inner(*address)].as_ref()
68 }
69
70 fn get_composite<T: Value>(&self, start: Address) -> Result<(T, usize), MemoryError> {
73 let mut values = self.addresses.iter().skip(inner(start)).cloned();
74 T::from_parts(&mut values)
75 }
76
77 fn stack_pop(&mut self) -> Result<Vec<Primitive>, MemoryError> {
78 self.stack.pop()
79 }
80
81 fn stack_peek(&self) -> std::result::Result<Vec<Primitive>, MemoryError> {
82 self.stack.peek().cloned()
83 }
84}
85
86impl Memory {
87 pub fn set(&mut self, address: Address, value: Primitive) {
89 let addr = address - Address::ZERO;
90 while addr > self.addresses.len() {
92 self.addresses.extend(vec![None; self.addresses.len()]);
93 }
94 self.addresses[addr] = Some(value);
95 }
96
97 pub fn set_composite<T: Value>(&mut self, start: Address, composite_value: T) -> usize {
101 let parts = composite_value.into_parts().into_iter();
102
103 let mut total_addrs = 0;
104 for (value, addr) in parts.zip(start - Address::ZERO..) {
105 self.addresses[addr] = Some(value);
106 total_addrs += 1;
107 }
108 total_addrs
109 }
110
111 pub fn iter(&self) -> impl Iterator<Item = (usize, &Option<Primitive>)> {
113 self.addresses.iter().enumerate()
114 }
115
116 pub fn get_primitive<T>(&self, addr: &Address) -> Result<T, ExecutionError>
118 where
119 T: TryFrom<Primitive, Error = MemoryError>,
120 {
121 let primitive = self
122 .get(addr)
123 .cloned()
124 .ok_or(ExecutionError::MemoryEmpty { addr: *addr })?;
125 primitive.try_into().map_err(ExecutionError::MemoryError)
126 }
127
128 pub fn get_size(&self, addr: &Address) -> Result<usize, ExecutionError> {
131 let primitive = self.get(addr).ok_or(ExecutionError::MemoryEmpty { addr: *addr })?;
132 let size = match primitive {
133 Primitive::NumericValue(NumericPrimitive::UInteger(size)) => *size,
134 Primitive::ListHeader(ListHeader { count: _, size }) => *size,
135 Primitive::ObjectHeader(ObjectHeader { properties: _, size }) => *size,
136 other => {
137 return Err(ExecutionError::MemoryError(MemoryError::MemoryWrongType {
138 expected: "ObjectHeader, ListHeader, or usize",
139 actual: format!("{other:?}"),
140 }))
141 }
142 };
143 Ok(size)
144 }
145
146 pub fn get_slice(&self, start: Address, len: usize) -> Result<Vec<Primitive>, ExecutionError> {
148 let slice = &self.addresses[inner(start)..inner(start) + len];
149 let x = slice
150 .iter()
151 .cloned()
152 .enumerate()
153 .map(|(addr, prim)| {
154 prim.ok_or(ExecutionError::MemoryEmpty {
155 addr: Address::ZERO + addr,
156 })
157 })
158 .collect::<Result<Vec<_>, _>>()?;
159 Ok(x)
160 }
161
162 pub fn get_in_memory<T: Value>(
164 &mut self,
165 source: InMemory,
166 field_name: &'static str,
167 events: &mut EventWriter,
168 ) -> Result<(T, usize), MemoryError> {
169 match source {
170 InMemory::Address(a) => {
171 events.push(Event {
172 text: format!("reading '{field_name}'"),
173 severity: kittycad_execution_plan_traits::events::Severity::Debug,
174 related_addresses: vec![a],
175 });
176 self.get_composite(a)
177 }
178 InMemory::StackPop => {
179 events.push(Event {
180 text: format!("popping '{field_name}' from stack"),
181 severity: kittycad_execution_plan_traits::events::Severity::Debug,
182 related_addresses: Default::default(),
183 });
184 let data = self.stack_pop()?;
185 let mut data_parts = data.iter().cloned().map(Some);
186 T::from_parts(&mut data_parts)
187 }
188 InMemory::StackPeek => {
189 events.push(Event {
190 text: format!("peeking '{field_name}' from stack"),
191 severity: kittycad_execution_plan_traits::events::Severity::Debug,
192 related_addresses: Default::default(),
193 });
194 let data = self.stack_peek()?;
195 let mut data_parts = data.iter().cloned().map(Some);
196 T::from_parts(&mut data_parts)
197 }
198 }
199 }
200
201 #[must_use]
203 pub fn debug_table_stack(&self) -> String {
204 #[derive(tabled::Tabled)]
205 struct StackLevel {
206 depth: usize,
207 value: String,
208 }
209
210 let table_data: Vec<_> = self
211 .stack
212 .inner
213 .iter()
214 .enumerate()
215 .map(|(depth, slice)| StackLevel {
216 depth,
217 value: format!("{slice:?}"),
218 })
219 .collect();
220 tabled::Table::new(table_data)
221 .with(tabled::settings::Style::sharp())
222 .to_string()
223 }
224
225 #[must_use]
227 pub fn debug_table(&self, up_to: Option<usize>) -> String {
228 #[derive(tabled::Tabled)]
229 struct MemoryAddr {
230 addr: String,
231 val_type: &'static str,
232 value: String,
233 }
234 let table_data: Vec<_> = self
235 .iter()
236 .filter_map(|(i, val)| {
237 if let Some(val) = val {
238 let (val_type, value) = pretty_print(val);
239 Some(MemoryAddr {
240 addr: i.to_string(),
241 val_type,
242 value,
243 })
244 } else if let Some(up_to) = up_to {
245 if i <= up_to {
246 Some(MemoryAddr {
247 addr: i.to_string(),
248 val_type: "",
249 value: "".to_owned(),
250 })
251 } else {
252 None
253 }
254 } else {
255 None
256 }
257 })
258 .collect();
259 tabled::Table::new(table_data)
260 .with(tabled::settings::Style::sharp())
261 .to_string()
262 }
263
264 #[must_use]
267 pub fn last_nonempty_address(&self) -> Option<usize> {
268 self.iter()
269 .filter_map(|(i, v)| if v.is_some() { Some(i) } else { None })
270 .last()
271 }
272
273 pub fn next_empty_cell(&self) -> Option<usize> {
276 self.iter().position(|(_, v)| v.is_none())
277 }
278
279 pub(crate) fn sketch_group_set(
280 &mut self,
281 sketch_group: crate::sketch_types::SketchGroup,
282 destination: usize,
283 ) -> Result<(), ExecutionError> {
284 match destination.cmp(&self.sketch_groups.len()) {
285 Ordering::Less => {
286 self.sketch_groups[destination] = sketch_group;
287 }
288 Ordering::Equal => {
289 self.sketch_groups.push(sketch_group);
290 }
291 Ordering::Greater => {
292 return Err(ExecutionError::SketchGroupNoGaps {
293 destination,
294 len: self.sketch_groups.len(),
295 });
296 }
297 }
298 Ok(())
299 }
300}
301
302fn pretty_print(p: &Primitive) -> (&'static str, String) {
303 match p {
304 Primitive::String(v) => ("String", v.to_owned()),
305 Primitive::NumericValue(NumericPrimitive::Float(v)) => ("Float", v.to_string()),
306 Primitive::NumericValue(NumericPrimitive::UInteger(v)) => ("Uint", v.to_string()),
307 Primitive::NumericValue(NumericPrimitive::Integer(v)) => ("Int", v.to_string()),
308 Primitive::Uuid(v) => ("Uuid", v.to_string()),
309 Primitive::Bytes(_) => ("Bytes", String::new()),
310 Primitive::Bool(v) => ("Bool", v.to_string()),
311 Primitive::ListHeader(ListHeader { count, size }) => {
312 ("List header", format!("{count} elements, {size} primitives"))
313 }
314 Primitive::ObjectHeader(ObjectHeader { properties, size }) => (
315 "Object header",
316 format!("keys {}, {size} primitives", properties.clone().join(",")),
317 ),
318 Primitive::Nil => ("Nil", String::new()),
319 Primitive::Address(a) => ("Address", a.to_string()),
320 }
321}
322
323fn inner(a: Address) -> usize {
324 a - Address::ZERO
325}
326
327#[derive(Debug, Eq, PartialEq, Default, Clone)]
329pub struct Stack<T> {
330 inner: Vec<T>,
331}
332
333impl<T> Stack<T> {
334 pub fn push(&mut self, t: T) {
336 self.inner.push(t);
337 }
338 pub fn pop(&mut self) -> Result<T, MemoryError> {
340 self.inner.pop().ok_or(MemoryError::StackEmpty)
341 }
342 pub fn peek(&self) -> Result<&T, MemoryError> {
344 self.inner.last().ok_or(MemoryError::StackEmpty)
345 }
346 pub fn is_empty(&self) -> bool {
348 self.inner.is_empty()
349 }
350 pub fn iter(&self) -> impl Iterator<Item = &T> {
352 self.inner.iter().rev()
353 }
354 pub fn len(&self) -> usize {
356 self.inner.len()
357 }
358}
359
360impl<T> Stack<Vec<T>> {
361 pub fn extend(&mut self, data: Vec<T>) -> Result<(), MemoryError> {
363 let mut start = self.pop()?;
364 start.extend(data);
365 self.push(start);
366 Ok(())
367 }
368}
369
370impl Stack<Vec<Primitive>> {
371 pub fn pop_single(&mut self) -> Result<Primitive, ExecutionError> {
374 let mut slice = self.pop()?;
375 let prim = slice.pop().ok_or(MemoryError::StackNotPrimitive { actual_length: 0 })?;
376 if !slice.is_empty() {
377 return Err(ExecutionError::MemoryError(MemoryError::StackNotPrimitive {
378 actual_length: slice.len() + 1,
379 }));
380 }
381 Ok(prim)
382 }
383}