Compare commits
1 Commits
v0.21.0
...
achalmers/
Author | SHA1 | Date | |
---|---|---|---|
36a5461de5 |
@ -1,36 +1,24 @@
|
|||||||
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];
|
[self.x, self.y, self.z]
|
||||||
points
|
.map(NumericValue::Float)
|
||||||
.into_iter()
|
.map(Value::NumericValue)
|
||||||
.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()?;
|
||||||
|
@ -6,9 +6,10 @@
|
|||||||
//! You can think of it as a domain-specific language for making KittyCAD API calls and using
|
//! You can think of it as a domain-specific language for making KittyCAD API calls and using
|
||||||
//! the results to make other API calls.
|
//! the results to make other API calls.
|
||||||
|
|
||||||
|
use std::{collections::HashMap, fmt};
|
||||||
|
|
||||||
use composite::Composite;
|
use composite::Composite;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, fmt};
|
|
||||||
|
|
||||||
mod composite;
|
mod composite;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -48,7 +49,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 +58,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,6 +271,18 @@ pub enum ExecutionError {
|
|||||||
CannotApplyOperation { op: Operation, operands: Vec<Value> },
|
CannotApplyOperation { op: Operation, operands: Vec<Value> },
|
||||||
#[error("Tried to read a '{expected}' from KCEP program memory, found an '{actual}' instead")]
|
#[error("Tried to read a '{expected}' from KCEP program memory, found an '{actual}' instead")]
|
||||||
MemoryWrongType { expected: &'static str, actual: String },
|
MemoryWrongType { expected: &'static str, actual: String },
|
||||||
#[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<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.into_iter().enumerate() {
|
||||||
|
out[i] = match res {
|
||||||
|
Ok(x) => Some(x),
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(out.map(|opt| opt.unwrap()))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user