Expand description
§Owned frames (experimental)
The owned-frame family (owned-frame-transport) exchanges whole
validated frames as owned values — and, the headline it earns over
the UTransport family: owned frames ride the selected-wire system.
Custom wire encodings, negotiated wire identities, native-prefix
metadata — the machinery the wire chapter
describes — compose over owned carriage, while the UTransport path’s
encoding stays whatever the transport does internally. Pick this family
when you want either of two things: pluggable wire formats, or
validation done once at the boundary when your technology naturally
hands over complete buffers (a DDS sample, a queue element).
You implement UOwnedTransportImpl; users call UOwnedTransport and
receive through UOwnedListener. The shape mirrors the UTransport
family with frames in place of messages — and validity is in the type:
UOwnedFrame written plain means UOwnedFrame<Validated>, the only
state a transport ever sees.
use up_rust::{UOwnedFrame, UOwnedTransportImpl, UStatus};
struct MyTransport { /* connection handle */ }
#[async_trait::async_trait]
impl UOwnedTransportImpl for MyTransport {
async fn send_validated_owned(&self, frame: UOwnedFrame) -> Result<(), UStatus> {
// `frame` is `UOwnedFrame<Validated>` by type: metadata checked,
// payload presence consistent — no re-checking here.
self.backend().publish(frame.metadata(), frame.payload())
}
// register/unregister owned listeners: same registry pattern as the
// UTransport tutorial.
}Building a frame is one step — constructors validate, so what you get back is already the state dispatch requires:
use up_rust::{PayloadEncoding, UMessageBuilder, UOwnedFrame, UUri};
let topic = UUri::try_from_parts("demo", 0x1_0001, 1, 0x8001)?;
let message = UMessageBuilder::publish(topic).build()?;
// Frame metadata is a projection of the same attributes a UMessage carries:
let metadata = message.attributes().to_frame_metadata(PayloadEncoding::RAW)?;
let frame = UOwnedFrame::with_payload(metadata, b"reading".to_vec())?;
assert_eq!(frame.payload_bytes(), b"reading");The other state exists for the receive side: bytes decoded off the wire
become UOwnedFrame<Unvalidated>, and the
only way forward is UOwnedFrame::validate, which transitions to
Validated. The state transition is the
validation; an invalid frame reaching a listener is a compile error,
not a runtime drop.
When to choose owned over zero-copy: your technology hands you complete, already-copied buffers anyway, so loan mechanics buy nothing — but wire pluggability and boundary validation still do.
If your technology should instead stay ignorant of frames entirely and
carry pre-encoded bytes, implement UOwnedTransportCore and let
UWireTransport compose the encoding above you
— the same composition story as the
zero-copy core, and the wire
chapter’s composition section shows the payoff:
the transport code is identical for every wire.
Shared obligations: the transport hub. Which trait is which: the trait map.