use nox::noun::{Order, NounId};
use super::{CompileError, formula_parts, body_pair, body_triple, atom_u64, axis_to_param,
detect_loop_setup, detect_back_edge};
const P: u64 = 0xFFFF_FFFF_0000_0001;
const OP_UNREACHABLE: u8 = 0x00;
const OP_IF: u8 = 0x04;
const OP_ELSE: u8 = 0x05;
const OP_END: u8 = 0x0B;
const OP_CALL: u8 = 0x10;
const OP_LOCAL_GET: u8 = 0x20;
const OP_LOCAL_SET: u8 = 0x21;
const OP_LOCAL_TEE: u8 = 0x22;
const OP_I64_CONST: u8 = 0x42;
const OP_I64_EQZ: u8 = 0x50;
const OP_I64_EQ: u8 = 0x51;
const OP_I64_LT_U: u8 = 0x53;
const OP_I64_GE_U: u8 = 0x57;
const OP_I64_ADD: u8 = 0x7C;
const OP_I64_SUB: u8 = 0x7D;
const OP_I64_MUL: u8 = 0x7E;
const OP_I64_AND: u8 = 0x83;
const OP_I64_XOR: u8 = 0x85;
const OP_I64_SHL: u8 = 0x86;
const OP_I64_SHR_U: u8 = 0x88;
const OP_I64_EXTEND_I32_U: u8 = 0xAD;
const SEC_TYPE: u8 = 1;
const SEC_FUNCTION: u8 = 3;
const SEC_EXPORT: u8 = 7;
const SEC_CODE: u8 = 10;
const TYPE_I64: u8 = 0x7E;
const TYPE_FUNC: u8 = 0x60;
pub fn compile_to_wasm<const N: usize>(
order: &Order<N>,
formula: NounId,
num_params: u32,
) -> Result<Vec<u8>, CompileError> {
let mut emitter = FormulaEmitter::new(num_params);
emitter.emit_formula(order, formula)?;
Ok(build_module(num_params, emitter))
}
#[derive(Clone)]
struct LoopState {
carried: Vec<u32>,
formula_local: u32,
}
struct FormulaEmitter {
num_params: u32,
num_locals: u32,
code: Vec<u8>,
subject: Vec<u32>,
loop_locals: Option<LoopState>,
}
impl FormulaEmitter {
fn new(num_params: u32) -> Self {
let subject = (0..num_params).rev().collect();
Self { num_params, num_locals: 0, code: Vec::with_capacity(256), subject, loop_locals: None }
}
fn alloc_local(&mut self) -> u32 {
let idx = self.num_params + self.num_locals;
self.num_locals += 1;
idx
}
fn emit_formula<const N: usize>(&mut self, order: &Order<N>, formula: NounId) -> Result<(), CompileError> {
let (tag, body) = formula_parts(order, formula)?;
match tag {
0 => self.emit_axis(order, body),
1 => self.emit_quote(order, body),
2 => self.emit_compose(order, body),
4 => self.emit_branch(order, body),
5 => self.emit_add(order, body),
6 => self.emit_sub(order, body),
7 => self.emit_mul(order, body),
9 => self.emit_eq(order, body),
10 => self.emit_lt(order, body),
11 => self.emit_xor(order, body),
12 => self.emit_and(order, body),
13 => self.emit_not(order, body),
14 => self.emit_shl(order, body),
_ => Err(CompileError::UnsupportedPattern(tag)),
}
}
fn emit_axis<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let addr = atom_u64(order, body)?;
let depth = axis_to_param(addr)?;
if (depth as usize) >= self.subject.len() {
return Err(CompileError::NoParams);
}
let local_idx = self.subject[depth as usize];
self.code.push(OP_LOCAL_GET);
leb128_u32(&mut self.code, local_idx);
Ok(())
}
fn emit_compose<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
if let Some((loop_body, inits)) = detect_loop_setup(order, body) {
return self.emit_loop(order, loop_body, &inits);
}
if let Some((new_subj, _axis)) = detect_back_edge(order, body) {
return self.emit_back_edge(order, new_subj);
}
let (a_formula, b_formula) = body_pair(order, body)?;
let (a_tag, a_body) = formula_parts(order, a_formula)?;
if a_tag != 3 { return Err(CompileError::UnsupportedPattern(2)); }
let (value_formula, identity) = body_pair(order, a_body)?;
let (id_tag, id_body) = formula_parts(order, identity)?;
if id_tag != 0 || atom_u64(order, id_body)? != 1 {
return Err(CompileError::UnsupportedPattern(2));
}
let (b_tag, body_formula) = formula_parts(order, b_formula)?;
if b_tag != 1 { return Err(CompileError::UnsupportedPattern(2)); }
self.emit_formula(order, value_formula)?;
let local = self.alloc_local();
self.code.push(OP_LOCAL_SET);
leb128_u32(&mut self.code, local);
self.subject.insert(0, local);
let result = self.emit_formula(order, body_formula);
self.subject.remove(0);
result
}
fn emit_loop<const N: usize>(
&mut self, order: &Order<N>, loop_body: NounId, inits: &[NounId],
) -> Result<(), CompileError> {
let num_carried = inits.len() as u32;
let formula_local = self.alloc_local(); let mut carried_locals = Vec::new();
for _ in 0..num_carried {
carried_locals.push(self.alloc_local());
}
for (i, &init) in inits.iter().enumerate() {
self.emit_formula(order, init)?;
self.code.push(OP_LOCAL_SET);
leb128_u32(&mut self.code, carried_locals[i]);
}
self.code.push(OP_I64_CONST);
leb128_i64(&mut self.code, 0);
self.code.push(OP_LOCAL_SET);
leb128_u32(&mut self.code, formula_local);
let saved_subject = self.subject.clone();
for &cl in carried_locals.iter() {
self.subject.insert(0, cl);
}
self.subject.insert(0, formula_local);
let prev_loop = self.loop_locals.take();
self.loop_locals = Some(LoopState {
carried: carried_locals.clone(),
formula_local,
});
self.code.push(0x02); self.code.push(TYPE_I64); self.code.push(0x03); self.code.push(0x40);
self.emit_formula(order, loop_body)?;
self.code.push(0x0C); leb128_u32(&mut self.code, 1);
self.code.push(OP_END); self.code.push(OP_END);
self.loop_locals = prev_loop;
self.subject = saved_subject;
Ok(())
}
fn emit_back_edge<const N: usize>(
&mut self, order: &Order<N>, new_subj_formula: NounId,
) -> Result<(), CompileError> {
let ls = self.loop_locals.as_ref()
.ok_or(CompileError::UnsupportedPattern(2))?
.clone();
let (tag, cons_body) = formula_parts(order, new_subj_formula)?;
if tag != 3 { return Err(CompileError::UnsupportedPattern(2)); }
let (_formula_ref, rest) = body_pair(order, cons_body)?;
let mut cur = rest;
for (i, &local) in ls.carried.iter().enumerate() {
let (tag, cb) = formula_parts(order, cur)?;
if tag != 3 {
break;
}
let (val_formula, tail) = body_pair(order, cb)?;
self.emit_formula(order, val_formula)?;
self.code.push(OP_LOCAL_SET);
leb128_u32(&mut self.code, local);
cur = tail;
}
self.code.push(0x0C); leb128_u32(&mut self.code, 0);
self.code.push(OP_UNREACHABLE);
Ok(())
}
fn emit_quote<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let val = atom_u64(order, body)?;
self.code.push(OP_I64_CONST);
leb128_i64(&mut self.code, val as i64);
Ok(())
}
fn emit_branch<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let (test, yes, no) = body_triple(order, body)?;
self.emit_formula(order, test)?;
self.code.push(OP_I64_EQZ);
self.code.push(OP_IF);
self.code.push(TYPE_I64);
self.emit_formula(order, yes)?;
self.code.push(OP_ELSE);
self.emit_formula(order, no)?;
self.code.push(OP_END);
Ok(())
}
fn emit_add<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let (a, b) = body_pair(order, body)?;
let la = self.alloc_local();
let lb = self.alloc_local();
let ls = self.alloc_local();
self.emit_formula(order, a)?;
self.code.push(OP_LOCAL_SET); leb128_u32(&mut self.code, la);
self.emit_formula(order, b)?;
self.code.push(OP_LOCAL_SET); leb128_u32(&mut self.code, lb);
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, la);
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, lb);
self.code.push(OP_I64_ADD);
self.code.push(OP_LOCAL_TEE); leb128_u32(&mut self.code, ls);
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, la);
self.code.push(OP_I64_LT_U);
self.code.push(OP_IF); self.code.push(TYPE_I64);
{
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, ls);
self.code.push(OP_I64_CONST); leb128_i64(&mut self.code, 0xFFFF_FFFF);
self.code.push(OP_I64_ADD);
self.code.push(OP_LOCAL_TEE); leb128_u32(&mut self.code, ls);
self.emit_reduce(ls);
}
self.code.push(OP_ELSE);
{
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, ls);
self.emit_reduce(ls);
}
self.code.push(OP_END);
Ok(())
}
fn emit_sub<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let (a, b) = body_pair(order, body)?;
let la = self.alloc_local();
let lb = self.alloc_local();
self.emit_formula(order, a)?;
self.code.push(OP_LOCAL_SET); leb128_u32(&mut self.code, la);
self.emit_formula(order, b)?;
self.code.push(OP_LOCAL_SET); leb128_u32(&mut self.code, lb);
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, la);
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, lb);
self.code.push(OP_I64_GE_U);
self.code.push(OP_IF); self.code.push(TYPE_I64);
{
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, la);
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, lb);
self.code.push(OP_I64_SUB);
}
self.code.push(OP_ELSE);
{
self.code.push(OP_I64_CONST); leb128_i64(&mut self.code, P as i64);
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, lb);
self.code.push(OP_I64_SUB);
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, la);
self.code.push(OP_I64_ADD);
}
self.code.push(OP_END);
Ok(())
}
fn emit_mul<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let (a, b) = body_pair(order, body)?;
self.emit_formula(order, a)?;
self.emit_formula(order, b)?;
self.code.push(OP_CALL);
leb128_u32(&mut self.code, 0);
Ok(())
}
fn emit_eq<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let (a, b) = body_pair(order, body)?;
self.emit_formula(order, a)?;
self.emit_formula(order, b)?;
self.code.push(OP_I64_EQ);
self.code.push(OP_I64_EXTEND_I32_U);
self.code.push(OP_I64_CONST); leb128_i64(&mut self.code, 1);
self.code.push(OP_I64_XOR);
Ok(())
}
fn emit_lt<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let (a, b) = body_pair(order, body)?;
self.emit_formula(order, a)?;
self.emit_formula(order, b)?;
self.code.push(OP_I64_LT_U);
self.code.push(OP_I64_EXTEND_I32_U);
self.code.push(OP_I64_CONST); leb128_i64(&mut self.code, 1);
self.code.push(OP_I64_XOR);
Ok(())
}
fn emit_xor<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let (a, b) = body_pair(order, body)?;
self.emit_formula(order, a)?;
self.emit_formula(order, b)?;
self.code.push(OP_I64_XOR);
Ok(())
}
fn emit_and<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let (a, b) = body_pair(order, body)?;
self.emit_formula(order, a)?;
self.emit_formula(order, b)?;
self.code.push(OP_I64_AND);
Ok(())
}
fn emit_not<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
self.emit_formula(order, body)?;
self.code.push(OP_I64_CONST); leb128_i64(&mut self.code, 0xFFFF_FFFF);
self.code.push(OP_I64_XOR);
Ok(())
}
fn emit_shl<const N: usize>(&mut self, order: &Order<N>, body: NounId) -> Result<(), CompileError> {
let (a, b) = body_pair(order, body)?;
self.emit_formula(order, a)?;
self.emit_formula(order, b)?;
self.code.push(OP_I64_SHL);
self.code.push(OP_I64_CONST); leb128_i64(&mut self.code, 0xFFFF_FFFF);
self.code.push(OP_I64_AND);
Ok(())
}
fn emit_reduce(&mut self, lv: u32) {
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, lv);
self.code.push(OP_I64_CONST); leb128_i64(&mut self.code, P as i64);
self.code.push(OP_I64_GE_U);
self.code.push(OP_IF); self.code.push(TYPE_I64);
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, lv);
self.code.push(OP_I64_CONST); leb128_i64(&mut self.code, P as i64);
self.code.push(OP_I64_SUB);
self.code.push(OP_ELSE);
self.code.push(OP_LOCAL_GET); leb128_u32(&mut self.code, lv);
self.code.push(OP_END);
}
}
fn emit_goldilocks_mul() -> (Vec<u8>, u32) {
let mut c = Vec::with_capacity(200);
let num_locals: u32 = 9;
let mask32: i64 = 0xFFFF_FFFF;
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 0);
c.push(OP_I64_CONST); leb128_i64(&mut c, mask32);
c.push(OP_I64_AND);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 2);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 0);
c.push(OP_I64_CONST); leb128_i64(&mut c, 32);
c.push(OP_I64_SHR_U);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 3);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 1);
c.push(OP_I64_CONST); leb128_i64(&mut c, mask32);
c.push(OP_I64_AND);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 4);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 1);
c.push(OP_I64_CONST); leb128_i64(&mut c, 32);
c.push(OP_I64_SHR_U);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 5);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 2);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 4);
c.push(OP_I64_MUL);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 6);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 3);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 5);
c.push(OP_I64_MUL);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 7);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 3);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 4);
c.push(OP_I64_MUL);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 8);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 7);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 8);
c.push(OP_I64_CONST); leb128_i64(&mut c, 32);
c.push(OP_I64_SHR_U);
c.push(OP_I64_ADD);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 7);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 6);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 8);
c.push(OP_I64_CONST); leb128_i64(&mut c, mask32);
c.push(OP_I64_AND);
c.push(OP_I64_CONST); leb128_i64(&mut c, 32);
c.push(OP_I64_SHL);
c.push(OP_I64_ADD);
c.push(OP_LOCAL_TEE); leb128_u32(&mut c, 9);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 6);
c.push(OP_I64_LT_U);
c.push(OP_IF); c.push(0x40); c.push(OP_LOCAL_GET); leb128_u32(&mut c, 7);
c.push(OP_I64_CONST); leb128_i64(&mut c, 1);
c.push(OP_I64_ADD);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 7);
c.push(OP_END);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 9);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 6);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 2);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 5);
c.push(OP_I64_MUL);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 8);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 7);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 8);
c.push(OP_I64_CONST); leb128_i64(&mut c, 32);
c.push(OP_I64_SHR_U);
c.push(OP_I64_ADD);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 7);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 6);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 8);
c.push(OP_I64_CONST); leb128_i64(&mut c, mask32);
c.push(OP_I64_AND);
c.push(OP_I64_CONST); leb128_i64(&mut c, 32);
c.push(OP_I64_SHL);
c.push(OP_I64_ADD);
c.push(OP_LOCAL_TEE); leb128_u32(&mut c, 9);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 6);
c.push(OP_I64_LT_U);
c.push(OP_IF); c.push(0x40);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 7);
c.push(OP_I64_CONST); leb128_i64(&mut c, 1);
c.push(OP_I64_ADD);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 7);
c.push(OP_END);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 9);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 6);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 6);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 10);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 7);
c.push(OP_I64_CONST); leb128_i64(&mut c, 32);
c.push(OP_I64_SHL);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 9);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 10);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 9);
c.push(OP_I64_ADD);
c.push(OP_LOCAL_TEE); leb128_u32(&mut c, 10);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 6);
c.push(OP_I64_LT_U);
c.push(OP_IF); c.push(0x40);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 10);
c.push(OP_I64_CONST); leb128_i64(&mut c, mask32);
c.push(OP_I64_ADD);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 10);
c.push(OP_END);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 10);
c.push(OP_LOCAL_TEE); leb128_u32(&mut c, 9); c.push(OP_LOCAL_GET); leb128_u32(&mut c, 7);
c.push(OP_I64_SUB);
c.push(OP_LOCAL_TEE); leb128_u32(&mut c, 10);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 9);
c.push(OP_I64_GT_U);
c.push(OP_IF); c.push(0x40);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 10);
c.push(OP_I64_CONST); leb128_i64(&mut c, mask32);
c.push(OP_I64_SUB);
c.push(OP_LOCAL_SET); leb128_u32(&mut c, 10);
c.push(OP_END);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 10);
c.push(OP_I64_CONST); leb128_i64(&mut c, P as i64);
c.push(OP_I64_GE_U);
c.push(OP_IF); c.push(TYPE_I64);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 10);
c.push(OP_I64_CONST); leb128_i64(&mut c, P as i64);
c.push(OP_I64_SUB);
c.push(OP_ELSE);
c.push(OP_LOCAL_GET); leb128_u32(&mut c, 10);
c.push(OP_END);
(c, num_locals)
}
const OP_I64_GT_U: u8 = 0x55;
fn build_module(num_params: u32, formula: FormulaEmitter) -> Vec<u8> {
let mut out = Vec::with_capacity(512);
out.extend_from_slice(b"\0asm");
out.extend_from_slice(&1u32.to_le_bytes());
{
let mut body = Vec::new();
leb128_u32(&mut body, 2);
body.push(TYPE_FUNC);
leb128_u32(&mut body, 2);
body.push(TYPE_I64); body.push(TYPE_I64);
leb128_u32(&mut body, 1);
body.push(TYPE_I64);
body.push(TYPE_FUNC);
leb128_u32(&mut body, num_params);
for _ in 0..num_params { body.push(TYPE_I64); }
leb128_u32(&mut body, 1);
body.push(TYPE_I64);
out.push(SEC_TYPE);
leb128_u32(&mut out, body.len() as u32);
out.extend_from_slice(&body);
}
{
let mut body = Vec::new();
leb128_u32(&mut body, 2);
leb128_u32(&mut body, 0); leb128_u32(&mut body, 1);
out.push(SEC_FUNCTION);
leb128_u32(&mut out, body.len() as u32);
out.extend_from_slice(&body);
}
{
let mut body = Vec::new();
leb128_u32(&mut body, 1);
leb128_u32(&mut body, 4);
body.extend_from_slice(b"main");
body.push(0x00);
leb128_u32(&mut body, 1);
out.push(SEC_EXPORT);
leb128_u32(&mut out, body.len() as u32);
out.extend_from_slice(&body);
}
{
let (mul_code, mul_locals) = emit_goldilocks_mul();
let mut func0 = Vec::new();
if mul_locals > 0 {
leb128_u32(&mut func0, 1);
leb128_u32(&mut func0, mul_locals);
func0.push(TYPE_I64);
} else {
leb128_u32(&mut func0, 0);
}
func0.extend_from_slice(&mul_code);
func0.push(OP_END);
let mut func1 = Vec::new();
if formula.num_locals > 0 {
leb128_u32(&mut func1, 1);
leb128_u32(&mut func1, formula.num_locals);
func1.push(TYPE_I64);
} else {
leb128_u32(&mut func1, 0);
}
func1.extend_from_slice(&formula.code);
func1.push(OP_END);
let mut section = Vec::new();
leb128_u32(&mut section, 2); leb128_u32(&mut section, func0.len() as u32);
section.extend_from_slice(&func0);
leb128_u32(&mut section, func1.len() as u32);
section.extend_from_slice(&func1);
out.push(SEC_CODE);
leb128_u32(&mut out, section.len() as u32);
out.extend_from_slice(§ion);
}
out
}
fn leb128_u32(buf: &mut Vec<u8>, mut val: u32) {
loop {
let byte = (val & 0x7F) as u8;
val >>= 7;
if val == 0 { buf.push(byte); break; }
buf.push(byte | 0x80);
}
}
fn leb128_i64(buf: &mut Vec<u8>, mut val: i64) {
loop {
let byte = (val & 0x7F) as u8;
val >>= 7;
if (val == 0 && byte & 0x40 == 0) || (val == -1 && byte & 0x40 != 0) {
buf.push(byte); break;
}
buf.push(byte | 0x80);
}
}