Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

convert v8 objects to Rust structs manually, without ops #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 144 additions & 65 deletions src/model.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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<Shape, Error> {
let object =
v8::Local::<v8::Object>::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<Sweep, Error> {
let object =
v8::Local::<v8::Object>::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<Shape2d, Error> {
let object =
v8::Local::<v8::Object>::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::<String>(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<Difference2d, Error> {
let object =
v8::Local::<v8::Object>::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::<v8::Array>::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<Sketch, Error> {
let object =
v8::Local::<v8::Object>::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::<v8::Object>::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::<String>(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<Shape, Error> {
let result = serde_v8::from_v8::<Group>(scope, value);
if result.is_ok() {
return Ok(result?.into());
}
let result = serde_v8::from_v8::<Difference2d>(scope, value);
if result.is_ok() {
return Ok(result?.into());
}
let result = serde_v8::from_v8::<Sketch>(scope, value);
if result.is_ok() {
return Ok(result?.into());
}
let result = serde_v8::from_v8::<Sweep>(scope, value);
if result.is_ok() {
return Ok(result?.into());
}
let result = serde_v8::from_v8::<Transform>(scope, value);
if result.is_ok() {
return Ok(result?.into());
}
bail!("Unable to convert value into Shape");
) -> Result<Circle, Error> {
let object =
v8::Local::<v8::Object>::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::<f64>(scope, radius_value)
.context("Unable to convert radius value to f64")?;
let circle = Circle::from_radius(radius);
Ok(circle)
}
29 changes: 9 additions & 20 deletions src/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
}
}

Expand Down