Rename Value to Primitive and Composite to Value

This commit is contained in:
Adam Chalmers
2023-12-12 15:16:33 -06:00
parent e456bde16c
commit 99083db731
6 changed files with 143 additions and 137 deletions

View File

@ -1,4 +1,4 @@
use crate::value::{NumericValue, Value};
use crate::primitive::{NumericPrimitive, Primitive};
use crate::{ExecutionError, Memory, Operand, Operation};
use serde::{Deserialize, Serialize};
@ -20,14 +20,20 @@ macro_rules! arithmetic_body {
$arith.operand1.eval(&$mem)?.clone(),
) {
// If both operands are numeric, then do the arithmetic operation.
(Value::NumericValue(x), Value::NumericValue(y)) => {
(Primitive::NumericValue(x), Primitive::NumericValue(y)) => {
let num = match (x, y) {
(NumericValue::Integer(x), NumericValue::Integer(y)) => NumericValue::Integer(x.$method(y)),
(NumericValue::Integer(x), NumericValue::Float(y)) => NumericValue::Float((x as f64).$method(y)),
(NumericValue::Float(x), NumericValue::Integer(y)) => NumericValue::Float(x.$method(y as f64)),
(NumericValue::Float(x), NumericValue::Float(y)) => NumericValue::Float(x.$method(y)),
(NumericPrimitive::Integer(x), NumericPrimitive::Integer(y)) => {
NumericPrimitive::Integer(x.$method(y))
}
(NumericPrimitive::Integer(x), NumericPrimitive::Float(y)) => {
NumericPrimitive::Float((x as f64).$method(y))
}
(NumericPrimitive::Float(x), NumericPrimitive::Integer(y)) => {
NumericPrimitive::Float(x.$method(y as f64))
}
(NumericPrimitive::Float(x), NumericPrimitive::Float(y)) => NumericPrimitive::Float(x.$method(y)),
};
Ok(Value::NumericValue(num))
Ok(Primitive::NumericValue(num))
}
// This operation can only be done on numeric types.
_ => Err(ExecutionError::CannotApplyOperation {
@ -43,7 +49,7 @@ macro_rules! arithmetic_body {
impl Arithmetic {
/// Calculate the the arithmetic equation.
/// May read values from the given memory.
pub fn calculate(self, mem: &Memory) -> Result<Value, ExecutionError> {
pub fn calculate(self, mem: &Memory) -> Result<Primitive, ExecutionError> {
use std::ops::{Add, Div, Mul, Sub};
match self.operation {
Operation::Add => {

View File

@ -1,13 +0,0 @@
use crate::{ExecutionError, Value};
mod impls;
/// 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 {
/// Store the value in memory.
fn into_parts(self) -> Vec<Value>;
/// Read the value from memory.
fn from_parts(values: &[Option<Value>]) -> Result<Self, ExecutionError>;
}

View File

@ -7,13 +7,13 @@
//! the results to make other API calls.
use self::arithmetic::Arithmetic;
use self::value::Value;
use composite::Composite;
use self::primitive::Primitive;
use serde::{Deserialize, Serialize};
use std::fmt;
use value::Value;
mod arithmetic;
mod composite;
mod primitive;
#[cfg(test)]
mod tests;
mod value;
@ -21,7 +21,7 @@ mod value;
/// KCEP's program memory. A flat, linear list of values.
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct Memory(Vec<Option<Value>>);
pub struct Memory(Vec<Option<Primitive>>);
impl Default for Memory {
fn default() -> Self {
@ -47,12 +47,12 @@ impl From<usize> for Address {
impl Memory {
/// Get a value from KCEP's program memory.
pub fn get(&self, Address(addr): &Address) -> Option<&Value> {
pub fn get(&self, Address(addr): &Address) -> Option<&Primitive> {
self.0[*addr].as_ref()
}
/// Store a value in KCEP's program memory.
pub fn set(&mut self, Address(addr): Address, value: Value) {
pub fn set(&mut self, Address(addr): Address, value: Primitive) {
// If isn't big enough for this value, double the size of memory until it is.
while addr > self.0.len() {
self.0.extend(vec![None; self.0.len()]);
@ -60,18 +60,18 @@ impl Memory {
self.0[addr] = Some(value);
}
/// Store a composite value (i.e. a value which takes up multiple addresses in memory).
/// Store a value 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<T: Composite>(&mut self, composite_value: T, start: Address) {
pub fn set_composite<T: Value>(&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[addr] = Some(value);
}
}
/// Get a composite value (i.e. a value which takes up multiple addresses in memory).
/// Get a value 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<T: Composite>(&self, start: Address) -> Result<T, ExecutionError> {
pub fn get_composite<T: Value>(&self, start: Address) -> Result<T, ExecutionError> {
let values = &self.0[start.0..];
T::from_parts(values)
}
@ -83,7 +83,7 @@ pub enum Instruction {
/// Call the KittyCAD API.
ApiRequest {
/// Which ModelingCmd to call.
/// It's a composite value starting at the given address.
/// It's a value value starting at the given address.
endpoint: Address,
/// Which address should the response be stored in?
store_response: Option<usize>,
@ -95,7 +95,7 @@ pub enum Instruction {
/// Which memory address to set.
address: Address,
/// What value to set the memory address to.
value: Value,
value: Primitive,
},
/// Perform arithmetic on values in memory.
Arithmetic {
@ -130,13 +130,13 @@ impl fmt::Display for Operation {
/// Argument to an operation.
#[derive(Deserialize, Serialize)]
pub enum Operand {
Literal(Value),
Literal(Primitive),
Reference(Address),
}
impl Operand {
/// Evaluate the operand, getting its value.
fn eval(&self, mem: &Memory) -> Result<Value, ExecutionError> {
fn eval(&self, mem: &Memory) -> Result<Primitive, ExecutionError> {
match self {
Operand::Literal(v) => Ok(v.to_owned()),
Operand::Reference(addr) => match mem.get(addr) {
@ -173,7 +173,7 @@ pub enum ExecutionError {
#[error("Memory address {addr} was not set")]
MemoryEmpty { addr: Address },
#[error("Cannot apply operation {op} to operands {operands:?}")]
CannotApplyOperation { op: Operation, operands: Vec<Value> },
CannotApplyOperation { op: Operation, operands: Vec<Primitive> },
#[error("Tried to read a '{expected}' from KCEP program memory, found an '{actual}' instead")]
MemoryWrongType { expected: &'static str, actual: String },
#[error("Wanted {expected} values but did not get enough")]

View File

@ -0,0 +1,87 @@
use crate::ExecutionError;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// A value stored in KCEP program memory.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum Primitive {
String(String),
NumericValue(NumericPrimitive),
Uuid(Uuid),
}
impl From<Uuid> for Primitive {
fn from(u: Uuid) -> Self {
Self::Uuid(u)
}
}
impl From<String> for Primitive {
fn from(value: String) -> Self {
Self::String(value)
}
}
impl From<f64> for Primitive {
fn from(value: f64) -> Self {
Self::NumericValue(NumericPrimitive::Float(value))
}
}
impl TryFrom<Primitive> for String {
type Error = ExecutionError;
fn try_from(value: Primitive) -> Result<Self, Self::Error> {
if let Primitive::String(s) = value {
Ok(s)
} else {
Err(ExecutionError::MemoryWrongType {
expected: "string",
actual: format!("{value:?}"),
})
}
}
}
impl TryFrom<Primitive> for Uuid {
type Error = ExecutionError;
fn try_from(value: Primitive) -> Result<Self, Self::Error> {
if let Primitive::Uuid(u) = value {
Ok(u)
} else {
Err(ExecutionError::MemoryWrongType {
expected: "uuid",
actual: format!("{value:?}"),
})
}
}
}
impl TryFrom<Primitive> for f64 {
type Error = ExecutionError;
fn try_from(value: Primitive) -> Result<Self, Self::Error> {
if let Primitive::NumericValue(NumericPrimitive::Float(x)) = value {
Ok(x)
} else {
Err(ExecutionError::MemoryWrongType {
expected: "float",
actual: format!("{value:?}"),
})
}
}
}
#[cfg(test)]
impl From<usize> for Primitive {
fn from(value: usize) -> Self {
Self::NumericValue(NumericPrimitive::Integer(value))
}
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum NumericPrimitive {
Integer(usize),
Float(f64),
}

View File

@ -1,87 +1,13 @@
use crate::ExecutionError;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::{ExecutionError, Primitive};
/// A value stored in KCEP program memory.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum Value {
String(String),
NumericValue(NumericValue),
Uuid(Uuid),
}
impl From<Uuid> for Value {
fn from(u: Uuid) -> Self {
Self::Uuid(u)
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Self::String(value)
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Self::NumericValue(NumericValue::Float(value))
}
}
impl TryFrom<Value> for String {
type Error = ExecutionError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
if let Value::String(s) = value {
Ok(s)
} else {
Err(ExecutionError::MemoryWrongType {
expected: "string",
actual: format!("{value:?}"),
})
}
}
}
impl TryFrom<Value> for Uuid {
type Error = ExecutionError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
if let Value::Uuid(u) = value {
Ok(u)
} else {
Err(ExecutionError::MemoryWrongType {
expected: "uuid",
actual: format!("{value:?}"),
})
}
}
}
impl TryFrom<Value> for f64 {
type Error = ExecutionError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
if let Value::NumericValue(NumericValue::Float(x)) = value {
Ok(x)
} else {
Err(ExecutionError::MemoryWrongType {
expected: "float",
actual: format!("{value:?}"),
})
}
}
}
#[cfg(test)]
impl From<usize> for Value {
fn from(value: usize) -> Self {
Self::NumericValue(NumericValue::Integer(value))
}
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum NumericValue {
Integer(usize),
Float(f64),
mod impls;
/// Types that can be written to or read from KCEP program memory.
/// If they require multiple memory addresses, they will be laid out
/// into multiple consecutive memory addresses.
pub trait Value: Sized {
/// Store the value in memory.
fn into_parts(self) -> Vec<Primitive>;
/// Read the value from memory.
fn from_parts(values: &[Option<Primitive>]) -> Result<Self, ExecutionError>;
}

View File

@ -1,21 +1,21 @@
use kittycad_modeling_cmds::{id::ModelingCmdId, shared::Point3d, MovePathPen};
use uuid::Uuid;
use crate::{Address, ExecutionError, Value};
use crate::{Address, ExecutionError, Primitive};
use super::Composite;
use super::Value;
impl<T> Composite for kittycad_modeling_cmds::shared::Point3d<T>
impl<T> Value for kittycad_modeling_cmds::shared::Point3d<T>
where
Value: From<T>,
T: TryFrom<Value, Error = ExecutionError>,
Primitive: From<T>,
T: TryFrom<Primitive, Error = ExecutionError>,
{
fn into_parts(self) -> Vec<Value> {
fn into_parts(self) -> Vec<Primitive> {
let points = [self.x, self.y, self.z];
points.into_iter().map(|component| component.into()).collect()
}
fn from_parts(values: &[Option<Value>]) -> Result<Self, ExecutionError> {
fn from_parts(values: &[Option<Primitive>]) -> Result<Self, ExecutionError> {
let err = ExecutionError::MemoryWrongSize { expected: 3 };
let [x, y, z] = [0, 1, 2].map(|n| values.get(n).ok_or(err.clone()));
let x = x?.to_owned().ok_or(err.clone())?.try_into()?;
@ -28,17 +28,17 @@ where
const START_PATH: &str = "StartPath";
const MOVE_PATH_PEN: &str = "MovePathPen";
impl Composite for MovePathPen {
fn into_parts(self) -> Vec<Value> {
impl Value for MovePathPen {
fn into_parts(self) -> Vec<Primitive> {
let MovePathPen { path, to } = self;
let to = to.into_parts();
let mut vals = Vec::with_capacity(1 + to.len());
vals.push(Value::Uuid(path.into()));
vals.push(Primitive::Uuid(path.into()));
vals.extend(to);
vals
}
fn from_parts(values: &[Option<Value>]) -> Result<Self, ExecutionError> {
fn from_parts(values: &[Option<Primitive>]) -> Result<Self, ExecutionError> {
let path = get_some(values, 0)?;
let path = Uuid::try_from(path)?;
let path = ModelingCmdId::from(path);
@ -51,14 +51,14 @@ impl Composite for MovePathPen {
/// Memory layout for modeling commands:
/// Field 0 is the command's name.
/// Fields 1 onwards are the command's fields.
impl Composite for kittycad_modeling_cmds::ModelingCmd {
fn into_parts(self) -> Vec<Value> {
impl Value for kittycad_modeling_cmds::ModelingCmd {
fn into_parts(self) -> Vec<Primitive> {
let (endpoint_name, params) = match self {
kittycad_modeling_cmds::ModelingCmd::StartPath => (START_PATH, vec![]),
kittycad_modeling_cmds::ModelingCmd::MovePathPen(MovePathPen { path, to }) => {
let to = to.into_parts();
let mut vals = Vec::with_capacity(1 + to.len());
vals.push(Value::Uuid(path.into()));
vals.push(Primitive::Uuid(path.into()));
vals.extend(to);
(MOVE_PATH_PEN, vals)
}
@ -70,7 +70,7 @@ impl Composite for kittycad_modeling_cmds::ModelingCmd {
out
}
fn from_parts(values: &[Option<Value>]) -> Result<Self, ExecutionError> {
fn from_parts(values: &[Option<Primitive>]) -> Result<Self, ExecutionError> {
// Check the array has an element at index 0
let first_memory = values
.get(0)
@ -90,7 +90,7 @@ impl Composite for kittycad_modeling_cmds::ModelingCmd {
}
}
fn get_some(values: &[Option<Value>], i: usize) -> Result<Value, ExecutionError> {
fn get_some(values: &[Option<Primitive>], i: usize) -> Result<Primitive, ExecutionError> {
let addr = Address(0); // TODO: pass the `start` addr in
let v = values.get(i).ok_or(ExecutionError::MemoryEmpty { addr })?.to_owned();
let v = v.ok_or(ExecutionError::MemoryEmpty { addr })?.to_owned();