buffa/view.rs
1//! Zero-copy borrowed message views.
2//!
3//! Buffa generates two representations for each protobuf message:
4//!
5//! - **Owned** (`MyMessage`): uses `String`, `Vec<u8>`, `Vec<T>` for fields.
6//! Suitable for building messages, long-lived storage, and mutation.
7//!
8//! - **Borrowed** (`MyMessageView<'a>`): uses `&'a str`, `&'a [u8]`, and
9//! slice-backed repeated fields. Borrows directly from the input buffer
10//! for zero-copy deserialization on the read path.
11//!
12//! # Motivation
13//!
14//! In a typical RPC handler, the request is parsed from a buffer, fields are
15//! read, and the buffer is discarded. With owned types, every string and bytes
16//! field requires an allocation + copy. With view types, strings and bytes
17//! borrow directly from the input buffer — no allocation at all.
18//!
19//! This is analogous to how Cap'n Proto's Rust implementation works, and how
20//! Go achieves zero-copy string deserialization via its garbage collector.
21//!
22//! # Usage pattern
23//!
24//! ```rust,ignore
25//! // Decode a view (zero-copy, borrows from `wire_bytes`)
26//! let request = MyRequestView::decode_view(&wire_bytes)?;
27//! println!("name: {}", request.name); // &str, no allocation
28//!
29//! // Build an owned response
30//! let response = MyResponse {
31//! id: request.id,
32//! status: "ok".into(),
33//! ..Default::default()
34//! };
35//!
36//! // Convert view to owned if needed for storage
37//! let owned: MyRequest = request.to_owned_message();
38//! ```
39//!
40//! # Generated code shape
41//!
42//! For a message like:
43//! ```protobuf
44//! message Person {
45//! string name = 1;
46//! int32 id = 2;
47//! bytes avatar = 3;
48//! repeated string tags = 4;
49//! Address address = 5;
50//! }
51//! ```
52//!
53//! Buffa generates:
54//! ```rust,ignore
55//! // Owned type (heap-allocated strings and vecs)
56//! pub struct Person {
57//! pub name: String,
58//! pub id: i32,
59//! pub avatar: Vec<u8>,
60//! pub tags: Vec<String>,
61//! pub address: MessageField<Address>,
62//! #[doc(hidden)] pub __buffa_unknown_fields: UnknownFields,
63//! #[doc(hidden)] pub __buffa_cached_size: /* internal */,
64//! }
65//!
66//! // Borrowed view type (zero-copy from input buffer)
67//! pub struct PersonView<'a> {
68//! pub name: &'a str,
69//! pub id: i32,
70//! pub avatar: &'a [u8],
71//! pub tags: RepeatedView<'a, &'a str>,
72//! pub address: MessageFieldView<AddressView<'a>>,
73//! pub __buffa_unknown_fields: UnknownFieldsView<'a>,
74//! }
75//! ```
76
77use crate::error::DecodeError;
78use crate::message::Message as _;
79use bytes::Bytes;
80
81/// Trait for zero-copy borrowed message views.
82///
83/// View types borrow from the input buffer and provide read-only access
84/// to message fields without allocation. Each generated `MyMessageView<'a>`
85/// implements this trait.
86///
87/// The lifetime `'a` ties the view to the input buffer — the view cannot
88/// outlive the buffer it was decoded from.
89pub trait MessageView<'a>: Sized {
90 /// The corresponding owned message type.
91 type Owned: crate::Message;
92
93 /// Decode a view from a buffer, borrowing string/bytes fields directly.
94 ///
95 /// The returned view borrows from `buf`'s underlying bytes. The caller
96 /// must ensure the buffer is contiguous (e.g., `&[u8]` or `bytes::Bytes`).
97 fn decode_view(buf: &'a [u8]) -> Result<Self, DecodeError>;
98
99 /// Decode a view with a custom recursion depth limit.
100 ///
101 /// Used by [`DecodeOptions::decode_view`](crate::DecodeOptions::decode_view)
102 /// to pass a non-default recursion budget. The default implementation
103 /// delegates to [`decode_view`](Self::decode_view) (ignoring the limit);
104 /// generated code overrides this to call `_decode_depth(buf, depth)`.
105 fn decode_view_with_limit(buf: &'a [u8], _depth: u32) -> Result<Self, DecodeError> {
106 Self::decode_view(buf)
107 }
108
109 /// Convert this view to the owned message type.
110 ///
111 /// This allocates and copies all borrowed fields.
112 fn to_owned_message(&self) -> Self::Owned;
113}
114
115/// Provides access to a lazily-initialized default view instance.
116///
117/// View types implement this trait so that [`MessageFieldView`] can
118/// dereference to a default when unset, just as [`MessageField`](crate::MessageField)
119/// does for owned types via [`DefaultInstance`](crate::DefaultInstance).
120///
121/// Generated view types like `FooView<'a>` contain only covariant borrows
122/// (`&'a str`, `&'a [u8]`, etc.). A default view contains only `'static`
123/// data (`""`, `&[]`, `0`), so a `&'static FooView<'static>` can be safely
124/// reinterpreted as `&'static FooView<'a>` for any `'a` via covariance.
125///
126/// This trait is implemented for the `'static` instantiation (e.g.,
127/// `FooView<'static>`) and the [`MessageFieldView`] `Deref` impl uses
128/// a lifetime transmute to serve it for any `'a`.
129///
130/// # Safety
131///
132/// Implementors must ensure:
133/// 1. The returned reference points to a validly-initialized default
134/// instance in a `'static` location that is never mutated.
135/// 2. The type is **covariant** in all lifetime parameters — the default
136/// `'static` instance must be safely reinterpretable at any shorter
137/// lifetime.
138pub unsafe trait DefaultViewInstance: Default + 'static {
139 /// Return a reference to the single default view instance.
140 fn default_view_instance() -> &'static Self;
141}
142
143/// A borrowed view of an optional message field.
144///
145/// Analogous to [`MessageField<T>`](crate::MessageField) but for the view
146/// layer. Like `MessageField`, the inner view is **boxed** — recursive
147/// message types (`Foo { NestedMessage { corecursive: Foo } }`) would
148/// otherwise have infinite size. The box is API-transparent: `Deref`
149/// returns `&V`, and `set()` takes `V` by value.
150///
151/// When `V` implements [`HasDefaultViewInstance`], this type implements
152/// [`Deref<Target = V>`](core::ops::Deref), returning a reference to a
153/// static default instance when the field is unset — making view code
154/// identical to owned code for field access:
155///
156/// ```rust,ignore
157/// // Both work the same, regardless of whether `address` is set:
158/// let city = owned_msg.address.city; // MessageField<Address>
159/// let city = view_msg.address.city; // MessageFieldView<AddressView>
160/// ```
161///
162/// The lifetime of the contained view type `V` (e.g. `AddressView<'a>`)
163/// ties this to the input buffer — no separate lifetime parameter is
164/// needed here.
165#[derive(Clone, Debug)]
166pub struct MessageFieldView<V> {
167 inner: Option<alloc::boxed::Box<V>>,
168}
169
170impl<V> MessageFieldView<V> {
171 /// An unset field (the default).
172 #[inline]
173 pub const fn unset() -> Self {
174 Self { inner: None }
175 }
176
177 /// A set field with the given view value.
178 #[inline]
179 pub fn set(v: V) -> Self {
180 Self {
181 inner: Some(alloc::boxed::Box::new(v)),
182 }
183 }
184
185 /// Returns `true` if the field has a value.
186 #[inline]
187 pub fn is_set(&self) -> bool {
188 self.inner.is_some()
189 }
190
191 /// Returns `true` if the field has no value.
192 #[inline]
193 pub fn is_unset(&self) -> bool {
194 self.inner.is_none()
195 }
196
197 /// Get a reference to the inner view, or `None` if unset.
198 #[inline]
199 pub fn as_option(&self) -> Option<&V> {
200 self.inner.as_deref()
201 }
202
203 /// Get a mutable reference to the inner view, or `None` if unset.
204 ///
205 /// Used by generated decode code to merge a second occurrence of a
206 /// message field into an existing value (proto merge semantics).
207 #[inline]
208 pub fn as_mut(&mut self) -> Option<&mut V> {
209 self.inner.as_deref_mut()
210 }
211}
212
213impl<V> Default for MessageFieldView<V> {
214 #[inline]
215 fn default() -> Self {
216 Self::unset()
217 }
218}
219
220/// Marker trait linking a lifetime-parameterized view type `V` (e.g.,
221/// `FooView<'a>`) to its `'static` instantiation that implements
222/// [`DefaultViewInstance`]. Generated code implements this for every
223/// view type.
224///
225/// The `default_view_ptr` method returns a raw pointer to avoid forcing
226/// `Self: 'static` — view types have a lifetime parameter that may not
227/// be `'static`, but the default instance only contains `'static` data
228/// and the types are covariant, so the pointer cast is sound.
229///
230/// # Safety
231///
232/// `Self` must be layout-identical to `Self::Static` (i.e., the only
233/// difference is the lifetime parameter), and `Self` must be covariant
234/// in that lifetime.
235pub unsafe trait HasDefaultViewInstance {
236 /// The `'static` instantiation of this view type.
237 type Static: DefaultViewInstance;
238
239 /// Return a pointer to the static default instance, erasing the
240 /// lifetime so it can be used for any `'a`.
241 fn default_view_ptr() -> *const u8 {
242 // Return as a thin `*const u8` to avoid Sized constraints on Self.
243 Self::Static::default_view_instance() as *const Self::Static as *const u8
244 }
245}
246
247impl<V: HasDefaultViewInstance> core::ops::Deref for MessageFieldView<V> {
248 type Target = V;
249
250 #[inline]
251 fn deref(&self) -> &V {
252 match &self.inner {
253 Some(v) => v,
254 // SAFETY: `default_view_ptr` returns a pointer to a `'static`
255 // default instance. The `HasDefaultViewInstance` safety contract
256 // guarantees the type is covariant, so the `'static` instance
257 // is valid at any shorter lifetime. The pointer is non-null and
258 // points to an initialized, immutable, `'static` value.
259 None => unsafe { &*(V::default_view_ptr() as *const V) },
260 }
261 }
262}
263
264/// Wire-equivalent equality: `Unset` equals `Set(v)` when `v` equals the
265/// default instance.
266///
267/// This matches [`MessageField::eq`](crate::MessageField) on the owned side,
268/// so `view_a == view_b` agrees with
269/// `view_a.to_owned_message() == view_b.to_owned_message()`.
270///
271/// The comparison against the default reuses the same covariant-lifetime
272/// pointer cast already established by the [`Deref`](core::ops::Deref) impl.
273impl<V: PartialEq + HasDefaultViewInstance> PartialEq for MessageFieldView<V> {
274 fn eq(&self, other: &Self) -> bool {
275 match (&self.inner, &other.inner) {
276 // Short-circuit: two unset fields are equal regardless of whether
277 // V::PartialEq is reflexive (e.g. a view containing an f64 NaN).
278 (None, None) => true,
279 // At least one side is set. Deref handles None → default.
280 _ => {
281 <Self as core::ops::Deref>::deref(self) == <Self as core::ops::Deref>::deref(other)
282 }
283 }
284 }
285}
286
287impl<V: Eq + HasDefaultViewInstance> Eq for MessageFieldView<V> {}
288
289/// A borrowed view of a repeated field.
290///
291/// For scalar repeated fields, this is backed by a decoded `Vec` (scalars
292/// can't be zero-copy because they require varint decoding). For string and
293/// bytes repeated fields, elements borrow from the input buffer.
294#[derive(Clone, Debug, PartialEq, Eq)]
295pub struct RepeatedView<'a, T> {
296 elements: alloc::vec::Vec<T>,
297 _marker: core::marker::PhantomData<&'a ()>,
298}
299
300impl<'a, T> RepeatedView<'a, T> {
301 /// Create from a vec of decoded elements.
302 pub fn new(elements: alloc::vec::Vec<T>) -> Self {
303 Self {
304 elements,
305 _marker: core::marker::PhantomData,
306 }
307 }
308
309 /// Returns the number of elements.
310 pub fn len(&self) -> usize {
311 self.elements.len()
312 }
313
314 /// Returns `true` if the repeated field contains no elements.
315 pub fn is_empty(&self) -> bool {
316 self.elements.is_empty()
317 }
318
319 /// Append an element (used by generated `decode_view` code).
320 #[doc(hidden)]
321 pub fn push(&mut self, elem: T) {
322 self.elements.push(elem);
323 }
324
325 /// Returns an iterator over the elements.
326 pub fn iter(&self) -> core::slice::Iter<'_, T> {
327 self.elements.iter()
328 }
329}
330
331impl<'a, T> Default for RepeatedView<'a, T> {
332 fn default() -> Self {
333 Self {
334 elements: alloc::vec::Vec::new(),
335 _marker: core::marker::PhantomData,
336 }
337 }
338}
339
340impl<'a, T> core::ops::Deref for RepeatedView<'a, T> {
341 type Target = [T];
342
343 fn deref(&self) -> &[T] {
344 &self.elements
345 }
346}
347
348impl<'a, T> IntoIterator for RepeatedView<'a, T> {
349 type Item = T;
350 type IntoIter = alloc::vec::IntoIter<T>;
351
352 fn into_iter(self) -> Self::IntoIter {
353 self.elements.into_iter()
354 }
355}
356
357impl<'b, 'a, T> IntoIterator for &'b RepeatedView<'a, T> {
358 type Item = &'b T;
359 type IntoIter = core::slice::Iter<'b, T>;
360
361 fn into_iter(self) -> Self::IntoIter {
362 self.elements.iter()
363 }
364}
365
366/// A borrowed view of a map field.
367///
368/// Protobuf `map<K, V>` fields are encoded as repeated sub-messages, each
369/// containing a key (field 1) and value (field 2). This type stores the
370/// decoded entries in a `Vec<(K, V)>`, borrowing string and bytes keys/values
371/// directly from the input buffer.
372///
373/// Lookup is O(n) linear scan, which is appropriate for the typically small
374/// maps found in protobuf messages (metadata labels, headers, etc.).
375/// If duplicate keys appear on the wire, [`get`](MapView::get) returns the
376/// last occurrence (last-write-wins, per the protobuf spec).
377///
378/// For larger maps where O(1) lookup matters, collect into a `HashMap`:
379///
380/// ```ignore
381/// use std::collections::HashMap;
382/// let index: HashMap<&str, &str> = view.labels.into_iter().collect();
383/// ```
384///
385/// Duplicate keys resolve last-write-wins in the collected map (matching
386/// proto map semantics), since `HashMap::from_iter` keeps the last value.
387///
388/// # Allocation
389///
390/// Like [`RepeatedView`], the `Vec` backing store requires allocation.
391/// The individual keys and values borrow from the input buffer where possible
392/// (string keys as `&'a str`, bytes values as `&'a [u8]`).
393#[derive(Clone, Debug, PartialEq, Eq)]
394pub struct MapView<'a, K, V> {
395 entries: alloc::vec::Vec<(K, V)>,
396 _marker: core::marker::PhantomData<&'a ()>,
397}
398
399impl<'a, K, V> MapView<'a, K, V> {
400 /// Returns the number of entries (including duplicates).
401 pub fn len(&self) -> usize {
402 self.entries.len()
403 }
404
405 /// Returns `true` if there are no entries.
406 pub fn is_empty(&self) -> bool {
407 self.entries.is_empty()
408 }
409
410 /// Append a key-value pair (used by generated `decode_view` code).
411 #[doc(hidden)]
412 pub fn push(&mut self, key: K, value: V) {
413 self.entries.push((key, value));
414 }
415
416 /// Iterate over all entries in wire order.
417 ///
418 /// If duplicate keys exist, all occurrences are yielded.
419 pub fn iter(&self) -> core::slice::Iter<'_, (K, V)> {
420 self.entries.iter()
421 }
422
423 /// Iterate over all keys in wire order.
424 pub fn keys(&self) -> impl Iterator<Item = &K> {
425 self.entries.iter().map(|(k, _)| k)
426 }
427
428 /// Iterate over all values in wire order.
429 pub fn values(&self) -> impl Iterator<Item = &V> {
430 self.entries.iter().map(|(_, v)| v)
431 }
432
433 /// Look up a value by key, returning the last occurrence (last-write-wins).
434 ///
435 /// Accepts any type that `K` can borrow as, so `map.get("key")` works
436 /// when `K` is `&str`. O(n) scan.
437 pub fn get<Q>(&self, key: &Q) -> Option<&V>
438 where
439 K: core::borrow::Borrow<Q>,
440 Q: PartialEq + ?Sized,
441 {
442 self.entries
443 .iter()
444 .rev()
445 .find(|(k, _)| k.borrow() == key)
446 .map(|(_, v)| v)
447 }
448
449 /// Returns `true` if an entry with the given key exists.
450 pub fn contains_key<Q>(&self, key: &Q) -> bool
451 where
452 K: core::borrow::Borrow<Q>,
453 Q: PartialEq + ?Sized,
454 {
455 self.entries.iter().any(|(k, _)| k.borrow() == key)
456 }
457}
458
459impl<'a, K, V> Default for MapView<'a, K, V> {
460 fn default() -> Self {
461 Self {
462 entries: alloc::vec::Vec::new(),
463 _marker: core::marker::PhantomData,
464 }
465 }
466}
467
468impl<'b, 'a, K, V> IntoIterator for &'b MapView<'a, K, V> {
469 type Item = &'b (K, V);
470 type IntoIter = core::slice::Iter<'b, (K, V)>;
471
472 fn into_iter(self) -> Self::IntoIter {
473 self.entries.iter()
474 }
475}
476
477impl<'a, K, V> IntoIterator for MapView<'a, K, V> {
478 type Item = (K, V);
479 type IntoIter = alloc::vec::IntoIter<(K, V)>;
480
481 fn into_iter(self) -> Self::IntoIter {
482 self.entries.into_iter()
483 }
484}
485
486/// A borrowed view of unknown fields.
487///
488/// Stores raw byte slices from the input buffer rather than decoded values,
489/// enabling zero-copy round-tripping of unknown fields.
490#[derive(Clone, Debug, Default)]
491pub struct UnknownFieldsView<'a> {
492 /// Raw (tag, value) byte spans from the input buffer.
493 raw_spans: alloc::vec::Vec<&'a [u8]>,
494}
495
496impl<'a> UnknownFieldsView<'a> {
497 /// Creates an empty view.
498 pub fn new() -> Self {
499 Self::default()
500 }
501
502 #[doc(hidden)]
503 pub fn push_raw(&mut self, span: &'a [u8]) {
504 self.raw_spans.push(span);
505 }
506
507 /// Returns `true` if no unknown fields were recorded.
508 pub fn is_empty(&self) -> bool {
509 self.raw_spans.is_empty()
510 }
511
512 /// Total byte length of all unknown field data.
513 pub fn encoded_len(&self) -> usize {
514 self.raw_spans.iter().map(|s| s.len()).sum()
515 }
516
517 /// Convert to an owned [`UnknownFields`](crate::UnknownFields) by parsing all stored raw byte spans.
518 ///
519 /// Each span is a complete (tag + value) record as it appeared on the wire.
520 /// Parsing uses [`crate::encoding::decode_unknown_field`] with the full
521 /// recursion limit so deeply nested group fields are handled correctly.
522 ///
523 /// # Errors
524 ///
525 /// Returns `Err` if any stored span is malformed — which should not occur
526 /// when the view was produced by `decode_view` from valid wire data.
527 pub fn to_owned(&self) -> Result<crate::UnknownFields, crate::DecodeError> {
528 use crate::encoding::{decode_unknown_field, Tag};
529
530 let mut out = crate::UnknownFields::new();
531 for span in &self.raw_spans {
532 let mut cur: &[u8] = span;
533 let tag = Tag::decode(&mut cur)?;
534 let field = decode_unknown_field(tag, &mut cur, crate::RECURSION_LIMIT)?;
535 out.push(field);
536 }
537 Ok(out)
538 }
539}
540
541/// An owned, `'static` container for a decoded message view.
542///
543/// `OwnedView` holds a [`Bytes`] buffer alongside the decoded view, ensuring
544/// the view's borrows remain valid for the container's lifetime. It implements
545/// [`Deref<Target = V>`](core::ops::Deref), so view fields are accessed
546/// directly — no `.get()` or unwrapping needed.
547///
548/// This type is `Send + Sync + 'static`, making it suitable for use across
549/// async boundaries, in tower services, and anywhere a `'static` bound is
550/// required.
551///
552/// # When to use
553///
554/// Use `OwnedView` when you need a zero-copy view that outlives the scope
555/// where the buffer was received — for example, in an RPC handler where the
556/// framework requires `'static` types:
557///
558/// ```rust,ignore
559/// use buffa::view::OwnedView;
560/// use bytes::Bytes;
561///
562/// let bytes: Bytes = receive_request_body().await;
563/// let view = OwnedView::<PersonView>::decode(bytes)?;
564///
565/// // Direct field access via Deref — no .get() needed
566/// println!("name: {}", view.name);
567/// println!("id: {}", view.id);
568///
569/// // Convert to owned if you need to store or mutate
570/// let owned: Person = view.to_owned_message();
571/// ```
572///
573/// For scoped access where the buffer's lifetime is known, use
574/// [`MessageView::decode_view`] directly — it has zero overhead beyond the
575/// decode itself.
576///
577/// # Safety
578///
579/// Internally, `OwnedView` extends the view's lifetime to `'static` via
580/// `transmute`. This is sound because:
581///
582/// 1. [`Bytes`] is reference-counted — its heap data pointer is stable across
583/// moves. The view's borrows always point into valid memory.
584/// 2. [`Bytes`] is immutable — the underlying data cannot be modified while
585/// borrowed.
586/// 3. A manual [`Drop`] impl explicitly drops the view before the bytes,
587/// ensuring no dangling references during cleanup. The view field uses
588/// [`ManuallyDrop`](core::mem::ManuallyDrop) to prevent the automatic
589/// drop from running out of order.
590pub struct OwnedView<V> {
591 // INVARIANT: `view` borrows from `bytes`. The `Drop` impl ensures
592 // `view` is dropped before `bytes`. `ManuallyDrop` prevents the compiler
593 // from dropping `view` automatically — our `Drop` impl handles it.
594 //
595 // CONSTRUCTORS: any constructor added here MUST ensure the view's
596 // borrows point into `self.bytes` (not into caller-owned memory).
597 // The auto-`Send`/`Sync` derivation is only sound under that invariant
598 // — there is no longer a `V: 'static` bound on `Send` to act as a
599 // second gate. See the comment block above `send_sync_assertions` below.
600 view: core::mem::ManuallyDrop<V>,
601 bytes: Bytes,
602}
603
604impl<V> Drop for OwnedView<V> {
605 fn drop(&mut self) {
606 // SAFETY: `view` borrows from `bytes`. We must drop the view before
607 // bytes is dropped. `ManuallyDrop::drop` runs V's destructor in place
608 // without moving it. After this, `bytes` drops automatically via the
609 // compiler-generated drop glue.
610 unsafe {
611 core::mem::ManuallyDrop::drop(&mut self.view);
612 }
613 }
614}
615
616impl<V> OwnedView<V>
617where
618 V: MessageView<'static>,
619{
620 /// Decode a view from a [`Bytes`] buffer.
621 ///
622 /// The view borrows directly from the buffer's data. Because [`Bytes`] is
623 /// reference-counted and its data pointer is stable across moves, the
624 /// view's borrows remain valid for the lifetime of this `OwnedView`.
625 ///
626 /// # Errors
627 ///
628 /// Returns [`DecodeError`] if the buffer contains invalid protobuf data.
629 pub fn decode(bytes: Bytes) -> Result<Self, DecodeError> {
630 // SAFETY: `Bytes` is StableDeref — its heap data never moves or is
631 // freed while we hold the `Bytes` value. We hold it in `self.bytes`,
632 // and drop order guarantees `view` drops first.
633 let view = unsafe {
634 let slice: &'static [u8] = core::mem::transmute::<&[u8], &'static [u8]>(&bytes);
635 V::decode_view(slice)?
636 };
637 Ok(Self {
638 view: core::mem::ManuallyDrop::new(view),
639 bytes,
640 })
641 }
642
643 /// Decode a view with custom [`DecodeOptions`](crate::DecodeOptions)
644 /// (recursion limit, max message size).
645 ///
646 /// # Errors
647 ///
648 /// Returns [`DecodeError`] if the buffer is invalid or exceeds the
649 /// configured limits.
650 pub fn decode_with_options(
651 bytes: Bytes,
652 opts: &crate::DecodeOptions,
653 ) -> Result<Self, DecodeError> {
654 // SAFETY: Same invariants as `decode` — see above.
655 let view = unsafe {
656 let slice: &'static [u8] = core::mem::transmute::<&[u8], &'static [u8]>(&bytes);
657 opts.decode_view::<V>(slice)?
658 };
659 Ok(Self {
660 view: core::mem::ManuallyDrop::new(view),
661 bytes,
662 })
663 }
664
665 /// Create an `OwnedView` from an owned message by encoding then decoding.
666 ///
667 /// This performs a full **encode → decode** round-trip: the message is
668 /// serialized to protobuf bytes, then a zero-copy view is decoded from
669 /// those bytes. This is useful when the original wire bytes are not
670 /// available (e.g., after JSON deserialization or programmatic construction),
671 /// but note the cost: one allocation + O(n) encode + O(n) decode.
672 ///
673 /// For the common case where you already have wire bytes, prefer
674 /// [`decode`](Self::decode) instead.
675 ///
676 /// # Errors
677 ///
678 /// Returns [`DecodeError`] if the re-encoded bytes are somehow invalid
679 /// (should not happen for well-formed messages).
680 pub fn from_owned(msg: &V::Owned) -> Result<Self, DecodeError> {
681 let bytes = Bytes::from(msg.encode_to_vec());
682 Self::decode(bytes)
683 }
684
685 /// Convert the view to the corresponding owned message type.
686 ///
687 /// This allocates and copies all borrowed fields.
688 pub fn to_owned_message(&self) -> V::Owned {
689 self.view.to_owned_message()
690 }
691
692 /// Get a reference to the underlying bytes buffer.
693 pub fn bytes(&self) -> &Bytes {
694 &self.bytes
695 }
696
697 /// Create an `OwnedView` from a buffer and a pre-decoded view.
698 ///
699 /// This avoids re-decoding when you already hold a decoded view and want
700 /// to wrap it for `'static` use.
701 ///
702 /// # Safety
703 ///
704 /// The caller must ensure that **all** borrows in `view` point into the
705 /// data region of `bytes`. In practice, `view` must have been decoded
706 /// from `bytes` (or a sub-slice that `bytes` fully contains). Violating
707 /// this invariant causes undefined behavior (dangling references).
708 pub unsafe fn from_parts(bytes: Bytes, view: V) -> Self {
709 Self {
710 view: core::mem::ManuallyDrop::new(view),
711 bytes,
712 }
713 }
714
715 /// Consume the `OwnedView`, returning the underlying [`Bytes`] buffer.
716 ///
717 /// The view is dropped before the buffer is returned.
718 pub fn into_bytes(mut self) -> Bytes {
719 // SAFETY: Drop the view first (while bytes data is still alive),
720 // then read bytes out via ptr::read, then forget self to prevent
721 // the Drop impl from double-dropping the view.
722 unsafe {
723 core::mem::ManuallyDrop::drop(&mut self.view);
724 let bytes = core::ptr::read(&self.bytes);
725 core::mem::forget(self);
726 bytes
727 }
728 }
729}
730
731impl<V> core::ops::Deref for OwnedView<V> {
732 type Target = V;
733
734 #[inline]
735 fn deref(&self) -> &V {
736 &self.view // Deref through ManuallyDrop is transparent
737 }
738}
739
740impl<V> core::fmt::Debug for OwnedView<V>
741where
742 V: core::fmt::Debug,
743{
744 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
745 (*self.view).fmt(f)
746 }
747}
748
749impl<V> Clone for OwnedView<V>
750where
751 V: Clone,
752{
753 fn clone(&self) -> Self {
754 // SAFETY: `Bytes::clone()` is a refcount bump — both the original and
755 // the clone share the same backing heap allocation. The cloned view's
756 // `'static` references remain valid because they point into data that
757 // is now kept alive by the cloned `Bytes` handle. This would be
758 // unsound if `Bytes::clone()` performed a deep copy to a new address.
759 Self {
760 view: self.view.clone(),
761 bytes: self.bytes.clone(),
762 }
763 }
764}
765
766impl<V> PartialEq for OwnedView<V>
767where
768 V: PartialEq,
769{
770 fn eq(&self, other: &Self) -> bool {
771 *self.view == *other.view
772 }
773}
774
775impl<V> Eq for OwnedView<V> where V: Eq {}
776
777// `OwnedView<V>` is auto-`Send`/`Sync` when `V` is — `ManuallyDrop<V>` and
778// `Bytes` both forward auto-traits. No manual `unsafe impl` is needed, and
779// adding one with a `V: 'static` bound is actively harmful: it is precisely
780// what triggers E0477 when `async fn` is used in a trait impl against an
781// RPITIT `+ Send` return type (rust-lang/rust#128095). The RPITIT desugaring
782// introduces a fresh lifetime for the `'static` in `FooView<'static>`, and
783// then cannot prove that fresh lifetime satisfies `'static` to discharge the
784// manual impl's bound.
785//
786// The bound was defensive — intended to prevent `OwnedView<FooView<'short>>`
787// from being `Send` when the view borrows from something outside `self.bytes`.
788// But that type is already unconstructible: `::decode()` and
789// `::decode_with_options()` are gated on `V: MessageView<'static>`, and the
790// fields are private. The short-lifetime case the bound guards against cannot
791// exist in safe code.
792//
793// Auto-trait soundness: `Bytes` is `Send + Sync`. The view's `&'static [u8]`
794// borrows point into `Bytes`'s heap allocation, which is immutable,
795// `StableDeref`, and moves with the struct. Sending the whole pair to another
796// thread preserves the invariant. The `'static` in `V` being a lie is about
797// *where* the reference points, not about thread safety.
798#[cfg(test)]
799mod send_sync_assertions {
800 use super::*;
801 fn assert_send<T: Send>() {}
802 fn assert_sync<T: Sync>() {}
803
804 // Any `V: Send + Sync` suffices — generated `FooView<'static>` types are
805 // auto-`Send + Sync` via their `&'static str` / `&'static [u8]` fields.
806 #[allow(dead_code)]
807 fn owned_view_is_send_sync<V: Send + Sync>() {
808 assert_send::<OwnedView<V>>();
809 assert_sync::<OwnedView<V>>();
810 }
811
812 // Concrete-type regression: `TinyView` is declared in the `tests` module
813 // below and has the same shape as generated view types (one `&'a str`).
814 #[allow(dead_code)]
815 fn owned_tiny_view_is_send_sync() {
816 assert_send::<OwnedView<super::tests::TinyView<'static>>>();
817 assert_sync::<OwnedView<super::tests::TinyView<'static>>>();
818 }
819}
820
821#[cfg(test)]
822mod tests {
823 use super::*;
824
825 // ── MessageFieldView ─────────────────────────────────────────────────
826
827 #[test]
828 fn message_field_view_default_is_unset() {
829 let v: MessageFieldView<i32> = MessageFieldView::default();
830 assert!(v.is_unset());
831 assert!(!v.is_set());
832 assert_eq!(v.as_option(), None);
833 }
834
835 #[test]
836 fn message_field_view_set_value() {
837 let v = MessageFieldView::set(42);
838 assert!(v.is_set());
839 assert!(!v.is_unset());
840 assert_eq!(v.as_option(), Some(&42));
841 }
842
843 #[test]
844 fn message_field_view_with_non_copy_type() {
845 let v = MessageFieldView::set(alloc::string::String::from("hello"));
846 assert!(v.is_set());
847 assert_eq!(v.as_option().map(|s| s.as_str()), Some("hello"));
848
849 let unset: MessageFieldView<alloc::string::String> = MessageFieldView::unset();
850 assert!(unset.is_unset());
851 assert_eq!(unset.as_option(), None);
852 }
853
854 // ── MessageFieldView Deref ─────────────────────────────────────────
855
856 /// A trivial view type for testing MessageFieldView Deref.
857 #[derive(Clone, Debug, Default, PartialEq)]
858 pub(super) struct TinyView<'a> {
859 pub value: &'a str,
860 }
861
862 // SAFETY: Default TinyView contains only &'static str (""), which is 'static.
863 unsafe impl DefaultViewInstance for TinyView<'static> {
864 fn default_view_instance() -> &'static Self {
865 static INST: crate::__private::OnceBox<TinyView<'static>> =
866 crate::__private::OnceBox::new();
867 INST.get_or_init(|| alloc::boxed::Box::new(TinyView::default()))
868 }
869 }
870
871 // SAFETY: TinyView is covariant in 'a (only contains &'a str).
872 unsafe impl<'a> HasDefaultViewInstance for TinyView<'a> {
873 type Static = TinyView<'static>;
874 }
875
876 #[test]
877 fn message_field_view_deref_set() {
878 let v = MessageFieldView::set(TinyView { value: "hello" });
879 // Deref gives access to the inner view
880 assert_eq!(v.value, "hello");
881 }
882
883 #[test]
884 fn message_field_view_deref_unset_returns_default() {
885 let v: MessageFieldView<TinyView<'_>> = MessageFieldView::unset();
886 // Deref transparently returns the default instance
887 assert_eq!(v.value, "");
888 }
889
890 #[test]
891 fn message_field_view_deref_chained_access() {
892 // Simulates accessing a nested field through an unset sub-message
893 let v: MessageFieldView<TinyView<'_>> = MessageFieldView::unset();
894 let len = v.value.len();
895 assert_eq!(len, 0);
896 }
897
898 // ── MessageFieldView PartialEq (wire-equivalent) ───────────────────
899
900 #[test]
901 fn message_field_view_equality() {
902 // None = Unset, Some(s) = Set(TinyView { value: s }).
903 // TinyView::default() has value == "", so Some("") encodes Set(default).
904 fn mk(c: Option<&str>) -> MessageFieldView<TinyView<'_>> {
905 match c {
906 None => MessageFieldView::unset(),
907 Some(v) => MessageFieldView::set(TinyView { value: v }),
908 }
909 }
910
911 #[rustfmt::skip]
912 let cases: &[(Option<&str>, Option<&str>, bool)] = &[
913 // Wire-equivalent semantics: Unset == Set(default), matching
914 // MessageField::PartialEq on the owned side.
915 (None, None, true ), // Unset == Unset
916 (None, Some(""), true ), // Unset == Set(default)
917 (Some(""), None, true ), // Set(default) == Unset (symmetric)
918 (Some(""), Some(""), true ), // Set(default) == Set(default)
919 (None, Some("x"), false), // Unset != Set(nondefault)
920 (Some("x"), None, false), // Set(nondefault) != Unset (symmetric)
921 (Some("x"), Some("x"), true ), // Set == Set (same)
922 (Some("x"), Some("y"), false), // Set != Set (different)
923 ];
924
925 for &(l, r, expect) in cases {
926 assert_eq!(
927 mk(l) == mk(r),
928 expect,
929 "({l:?} == {r:?}) should be {expect}"
930 );
931 }
932 }
933
934 // ── RepeatedView ─────────────────────────────────────────────────────
935
936 #[test]
937 fn repeated_view_new_and_accessors() {
938 let rv = RepeatedView::new(alloc::vec![10, 20, 30]);
939 assert_eq!(rv.len(), 3);
940 assert!(!rv.is_empty());
941 assert_eq!(&*rv, &[10, 20, 30]);
942 }
943
944 #[test]
945 fn repeated_view_default_is_empty() {
946 let rv: RepeatedView<'_, u8> = RepeatedView::default();
947 assert!(rv.is_empty());
948 assert_eq!(rv.len(), 0);
949 }
950
951 #[test]
952 fn repeated_view_push_and_iter() {
953 let mut rv = RepeatedView::<i32>::default();
954 rv.push(1);
955 rv.push(2);
956 let collected: alloc::vec::Vec<_> = rv.iter().copied().collect();
957 assert_eq!(collected, alloc::vec![1, 2]);
958 }
959
960 #[test]
961 fn repeated_view_with_borrowed_str() {
962 let data = alloc::string::String::from("hello world");
963 let parts: alloc::vec::Vec<&str> = data.split_whitespace().collect();
964 let rv = RepeatedView::new(parts);
965 assert_eq!(rv.len(), 2);
966 assert_eq!(rv[0], "hello");
967 assert_eq!(rv[1], "world");
968 }
969
970 #[test]
971 fn repeated_view_into_iter_by_ref() {
972 let rv = RepeatedView::new(alloc::vec![1, 2, 3]);
973 let sum: i32 = (&rv).into_iter().sum();
974 assert_eq!(sum, 6);
975 // `for x in &rv` syntax works:
976 let mut count = 0;
977 for _ in &rv {
978 count += 1;
979 }
980 assert_eq!(count, 3);
981 }
982
983 #[test]
984 fn repeated_view_into_iter_by_value() {
985 let rv = RepeatedView::new(alloc::vec![
986 alloc::string::String::from("a"),
987 alloc::string::String::from("b"),
988 ]);
989 let collected: alloc::vec::Vec<_> = rv.into_iter().collect();
990 assert_eq!(collected, alloc::vec!["a".to_string(), "b".to_string()]);
991 }
992
993 // ── MapView ──────────────────────────────────────────────────────────
994
995 #[test]
996 fn map_view_get_with_borrow() {
997 let mut mv = MapView::<&str, i32>::default();
998 mv.push("apples", 3);
999 mv.push("bananas", 5);
1000
1001 // Ergonomic: get("key") works via Borrow<str> on &str
1002 assert_eq!(mv.get("apples"), Some(&3));
1003 assert_eq!(mv.get("bananas"), Some(&5));
1004 assert_eq!(mv.get("oranges"), None);
1005
1006 // Old style still works
1007 assert_eq!(mv.get(&"apples"), Some(&3));
1008 }
1009
1010 #[test]
1011 fn map_view_contains_key_with_borrow() {
1012 let mut mv = MapView::<&str, i32>::default();
1013 mv.push("key", 1);
1014
1015 assert!(mv.contains_key("key"));
1016 assert!(!mv.contains_key("missing"));
1017 }
1018
1019 #[test]
1020 fn map_view_get_last_write_wins() {
1021 let mut mv = MapView::<&str, i32>::default();
1022 mv.push("x", 1);
1023 mv.push("x", 2);
1024 assert_eq!(mv.get("x"), Some(&2));
1025 }
1026
1027 #[test]
1028 fn map_view_keys_and_values() {
1029 let mut mv = MapView::<&str, i32>::default();
1030 mv.push("a", 1);
1031 mv.push("b", 2);
1032 mv.push("c", 3);
1033
1034 let keys: alloc::vec::Vec<_> = mv.keys().copied().collect();
1035 assert_eq!(keys, alloc::vec!["a", "b", "c"]);
1036
1037 let values: alloc::vec::Vec<_> = mv.values().copied().collect();
1038 assert_eq!(values, alloc::vec![1, 2, 3]);
1039 }
1040
1041 #[test]
1042 fn map_view_keys_and_values_empty() {
1043 let mv = MapView::<&str, i32>::default();
1044 assert_eq!(mv.keys().count(), 0);
1045 assert_eq!(mv.values().count(), 0);
1046 }
1047
1048 #[test]
1049 fn map_view_into_iter_collect_to_hashmap() {
1050 let mut mv = MapView::<&str, i32>::default();
1051 mv.push("a", 1);
1052 mv.push("b", 2);
1053 mv.push("a", 3); // duplicate — last-write-wins on collect
1054 let m: crate::__private::HashMap<&str, i32> = mv.into_iter().collect();
1055 assert_eq!(m.len(), 2);
1056 assert_eq!(m.get("a"), Some(&3)); // last value kept
1057 assert_eq!(m.get("b"), Some(&2));
1058 }
1059
1060 // ── UnknownFieldsView ────────────────────────────────────────────────
1061
1062 #[test]
1063 fn unknown_fields_view_new_is_empty() {
1064 let uf = UnknownFieldsView::new();
1065 assert!(uf.is_empty());
1066 assert_eq!(uf.encoded_len(), 0);
1067 }
1068
1069 #[test]
1070 fn unknown_fields_view_push_raw_and_encoded_len() {
1071 let mut uf = UnknownFieldsView::new();
1072 uf.push_raw(&[0x08, 0x01]); // field 1, varint 1
1073 uf.push_raw(&[0x10, 0x02]); // field 2, varint 2
1074 assert!(!uf.is_empty());
1075 assert_eq!(uf.encoded_len(), 4);
1076 }
1077
1078 #[test]
1079 fn unknown_fields_view_to_owned_single_field() {
1080 // Build a valid unknown field: tag for field 99, varint wire type,
1081 // value 42. Tag = (99 << 3) | 0 = 792 = varint bytes [0x98, 0x06].
1082 let span: &[u8] = &[0x98, 0x06, 0x2A];
1083 let mut uf = UnknownFieldsView::new();
1084 uf.push_raw(span);
1085
1086 let owned = uf.to_owned().expect("valid wire data");
1087 assert_eq!(owned.len(), 1);
1088 let field = owned.iter().next().unwrap();
1089 assert_eq!(field.number, 99);
1090 assert_eq!(
1091 field.data,
1092 crate::unknown_fields::UnknownFieldData::Varint(42)
1093 );
1094 }
1095
1096 #[test]
1097 fn unknown_fields_view_to_owned_multiple_fields() {
1098 let mut uf = UnknownFieldsView::new();
1099 // Field 1, varint, value 7: tag = (1<<3)|0 = 0x08, value = 0x07
1100 uf.push_raw(&[0x08, 0x07]);
1101 // Field 2, fixed32, value 0x01020304:
1102 // tag = (2<<3)|5 = 0x15, then 4 LE bytes
1103 uf.push_raw(&[0x15, 0x04, 0x03, 0x02, 0x01]);
1104
1105 let owned = uf.to_owned().expect("valid wire data");
1106 assert_eq!(owned.len(), 2);
1107
1108 let mut it = owned.iter();
1109 let f1 = it.next().unwrap();
1110 assert_eq!(f1.number, 1);
1111 assert_eq!(f1.data, crate::unknown_fields::UnknownFieldData::Varint(7));
1112
1113 let f2 = it.next().unwrap();
1114 assert_eq!(f2.number, 2);
1115 assert_eq!(
1116 f2.data,
1117 crate::unknown_fields::UnknownFieldData::Fixed32(0x01020304)
1118 );
1119 }
1120
1121 #[test]
1122 fn unknown_fields_view_to_owned_malformed_returns_error() {
1123 // A truncated tag (high continuation bit, then EOF).
1124 let mut uf = UnknownFieldsView::new();
1125 uf.push_raw(&[0x80]);
1126 assert!(uf.to_owned().is_err());
1127 }
1128
1129 // ── OwnedView ──────────────────────────────────────────────────────
1130
1131 // Minimal types to test OwnedView without depending on generated code.
1132
1133 use crate::message::Message;
1134
1135 /// A trivial "message" for the owned side of the view contract.
1136 #[derive(Clone, Debug, Default, PartialEq)]
1137 struct SimpleMessage {
1138 pub id: i32,
1139 pub name: alloc::string::String,
1140 }
1141
1142 // SAFETY: Returns a lazily-initialized static default instance.
1143 unsafe impl crate::DefaultInstance for SimpleMessage {
1144 fn default_instance() -> &'static Self {
1145 static INST: crate::__private::OnceBox<SimpleMessage> =
1146 crate::__private::OnceBox::new();
1147 INST.get_or_init(|| alloc::boxed::Box::new(SimpleMessage::default()))
1148 }
1149 }
1150
1151 impl crate::Message for SimpleMessage {
1152 fn compute_size(&self) -> u32 {
1153 let mut size = 0u32;
1154 if self.id != 0 {
1155 size += 1 + crate::types::int32_encoded_len(self.id) as u32;
1156 }
1157 if !self.name.is_empty() {
1158 size += 1 + crate::types::string_encoded_len(&self.name) as u32;
1159 }
1160 size
1161 }
1162
1163 fn write_to(&self, buf: &mut impl bytes::BufMut) {
1164 if self.id != 0 {
1165 crate::encoding::Tag::new(1, crate::encoding::WireType::Varint).encode(buf);
1166 crate::types::encode_int32(self.id, buf);
1167 }
1168 if !self.name.is_empty() {
1169 crate::encoding::Tag::new(2, crate::encoding::WireType::LengthDelimited)
1170 .encode(buf);
1171 crate::types::encode_string(&self.name, buf);
1172 }
1173 }
1174
1175 fn merge_field(
1176 &mut self,
1177 tag: crate::encoding::Tag,
1178 buf: &mut impl bytes::Buf,
1179 _depth: u32,
1180 ) -> Result<(), DecodeError> {
1181 match tag.field_number() {
1182 1 => self.id = crate::types::decode_int32(buf)?,
1183 2 => crate::types::merge_string(&mut self.name, buf)?,
1184 _ => crate::encoding::skip_field(tag, buf)?,
1185 }
1186 Ok(())
1187 }
1188
1189 fn cached_size(&self) -> u32 {
1190 0
1191 }
1192
1193 fn clear(&mut self) {
1194 self.id = 0;
1195 self.name.clear();
1196 }
1197 }
1198
1199 /// A zero-copy view of `SimpleMessage`. Borrows `name` as `&str`.
1200 #[derive(Clone, Debug, Default, PartialEq)]
1201 struct SimpleMessageView<'a> {
1202 pub id: i32,
1203 pub name: &'a str,
1204 }
1205
1206 impl<'a> MessageView<'a> for SimpleMessageView<'a> {
1207 type Owned = SimpleMessage;
1208
1209 fn decode_view(buf: &'a [u8]) -> Result<Self, DecodeError> {
1210 let mut view = SimpleMessageView::default();
1211 let mut cursor: &'a [u8] = buf;
1212 while !cursor.is_empty() {
1213 let tag = crate::encoding::Tag::decode(&mut cursor)?;
1214 match tag.field_number() {
1215 1 => view.id = crate::types::decode_int32(&mut cursor)?,
1216 2 => view.name = crate::types::borrow_str(&mut cursor)?,
1217 _ => crate::encoding::skip_field(tag, &mut cursor)?,
1218 }
1219 }
1220 Ok(view)
1221 }
1222
1223 fn to_owned_message(&self) -> SimpleMessage {
1224 SimpleMessage {
1225 id: self.id,
1226 name: self.name.into(),
1227 }
1228 }
1229 }
1230
1231 /// Encode a SimpleMessage to Bytes for testing.
1232 fn encode_simple(id: i32, name: &str) -> Bytes {
1233 let msg = SimpleMessage {
1234 id,
1235 name: name.into(),
1236 };
1237 Bytes::from(msg.encode_to_vec())
1238 }
1239
1240 #[test]
1241 fn owned_view_decode_and_deref() {
1242 let bytes = encode_simple(42, "hello");
1243 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
1244
1245 // Access via Deref — no .get() needed
1246 assert_eq!(view.id, 42);
1247 assert_eq!(view.name, "hello");
1248 }
1249
1250 #[test]
1251 fn owned_view_to_owned_message() {
1252 let bytes = encode_simple(7, "world");
1253 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
1254 let owned = view.to_owned_message();
1255
1256 assert_eq!(owned.id, 7);
1257 assert_eq!(owned.name, "world");
1258 }
1259
1260 #[test]
1261 fn owned_view_debug_delegates_to_view() {
1262 let bytes = encode_simple(1, "test");
1263 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
1264 let debug = alloc::format!("{:?}", view);
1265 assert!(debug.contains("test"));
1266 assert!(debug.contains("1"));
1267 }
1268
1269 #[test]
1270 fn owned_view_bytes_accessor() {
1271 let bytes = encode_simple(5, "data");
1272 let original_len = bytes.len();
1273 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
1274
1275 assert_eq!(view.bytes().len(), original_len);
1276 }
1277
1278 #[test]
1279 fn owned_view_into_bytes_recovers_buffer() {
1280 let bytes = encode_simple(99, "recover");
1281 let expected = bytes.clone();
1282 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
1283 let recovered = view.into_bytes();
1284
1285 assert_eq!(recovered, expected);
1286 }
1287
1288 #[test]
1289 fn owned_view_decode_invalid_data_returns_error() {
1290 // Truncated varint
1291 let bad = Bytes::from_static(&[0x08, 0x80]);
1292 let result = OwnedView::<SimpleMessageView<'static>>::decode(bad);
1293 assert!(result.is_err());
1294 }
1295
1296 #[test]
1297 fn owned_view_empty_message() {
1298 let bytes = Bytes::from_static(&[]);
1299 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
1300 assert_eq!(view.id, 0);
1301 assert_eq!(view.name, "");
1302 }
1303
1304 #[test]
1305 fn owned_view_is_send_and_sync() {
1306 fn assert_send_sync<T: Send + Sync>() {}
1307 assert_send_sync::<OwnedView<SimpleMessageView<'static>>>();
1308 }
1309
1310 #[test]
1311 fn owned_view_from_owned_roundtrips() {
1312 let msg = SimpleMessage {
1313 id: 99,
1314 name: "roundtrip".into(),
1315 };
1316 let view = OwnedView::<SimpleMessageView<'static>>::from_owned(&msg).expect("from_owned");
1317 assert_eq!(view.id, 99);
1318 assert_eq!(view.name, "roundtrip");
1319
1320 let back = view.to_owned_message();
1321 assert_eq!(back, msg);
1322 }
1323
1324 #[test]
1325 fn owned_view_decode_with_options() {
1326 let bytes = encode_simple(42, "opts");
1327 let opts = crate::DecodeOptions::new().with_max_message_size(1024);
1328 let view =
1329 OwnedView::<SimpleMessageView<'static>>::decode_with_options(bytes, &opts).unwrap();
1330 assert_eq!(view.id, 42);
1331 assert_eq!(view.name, "opts");
1332 }
1333
1334 #[test]
1335 fn owned_view_decode_with_options_rejects_oversized() {
1336 let bytes = encode_simple(42, "too large");
1337 let opts = crate::DecodeOptions::new().with_max_message_size(2);
1338 let result = OwnedView::<SimpleMessageView<'static>>::decode_with_options(bytes, &opts);
1339 assert!(result.is_err());
1340 }
1341
1342 #[test]
1343 fn owned_view_clone_survives_original_drop() {
1344 let bytes = encode_simple(42, "cloned");
1345 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
1346 let cloned = view.clone();
1347 drop(view); // drop original — clone must still be valid
1348 assert_eq!(cloned.id, 42);
1349 assert_eq!(cloned.name, "cloned");
1350 }
1351
1352 #[test]
1353 fn owned_view_clone_equality() {
1354 let bytes = encode_simple(42, "eq");
1355 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
1356 let cloned = view.clone();
1357 assert_eq!(view, cloned);
1358 }
1359
1360 #[test]
1361 fn owned_view_eq_same_data() {
1362 let a = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(1, "x")).unwrap();
1363 let b = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(1, "x")).unwrap();
1364 assert_eq!(a, b);
1365 }
1366
1367 #[test]
1368 fn owned_view_ne_different_data() {
1369 let a = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(1, "x")).unwrap();
1370 let b = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(2, "y")).unwrap();
1371 assert_ne!(a, b);
1372 }
1373
1374 #[test]
1375 fn owned_view_into_bytes_after_clone() {
1376 let bytes = encode_simple(42, "test");
1377 let expected = bytes.clone();
1378 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
1379 let cloned = view.clone();
1380 drop(view); // drop original first
1381 let recovered = cloned.into_bytes();
1382 assert_eq!(recovered, expected);
1383 }
1384
1385 #[test]
1386 fn owned_view_drop_count() {
1387 use core::sync::atomic::{AtomicUsize, Ordering};
1388
1389 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1390
1391 /// A wrapper view that counts drops.
1392 struct DropCountingView<'a> {
1393 inner: SimpleMessageView<'a>,
1394 }
1395
1396 impl Drop for DropCountingView<'_> {
1397 fn drop(&mut self) {
1398 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1399 }
1400 }
1401
1402 impl<'a> MessageView<'a> for DropCountingView<'a> {
1403 type Owned = SimpleMessage;
1404
1405 fn decode_view(buf: &'a [u8]) -> Result<Self, DecodeError> {
1406 Ok(DropCountingView {
1407 inner: SimpleMessageView::decode_view(buf)?,
1408 })
1409 }
1410
1411 fn to_owned_message(&self) -> SimpleMessage {
1412 self.inner.to_owned_message()
1413 }
1414 }
1415
1416 // Test normal drop: view drops exactly once.
1417 DROP_COUNT.store(0, Ordering::SeqCst);
1418 {
1419 let bytes = encode_simple(1, "drop");
1420 let _view = OwnedView::<DropCountingView<'static>>::decode(bytes).unwrap();
1421 }
1422 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1, "normal drop");
1423
1424 // Test into_bytes: view drops exactly once.
1425 DROP_COUNT.store(0, Ordering::SeqCst);
1426 {
1427 let bytes = encode_simple(2, "into");
1428 let view = OwnedView::<DropCountingView<'static>>::decode(bytes).unwrap();
1429 let _bytes = view.into_bytes();
1430 }
1431 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1, "into_bytes drop");
1432 }
1433
1434 #[test]
1435 fn owned_view_name_borrows_from_bytes_buffer() {
1436 let bytes = encode_simple(42, "borrowed");
1437 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
1438 let buf = view.bytes();
1439 let buf_start = buf.as_ptr() as usize;
1440 let buf_end = buf_start + buf.len();
1441 let name_ptr = view.name.as_ptr() as usize;
1442 assert!(
1443 (buf_start..buf_end).contains(&name_ptr),
1444 "view.name should point into the Bytes buffer"
1445 );
1446 }
1447
1448 #[test]
1449 fn owned_view_concurrent_read() {
1450 use alloc::sync::Arc;
1451
1452 let bytes = encode_simple(42, "concurrent");
1453 let view = Arc::new(OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap());
1454 let handles: alloc::vec::Vec<_> = (0..4)
1455 .map(|_| {
1456 let v = Arc::clone(&view);
1457 std::thread::spawn(move || {
1458 assert_eq!(v.id, 42);
1459 assert_eq!(v.name, "concurrent");
1460 })
1461 })
1462 .collect();
1463 for h in handles {
1464 h.join().unwrap();
1465 }
1466 }
1467
1468 #[test]
1469 fn owned_view_from_parts_roundtrip() {
1470 let bytes = encode_simple(42, "parts");
1471 // Decode a view from the bytes, then wrap via from_parts.
1472 // SAFETY: `view` was decoded from `bytes`.
1473 let view = unsafe {
1474 let slice: &'static [u8] = core::mem::transmute::<&[u8], &'static [u8]>(&bytes);
1475 let decoded = SimpleMessageView::decode_view(slice).unwrap();
1476 OwnedView::<SimpleMessageView<'static>>::from_parts(bytes, decoded)
1477 };
1478 assert_eq!(view.id, 42);
1479 assert_eq!(view.name, "parts");
1480 }
1481}