pub fn atomic_request_reply() -> ChunkExpand description
Atomic request-reply with crate::Value::Message (one envelope per hop).
Requires crate::std_native_table (make_msg / msg_* / print).
§Why “Atomic Hop”
Correlation (request_id) and reply routing (sender) travel in a
single mailbox value. Classic actor runtimes often allow any scalar
on Send; Byteflow rejects that ÔÇö every hop is a typed envelope.
§Protocol
mainspawnsserver, buildsMessage { id=1, tag=REQ, payload=41 }(sender placeholder ignored)serverreceives, logs viaprint, repliestag=REP, payload=42viamsg_reply_cap(echoingrequest_id)mainreturns the reply payload42
§Register discipline (CallNative clobbers r[a])
CallNative ra, , nc reads args from r[a..a+nc] and writes the
result into r[a]. Keeping the original Message in r0 therefore
means every unpack is Move ri, r0 then CallNative ri, msg_*, 1.
make_msg needs four contiguous arg registers; the server rearranges
into r4..r7 before the call.
Examples found in repository?
examples/atomic_actors.rs (line 22)
21fn main() {
22 let chunk = samples::atomic_request_reply();
23 let rt = match Runtime::with_natives_and_config(
24 chunk,
25 std_native_table(),
26 RuntimeConfig {
27 workers: 2,
28 quantum: 10_000,
29 mailbox: byteflow::MailboxConfig::DEFAULT,
30 },
31 ) {
32 Ok(rt) => rt,
33 Err(e) => {
34 eprintln!("runtime: {e}");
35 std::process::exit(1);
36 }
37 };
38 let Some(main) = rt.function_index("main") else {
39 eprintln!("missing main");
40 std::process::exit(1);
41 };
42 let handle = match rt.spawn(main, &[]) {
43 Ok(h) => h,
44 Err(e) => {
45 eprintln!("spawn: {e}");
46 std::process::exit(1);
47 }
48 };
49 let outcome = handle.join();
50 let metrics = rt.metrics();
51 rt.shutdown();
52
53 match outcome {
54 FlowOutcome::Completed(Value::Int(42)) => {
55 println!("atomic request-reply ok: payload=42");
56 println!("{metrics}");
57 }
58 other => {
59 eprintln!("unexpected {other:?}");
60 std::process::exit(1);
61 }
62 }
63}