▝▖▞▖▐▖█▖▖▖▞▖

3 min readalemi2024-07-26 15:02

▝▖▞▖▐▖█▖▖▖▞▖

▀▖░░▗▞▞▖▐▖▞▖▙▖▖▞▌▖▀▞░░▄▖█▖▞▞▙▖▖▖░░█▖▞▞▖▞░░▝▖▗▖█▖▞▞▖▞░░▖▖█▖▌▖▌▖▐▖█▖▖▖▞▖▌░░░▝▖░░▄▞▞▖▗▞▀▞░░░▞▗▞▞▖▖▞▖▞▀▞░░▞▖▙▖▐▖█▖▖▖▀▖▙▖▟▖░░▟▞▘▖▀▖▐▖▘▖░░▌▖█▖█▖▜▖▐▞░░▌▖▀▖▜▖▞▖░░▗▖▝▖▗▞▐▖█▖▖▖▞▖▐▞░░▝▖▙▖▖▖░░▐▖▝▖▙▖░░▗▖▞▖░░▖▖▀▖▐▞░▞▌▖▝▖▀▞▞▖▖▖░░▟▞▀▖▖▞▘▖░░▞▞▙▖▀▖▐▖█▖▖▖▞▖░░▗▖▌▖█▖▐▖▜▖▐▞▝░░░▟▞▘▖▀▖▌▖▞▖░░▀▖▖▞░░▌▖█▖█▖▜▖▐▞░░▐▞▞▞░▞▞▖▗▞░░▐▖█▖█▖▌▖░░▀▖▖▞▐▞░░░▞▗▞▀▖▛▖▝▖▗▞▀▖▌▖▀▞░░▖▞▘▖█▖▞▞▟▖▘▖▖▞░░▄▖█▖▗▞░░▙▖▞▞▛▖▗▖▞▖▗▞▐▞▌░░░▞▖▙▖▐▖█▖▖▖▀▖▙▖▟▖░░▖▞▞▖▘▞▖▞░░▟▞▀▖▖▞▘▖░░▀▖▖▞░░▀▖▐▞░░▜▖▀▖▙▖▖▖░░█▖▄▖░░▝▖▟▞▜▖▟▞▝▖▗▞▖▖▌░░░▐▖█▖▞▞▌▖▖▖░░▀▖░░▐▖█▖▛▖▞▖░░▞▞░▞░░▟▞▀▖▖▞▘▖░░▐▞█▖▛▖▞▖▖▞▘▖▀▖▙▖▟▖░░▛▖█▖▗▞▞▖░░▞▖▄▖▄▖▀▖▐▖▀▖▞▖▙▖▖▞█▝░░▖▖▞▖▄▖▀▖▙▖▀▖▖▞▞▖▌▖▀▞▌░░░▗▖▞▞▖▞░░▀▖▛▖░░▙▖█▖▖▞░░▗▞▞▖▝▖▌▖▌▖▀▞░░▟▖█▖█▖▖▖░░▝▖▖▞░░▖▞▘▖▀▖▐▞░░▐▞█▖░░▛▖▀▞░░▄▖▀▖▗▞▐▞▖▞░░▝▖▖▞▖▞▞▖▛▖░▞▖▞░░▀▖▐▞░░▝▖▞▖▐▖█▖▖▖▞▖▝░░░▝▖░░▐▞▖▞▞▞░▞▀▖▖▖░░▐▞▀▖▛▖░▞▌▖▞▖░░▝▖▙▖▖▖░░▄▞▀▖▐▞▞▞▝▖▌▖▌▖▀▞░░▛▖█▖▗▞▞▖░░▐▖█▖▛▖░▞▝▖▐▖▖▞░░▟▞▝▖▀▞░░▖▞█▖░░▞▖▙▖▐▖█▖▖▖▞▖░░▖▞▞▖▘▞▖▞▙░░░▛▖█▖▗▞▞▖░░▀▖▖▞▞▖▗▞▝▖▖▞▀▖█▖▙▖▐▞░░▖▞█▖░░▄▖█▖▌▖▌▖█▖▟▞▌░░░▗▖▞▞▖▞░░▀▖▙▖░░▖▞▘▖▞▖░░▛▖▞▖▝▖▙▖▖▞▀▖▛▖▞▖░░▘▖▞▖▗▞▞▖▐▞░░▝▖░░▖▖▞▖▐▖█▖▖▖▞▖▗▞░░▖▞█▖░░░▞▌▖▝▖▀▞░░▝▖▗▞█▖▞▞▙▖▖▖░░▝▖░░▗▖▀▖▖▞



▐▖▝▖▙▖░░▀▞█▖▞▞░░▄▖▀▖▟▖▞▞▗▞▞▖░░█▖▞▞▖▞░░▘▖█▖▟▞░░▖▞█▖░░▞▖▙▖▐▖█▖▖▖▞▖█▝

do you want to see how funny it is to deal with strings in wasm??
use std::ffi::{c_char, CString};

// global static muts because i want to watch the world burn
static mut IN: Option<Vec<u8>> = None;
static mut OUT: Option<CString> = None;
static mut SIZE: usize = 0;

#[no_mangle]
pub extern "C" fn encode() -> i32 {
	let Some(input) = get_string() else { return 0 };
	let out = aecode::encode(input.as_bytes());
	if set_string(&out) { 1 } else { 42 }
}

#[no_mangle]
pub extern "C" fn decode() -> i32 {
	let Some(input) = get_string() else { return 0 };
	let out = aecode::decode(input);
	let Ok(out_txt) = std::str::from_utf8(&out) else { return 999 };
	if set_string(out_txt) { 1 } else { 42 }
}

fn get_string() -> Option<&'static str> { // yeahh sure static...
	let txt = unsafe { IN.as_ref()? };
	let mut parsed = std::str::from_utf8(txt).ok()?;
	// get rid of trailing null byte because CString doesnt like it
	if parsed.ends_with('\0') {
		parsed = &parsed[..parsed.len()-1];
	}
	Some(parsed)
}

fn set_string(txt: &str) -> bool {
	let Ok(new) = CString::new(txt) else { return false };
	unsafe { SIZE = new.as_bytes().len() };
	if let Some(old) = unsafe { OUT.replace(new) } {
		drop(old);
	}
	true
}

#[no_mangle]
pub extern "C" fn ptr() -> *const c_char {
	match unsafe { OUT.as_ref() } {
		Some(cstr) => cstr.as_ptr(),
		None => std::ptr::null(),
	}
}

#[no_mangle]
pub extern "C" fn size() -> usize {
	unsafe { SIZE }
}

#[no_mangle]
pub extern "C" fn alloc(size: usize) -> *const u8 {
	let buffer = vec![0; size];
	let addr = buffer.as_ptr();
	if let Some(old) = unsafe { IN.replace(buffer) } {
		drop(old);
	}
	addr
}
let aecode = null;
fetch("https://cdn.alemi.dev/web/aecode.wasm")
    .then((response) => response.arrayBuffer())
    .then((bytes) => WebAssembly.instantiate(bytes))
    .then((results) => {
        aecode = results.instance;
    });

function into_wasm_string(txt) {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(txt);
    const ptr = aecode.exports.alloc(bytes.byteLength + 1);
    const buffer = new Uint8Array(aecode.exports.memory.buffer, ptr, bytes.byteLength + 1);
    buffer.set(bytes);
}

function from_wasm_string(offset, length) {
    const buffer = new Uint8Array(aecode.exports.memory.buffer, offset, length);
    const dec = new TextDecoder();
    return dec.decode(buffer);
}

function doit() {
    let input = document.getElementById("input").value;
    into_wasm_string(input);
    let res = aecode.exports.decode();
    let output = from_wasm_string(aecode.exports.ptr(), aecode.exports.size());
    document.getElementById("output").innerHTML = output;
}