@@ -45,6 +45,32 @@ use crate::adapter::RustMessageAdapter;
4545use crate :: ffi:: ffi;
4646use crate :: ffi:: ffi:: TypeErasedBox ;
4747
48+ /// Adapter for inspecting a C++ pipeline message without taking it out of its
49+ /// [`TypeErasedBox`].
50+ ///
51+ /// This is the zero-allocation path for opaque inline C++ messages. The view is
52+ /// tied to the callback-scoped box borrow and must not be retained. After the
53+ /// view is dropped, the handler can forward the original box unchanged.
54+ ///
55+ /// # Safety
56+ ///
57+ /// Implementations must return a view of the exact C++ type checked by
58+ /// `holds`, and the view must not outlive or move the value in `message`.
59+ pub unsafe trait BorrowedMessageAdapter {
60+ type View < ' a >
61+ where
62+ Self : ' a ;
63+
64+ fn holds ( message : & TypeErasedBox ) -> bool ;
65+
66+ /// # Safety
67+ ///
68+ /// `message` must currently contain the exact C++ type recognized by
69+ /// [`Self::holds`]. The contained value must not be moved, replaced, or
70+ /// otherwise invalidated for the lifetime of the returned view.
71+ unsafe fn borrow < ' a > ( message : Pin < & ' a mut TypeErasedBox > ) -> Self :: View < ' a > ;
72+ }
73+
4874/// Provides the dev-mode type check used by [`RustTypeErasedBox::take`].
4975/// Implemented once per message type via a tiny per-type C++ thunk that compares
5076/// `typeid` — exactly like the per-type C++ `RustMessageAdapter<T>`. In release
@@ -121,6 +147,23 @@ impl<'a> RustTypeErasedBox<'a> {
121147 M :: from_cpp ( cpp)
122148 }
123149
150+ /// Borrow a typed view of the message while leaving the box intact.
151+ ///
152+ /// Drop the returned view before forwarding `self` with
153+ /// [`CallbackContext::forward_read`](crate::CallbackContext::forward_read)
154+ /// or [`CallbackContext::forward_write`](crate::CallbackContext::forward_write).
155+ pub fn borrow < M : BorrowedMessageAdapter > ( & mut self ) -> M :: View < ' _ > {
156+ assert ! (
157+ M :: holds( self . inner. as_ref( ) . get_ref( ) ) ,
158+ "RustTypeErasedBox::borrow: box does not hold the requested type"
159+ ) ;
160+ // SAFETY: the unconditional `M::holds` check establishes that the box
161+ // contains the adapter's exact C++ type. The returned view is tied to
162+ // this exclusive pinned borrow, so the value cannot be moved or
163+ // replaced while the view is live.
164+ unsafe { M :: borrow ( self . inner . as_mut ( ) ) }
165+ }
166+
124167 /// True if the box currently holds no value.
125168 pub fn is_empty ( & self ) -> bool {
126169 ffi:: rust_teb_is_empty ( & self . inner )
0 commit comments