From b01357b49e8c1db25e747b1c35525ec1cfdbecd0 Mon Sep 17 00:00:00 2001 From: Adam Chalmers Date: Tue, 12 Dec 2023 09:26:36 -0600 Subject: [PATCH] Impl composite for Modeling Command types (#1196) --- src/wasm-lib/Cargo.lock | 270 ++++++++++++++++-- src/wasm-lib/execution-plan/Cargo.toml | 2 + .../execution-plan/src/composite/impls.rs | 88 +++++- src/wasm-lib/execution-plan/src/lib.rs | 58 +++- src/wasm-lib/execution-plan/src/tests.rs | 34 ++- 5 files changed, 417 insertions(+), 35 deletions(-) diff --git a/src/wasm-lib/Cargo.lock b/src/wasm-lib/Cargo.lock index 5f71a6c83..e2cc4e5f9 100644 --- a/src/wasm-lib/Cargo.lock +++ b/src/wasm-lib/Cargo.lock @@ -127,6 +127,12 @@ dependencies = [ "backtrace", ] +[[package]] +name = "approx" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" + [[package]] name = "arc-swap" version = "1.6.0" @@ -243,7 +249,7 @@ dependencies = [ "libm", "num-bigint", "num-integer", - "num-traits", + "num-traits 0.2.17", "serde", ] @@ -329,7 +335,7 @@ dependencies = [ "indexmap 1.9.3", "js-sys", "once_cell", - "rand", + "rand 0.8.5", "serde", "serde_bytes", "serde_json", @@ -394,6 +400,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cgmath" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" +dependencies = [ + "approx", + "mint", + "num-traits 0.1.43", + "rand 0.4.6", +] + [[package]] name = "chrono" version = "0.4.31" @@ -402,8 +420,10 @@ checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", - "num-traits", + "js-sys", + "num-traits 0.2.17", "serde", + "wasm-bindgen", "windows-targets 0.48.5", ] @@ -580,7 +600,7 @@ dependencies = [ "criterion-plot", "is-terminal", "itertools 0.10.5", - "num-traits", + "num-traits 0.2.17", "once_cell", "oorandom", "plotters", @@ -677,9 +697,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "databake" @@ -742,6 +762,49 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "diesel" +version = "2.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62c6fcf842f17f8c78ecf7c81d75c5ce84436b41ee07e03f490fbb5f5a8731d8" +dependencies = [ + "bigdecimal", + "bitflags 2.4.1", + "byteorder", + "chrono", + "diesel_derives", + "mysqlclient-sys", + "num-bigint", + "num-integer", + "num-traits 0.2.17", + "percent-encoding", + "r2d2", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "diesel_derives" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44" +dependencies = [ + "diesel_table_macro_syntax", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" +dependencies = [ + "syn 2.0.39", +] + [[package]] name = "diff" version = "0.1.13" @@ -806,6 +869,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-iterator" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7add3873b5dd076766ee79c8e406ad1a472c385476b9e38849f8eec24f1be689" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -822,14 +905,26 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "euler" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f19d11568a4a46aee488bdab3a2963e5e2c3cfd6091aa0abceaddcea82c0bc1" +dependencies = [ + "approx", + "cgmath", +] + [[package]] name = "execution-plan" version = "0.1.0" dependencies = [ "bytes", "kittycad", + "kittycad-modeling-cmds", "serde", "thiserror", + "uuid", ] [[package]] @@ -946,6 +1041,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "funty" version = "2.0.0" @@ -1299,7 +1400,7 @@ dependencies = [ "gif", "jpeg-decoder", "num-rational", - "num-traits", + "num-traits 0.2.17", "png", "qoi", "tiff", @@ -1338,6 +1439,12 @@ dependencies = [ "serde", ] +[[package]] +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + [[package]] name = "insta" version = "1.34.0" @@ -1504,7 +1611,7 @@ dependencies = [ "log", "parse-display", "phonenumber", - "rand", + "rand 0.8.5", "reqwest", "reqwest-conditional-middleware", "reqwest-middleware", @@ -1521,6 +1628,42 @@ dependencies = [ "uuid", ] +[[package]] +name = "kittycad-modeling-cmds" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3217f9ffe9dce4b16303eeef539e7e27b743bc1c46eff8ce64657745a2b75ca" +dependencies = [ + "chrono", + "data-encoding", + "diesel", + "diesel_derives", + "enum-iterator", + "enum-iterator-derive", + "euler", + "http", + "kittycad-unit-conversion-derive", + "measurements", + "parse-display", + "parse-display-derive", + "schemars", + "serde", + "serde_bytes", + "uuid", +] + +[[package]] +name = "kittycad-unit-conversion-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7001c46a92c1edce6722a3900539b198230980799035f02d92b4e7df3fc08738" +dependencies = [ + "inflections", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1620,6 +1763,15 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "measurements" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5b734b4e8187ea5777bc29c086f0970a27d8de42061b48f5af32cafc0ca904b" +dependencies = [ + "libm", +] + [[package]] name = "memchr" version = "2.6.4" @@ -1667,6 +1819,12 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mint" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" + [[package]] name = "mio" version = "0.8.9" @@ -1678,6 +1836,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mysqlclient-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f61b381528ba293005c42a409dd73d034508e273bf90481f17ec2e964a6e969b" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "newline-converter" version = "0.3.0" @@ -1705,7 +1873,7 @@ checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", - "num-traits", + "num-traits 0.2.17", ] [[package]] @@ -1715,7 +1883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", - "num-traits", + "num-traits 0.2.17", ] [[package]] @@ -1726,7 +1894,16 @@ checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", "num-integer", - "num-traits", + "num-traits 0.2.17", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.17", ] [[package]] @@ -1812,7 +1989,7 @@ dependencies = [ "phonenumber", "proc-macro2", "quote", - "rand", + "rand 0.8.5", "regex", "reqwest", "reqwest-middleware", @@ -1864,7 +2041,7 @@ dependencies = [ "lazy_static", "percent-encoding", "pin-project", - "rand", + "rand 0.8.5", "thiserror", ] @@ -2019,7 +2196,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ - "num-traits", + "num-traits 0.2.17", "plotters-backend", "plotters-svg", "wasm-bindgen", @@ -2136,12 +2313,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot 0.12.1", + "scheduled-thread-pool", +] + [[package]] name = "radium" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + [[package]] name = "rand" version = "0.8.5" @@ -2150,7 +2351,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2160,9 +2361,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.4" @@ -2192,6 +2408,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -2400,7 +2625,7 @@ checksum = "e09bbcb5003282bcb688f0bae741b278e9c7e8f378f561522c9806c58e075d9b" dependencies = [ "anyhow", "chrono", - "rand", + "rand 0.8.5", ] [[package]] @@ -2528,6 +2753,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot 0.12.1", +] + [[package]] name = "schemars" version = "0.8.16" @@ -3444,7 +3678,7 @@ dependencies = [ "http", "httparse", "log", - "rand", + "rand 0.8.5", "rustls", "sha1", "thiserror", diff --git a/src/wasm-lib/execution-plan/Cargo.toml b/src/wasm-lib/execution-plan/Cargo.toml index 2bf46867e..3d09f2fa5 100644 --- a/src/wasm-lib/execution-plan/Cargo.toml +++ b/src/wasm-lib/execution-plan/Cargo.toml @@ -9,5 +9,7 @@ description = "A DSL for composing KittyCAD API queries" [dependencies] bytes = "1.5" kittycad = { workspace = true, features = ["requests"] } +kittycad-modeling-cmds = "0.1.4" serde = { version = "1", features = ["derive"] } thiserror = "1" +uuid = "1.6.1" diff --git a/src/wasm-lib/execution-plan/src/composite/impls.rs b/src/wasm-lib/execution-plan/src/composite/impls.rs index 924e57540..e68ec92a8 100644 --- a/src/wasm-lib/execution-plan/src/composite/impls.rs +++ b/src/wasm-lib/execution-plan/src/composite/impls.rs @@ -1,14 +1,18 @@ -use crate::{ExecutionError, Value}; +use kittycad_modeling_cmds::{id::ModelingCmdId, shared::Point3d, MovePathPen}; +use uuid::Uuid; + +use crate::{Address, ExecutionError, Value}; use super::Composite; -impl Composite for kittycad::types::Point3D { +impl Composite for kittycad_modeling_cmds::shared::Point3d +where + Value: From, + T: TryFrom, +{ fn into_parts(self) -> Vec { let points = [self.x, self.y, self.z]; - points - .into_iter() - .map(|x| Value::NumericValue(crate::NumericValue::Float(x))) - .collect() + points.into_iter().map(|component| component.into()).collect() } fn from_parts(values: &[Option]) -> Result { @@ -20,3 +24,75 @@ impl Composite for kittycad::types::Point3D { Ok(Self { x, y, z }) } } + +const START_PATH: &str = "StartPath"; +const MOVE_PATH_PEN: &str = "MovePathPen"; + +impl Composite for MovePathPen { + fn into_parts(self) -> Vec { + 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.extend(to); + vals + } + + fn from_parts(values: &[Option]) -> Result { + let path = get_some(values, 0)?; + let path = Uuid::try_from(path)?; + let path = ModelingCmdId::from(path); + let to = Point3d::from_parts(&values[1..])?; + let params = MovePathPen { path, to }; + Ok(params) + } +} + +/// 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 { + 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.extend(to); + (MOVE_PATH_PEN, vals) + } + _ => todo!(), + }; + let mut out = Vec::with_capacity(params.len() + 1); + out.push(endpoint_name.to_owned().into()); + out.extend(params); + out + } + + fn from_parts(values: &[Option]) -> Result { + // Check the array has an element at index 0 + let first_memory = values + .get(0) + .ok_or(ExecutionError::MemoryWrongSize { expected: 1 })? + .to_owned(); + // The element should be Some + let first_memory = first_memory.ok_or(ExecutionError::MemoryWrongSize { expected: 1 })?; + let endpoint_name: String = first_memory.try_into()?; + match endpoint_name.as_str() { + START_PATH => Ok(Self::StartPath), + MOVE_PATH_PEN => { + let params = MovePathPen::from_parts(&values[1..])?; + Ok(Self::MovePathPen(params)) + } + other => Err(ExecutionError::UnrecognizedEndpoint(other.to_owned())), + } + } +} + +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) +} diff --git a/src/wasm-lib/execution-plan/src/lib.rs b/src/wasm-lib/execution-plan/src/lib.rs index 4a04e6524..c85c53a21 100644 --- a/src/wasm-lib/execution-plan/src/lib.rs +++ b/src/wasm-lib/execution-plan/src/lib.rs @@ -9,6 +9,7 @@ use composite::Composite; use serde::{Deserialize, Serialize}; use std::fmt; +use uuid::Uuid; mod composite; #[cfg(test)] @@ -78,8 +79,56 @@ impl Memory { pub enum Value { String(String), NumericValue(NumericValue), + Uuid(Uuid), } +impl From for Value { + fn from(u: Uuid) -> Self { + Self::Uuid(u) + } +} + +impl From for Value { + fn from(value: String) -> Self { + Self::String(value) + } +} + +impl From for Value { + fn from(value: f64) -> Self { + Self::NumericValue(NumericValue::Float(value)) + } +} + +impl TryFrom for String { + type Error = ExecutionError; + + fn try_from(value: Value) -> Result { + if let Value::String(s) = value { + Ok(s) + } else { + Err(ExecutionError::MemoryWrongType { + expected: "string", + actual: format!("{value:?}"), + }) + } + } +} + +impl TryFrom for Uuid { + type Error = ExecutionError; + + fn try_from(value: Value) -> Result { + if let Value::Uuid(u) = value { + Ok(u) + } else { + Err(ExecutionError::MemoryWrongType { + expected: "uuid", + actual: format!("{value:?}"), + }) + } + } +} impl TryFrom for f64 { type Error = ExecutionError; @@ -95,13 +144,6 @@ impl TryFrom for f64 { } } -#[cfg(test)] -impl From for Value { - fn from(value: f64) -> Self { - Self::NumericValue(NumericValue::Float(value)) - } -} - #[cfg(test)] impl From for Value { fn from(value: usize) -> Self { @@ -276,4 +318,6 @@ pub enum ExecutionError { MemoryWrongType { expected: &'static str, actual: String }, #[error("Wanted {expected} values but did not get enough")] MemoryWrongSize { expected: usize }, + #[error("No endpoint {0} recognized")] + UnrecognizedEndpoint(String), } diff --git a/src/wasm-lib/execution-plan/src/tests.rs b/src/wasm-lib/execution-plan/src/tests.rs index 2704eb67d..817927311 100644 --- a/src/wasm-lib/execution-plan/src/tests.rs +++ b/src/wasm-lib/execution-plan/src/tests.rs @@ -1,4 +1,4 @@ -use kittycad::types::Point3D; +use kittycad_modeling_cmds::{id::ModelingCmdId, shared::Point3d, ModelingCmd, MovePathPen}; use super::*; @@ -57,7 +57,11 @@ fn add_to_composite_value() { let mut mem = Memory::default(); // Write a point to memory. - let point_before = Point3D { x: 2.0, y: 3.0, z: 4.0 }; + let point_before = Point3d { + x: 2.0f64, + y: 3.0, + z: 4.0, + }; let start_addr = Address(0); mem.set_composite(point_before, start_addr); assert_eq!(mem.0[0], Some(2.0.into())); @@ -79,13 +83,35 @@ fn add_to_composite_value() { .unwrap(); // Read the point out of memory, validate it. - let point_after: Point3D = mem.get_composite(start_addr).unwrap(); + let point_after: Point3d = mem.get_composite(start_addr).unwrap(); assert_eq!( point_after, - Point3D { + Point3d { x: 42.0, y: 3.0, z: 4.0 } ) } + +#[test] +fn api_types() { + let mut mem = Memory::default(); + let start_addr = Address(0); + let id = ModelingCmdId(Uuid::parse_str("6306afa2-3999-4b03-af30-1efad7cdc6fc").unwrap()); + let p = Point3d { + x: 2.0f64, + y: 3.0, + z: 4.0, + }; + let val_in = ModelingCmd::MovePathPen(MovePathPen { path: id, to: p }); + mem.set_composite(val_in, start_addr); + let val_out: ModelingCmd = mem.get_composite(start_addr).unwrap(); + match val_out { + ModelingCmd::MovePathPen(params) => { + assert_eq!(params.to, p); + assert_eq!(params.path, id); + } + _ => panic!("unexpected ModelingCmd variant"), + } +}