wasm-bindgen icon indicating copy to clipboard operation
wasm-bindgen copied to clipboard

Proposal: Use Symbol for trait impls

Open KSXGitHub opened this issue 4 years ago • 6 comments

Motivation

Currently, #[wasm_bindgen] cannot be applied to trait impls, I guess this is to avoid method name collision? If that is the case, then JavaScript Symbol is a perfect solution for this.

Proposed Solution

Convert trait methods to JavaScript methods with symbols for names, and trait names can be converted to a namespace object of symbols. For example:

This code:

// src/lib.rs
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct Foo {
    value: i32,
}

#[wasm_bindgen]
impl Foo {
    #[wasm_bindgen(constructor)]
    pub fn new(value: i32) -> Self {
        Foo { value }
    }

    #[wasm_bindgen]
    pub fn read(&self) -> i32 {
        self.value
    }
}

#[wasm_bingen]
trait Read {
    fn read(&self) -> i32;
}

#[wasm_bindgen]
impl Read for Foo {
    #[wasm_bindgen]
    fn read(&self) -> i32 {
        self.value
    }
}

can be converted to this TypeScript declaration:

// from Read trait in the Rust source
// all Rust structs that impl Read trait will be converted to TypeScript classes that implements Read interface
export interface Read {
  // from Read::read in the Rust source
  [Read.read](this: this): number
}

// from Read trait in the Rust source
// namespaces in TypeScript are just objects in JavaScript
export declare namespace Read {
  // from Read::read in the Rust source
  const read: unique symbol;
  type read = typeof read;
}

export declare class Foo implements Read {
  public constructor(value: number);
  public read(this: Foo): number;

  // from Read::read in the Rust source
  public [Read.read](this: this): number;
}

[!NOTE] In the JavaScript glue code, Read object must always be created before class Foo.

Alternatives

Additional Context

KSXGitHub avatar Apr 07 '20 04:04 KSXGitHub