Open dtysky opened 5 years ago
Thanks for the report! Unfortunately this is quite difficult to support in wasm-bindgen due to the nature of the GC in JS. In your proposed solution, for example, the Vector3
cannot live longer than Transform
but there's nothing preventing that and it allows for a use-after-free.
It's possible for us to tie all these lifetimes together somewhat but then borrowing also gets really tricky. For example storing Vector3
in Rust and having a handle to it in JS is actually quite different, in Rust there's no RefCell
but with the JS handle there's a hidden RefCell
.
I think this may be possible to do in the long run if we get really creative, but today there's no clear, safe, and workable method to implement this.
@alexcrichton
Thanks for your detailed reply, I can understand what you are worry about, but these problems really confuse me, for example, what is the best way to change the position
of Camera
and Mesh
:
#[wasm_bindgen]
pub struct Transform {
anchor: Cell<Vector3>,
position: Cell<Vector3>,
rotation: Cell<Vector3>,
scale: Cell<Vector3>,
quaternion: Cell<Quaternion>,
world_matrix: Cell<Matrix4>
}
#[wasm_bindgen]
pub struct Camera {
transform: Cell<Transform>,
fov: f64,
aspect: f64,
near: f64,
far: f64,
view_matrix: Cell<Matrix4>,
projection_matrix: Cell<Matrix4>
}
#[wasm_bindgen]
pub struct Mesh {
transform: Cell<Transform>,
vertices: Cell<Vec<Vector3>>,
colors: Cell<Vec<Vector3>>,
}
wasm_bindgen does not support trait
now, and rust does not support extends
, so I have to write many functions for each struct which has Transform
using ugly procedure-oriented way:
#[wasm_bindgen]
impl Transform {
// could not return refer
#[wasm_bindgen(method, js_name="getPosition")]
pub fn get_position(&mut self) -> Vector3 {
self.position.get_mut().clone()
}
#[wasm_bindgen(method, js_name="setPosition")]
pub fn set_position(&mut self, value: &Vector3) {
self.position.get_mut().copy(value)
}
}
#[wasm_bindgen]
pub fn set_camera_position(camera: &mut Camera, vector: &Vector3) {
// `position` must be private, wasm_bindgen does not support public struct in struct
camera.transform.get_mut().set_position(vector);
}
// could not return refer
#[wasm_bindgen]
pub fn get_camera_position(camera: &mut Camera) -> Vector3 {
// a hidden clone
camera.transform.get_mut().get_position()
}
emmm... Of course these problems could be solved by some design patterns like "ECS" , but those solutions are not universal and will make lot of developers give up.
So could we give developers a selection to do these if they can control the risk of memory themselves?
I definitely agree that we want to solve this somehow! I'm just not sure personally how best to do so, so I'm not sure how to make progress on this.
Motivation
Example:
In these code we define a struct
Vector
and use it as a memberposition
in another structTransform
, there is no way to pass refer ofposition
to javascript by 'wasm_bindgen' attribute.But It's really a common scene, it had took me lots of time, at last i found this problem could be solved on pure javascript side, see 'Proposed Solution'.
Proposed Solution
After some trials, I wrote following code to solve this problem:
Additional Context
So, is it possible to support using public custom struct in custom struct or returning rust object's refer to javascript like these:
Thanks.