DelSkayn / rquickjs

High level bindings to the quickjs javascript engine
MIT License
431 stars 58 forks source link

Getter not clone #279

Closed Sytten closed 3 months ago

Sytten commented 3 months ago

I have a question, if I have

#[derive(Trace)]
#[rquickjs::class(frozen)]
pub struct Sdk {
    #[qjs(get)]
    console: Console,
}

Is it possible for Console to be not Clone? I know I can wrap it in an Arc but there is no need for it to be clone.

Sytten commented 3 months ago

If I try to do:

    #[qjs(get)]
    pub fn console2(&self) -> &Console {
        &self.console
    }

I get:

the trait bound `&console::Console: rquickjs::IntoJs<'_>` is not satisfied
the trait `rquickjs::IntoJs<'_>` is implemented for `console::Console`
DelSkayn commented 3 months ago

It needs to be clone because on the JavaScript side it will be wrapped in an object. As the lifetime of these objects is completely unknown they need to own all the values they contain.

Suppose you have your Sdk object in the variable sdk and you do this.

globalThis.console = sdk.console2();
sdk = null;

The sdk is now freed and the console object would still be alive on the global object. if the console object contained a reference to the inside of the sdk object you end up with an invalid reference once the sdk object is garbage collected.

Sytten commented 3 months ago

That makes sense, is there a way to make Arc implement AsProperty? Essentially I am trying to see how we can avoid making copies of large objects, since the class is frozen it should be ok to allow an Arc.

Sytten commented 3 months ago

I guess it doesn't make sense because we can't prevent the object from being mutated on the JS side.