Skip to content

Commit

Permalink
execution-plan: Macro for implementing Value on a struct
Browse files Browse the repository at this point in the history
  • Loading branch information
adamchalmers committed Dec 19, 2023
1 parent 3e218fa commit 96394a8
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 29 deletions.
30 changes: 29 additions & 1 deletion execution-plan/src/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ impl From<String> for Primitive {
}
}

impl From<f32> for Primitive {
fn from(value: f32) -> Self {
Self::NumericValue(NumericPrimitive::Float(value as f64))
}
}

impl From<f64> for Primitive {
fn from(value: f64) -> Self {
Self::NumericValue(NumericPrimitive::Float(value))
Expand Down Expand Up @@ -113,6 +119,14 @@ impl TryFrom<Primitive> for f64 {
}
}

impl TryFrom<Primitive> for f32 {
type Error = ExecutionError;

fn try_from(value: Primitive) -> Result<Self, Self::Error> {
f64::try_from(value).map(|x| x as f32)
}
}

impl TryFrom<Primitive> for Vec<u8> {
type Error = ExecutionError;

Expand Down Expand Up @@ -143,7 +157,21 @@ impl TryFrom<Primitive> for bool {
}
}

#[cfg(test)]
impl TryFrom<Primitive> for usize {
type Error = ExecutionError;

fn try_from(value: Primitive) -> Result<Self, Self::Error> {
if let Primitive::NumericValue(NumericPrimitive::Integer(x)) = value {
Ok(x)
} else {
Err(ExecutionError::MemoryWrongType {
expected: "usize",
actual: format!("{value:?}"),
})
}
}
}

impl From<usize> for Primitive {
fn from(value: usize) -> Self {
Self::NumericValue(NumericPrimitive::Integer(value))
Expand Down
94 changes: 66 additions & 28 deletions execution-plan/src/value/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use kittycad_modeling_cmds::{
output,
shared::{Angle, PathSegment, Point2d, Point3d},
};
use uuid::Uuid;

use super::Value;
use crate::{ExecutionError, Primitive};
Expand All @@ -25,45 +26,82 @@ fn err() -> ExecutionError {
ExecutionError::MemoryWrongSize
}

macro_rules! impl_value_on_primitive_ish {
($subject:ident) => {
impl Value for $subject {
fn into_parts(self) -> Vec<Primitive> {
vec![self.into()]
}

fn from_parts<I>(values: &mut I) -> Result<Self, ExecutionError>
where
I: Iterator<Item = Option<Primitive>>,
{
values.next().ok_or(err())?.to_owned().ok_or(err())?.try_into()
}
}
};
}

impl_value_on_primitive_ish!(f32);
impl_value_on_primitive_ish!(f64);
impl_value_on_primitive_ish!(bool);
impl_value_on_primitive_ish!(String);
impl_value_on_primitive_ish!(Uuid);
type VecU8 = Vec<u8>;
impl_value_on_primitive_ish!(VecU8);
impl_value_on_primitive_ish!(Angle);
impl_value_on_primitive_ish!(usize);

/// Macro to generate the methods of trait `Value` for the given fields.
/// Args:
/// `$field`: Repeated 0 or more times. Listing of each field in the struct.
/// The order in which these fields are given determines the order that fields are
/// written to and read from memory.
macro_rules! impl_value_on_struct_fields {
($($field:ident),*) => {
fn into_parts(self) -> Vec<Primitive> {
let mut parts = Vec::new();
$(
parts.extend(self.$field.into_parts());
)*
parts
}

fn from_parts<I>(values: &mut I) -> Result<Self, ExecutionError>
where
I: Iterator<Item = Option<Primitive>>,
{
$(
let $field = Value::from_parts(values)?;
)*
Ok(Self {
$(
$field,
)*
})
}
};
}

impl<T> Value for Point2d<T>
where
Primitive: From<T>,
T: TryFrom<Primitive, Error = ExecutionError>,
T: Value,
{
fn into_parts(self) -> Vec<Primitive> {
let points = [self.x, self.y];
points.into_iter().map(|component| component.into()).collect()
}

fn from_parts<I>(values: &mut I) -> Result<Self, ExecutionError>
where
I: Iterator<Item = Option<Primitive>>,
{
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 })
}
impl_value_on_struct_fields!(x, y);
}

impl<T> Value for Point3d<T>
where
Primitive: From<T>,
T: TryFrom<Primitive, Error = ExecutionError>,
T: Value,
{
fn into_parts(self) -> Vec<Primitive> {
let points = [self.x, self.y, self.z];
points.into_iter().map(|component| component.into()).collect()
}
impl_value_on_struct_fields!(x, y, z);
}

fn from_parts<I>(values: &mut I) -> Result<Self, ExecutionError>
where
I: Iterator<Item = Option<Primitive>>,
{
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 })
}
impl Value for kittycad_modeling_cmds::shared::Color {
impl_value_on_struct_fields!(r, g, b, a);
}

/// Layout:
Expand Down

0 comments on commit 96394a8

Please sign in to comment.