rustwasm / book

The Rust and WebAssembly Book
https://rustwasm.github.io/docs/book/
MIT License
1.73k stars 208 forks source link

Can't build wasm at the 4.4 chapter #249

Open paadam94 opened 3 years ago

paadam94 commented 3 years ago

In foreword, I'm sorry if this is not the place for asking for help. I got this error, when I tried to build at the end of chapter 4.4 - rust implementation

[foo12@archT520 wasm-game-of-life]$ wasm-pack build
[INFO]: Checking for the Wasm target...
[INFO]: Compiling to Wasm...
   Compiling wasm-game-of-life v0.1.0 (/home/foo12/programs/rust/wasm-game-of-life)
error[E0277]: the trait bound `Universe: IntoWasmAbi` is not satisfied
  --> src/lib.rs:33:1
   |
33 | #[wasm_bindgen]
   | ^^^^^^^^^^^^^^^ the trait `IntoWasmAbi` is not implemented for `Universe`
   |
   = note: required because of the requirements on the impl of `ReturnWasmAbi` for `Universe`
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `wasm-game-of-life`

To learn more, run the command again with --verbose.
Error: Compiling your crate to WebAssembly failed
Caused by: failed to execute `cargo build`: exited with exit code: 101
  full command: "cargo" "build" "--lib" "--release" "--target" "wasm32-unknown-unknown"

lib.rs:

mod utils;

use std::fmt;

use wasm_bindgen::prelude::*;

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

#[wasm_bindgen]
extern {
    fn alert(s: &str);
}

#[wasm_bindgen]
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Cell {
    Dead = 0,
    Alive = 1,
}

pub struct Universe {
    width: u32,
    height: u32,
    cells: Vec<Cell>,
}

// Public methods, exported to JavaScript.
#[wasm_bindgen]
impl Universe {
    pub fn tick(&mut self) {
    let mut next = self.cells.clone();

    for row in 0..self.height {
        for col in 0..self.width {
        let idx = self.get_index(row, col);
        let cell = self.cells[idx];
        let live_neighbours = self.live_neighbour_count(row, col);

        let next_cell = match (cell, live_neighbours) {
            // Rule 1: Any live cell with fewer than two live neighbours
            // dies as if caused by underpopulation.
            (Cell::Alive, x) if x < 2 => Cell::Dead,
            // Rule 2: Any live cell with two or three live neighbours
            // lives on to the next generation.
            (Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive,
            // Rule 3: Any live cell with more than three live
            // neighbours dies, as if by overpopulation.
            (Cell::Alive, x) if x > 3 => Cell::Dead,
            // Rule 4: Any dead cell with exactly three live neighbours
            // becomes a live cell, as if by reproduction,
            (Cell::Dead, 3) => Cell::Alive,
            // All other cells remain in the same state.
            (otherwise, _) => otherwise,
        };

        next[idx] = next_cell;
        }
    }

        self.cells = next;
    }

    fn get_index(&self, row: u32, column: u32) -> usize {
    (row * self.width + column) as usize
    }

    fn live_neighbour_count(&self, row: u32, column: u32) -> u8 {
    let mut count = 0;
    for delta_row in [self.height - 1, 0, 1].iter().cloned() {
        for delta_col in [self.width -1, 0, 1].iter().cloned() {
        if delta_row == 0 && delta_col == 0 {
            continue;
        }

        let neighbour_row = (row + delta_row) % self.height;
        let neighbour_col = (column + delta_col) % self.width;
        let idx = self.get_index(neighbour_row, neighbour_col);
        count += self.cells[idx] as u8;
        }
    }
    count
    }

    pub fn new() -> Universe {
    let width = 64;
    let height = 64;

    let cells = (0..width * height)
        .map(|i| {
        if i % 2 == 0 || i % 7 == 0 {
            Cell::Alive
        } else {
            Cell::Dead
        }
        })
        .collect();

    Universe {
        width,
        height,
        cells,
    }
    }

    pub fn render(&self) -> String {
    self.to_string()
    }
}

impl fmt::Display for Universe {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    for line in self.cells.as_slice().chunks(self.width as usize) {
        for &cell in line {
        let symbol = if cell == Cell::Dead { '◻' } else { '◼' };
        write!(f, "{}", symbol)?;
        }
        write!(f, "\n")?;
    }

    Ok(())
    }
}

wasm-pack-build version - 0.9.1 rustc version - rustc 1.49.0 (e1884a8e3 2020-12-29)

jjant commented 3 years ago

Hey @paadam94 were you able to get this working? I'm stuck on the same thing.

apc518 commented 2 years ago

I figured it out @jjant @paadam94

I had a very similar issue, and when I reorganized my code to be the same as paadam's, I got the exact same error.

It turns out that both paadam and I forgot to include the #[wasm_bindgen] above the definition of the Universe struct.

So:


pub struct Universe {
    width: u32,
    height: u32,
    cells: Vec<Cell>,
}

needs to instead be

#[wasm_bindgen]
pub struct Universe {
    width: u32,
    height: u32,
    cells: Vec<Cell>,
}

with this change the error went away

This is actually in the book, but its snuck in there and easy to miss (as we all apparently did) image

Lazerbeak12345 commented 2 years ago

This is definitely the same issue as #265

Linking them to "link all the things"

eboody commented 1 year ago

@apc518 omg i love you. this is one of those learning moments where ill run into something similar in the future and know how to handle it even though the error wasnt very clear!

saku-koodari commented 1 year ago

I also have this issue. For some reason the frontend (www) can't refer to wasm properly. My workaround is to refer to the pkg directly in my index.js

import { Universe, Cell } from "../pkg";