dcre-native 0.1.0

High-performance Rust core for DCRE Mesh
Documentation
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]
pub struct Lattice {
    width: u32,
    height: u32,
    cells: Vec<u8>,
    modulus: u8,
}

#[wasm_bindgen]
impl Lattice {
    #[wasm_bindgen(constructor)]
    pub fn new(width: u32, height: u32, modulus: u8) -> Lattice {
        // Initialize with zeros
        let cells = vec![0; (width * height) as usize];
        Lattice {
            width,
            height,
            cells,
            modulus,
        }
    }

    pub fn width(&self) -> u32 {
        self.width
    }

    pub fn height(&self) -> u32 {
        self.height
    }

    pub fn modulus(&self) -> u8 {
        self.modulus
    }

    /// Access memory directly from JS for zero-copy
    pub fn cells_ptr(&self) -> *const u8 {
        self.cells.as_ptr()
    }

    pub fn get(&self, row: u32, col: u32) -> u8 {
        self.cells[(row * self.width + col) as usize]
    }

    pub fn set(&mut self, row: u32, col: u32, value: u8) {
        self.cells[(row * self.width + col) as usize] = value % self.modulus;
    }

    /// Optimized Lattice Evolution
    /// 
    /// Applies the DCRE matrix [[2, 1], [1, 1]] to 2x2 blocks in a checkerboard pattern.
    /// This implementation is single-threaded O(N^2) but allocation-free.
    pub fn evolve(&mut self) {
        let width = self.width;
        let modulus = self.modulus as u16; // Use u16 to prevent overflow during calc

        // Phase 1: Even blocks (0,0), (0,2)...
        for r in (0..width).step_by(2) {
            for c in (0..width).step_by(2) {
                self.apply_block(r, c, modulus);
            }
        }

        // Phase 2: Odd blocks (1,1), (1,3)...
        for r in (1..width).step_by(2) {
            for c in (1..width).step_by(2) {
                self.apply_block(r, c, modulus);
            }
        }
    }

    #[inline(always)]
    fn apply_block(&mut self, r: u32, c: u32, modulus: u16) {
        let w = self.width;
        
        // Wrap coordinates (Toroidal topology)
        let r1 = (r + 1) % w;
        let c1 = (c + 1) % w;

        // Indices
        let i_a = (r * w + c) as usize;
        let i_b = (r * w + c1) as usize;
        let i_c = (r1 * w + c) as usize;
        let i_d = (r1 * w + c1) as usize;

        // Load values
        let a = self.cells[i_a] as u16;
        let b = self.cells[i_b] as u16;
        let cc = self.cells[i_c] as u16; // 'cc' because 'c' is column
        let d = self.cells[i_d] as u16;

        // Matrix Multiply:
        // [new_a, new_b]   [2 1] [a b]   [2a+b   a+b]
        // [new_c, new_d] = [1 1] [c d] = [2c+d   c+d]
        
        self.cells[i_a] = ((2 * a + b) % modulus) as u8;
        self.cells[i_b] = ((a + b) % modulus) as u8;
        self.cells[i_c] = ((2 * cc + d) % modulus) as u8;
        self.cells[i_d] = ((cc + d) % modulus) as u8;
    }
}