diff --git a/execution-plan/src/api_endpoint.rs b/execution-plan/src/api_endpoint.rs index 9c0a69b8..35d38670 100644 --- a/execution-plan/src/api_endpoint.rs +++ b/execution-plan/src/api_endpoint.rs @@ -27,9 +27,9 @@ impl ApiEndpoint for MovePathPen { where I: Iterator, { - let path: Uuid = read::(values.next(), 2, mem)?.try_into()?; + let path: Uuid = read::(values.next(), mem)?.try_into()?; let path = ModelingCmdId::from(path); - let to = read(values.next(), 2, mem)?; + let to = read(values.next(), mem)?; Ok(Self { path, to }) } } @@ -39,15 +39,15 @@ impl ApiEndpoint for ExtendPath { where I: Iterator, { - let path = read::(values.next(), 2, mem) + let path = read::(values.next(), mem) .and_then(Uuid::try_from) .map(ModelingCmdId::from)?; - let segment = read(values.next(), 2, mem)?; + let segment = read(values.next(), mem)?; Ok(Self { path, segment }) } } -fn read(start_addr: Option
, expected_num: usize, mem: &Memory) -> Result { - let start_addr = start_addr.ok_or(ExecutionError::MemoryWrongSize { expected: expected_num })?; +fn read(start_addr: Option
, mem: &Memory) -> Result { + let start_addr = start_addr.ok_or(ExecutionError::MemoryWrongSize)?; mem.get_composite(start_addr) } diff --git a/execution-plan/src/lib.rs b/execution-plan/src/lib.rs index c30276e7..d6a07e0c 100644 --- a/execution-plan/src/lib.rs +++ b/execution-plan/src/lib.rs @@ -77,8 +77,8 @@ impl 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(&self, start: Address) -> Result { - let values = &self.0[start.0..]; - T::from_parts(values) + let mut values = self.0.iter().skip(start.0).cloned(); + T::from_parts(&mut values) } } @@ -238,11 +238,8 @@ pub enum ExecutionError { actual: String, }, /// Memory address was not set. - #[error("Wanted {expected} values but did not get enough")] - MemoryWrongSize { - /// How many values were expected - expected: usize, - }, + #[error("Tried to read from empty memory address")] + MemoryWrongSize, /// You tried to call a KittyCAD endpoint that doesn't exist or isn't implemented. #[error("No endpoint {name} recognized")] UnrecognizedEndpoint { diff --git a/execution-plan/src/primitive.rs b/execution-plan/src/primitive.rs index 3963bb1e..7ba08052 100644 --- a/execution-plan/src/primitive.rs +++ b/execution-plan/src/primitive.rs @@ -161,9 +161,14 @@ impl crate::value::Value for Primitive { vec![self] } - fn from_parts(values: &[Option]) -> Result { - let v = values.get(0).ok_or(ExecutionError::MemoryWrongSize { expected: 1 })?; - v.to_owned().ok_or(ExecutionError::MemoryWrongSize { expected: 1 }) + fn from_parts(values: &mut I) -> Result + where + I: Iterator>, + { + values + .next() + .and_then(|v| v.to_owned()) + .ok_or(ExecutionError::MemoryWrongSize) } } diff --git a/execution-plan/src/value.rs b/execution-plan/src/value.rs index 4a18e83e..0b33d074 100644 --- a/execution-plan/src/value.rs +++ b/execution-plan/src/value.rs @@ -9,5 +9,7 @@ pub trait Value: Sized { /// Store the value in memory. fn into_parts(self) -> Vec; /// Read the value from memory. - fn from_parts(values: &[Option]) -> Result; + fn from_parts(values: &mut I) -> Result + where + I: Iterator>; } diff --git a/execution-plan/src/value/impls.rs b/execution-plan/src/value/impls.rs index ed4e594b..66de00b2 100644 --- a/execution-plan/src/value/impls.rs +++ b/execution-plan/src/value/impls.rs @@ -7,11 +7,11 @@ use kittycad_modeling_cmds::{ ok_response::OkModelingCmdResponse, output, - shared::{PathSegment, Point2d, Point3d}, + shared::{Angle, PathSegment, Point2d, Point3d}, }; use super::Value; -use crate::{Address, ExecutionError, Primitive}; +use crate::{ExecutionError, Primitive}; const EMPTY: &str = "EMPTY"; const TAKE_SNAPSHOT: &str = "TAKE_SNAPSHOT"; @@ -21,6 +21,10 @@ const TAN_ARC: &str = "tan_arc"; const TAN_ARC_TO: &str = "tan_arc_to"; const BEZIER: &str = "bezier"; +fn err() -> ExecutionError { + ExecutionError::MemoryWrongSize +} + impl Value for Point2d where Primitive: From, @@ -31,17 +35,12 @@ where points.into_iter().map(|component| component.into()).collect() } - fn from_parts(values: &[Option]) -> Result { - let err = || ExecutionError::MemoryWrongSize { expected: 2 }; - let [x, y] = [0, 1].map(|n| values.get(n).ok_or(err())); - let x = x? - .to_owned() - .ok_or(ExecutionError::MemoryWrongSize { expected: 2 })? - .try_into()?; - let y = y? - .to_owned() - .ok_or(ExecutionError::MemoryWrongSize { expected: 2 })? - .try_into()?; + fn from_parts(values: &mut I) -> Result + where + I: Iterator>, + { + let x = values.next().ok_or(err())?.to_owned().ok_or(err())?.try_into()?; + let y = values.next().ok_or(err())?.to_owned().ok_or(err())?.try_into()?; Ok(Self { x, y }) } } @@ -56,21 +55,13 @@ where points.into_iter().map(|component| component.into()).collect() } - fn from_parts(values: &[Option]) -> Result { - let err = || ExecutionError::MemoryWrongSize { expected: 3 }; - let [x, y, z] = [0, 1, 2].map(|n| values.get(n).ok_or(err())); - let x = x? - .to_owned() - .ok_or(ExecutionError::MemoryWrongSize { expected: 3 })? - .try_into()?; - let y = y? - .to_owned() - .ok_or(ExecutionError::MemoryWrongSize { expected: 3 })? - .try_into()?; - let z = z? - .to_owned() - .ok_or(ExecutionError::MemoryWrongSize { expected: 3 })? - .try_into()?; + fn from_parts(values: &mut I) -> Result + where + I: Iterator>, + { + let x = values.next().ok_or(err())?.to_owned().ok_or(err())?.try_into()?; + let y = values.next().ok_or(err())?.to_owned().ok_or(err())?.try_into()?; + let z = values.next().ok_or(err())?.to_owned().ok_or(err())?.try_into()?; Ok(Self { x, y, z }) } } @@ -91,12 +82,15 @@ impl Value for OkModelingCmdResponse { } } - fn from_parts(values: &[Option]) -> Result { - let variant_name: String = get_some(values, 0)?.try_into()?; + fn from_parts(values: &mut I) -> Result + where + I: Iterator>, + { + let variant_name: String = next(values)?; match variant_name.as_str() { EMPTY => Ok(OkModelingCmdResponse::Empty), TAKE_SNAPSHOT => { - let contents: Vec = get_some(values, 1)?.try_into()?; + let contents: Vec = next(values)?; Ok(OkModelingCmdResponse::TakeSnapshot(output::TakeSnapshot { contents: contents.into(), })) @@ -112,19 +106,27 @@ impl Value for output::TakeSnapshot { vec![Primitive::Bytes(self.contents.into())] } - fn from_parts(values: &[Option]) -> Result { - let contents: Vec = get_some(values, 0)?.try_into()?; + fn from_parts(values: &mut I) -> Result + where + I: Iterator>, + { + let contents: Vec = next(values)?; Ok(Self { contents: contents.into(), }) } } -fn get_some(values: &[Option], i: usize) -> Result { - 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(); - Ok(v) +/// Read the next primitive. +/// If it's +fn next(values: &mut I) -> Result +where + I: Iterator>, + T: TryFrom, +{ + let v = values.next().ok_or_else(err)?; + let v = v.ok_or_else(err)?; + T::try_from(v) } /// Layout: @@ -193,25 +195,59 @@ impl Value for PathSegment { parts } - fn from_parts(values: &[Option]) -> Result { - let variant_name: String = get_some(values, 0)?.try_into()?; + fn from_parts(values: &mut I) -> Result + where + I: Iterator>, + { + let variant_name: String = next(values)?; match variant_name.as_str() { LINE => { let end = Point3d::from_parts(values)?; - let relative = get_some(values, 1)?.try_into()?; + let relative = next(values)?; Ok(Self::Line { end, relative }) } ARC => { - todo!() + let center = Point2d::from_parts(values)?; + let radius = Primitive::from_parts(values)?.try_into()?; + let start = Primitive::from_parts(values)?.try_into()?; + let end = Primitive::from_parts(values)?.try_into()?; + let relative = Primitive::from_parts(values)?.try_into()?; + Ok(Self::Arc { + center, + radius, + start, + end, + relative, + }) } BEZIER => { - todo!() + let control1 = Point3d::from_parts(values)?; + let control2 = Point3d::from_parts(values)?; + let end = Point3d::from_parts(values)?; + let relative = Primitive::from_parts(values)?.try_into()?; + Ok(Self::Bezier { + control1, + control2, + end, + relative, + }) } TAN_ARC => { - todo!() + let radius = Primitive::from_parts(values).and_then(f64::try_from)?; + let offset = Primitive::from_parts(values).and_then(Angle::try_from)?; + Ok(Self::TangentialArc { radius, offset }) } TAN_ARC_TO => { - todo!() + let to = Point3d::from_parts(values)?; + let angle_snap_increment = if let Some(Some(primitive)) = values.next() { + Some(Angle::try_from(primitive)?) + } else { + None + }; + Ok(Self::TangentialArcTo { + to, + angle_snap_increment, + }) } other => Err(ExecutionError::InvalidEnumVariant { expected_type: "line segment".to_owned(),