Skip to content

__wrap not generated when only #[wasm_bindgen(constructor)] returns Self #4496

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

Open
Larkooo opened this issue Apr 30, 2025 · 0 comments
Open
Labels

Comments

@Larkooo
Copy link

Larkooo commented Apr 30, 2025

Describe the Bug

wasm-bindgen does not generate the static __wrap(ptr) method for a JavaScript class corresponding to a Rust struct if the only way instances are created is via a #[wasm_bindgen(constructor)] on the Rust side. This occurs even though the generated JavaScript class correctly manages the WASM pointer's lifetime using FinalizationRegistry and includes free() / __destroy_into_raw() methods.

The lack of __wrap seems inconsistent, as the generated JS class is fundamentally wrapping a WASM resource, regardless of whether instances are created solely via the constructor or also returned from other functions.

Steps to Reproduce

  1. Define a Rust struct and mark it with #[wasm_bindgen]:
    use wasm_bindgen::prelude::*;
    
    #[wasm_bindgen]
    pub struct MyThing {
        // internal data
    }
    
    #[wasm_bindgen]
    impl MyThing {
        #[wasm_bindgen(constructor)]
        pub fn new() -> Self {
            // Logic to create the thing
            MyThing { /* ... */ }
        }
    
        // Add some methods that use `&self` or `&mut self`
        #[wasm_bindgen]
        pub fn do_something(&self) {
            // ...
        }
    }
    
    // IMPORTANT: Do NOT add any other function like this:
    // #[wasm_bindgen]
    // pub fn get_a_thing() -> MyThing { /* ... */ }
  2. Compile the Rust code to WASM and generate JavaScript bindings using wasm-bindgen.
  3. Inspect the generated JavaScript file (e.g., my_module.js).
  4. Observe that the MyThing class in the JavaScript file is missing the static __wrap(ptr) method, although it will have free(), __destroy_into_raw(), and the corresponding FinalizationRegistry.

Expected Behavior

The generated JavaScript MyThing class should include the static __wrap(ptr) method. Its presence indicates that the class wraps a WASM pointer, which is true even if the only creation path is the constructor. The generation of lifetime management code (FinalizationRegistry, free) further implies that __wrap should logically be present.

Actual Behavior

The generated JavaScript MyThing class lacks the static __wrap(ptr) method.

Additional Context

This issue was encountered when creating bindings for a Provider struct in a Rust library. Instances were only ever created via #[wasm_bindgen(constructor)]. Other structs in the same library, which had functions returning instances (in addition to potentially having constructors), did have the __wrap method generated correctly.

Furthermore, generating __wrap consistently is beneficial in specific environments. For instance, in Unity WebGL builds, JavaScript object references might not persist reliably across certain engine events or callbacks. A common pattern is to use __destroy_into_raw() to obtain the raw WASM pointer (which can be stored as a simple number), and later use __wrap() to reconstruct the JavaScript wrapper object when it's needed again. The absence of __wrap prevents this manual lifetime management pattern for classes that only have a #[wasm_bindgen(constructor)].

A workaround is to add a dummy #[wasm_bindgen] function to the Rust impl block that simply returns Self or a clone, for example:

    #[wasm_bindgen]
    impl MyThing {
        // ... other methods ...

        // Dummy method to force __wrap generation
        #[wasm_bindgen(js_name = internalGetSelf)]
        pub fn internal_get_self(&self) -> Self {
             // Return self or a clone as appropriate
             MyThing { /* ... */ } // Or self.clone() if Clone is implemented
        }
    }

Adding this unnecessary function forces wasm-bindgen to generate the __wrap method in the JavaScript output. This suggests the generation logic for __wrap is currently tied only to non-constructor functions returning the type.

@Larkooo Larkooo added the bug label Apr 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant