Working with char - The `wasm-bindgen` Guide

# Working with the `char` type

View full source code or view the compiled example online

The `#[wasm_bindgen]` macro will convert the rust `char` type to a single code-point js `string`, and this example shows how to work with this.

Opening this example should display a single counter with a random character for it's `key` and 0 for its `count`. You can click the `+` button to increase a counter's count. By clicking on the "add counter" button you should see a new counter added to the list with a different random character for it's `key`.

Under the hood javascript is choosing a random character from an Array of characters and passing that to the rust Counter struct's constructor so the character you are seeing on the page has made the full round trip from js to rust and back to js.

## `src/lib.rs`

    #![allow(unused)]
    fn main() {
    use wasm_bindgen::prelude::*;

    // lifted from the `console_log` example
    #[wasm_bindgen]
    extern "C" {
        #[wasm_bindgen(js_namespace = console)]
        fn log(s: &str);
    }

    #[wasm_bindgen]
    #[derive(Debug)]
    pub struct Counter {
        key: char,
        count: i32,
    }

    #[wasm_bindgen]
    impl Counter {
        pub fn new(key: char, count: i32) -> Counter {
            log(&format!("Counter::new({}, {})", key, count));
            Counter { key, count }
        }

        pub fn key(&self) -> char {
            log("Counter.key()");
            self.key
        }

        pub fn count(&self) -> i32 {
            log("Counter.count");
            self.count
        }

        pub fn increment(&mut self) {
            log("Counter.increment");
            self.count += 1;
        }

        pub fn update_key(&mut self, key: char) {
            self.key = key;
        }
    }
    }

## `index.js`

    /* eslint-disable no-unused-vars */
    import { chars } from './chars-list.js';
    let imp = import('./pkg');
    let mod;

    let counters = [];
    imp
      .then(wasm => {
          mod = wasm;
          addCounter();
          let b = document.getElementById('add-counter');
          if (!b) throw new Error('Unable to find #add-counter');
          b.addEventListener('click', ev => addCounter());
      })
      .catch(console.error);

    function addCounter() {
        let ctr = mod.Counter.new(randomChar(), 0);
        counters.push(ctr);
        update();
    }

    function update() {
        let container = document.getElementById('container');
        if (!container) throw new Error('Unable to find #container in dom');
        while (container.hasChildNodes()) {
            if (container.lastChild.id == 'add-counter') break;
            container.removeChild(container.lastChild);
        }
        for (var i = 0; i < counters.length; i++) {
            let counter = counters[i];
            container.appendChild(newCounter(counter.key(), counter.count(), ev => {
                counter.increment();
                update();
            }));
        }
    }

    function randomChar() {
        console.log('randomChar');
        let idx = Math.floor(Math.random() * (chars.length - 1));
        console.log('index', idx);
        let ret = chars.splice(idx, 1)[0];
        console.log('char', ret);
        return ret;
    }

    function newCounter(key, value, cb) {
        let container = document.createElement('div');
        container.setAttribute('class', 'counter');
        let title = document.createElement('h1');
        title.appendChild(document.createTextNode('Counter ' + key));
        container.appendChild(title);
        container.appendChild(newField('Count', value));
        let plus = document.createElement('button');
        plus.setAttribute('type', 'button');
        plus.setAttribute('class', 'plus-button');
        plus.appendChild(document.createTextNode('+'));
        plus.addEventListener('click', cb);
        container.appendChild(plus);
        return container;
    }

    function newField(key, value) {
        let ret = document.createElement('div');
        ret.setAttribute('class', 'field');
        let name = document.createElement('span');
        name.setAttribute('class', 'name');
        name.appendChild(document.createTextNode(key));
        ret.appendChild(name);
        let val = document.createElement('span');
        val.setAttribute('class', 'value');
        val.appendChild(document.createTextNode(value));
        ret.appendChild(val);
        return ret;
    }