Skip to main content

nub_host_common/
rpc.rs

1//! Wire envelope for the host ↔ guest RPC.
2//!
3//! Both directions (host → guest function call, guest → host
4//! callback) use the same `Request` / `Response` shapes. The
5//! payload is opaque bytes — each `fn_id` defines its own inner
6//! codec (today: rkyv-archived domain types like
7//! `nub_arch_x86_abi::{InvocationSpec, InvocationResult}`).
8//!
9//! ## Wire layout
10//!
11//! Serializing a [`Request`] or [`Response`] with `rkyv::to_bytes`
12//! produces an `AlignedVec<u8>` that contains:
13//!
14//! 1. An archived `Request`/`Response` whose `payload` field is an
15//!    `ArchivedVec<u8>` (the bytes laid out inline).
16//! 2. The rkyv root pointer trailer (a relative offset + length).
17//!
18//! Readers run `rkyv::access::<ArchivedRequest, _>(&bytes)` (with
19//! bytecheck) and pull `archived.payload.as_ref() -> &[u8]` to
20//! reach the inner payload — zero allocation, single pointer cast
21//! plus the cheap bytecheck pass.
22//!
23//! Direction is encoded by which shared-memory ring the bytes live
24//! in (host's input vs output ring), not by the type.
25
26use alloc::string::String;
27use alloc::vec::Vec;
28
29/// Host → guest function call OR guest → host callback. The
30/// `payload` is opaque to the envelope: the fn_id selects what
31/// inner codec applies.
32#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize)]
33#[rkyv(derive(Debug))]
34pub struct Request {
35    /// Compile-time-assigned identifier for the target function.
36    /// Receiver matches on this to route to the right handler.
37    pub fn_id: u32,
38    /// Opaque payload bytes — the fn-specific codec lives inside.
39    pub payload: Vec<u8>,
40}
41
42/// Reply to a [`Request`]. `status == 0` means OK; non-zero is a
43/// receiver-defined error code with the human-readable detail in
44/// `error_msg` (mostly for debugging).
45///
46/// On OK, `payload` holds the function's archived return value.
47/// On error, `payload` is typically empty but the field is kept
48/// for symmetry / future use.
49#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize)]
50#[rkyv(derive(Debug))]
51pub struct Response {
52    /// 0 = ok; non-zero = error (handler-specific code).
53    pub status: u32,
54    /// Human-readable error detail on non-zero status.
55    pub error_msg: Option<String>,
56    /// Archived return-value bytes on success; empty on error.
57    pub payload: Vec<u8>,
58}
59
60impl Response {
61    /// Construct a success response with the given archived payload.
62    pub fn ok(payload: Vec<u8>) -> Self {
63        Self {
64            status: 0,
65            error_msg: None,
66            payload,
67        }
68    }
69
70    /// Construct an error response. `status` must be non-zero.
71    pub fn err(status: u32, msg: impl Into<String>) -> Self {
72        debug_assert!(status != 0, "Response::err with status=0 is OK, not error");
73        Self {
74            status,
75            error_msg: Some(msg.into()),
76            payload: Vec::new(),
77        }
78    }
79}