From c9e27ffb9599a0b14519e2ba9332c5914b479fd0 Mon Sep 17 00:00:00 2001 From: Adam Chalmers Date: Mon, 4 Dec 2023 12:16:50 -0600 Subject: [PATCH] WIP --- src/wasm-lib/execution-plan/src/composite.rs | 31 +++++------------ src/wasm-lib/execution-plan/src/lib.rs | 35 +++++++++++++------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/wasm-lib/execution-plan/src/composite.rs b/src/wasm-lib/execution-plan/src/composite.rs index 745f3ab0f..94c830931 100644 --- a/src/wasm-lib/execution-plan/src/composite.rs +++ b/src/wasm-lib/execution-plan/src/composite.rs @@ -1,36 +1,23 @@ -use crate::{ExecutionError, Value}; +use crate::{ExecutionError, NumericValue, Value}; /// Types that can be written to or read from KCEP program memory, /// but require multiple values to store. /// They get laid out into multiple consecutive memory addresses. -pub trait Composite: Sized { - /// How many memory addresses are required to store this value? - const SIZE: usize; +pub trait Composite: Sized { /// Store the value in memory. - fn into_parts(self) -> Vec; + fn into_parts(self) -> [Value; SIZE]; /// Read the value from memory. - fn from_parts(values: Vec) -> Result; + fn from_parts(values: [Value; SIZE]) -> Result; } -impl Composite for kittycad::types::Point3D { - fn into_parts(self) -> Vec { +impl Composite<3> for kittycad::types::Point3D { + fn into_parts(self) -> [Value; 3] { let points = [self.x, self.y, self.z]; - points - .into_iter() - .map(|x| Value::NumericValue(crate::NumericValue::Float(x))) - .collect() + points.map(NumericValue::Float).map(Value::NumericValue) } - const SIZE: usize = 3; - - fn from_parts(values: Vec) -> Result { - let n = values.len(); - let Ok([x, y, z]): Result<[Value; 3], _> = values.try_into() else { - return Err(ExecutionError::MemoryWrongSize { - actual: n, - expected: Self::SIZE, - }); - }; + fn from_parts(values: [Value; 3]) -> Result { + let [x, y, z] = values; let x = x.try_into()?; let y = y.try_into()?; let z = z.try_into()?; diff --git a/src/wasm-lib/execution-plan/src/lib.rs b/src/wasm-lib/execution-plan/src/lib.rs index 6ba5c53cb..b3fd66dfc 100644 --- a/src/wasm-lib/execution-plan/src/lib.rs +++ b/src/wasm-lib/execution-plan/src/lib.rs @@ -48,7 +48,7 @@ impl Memory { /// Store a composite value (i.e. a value which takes up multiple addresses in memory). /// Store its parts in consecutive memory addresses starting at `start`. - pub fn set_composite(&mut self, composite_value: T, start: Address) { + pub fn set_composite, const N: usize>(&mut self, composite_value: T, start: Address) { let parts = composite_value.into_parts().into_iter(); for (value, addr) in parts.zip(start.0..) { self.0.insert(addr, value); @@ -57,17 +57,14 @@ impl Memory { /// Get a composite value (i.e. a value which takes up multiple addresses in memory). /// Its parts are stored in consecutive memory addresses starting at `start`. - pub fn get_composite(&self, start: Address) -> Result { - let addrs = start.0..start.0 + T::SIZE; - let values: Vec = addrs - .into_iter() - .map(|a| { - let addr = Address(a); - self.get(&addr) - .map(|x| x.to_owned()) - .ok_or(ExecutionError::MemoryEmpty { addr }) - }) - .collect::>()?; + pub fn get_composite, const N: usize>(&self, start: Address) -> Result { + let addrs: [Address; N] = core::array::from_fn(|i| Address(i + start.0)); + let values: [Value; N] = arr_res_to_res_array(addrs.map(|addr| { + self.get(&addr) + .map(|x| x.to_owned()) + .ok_or(ExecutionError::MemoryEmpty { addr }) + }))?; + T::from_parts(values) } } @@ -276,3 +273,17 @@ pub enum ExecutionError { #[error("Wrong size of memory trying to read value from KCEP program memory: got {actual} but wanted {expected}")] MemoryWrongSize { expected: usize, actual: usize }, } + +/// Take an array of result and return a result of array. +/// If all members of the array are Ok(T), returns Ok with an array of the T values. +/// If any member of the array was Err(E), return Err with the first E value. +fn arr_res_to_res_array(arr: [Result; N]) -> Result<[T; N], E> { + let mut out = core::array::from_fn(|_| None); + for (i, res) in arr.enumerate() { + out[i] = match res { + Ok(x) => x, + Err(e) => return Err(e), + }; + } + Ok(out.map(|opt| opt.unwrap())) +}