diff --git a/src/model.rs b/src/model.rs index b740f1b..2456995 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,8 +1,8 @@ use anyhow::{bail, Context, Error, Result}; use deno_core::{ - include_js_files, op, serde_v8, url::Url, v8, Extension, JsRuntime, ModuleId, RuntimeOptions, + include_js_files, serde_v8, url::Url, v8, Extension, JsRuntime, ModuleId, RuntimeOptions, }; -use fj::{Circle, Difference2d, Group, Shape, Sketch, Sweep, Transform}; +use fj::{Circle, Difference2d, Shape, Shape2d, Sketch, Sweep}; use std::rc::Rc; use crate::module::ModuleLoader; @@ -16,16 +16,6 @@ impl ModelLoader { pub fn new() -> Self { let js_extension = Extension::builder("sandkit") .esm(include_js_files!("runtime.js",)) - .ops(vec![ - op_sketch_from_circle::decl(), - op_circle_from_radius::decl(), - op_difference2d_from_shapes_sketch_sketch::decl(), - op_difference2d_from_shapes_difference2d_sketch::decl(), - op_difference2d_from_shapes_sketch_difference2d::decl(), - op_difference2d_from_shapes_difference2d_difference2d::decl(), - op_sweep_from_paths_sketch::decl(), - op_sweep_from_paths_difference2d::decl(), - ]) .build(); let js = JsRuntime::new(RuntimeOptions { @@ -110,72 +100,161 @@ impl ModelLoader { } } -#[op] -fn op_circle_from_radius(radius: f64) -> Circle { - Circle::from_radius(radius) -} +fn into_shape<'a, 'b, 's>( + scope: &'b mut v8::HandleScope<'s>, + value: v8::Local<'a, v8::Value>, +) -> Result { + let object = + v8::Local::::try_from(value).context("Shape value is not an object")?; + let type_name = v8::String::new(scope, "type") + .context("Unable to create JavaScript string \"type\".")? + .into(); + let type_value = object + .get(scope, type_name) + .context("Unable to get \"type\" from shape object")?; + let type_id: String = + serde_v8::from_v8(scope, type_value).context("Unable to convert shape type to String")?; -#[op] -fn op_sketch_from_circle(circle: Circle) -> Sketch { - Sketch::from_circle(circle) -} + let shape: Shape = match type_id.as_str() { + "Difference2d" => into_difference2d(scope, value)?.into(), + "Sketch" => into_sketch(scope, value)?.into(), + "Sweep" => into_sweep(scope, value)?.into(), + _ => { + bail!("Unknown shape type: {}", type_id); + } + }; -#[op] -fn op_difference2d_from_shapes_sketch_sketch(a: Sketch, b: Sketch) -> Difference2d { - Difference2d::from_shapes([a.into(), b.into()]) + Ok(shape) } -#[op] -fn op_difference2d_from_shapes_difference2d_sketch(a: Difference2d, b: Sketch) -> Difference2d { - Difference2d::from_shapes([a.into(), b.into()]) +fn into_sweep<'a, 'b, 's>( + scope: &'b mut v8::HandleScope<'s>, + value: v8::Local<'a, v8::Value>, +) -> Result { + let object = + v8::Local::::try_from(value).context("Sweep value is not an object")?; + let shape_name = v8::String::new(scope, "shape") + .context("Unable to create JavaScript string \"shape\".")? + .into(); + let shape_value = object + .get(scope, shape_name) + .context("Unable to get \"shape\" from Sweep object")?; + let shape = into_shape2d(scope, shape_value).context("Sweep shape is not a shape")?; + let path_name = v8::String::new(scope, "path") + .context("Unable to create JavaScript string \"path\".")? + .into(); + let path_value = object + .get(scope, path_name) + .context("Unable to get \"path\" from Sweep object")?; + let path = serde_v8::from_v8::<[f64; 3]>(scope, path_value) + .context("Unable to parse Sweep path value")?; + let sweep = Sweep::from_path(shape, path); + Ok(sweep) } -#[op] -fn op_difference2d_from_shapes_sketch_difference2d(a: Sketch, b: Difference2d) -> Difference2d { - Difference2d::from_shapes([a.into(), b.into()]) -} +fn into_shape2d<'a, 'b, 's>( + scope: &'b mut v8::HandleScope<'s>, + value: v8::Local<'a, v8::Value>, +) -> Result { + let object = + v8::Local::::try_from(value).context("Shape2d value is not an object")?; + let type_name = v8::String::new(scope, "type") + .context("Unable to create JavaScript string \"type\".")? + .into(); + let type_value = object + .get(scope, type_name) + .context("Unable to get \"type\" from Shape2d object")?; + let type_id = serde_v8::from_v8::(scope, type_value) + .context("Unable to convert shape2d type to String")?; + + let shape: Shape2d = match type_id.as_str() { + "Difference2d" => into_difference2d(scope, value)?.into(), + "Sketch" => into_sketch(scope, value)?.into(), + _ => { + bail!("Unknown shape2d type: {}", type_id); + } + }; -#[op] -fn op_difference2d_from_shapes_difference2d_difference2d( - a: Difference2d, - b: Difference2d, -) -> Difference2d { - Difference2d::from_shapes([a.into(), b.into()]) + Ok(shape) } -#[op] -fn op_sweep_from_paths_sketch(shape: Sketch, path: [f64; 3]) -> Sweep { - Sweep::from_path(shape.into(), path) +fn into_difference2d<'a, 'b, 's>( + scope: &'b mut v8::HandleScope<'s>, + value: v8::Local<'a, v8::Value>, +) -> Result { + let object = + v8::Local::::try_from(value).context("Difference2d value is not an object")?; + let shapes_name = v8::String::new(scope, "shapes") + .context("Unable to create JavaScript string \"shapes\".")? + .into(); + let shapes_value = object + .get(scope, shapes_name) + .context("Unable to get \"shapes\" from Difference2d object")?; + let shapes_array = v8::Local::::try_from(shapes_value) + .context("Difference2d shapes is not an Array")?; + let shapes_a_value = shapes_array + .get_index(scope, 0) + .context("Unable to get shapes[0] value from Difference2d shapes object")?; + let shapes_a = + into_shape2d(scope, shapes_a_value).context("Difference2d shapes[0] is not a shape")?; + let shapes_b_value = shapes_array + .get_index(scope, 1) + .context("Unable to get shapes[1] value from Difference2d shapes object")?; + let shapes_b = + into_shape2d(scope, shapes_b_value).context("Difference2d shapes[1] is not a shape")?; + let difference2d = Difference2d::from_shapes([shapes_a.into(), shapes_b.into()]); + Ok(difference2d) } -#[op] -fn op_sweep_from_paths_difference2d(shape: Difference2d, path: [f64; 3]) -> Sweep { - Sweep::from_path(shape.into(), path) +fn into_sketch<'a, 'b, 's>( + scope: &'b mut v8::HandleScope<'s>, + value: v8::Local<'a, v8::Value>, +) -> Result { + let object = + v8::Local::::try_from(value).context("Sketch value is not an object")?; + let chain_name = v8::String::new(scope, "chain") + .context("Unable to create JavaScript string \"chain\".")? + .into(); + let chain_value = object + .get(scope, chain_name) + .context("Unable to get \"chain\" from Sketch object")?; + let chain_object = + v8::Local::::try_from(chain_value).context("Sketch chain is not an object")?; + let chain_type_name = v8::String::new(scope, "type") + .context("Unable to create JavaScript string \"type\".")? + .into(); + let chain_type_value = chain_object + .get(scope, chain_type_name) + .context("Unable to get \"type\" from Sketch chain object")?; + let chain_type = serde_v8::from_v8::(scope, chain_type_value) + .context("Unable to convert chain.type to String")?; + println!("chain type: {}", chain_type); + let sketch = match chain_type.as_str() { + "Circle" => { + let circle = into_circle(scope, chain_value)?; + Sketch::from_circle(circle) + } + _ => { + bail!("Unknown Chain type: {}", chain_type); + } + }; + Ok(sketch) } -fn into_shape<'a, 'b, 's>( +fn into_circle<'a, 'b, 's>( scope: &'b mut v8::HandleScope<'s>, value: v8::Local<'a, v8::Value>, -) -> Result { - let result = serde_v8::from_v8::(scope, value); - if result.is_ok() { - return Ok(result?.into()); - } - let result = serde_v8::from_v8::(scope, value); - if result.is_ok() { - return Ok(result?.into()); - } - let result = serde_v8::from_v8::(scope, value); - if result.is_ok() { - return Ok(result?.into()); - } - let result = serde_v8::from_v8::(scope, value); - if result.is_ok() { - return Ok(result?.into()); - } - let result = serde_v8::from_v8::(scope, value); - if result.is_ok() { - return Ok(result?.into()); - } - bail!("Unable to convert value into Shape"); +) -> Result { + let object = + v8::Local::::try_from(value).context("Circle value is not an object")?; + let radius_name = v8::String::new(scope, "radius") + .context("Unable to create JavaScript string \"radius\".")? + .into(); + let radius_value = object + .get(scope, radius_name) + .context("Unable to get \"radius\" from Circle object")?; + let radius = serde_v8::from_v8::(scope, radius_value) + .context("Unable to convert radius value to f64")?; + let circle = Circle::from_radius(radius); + Ok(circle) } diff --git a/src/runtime.js b/src/runtime.js index 05dee9d..27ecc65 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -12,58 +12,47 @@ const console = { } class Circle { + type = "Circle" constructor({ radius }) { this.radius = radius } static fromRadius(radius) { - return new Circle(ops.op_circle_from_radius(radius)) + return new Circle({ radius }) } } class Sketch { - constructor({ chain, color }) { + type = "Sketch" + constructor({ chain }) { this.chain = chain - this.color = color } static fromCircle(circle) { - return new Sketch(ops.op_sketch_from_circle(circle)) + return new Sketch({ chain: circle }) } } class Difference2d { + type = "Difference2d" constructor({ shapes }) { this.shapes = shapes } static fromShapes(a, b) { - switch (true) { - case a instanceof Sketch && b instanceof Sketch: - return new Difference2d(ops.op_difference2d_from_shapes_sketch_sketch(a, b)) - case a instanceof Difference2d && b instanceof Sketch: - return new Difference2d(ops.op_difference2d_from_shapes_difference2d_sketch(a, b)) - case a instanceof Sketch && b instanceof Difference2d: - return new Difference2d(ops.op_difference2d_from_shapes_sketch_difference2d(a, b)) - case a instanceof Difference2d && b instanceof Difference2d: - return new Difference2d(ops.op_difference2d_from_shapes_difference2d_difference2d(a, b)) - } + return new Difference2d({ shapes: [a, b] }) } } class Sweep { + type = "Sweep" constructor({ shape, path }) { this.shape = shape this.path = path } static fromPath(shape, path) { - switch (true) { - case shape instanceof Sketch: - return new Sweep(ops.op_sweep_from_paths_sketch(shape, path)) - case shape instanceof Difference2d: - return new Sweep(ops.op_sweep_from_paths_difference2d(shape, path)) - } + return new Sweep({ shape, path }) } }