Compare commits

...

1 Commits

Author SHA1 Message Date
c9e27ffb95 WIP 2023-12-04 12:16:50 -06:00
2 changed files with 32 additions and 34 deletions

View File

@ -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, /// Types that can be written to or read from KCEP program memory,
/// but require multiple values to store. /// but require multiple values to store.
/// They get laid out into multiple consecutive memory addresses. /// They get laid out into multiple consecutive memory addresses.
pub trait Composite: Sized { pub trait Composite<const SIZE: usize>: Sized {
/// How many memory addresses are required to store this value?
const SIZE: usize;
/// Store the value in memory. /// Store the value in memory.
fn into_parts(self) -> Vec<Value>; fn into_parts(self) -> [Value; SIZE];
/// Read the value from memory. /// Read the value from memory.
fn from_parts(values: Vec<Value>) -> Result<Self, ExecutionError>; fn from_parts(values: [Value; SIZE]) -> Result<Self, ExecutionError>;
} }
impl Composite for kittycad::types::Point3D { impl Composite<3> for kittycad::types::Point3D {
fn into_parts(self) -> Vec<Value> { fn into_parts(self) -> [Value; 3] {
let points = [self.x, self.y, self.z]; let points = [self.x, self.y, self.z];
points points.map(NumericValue::Float).map(Value::NumericValue)
.into_iter()
.map(|x| Value::NumericValue(crate::NumericValue::Float(x)))
.collect()
} }
const SIZE: usize = 3; fn from_parts(values: [Value; 3]) -> Result<Self, ExecutionError> {
let [x, y, z] = values;
fn from_parts(values: Vec<Value>) -> Result<Self, ExecutionError> {
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,
});
};
let x = x.try_into()?; let x = x.try_into()?;
let y = y.try_into()?; let y = y.try_into()?;
let z = z.try_into()?; let z = z.try_into()?;

View File

@ -48,7 +48,7 @@ impl Memory {
/// Store a composite value (i.e. a value which takes up multiple addresses in 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`. /// Store its parts in consecutive memory addresses starting at `start`.
pub fn set_composite<T: Composite>(&mut self, composite_value: T, start: Address) { pub fn set_composite<T: Composite<{ N }>, const N: usize>(&mut self, composite_value: T, start: Address) {
let parts = composite_value.into_parts().into_iter(); let parts = composite_value.into_parts().into_iter();
for (value, addr) in parts.zip(start.0..) { for (value, addr) in parts.zip(start.0..) {
self.0.insert(addr, value); 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). /// 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`. /// Its parts are stored in consecutive memory addresses starting at `start`.
pub fn get_composite<T: Composite>(&self, start: Address) -> Result<T, ExecutionError> { pub fn get_composite<T: Composite<{ N }>, const N: usize>(&self, start: Address) -> Result<T, ExecutionError> {
let addrs = start.0..start.0 + T::SIZE; let addrs: [Address; N] = core::array::from_fn(|i| Address(i + start.0));
let values: Vec<Value> = addrs let values: [Value; N] = arr_res_to_res_array(addrs.map(|addr| {
.into_iter() self.get(&addr)
.map(|a| { .map(|x| x.to_owned())
let addr = Address(a); .ok_or(ExecutionError::MemoryEmpty { addr })
self.get(&addr) }))?;
.map(|x| x.to_owned())
.ok_or(ExecutionError::MemoryEmpty { addr })
})
.collect::<Result<_, _>>()?;
T::from_parts(values) 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}")] #[error("Wrong size of memory trying to read value from KCEP program memory: got {actual} but wanted {expected}")]
MemoryWrongSize { expected: usize, actual: usize }, 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<T, E, const N: usize>(arr: [Result<T, E>; 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()))
}