Preview of the proposed up-rust native-frame-model branch (up-rust b6b99c6d, up-spec f0e9b17) — not released documentation. branch · write-up

up_rust/payload/
loan.rs

1/********************************************************************************
2 * Copyright (c) 2026 Contributors to the Eclipse Foundation
3 *
4 * See the NOTICE file(s) distributed with this work for additional
5 * information regarding copyright ownership.
6 *
7 * This program and the accompanying materials are made available under the
8 * terms of the Apache License Version 2.0 which is available at
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * SPDX-License-Identifier: Apache-2.0
12 ********************************************************************************/
13
14#[cfg(feature = "zero-copy-transport")]
15use std::{mem, ptr::NonNull};
16
17#[cfg(feature = "zero-copy-transport")]
18use crate::zero_copy::LoanedPayloadUninitMut;
19
20use super::{codec::PayloadCodec, codec::PayloadLayout, UWireError};
21
22/// Borrows a typed payload directly from contiguous receive storage.
23///
24/// This is the receive-side true zero-copy codec hook. Implementors must not
25/// allocate, copy, or deserialize into owned storage before returning `&T`.
26///
27/// # Safety
28///
29/// Implementors must validate that `src` has the exact length and alignment for
30/// one initialized `T`, that the bytes are a valid representation for `T` under
31/// this codec, and that returning `&T` cannot observe uninitialized padding or
32/// process-local state.
33pub unsafe trait BorrowPayload<T>: PayloadCodec {
34    /// Borrows `T` from contiguous payload bytes.
35    ///
36    /// # Errors
37    ///
38    /// Returns an error if the payload bytes cannot be borrowed as one valid `T`.
39    fn borrow_payload(src: &[u8]) -> Result<&T, UWireError>;
40}
41
42/// Initializes and borrows a typed value directly in initialized transmit storage.
43///
44/// # Safety
45///
46/// Implementors must guarantee that [`LoanPayload::loan_payload`] returns
47/// `&mut T` only when the destination byte range is uniquely borrowed, has the
48/// exact layout returned by [`LoanPayload::loan_layout`], and contains one valid
49/// initialized `T` for the returned lifetime.
50pub unsafe trait LoanPayload<T>: PayloadCodec {
51    /// Returns the exact layout required for a typed initialized transmit loan.
52    ///
53    /// # Errors
54    ///
55    /// Returns an error if this codec cannot loan `T` into initialized TX storage.
56    fn loan_layout() -> Result<PayloadLayout, UWireError>;
57
58    /// Initializes `dst` and returns a typed mutable view over the loaned payload.
59    ///
60    /// # Errors
61    ///
62    /// Returns an error if `dst` does not have the required length or alignment.
63    fn loan_payload(dst: &mut [u8]) -> Result<&mut T, UWireError>;
64}
65
66/// Initializes a typed value directly in uninitialized transmit storage.
67///
68/// # Safety
69///
70/// Implementors must guarantee that [`LoanUninitPayload::loan_uninit_payload`]
71/// validates the destination range and only returns a slot when the range is one
72/// uniquely borrowed allocation, has the exact layout returned by
73/// [`LoanUninitPayload::loan_uninit_layout`], and is valid for writes of one
74/// `MaybeUninit<T>`.
75#[cfg(feature = "zero-copy-transport")]
76pub unsafe trait LoanUninitPayload<T>: PayloadCodec {
77    /// Returns the exact layout required for a typed uninitialized transmit loan.
78    ///
79    /// # Errors
80    ///
81    /// Returns an error if this codec cannot loan `T` into uninitialized TX storage.
82    fn loan_uninit_layout() -> Result<PayloadLayout, UWireError>;
83
84    /// Validates `dst` and returns an uninitialized typed payload slot.
85    ///
86    /// # Errors
87    ///
88    /// Returns an error if `dst` does not have the required length or alignment.
89    fn loan_uninit_payload<'a>(
90        dst: LoanedPayloadUninitMut<'a>,
91    ) -> Result<LoanedUninitPayload<'a, T>, UWireError>;
92}
93
94/// Uninitialized typed payload slot borrowed from a transmit loan.
95#[cfg(feature = "zero-copy-transport")]
96pub struct LoanedUninitPayload<'a, T> {
97    // Safe-by-construction: an exclusive borrow of the uninitialized target.
98    slot: &'a mut mem::MaybeUninit<T>,
99}
100
101#[cfg(feature = "zero-copy-transport")]
102impl<'a, T> core::fmt::Debug for LoanedUninitPayload<'a, T> {
103    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104        f.debug_struct("LoanedUninitPayload")
105            .finish_non_exhaustive()
106    }
107}
108
109#[cfg(feature = "zero-copy-transport")]
110impl<'a, T> LoanedUninitPayload<'a, T> {
111    /// Wraps an exclusive borrow of the uninitialized target value.
112    #[must_use]
113    pub fn new(slot: &'a mut mem::MaybeUninit<T>) -> Self {
114        Self { slot }
115    }
116
117    /// Initializes the target by move and returns the initialized handle.
118    ///
119    /// Fully safe: `MaybeUninit::write` performs the move and hands back the
120    /// initialized reference; no copy occurs beyond the value move itself.
121    #[must_use]
122    pub fn write(self, value: T) -> LoanedInitPayload<'a, T> {
123        LoanedInitPayload {
124            value: self.slot.write(value),
125        }
126    }
127
128    pub(crate) fn uninit_ptr(&self) -> NonNull<mem::MaybeUninit<T>> {
129        NonNull::from(&*self.slot)
130    }
131}
132
133/// An initialized, exclusively borrowed payload value inside loaned storage.
134#[cfg(feature = "zero-copy-transport")]
135pub struct LoanedInitPayload<'a, T> {
136    value: &'a mut T,
137}
138
139#[cfg(feature = "zero-copy-transport")]
140impl<'a, T> core::fmt::Debug for LoanedInitPayload<'a, T> {
141    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
142        f.debug_struct("LoanedInitPayload").finish_non_exhaustive()
143    }
144}
145
146#[cfg(feature = "zero-copy-transport")]
147impl<'a, T> LoanedInitPayload<'a, T> {
148    pub(crate) fn initialized_ptr(&self) -> NonNull<T> {
149        NonNull::from(&*self.value)
150    }
151}
152
153#[cfg(feature = "zero-copy-transport")]
154impl<T> AsMut<T> for LoanedInitPayload<'_, T> {
155    fn as_mut(&mut self) -> &mut T {
156        self.value
157    }
158}
159
160#[cfg(feature = "zero-copy-transport")]
161impl<T> AsRef<T> for LoanedInitPayload<'_, T> {
162    fn as_ref(&self) -> &T {
163        self.value
164    }
165}