Skip to main content

OwnedView

Struct OwnedView 

Source
pub struct OwnedView<V> { /* private fields */ }
Expand description

An owned, 'static container for a decoded message view.

OwnedView holds a Bytes buffer alongside the decoded view, ensuring the view’s borrows remain valid for the container’s lifetime. The inner view is reached through reborrow(), which returns it with a lifetime tied to &self.

This type is Send + Sync + 'static, making it suitable for use across async boundaries, in tower services, and anywhere a 'static bound is required.

§When to use

Use OwnedView when you need a zero-copy view that outlives the scope where the buffer was received — for example, in an RPC handler where the framework requires 'static types:

use buffa::view::OwnedView;
use bytes::Bytes;

let bytes: Bytes = receive_request_body().await;
let view = OwnedView::<PersonView>::decode(bytes)?;

// Field access through reborrow — the borrow is tied to `view`.
let person = view.reborrow();
println!("name: {}", person.name);
println!("id: {}", person.id);

// Convert to owned if you need to store or mutate
let owned: Person = view.to_owned_message();

Generated code additionally provides a per-message FooOwnedView wrapper around OwnedView<FooView<'static>> with per-field accessor methods (owned.name(), owned.id(), …), so most handler code never touches OwnedView or reborrow directly.

For scoped access where the buffer’s lifetime is known, use MessageView::decode_view directly — it has zero overhead beyond the decode itself.

§Why field access goes through reborrow

OwnedView stores V = FooView<'static>: the view’s borrows really point into self’s Bytes buffer, and the 'static is a synthetic lifetime established by the constructor. Exposing &V directly (for example via a Deref impl) would let borrowed fields appear 'static to the compiler and escape the OwnedView’s scope, dangling once it drops. reborrow() narrows the synthetic 'static down to the OwnedView’s real lifetime, so the borrow checker enforces the actual validity of every field borrow:

// Inline reads: reborrow once, then use plain field access.
fn log(owned: &OwnedView<PersonView<'static>>) {
    let person = owned.reborrow();
    println!("{}", person.name);
}

// Returning a borrowed field: the result is tied to the OwnedView.
fn name<'a>(owned: &'a OwnedView<PersonView<'static>>) -> &'a str {
    owned.reborrow().name  // &'a str tied to the OwnedView's lifetime
}

View fields are not reachable directly on the handle — this fails to compile rather than handing out a 'static borrow into the buffer:

fn field(owned: &OwnedView<PersonView<'static>>) -> &'static str {
    owned.name // error[E0609]: no field `name` on type `&OwnedView<...>`
}

§Safety

Internally, OwnedView extends the view’s lifetime to 'static via transmute in its constructors. This is sound because:

  1. Bytes is reference-counted — its heap data pointer is stable across moves. The view’s borrows always point into valid memory.
  2. Bytes is immutable — the underlying data cannot be modified while borrowed.
  3. A manual Drop impl explicitly drops the view before the bytes, ensuring no dangling references during cleanup. The view field uses ManuallyDrop to prevent the automatic drop from running out of order.

reborrow is a plain Rust subtype coercion (no unsafe, no pointer cast): the ViewReborrow trait method coerces &'b FooView<'static> into &'b FooView<'b> via standard lifetime variance for covariant view types. See ViewReborrow’s docs for the soundness argument.

Implementations§

Source§

impl<V> OwnedView<V>
where V: MessageView<'static>,

Source

pub fn decode(bytes: Bytes) -> Result<Self, DecodeError>

Decode a view from a Bytes buffer.

The view borrows directly from the buffer’s data. Because Bytes is reference-counted and its data pointer is stable across moves, the view’s borrows remain valid for the lifetime of this OwnedView.

§Errors

Returns DecodeError if the buffer contains invalid protobuf data.

Source

pub fn decode_with_options( bytes: Bytes, opts: &DecodeOptions, ) -> Result<Self, DecodeError>

Decode a view with custom DecodeOptions (recursion limit, max message size).

§Errors

Returns DecodeError if the buffer is invalid or exceeds the configured limits.

Source

pub fn from_owned(msg: &V::Owned) -> Result<Self, DecodeError>

Create an OwnedView from an owned message by encoding then decoding.

This performs a full encode → decode round-trip: the message is serialized to protobuf bytes, then a zero-copy view is decoded from those bytes. This is useful when the original wire bytes are not available (e.g., after JSON deserialization or programmatic construction), but note the cost: one allocation + O(n) encode + O(n) decode.

For the common case where you already have wire bytes, prefer decode instead.

§Errors

Returns DecodeError if the re-encoded bytes are somehow invalid (should not happen for well-formed messages).

Source

pub fn to_owned_message(&self) -> V::Owned

Convert the view to the corresponding owned message type.

bytes::Bytes-typed fields are produced via Bytes::slice_ref into the retained buffer (zero-copy); other borrowed fields are allocated and copied.

Source

pub fn bytes(&self) -> &Bytes

Get a reference to the underlying bytes buffer.

Source

pub unsafe fn from_parts(bytes: Bytes, view: V) -> Self

Create an OwnedView from a buffer and a pre-decoded view.

This avoids re-decoding when you already hold a decoded view and want to wrap it for 'static use.

§Safety

The caller must ensure that all borrows in view point into the data region of bytes. In practice, view must have been decoded from bytes (or a sub-slice that bytes fully contains). Violating this invariant causes undefined behavior (dangling references).

Source

pub fn into_bytes(self) -> Bytes

Consume the OwnedView, returning the underlying Bytes buffer.

The view is dropped before the buffer is returned.

Source

pub fn reborrow<'b>(&'b self) -> &'b V::Reborrowed<'b>
where V: ViewReborrow,

Reborrow the view with a lifetime tied to &'b self.

OwnedView<V> stores V with a 'static lifetime — the actual borrows point into self’s internal Bytes buffer and are only valid while self is alive. reborrow makes that real lifetime visible to the borrow checker: the returned &'b V::Reborrowed<'b> cannot outlive &'b self.

§Example
fn handler<'a>(req: &'a OwnedView<PersonView<'static>>) -> &'a str {
    // The explicit annotation is for emphasis; inference works without it.
    // If you need to name the lifetime, store the reborrow in a `let` first.
    let req_view: &PersonView<'a> = req.reborrow();
    req_view.name  // zero-copy from the OwnedView's buffer
}

The returned reference is tied to &'b self — the borrow checker prevents the reborrowed view from outliving the OwnedView:

let name: &str;
{
    // SAFETY: empty Bytes, no borrows — safe to construct directly.
    let owned = unsafe {
        OwnedView::<PersonView<'static>>::from_parts(
            ::buffa::bytes::Bytes::new(),
            PersonView::default(),
        )
    };
    name = owned.reborrow().name; // error[E0597]: `owned` does not live long enough
}
println!("{name}"); // name is dangling — borrow checker rejects this
§How it works

The trait method ViewReborrow::reborrow is a plain Rust subtype coercion: &'b V (where V = FooView<'static>) flows into the return slot &'b V::Reborrowed<'b> (= &'b FooView<'b>). Variance makes this safe — covariant view types narrow 'static down to 'b automatically. No unsafe, no pointer cast, no layout assertions. OwnedView’s own invariant (every borrow in view points into self.bytes, established by decode or upheld by the unsafe from_parts caller) guarantees the pointed-to data lives at least as long as 'b.

Trait Implementations§

Source§

impl<V> Clone for OwnedView<V>
where V: Clone,

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<V> Debug for OwnedView<V>
where V: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<V> Drop for OwnedView<V>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<V> Eq for OwnedView<V>
where V: Eq,

Source§

impl<V> PartialEq for OwnedView<V>
where V: PartialEq,

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<V: Serialize> Serialize for OwnedView<V>

Available on crate feature json only.

Serialize an OwnedView<V> by delegating to the inner view’s Serialize impl.

Equivalent to serializing owned_view.reborrow() directly, so serde_json::to_string(&owned_view) works on the handle itself. When V is a buffa-generated view with generate_json enabled, this produces protobuf JSON; the impl itself just forwards to whatever V::serialize does.

Only available when the json feature is enabled.

Source§

fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error>

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl<V> !Freeze for OwnedView<V>

§

impl<V> RefUnwindSafe for OwnedView<V>
where V: RefUnwindSafe,

§

impl<V> Send for OwnedView<V>
where V: Send,

§

impl<V> Sync for OwnedView<V>
where V: Sync,

§

impl<V> Unpin for OwnedView<V>
where V: Unpin,

§

impl<V> UnsafeUnpin for OwnedView<V>
where V: UnsafeUnpin,

§

impl<V> UnwindSafe for OwnedView<V>
where V: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.