use crate::{Chunk, ChunkBuilder, Opcode};
const N_PRINT: u32 = 0;
const N_MAKE_MSG: u32 = 2;
const N_MSG_SENDER: u32 = 3;
const N_MSG_REQUEST_ID: u32 = 4;
const N_MSG_TAG: u32 = 5;
const N_MSG_PAYLOAD: u32 = 6;
pub const TAG_REQ: i32 = 1;
pub const TAG_REP: i32 = 2;
pub fn add_forty_two() -> Chunk {
let mut b = ChunkBuilder::new("add-forty-two");
b.begin_function("main", 0, 2);
b.emit_load_imm(0, 41);
b.emit_load_imm(1, 1);
b.emit_binop(Opcode::Add, 0, 0, 1);
b.emit_return(0);
b.finish()
}
pub fn ping_pong() -> Chunk {
let mut b = ChunkBuilder::new("ping-pong");
let pong = b.begin_function("pong", 0, 3);
b.emit_receive(0);
b.emit_receive(1);
b.emit_load_imm(2, 1);
b.emit_binop(Opcode::Add, 1, 1, 2);
b.emit_send(0, 1);
b.emit_exit(1);
b.begin_function("main", 0, 4);
b.emit_self_pid(1);
b.emit_spawn(0, pong, 0);
b.emit_send(0, 1);
b.emit_load_imm(2, 1);
b.emit_send(0, 2);
b.emit_receive(3);
b.emit_return(3);
b.finish()
}
pub fn atomic_request_reply() -> Chunk {
let mut b = ChunkBuilder::new("atomic-request-reply");
let server = b.begin_function("server", 0, 8);
b.emit_receive(0);
b.emit_move(7, 0);
b.emit_call_native(7, N_PRINT, 1);
b.emit_move(1, 0);
b.emit_call_native(1, N_MSG_SENDER, 1);
b.emit_move(2, 0);
b.emit_call_native(2, N_MSG_REQUEST_ID, 1);
b.emit_move(3, 0);
b.emit_call_native(3, N_MSG_TAG, 1);
b.emit_move(4, 0);
b.emit_call_native(4, N_MSG_PAYLOAD, 1);
b.emit_load_imm(7, 1);
b.emit_binop(Opcode::Add, 4, 4, 7);
b.emit_self_pid(5);
b.emit_move(7, 4);
b.emit_move(4, 5);
b.emit_move(5, 2);
b.emit_load_imm(6, TAG_REP);
b.emit_call_native(4, N_MAKE_MSG, 4);
b.emit_move(7, 4);
b.emit_call_native(7, N_PRINT, 1);
b.emit_send(1, 4);
b.emit_exit(4);
b.begin_function("main", 0, 8);
b.emit_self_pid(1);
b.emit_spawn(0, server, 0);
b.emit_move(2, 1);
b.emit_load_imm(3, 1);
b.emit_load_imm(4, TAG_REQ);
b.emit_load_imm(5, 41);
b.emit_call_native(2, N_MAKE_MSG, 4);
b.emit_move(7, 2);
b.emit_call_native(7, N_PRINT, 1);
b.emit_send(0, 2);
b.emit_receive(6);
b.emit_move(7, 6);
b.emit_call_native(7, N_PRINT, 1);
b.emit_move(4, 6);
b.emit_call_native(4, N_MSG_PAYLOAD, 1);
b.emit_return(4);
b.finish()
}
pub fn boom() -> Chunk {
let mut b = ChunkBuilder::new("boom");
b.begin_function("boom", 0, 1);
b.emit_trap(1);
b.finish()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
decode, encode, std_native_table, verify, ProcessOutcome, Runtime, RuntimeConfig, Value,
};
fn tiny(chunk: Chunk) -> Runtime {
Runtime::with_config(
chunk,
RuntimeConfig {
workers: 1,
quantum: 10_000,
},
)
.expect("runtime")
}
fn tiny_natives(chunk: Chunk) -> Runtime {
Runtime::with_natives_and_config(
chunk,
std_native_table(),
RuntimeConfig {
workers: 1,
quantum: 10_000,
},
)
.expect("runtime")
}
#[test]
fn add_forty_two_joins_42() {
let rt = tiny(add_forty_two());
let idx = rt.function_index("main").expect("main");
let outcome = rt.spawn(idx, &[]).expect("spawn").join();
rt.shutdown();
assert!(matches!(outcome, ProcessOutcome::Completed(Value::Int(42))));
}
#[test]
fn ping_pong_joins_2() {
let chunk = ping_pong();
assert!(verify(&chunk).is_ok());
let bytes = encode(&chunk);
let chunk = decode(&bytes).expect("decode");
let rt = tiny(chunk);
let idx = rt.function_index("main").expect("main");
let outcome = rt.spawn(idx, &[]).expect("spawn").join();
let sent = rt.metrics().messages_sent;
rt.shutdown();
assert!(matches!(outcome, ProcessOutcome::Completed(Value::Int(2))));
assert!(sent >= 2);
}
#[test]
fn atomic_request_reply_joins_42() {
let chunk = atomic_request_reply();
assert!(verify(&chunk).is_ok());
let bytes = encode(&chunk);
let chunk = decode(&bytes).expect("decode");
let rt = tiny_natives(chunk);
let idx = rt.function_index("main").expect("main");
let outcome = rt.spawn(idx, &[]).expect("spawn").join();
let sent = rt.metrics().messages_sent;
rt.shutdown();
assert!(
matches!(outcome, ProcessOutcome::Completed(Value::Int(42))),
"got {outcome:?}"
);
assert!(sent >= 1);
}
}