[WASM] Access WebAssembly Memory Directly from JavaScript

While JavaScript has a garbage-collected heap, WebAssembly has a linear memory space. Nevertheless using a JavaScript ArrayBuffer, we can read and write to WebAssembly’s memory space.

lib.rs:

#[macro_use]
extern crate cfg_if;

extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

cfg_if! {
    // When the `console_error_panic_hook` feature is enabled, we can call the
    // `set_panic_hook` function to get better error messages if we ever panic.
    if #[cfg(feature = "console_error_panic_hook")] {
        extern crate console_error_panic_hook;
        use console_error_panic_hook::set_once as set_panic_hook;
    }
}

cfg_if! {
    // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
    // allocator.
    if #[cfg(feature = "wee_alloc")] {
        extern crate wee_alloc;
        #[global_allocator]
        static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
    }
}

// Definitions of the functionality available in JS, which wasm-bindgen will
// generate shims for today (and eventually these should be near-0 cost!)
//
// These definitions need to be hand-written today but the current vision is
// that we'll use WebIDL to generate this `extern` block into a crate which you
// can link and import. There's a tracking issue for this at
// https://github.com/rustwasm/wasm-bindgen/issues/42
//
// In the meantime these are written out by hand and correspond to the names and
// signatures documented on MDN, for example
#[wasm_bindgen]
extern "C" {
    type HTMLDocument;
    static document: HTMLDocument;
    #[wasm_bindgen(method)]
    fn createElement(this: &HTMLDocument, tagName: &str) -> Element;
    #[wasm_bindgen(method, getter)]
    fn body(this: &HTMLDocument) -> Element;

    type Element;
    #[wasm_bindgen(method, setter = innerHTML)]
    fn set_inner_html(this: &Element, html: &str);
    #[wasm_bindgen(method, js_name = appendChild)]
    fn append_child(this: &Element, other: Element);
    #[wasm_bindgen(js_namespace = console)]
    fn log(msg: &str);
}

macro_rules! log {
    ($($t:tt)*) => (log(&format!($($t)*)))
}
View Code
#[wasm_bindgen]
pub struct Color {
    red: u8,
    green: u8,
    blue: u8,
}

#[wasm_bindgen]
pub struct Image {
    pixels: Vec<Color>,
}

#[wasm_bindgen]
impl Image {
    pub fn new() -> Image {
        let color1 = Color {
            red: 255,
            green: 0,
            blue: 0,
        };
        let color2 = Color {
            red: 60,
            green: 70,
            blue: 90,
        };
        let pixels = vec![color1, color2];
        Image {
            pixels
        }
    }

    pub fn pixels_ptr(&self) -> *const Color {
        self.pixels.as_ptr()
    }
}

We create a Image object, which has two functions, new() and pixels_ptr() which can be called by javascript. new() is a constructor function, pixels_ptr() is a instant method.

app.js:

import { memory } from "../crate/pkg/rust_webpack_bg";
import { Image } from "../crate/pkg/rust_webpack";

const image = Image.new();
const pixelsPointer = image.pixels_ptr();
const pixels = new Uint8Array(memory.buffer, pixelsPointer, 6);
console.log(pixels);

function numToHex(value) {
    const hex = value.toString(16);
    return hex.length === 1 ? `0${hex}` : hex;
  }
  
  function drawPixel(x, y, color) {
    const ctx = canvas.getContext("2d");
    ctx.fillStyle = `#${numToHex(color[0])}${numToHex(color[1])}${numToHex(
      color[2]
    )}`;
    ctx.fillRect(x, y, 100, 100);
  }
  
  const canvas = document.createElement("canvas");
  document.body.appendChild(canvas);
  drawPixel(0, 0, pixels.slice(0, 3));
  drawPixel(100, 0, pixels.slice(3, 6));

猜你喜欢

转载自www.cnblogs.com/Answer1215/p/9919993.html