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//! # Reborrowing from `OwnedView`
41//!
42//! [`OwnedView<V>`](OwnedView) wraps a decoded view with the lifetime erased
43//! to `'static`. The inner view is reached through
44//! [`OwnedView::reborrow`], which ties the borrow to the `OwnedView` itself —
45//! field reads, assigning the view to a binding, passing it to a function
46//! with a non-`'static` lifetime parameter, and returning a borrowed field
47//! all go through the same call:
48//!
49//! ```no_run
50//! # use buffa::view::OwnedView;
51//! # use buffa::__doctest_fixtures::PersonView;
52//! // reborrow ties the returned borrow to the OwnedView's lifetime.
53//! fn handler<'a>(req: &'a OwnedView<PersonView<'static>>) -> &'a str {
54//! req.reborrow().name
55//! }
56//! ```
57//!
58//! The view is deliberately not exposed as `&V` (e.g. via `Deref`): `V` is
59//! `FooView<'static>`, so its borrowed fields would *appear* `'static` to the
60//! compiler and could outlive the buffer they point into. `reborrow` narrows
61//! that synthetic `'static` down to the `OwnedView`'s real lifetime. Generated
62//! code also provides a per-message `FooOwnedView` wrapper with field accessor
63//! methods, so handler code rarely needs to call `reborrow` directly. See
64//! [`OwnedView`] for details.
65//!
66//! # Generated code shape
67//!
68//! For a message like:
69//! ```protobuf
70//! message Person {
71//! string name = 1;
72//! int32 id = 2;
73//! bytes avatar = 3;
74//! repeated string tags = 4;
75//! Address address = 5;
76//! }
77//! ```
78//!
79//! Buffa generates:
80//! ```rust,ignore
81//! // Owned type (heap-allocated strings and vecs)
82//! pub struct Person {
83//! pub name: String,
84//! pub id: i32,
85//! pub avatar: Vec<u8>,
86//! pub tags: Vec<String>,
87//! pub address: MessageField<Address>,
88//! #[doc(hidden)] pub __buffa_unknown_fields: UnknownFields,
89//! }
90//!
91//! // Borrowed view type (zero-copy from input buffer)
92//! pub struct PersonView<'a> {
93//! pub name: &'a str,
94//! pub id: i32,
95//! pub avatar: &'a [u8],
96//! pub tags: RepeatedView<'a, &'a str>,
97//! pub address: MessageFieldView<AddressView<'a>>,
98//! pub __buffa_unknown_fields: UnknownFieldsView<'a>,
99//! }
100//! ```
101
102use crate::error::DecodeError;
103use crate::message::Message as _;
104use bytes::{BufMut, Bytes};
105
106/// Trait for zero-copy borrowed message views.
107///
108/// View types borrow from the input buffer and provide read-only access
109/// to message fields without allocation. Each generated `MyMessageView<'a>`
110/// implements this trait.
111///
112/// The lifetime `'a` ties the view to the input buffer — the view cannot
113/// outlive the buffer it was decoded from.
114pub trait MessageView<'a>: Sized {
115 /// The corresponding owned message type.
116 type Owned: crate::Message;
117
118 /// Decode a view from a buffer, borrowing string/bytes fields directly.
119 ///
120 /// The returned view borrows from `buf`'s underlying bytes. The caller
121 /// must ensure the buffer is contiguous (e.g., `&[u8]` or `bytes::Bytes`).
122 ///
123 /// Decoding validates the whole message tree eagerly. For
124 /// decode-on-access of large sub-message trees, see the opt-in
125 /// [`LazyMessageView`] family (`lazy_views` codegen option).
126 ///
127 /// Generated impls construct a default [`DecodeContext`](crate::DecodeContext)
128 /// and delegate to [`decode_view_ctx`](Self::decode_view_ctx). (Kept
129 /// required, without a `Self: Default` bound, so generic callers stay
130 /// bound-free.)
131 fn decode_view(buf: &'a [u8]) -> Result<Self, DecodeError>;
132
133 /// Decode a view under custom decode limits.
134 ///
135 /// Used by [`DecodeOptions::decode_view`](crate::DecodeOptions::decode_view)
136 /// to pass a non-default recursion depth and unknown-field allowance.
137 /// The default implementation delegates to
138 /// [`decode_view`](Self::decode_view) and **ignores the context** —
139 /// a hand-written `MessageView` that recurses or preserves unknown
140 /// fields must override this method to honor the limits configured on
141 /// `DecodeOptions`. Implementing
142 /// [`merge_view_field`](Self::merge_view_field) is **not sufficient**:
143 /// without this override, `DecodeOptions` limits never reach your
144 /// field arms. The one-line override is
145 /// `Self::decode_view_ctx(buf, ctx)` (when `Self: Default`). Generated
146 /// code always overrides it that way.
147 ///
148 /// Not to be confused with [`decode_view_ctx`](Self::decode_view_ctx),
149 /// which is the provided decoder that *honors* the context; this method
150 /// is the override point `DecodeOptions` calls.
151 fn decode_view_with_ctx(
152 buf: &'a [u8],
153 _ctx: crate::DecodeContext<'_>,
154 ) -> Result<Self, DecodeError> {
155 Self::decode_view(buf)
156 }
157
158 /// Decode a view under an explicit [`DecodeContext`](crate::DecodeContext)
159 /// (remaining recursion depth and unknown-field allowance), driving the
160 /// provided tag loop over [`merge_view_field`](Self::merge_view_field).
161 ///
162 /// This is the bridge a hand-written impl uses to wire its required
163 /// `decode_view` to its required `merge_view_field`:
164 ///
165 /// ```rust,ignore
166 /// fn decode_view(buf: &'a [u8]) -> Result<Self, buffa::DecodeError> {
167 /// let limit = core::cell::Cell::new(buffa::DEFAULT_UNKNOWN_FIELD_LIMIT);
168 /// Self::decode_view_ctx(
169 /// buf,
170 /// buffa::DecodeContext::new(buffa::RECURSION_LIMIT, &limit),
171 /// )
172 /// }
173 /// ```
174 ///
175 /// Also called by generated sub-message decode arms with a descended
176 /// context. Not to be confused with
177 /// [`decode_view_with_ctx`](Self::decode_view_with_ctx), the
178 /// `DecodeOptions` override point whose *default* ignores the context.
179 ///
180 /// # Errors
181 ///
182 /// Returns a [`DecodeError`] on malformed input, a wire-type mismatch, or
183 /// when a configured decode limit (recursion depth, unknown-field
184 /// allowance) is exceeded.
185 fn decode_view_ctx(buf: &'a [u8], ctx: crate::DecodeContext<'_>) -> Result<Self, DecodeError>
186 where
187 Self: Default,
188 {
189 let mut view = Self::default();
190 view.merge_into_view(buf, ctx)?;
191 Ok(view)
192 }
193
194 /// Merge fields from `buf` into this view (proto merge semantics):
195 /// repeated fields append, singular fields last-wins, singular message
196 /// fields merge recursively.
197 ///
198 /// The per-message work is the field `match` in
199 /// [`merge_view_field`](Self::merge_view_field); this provided method
200 /// owns the tag loop that every generated view previously restated.
201 /// Each iteration consumes the field's tag itself, so the loop makes
202 /// progress even if an arm consumes no payload bytes.
203 ///
204 /// # Errors
205 ///
206 /// Returns a [`DecodeError`] on malformed input, a wire-type mismatch, or
207 /// when a configured decode limit (recursion depth, unknown-field
208 /// allowance) is exceeded.
209 fn merge_into_view(
210 &mut self,
211 buf: &'a [u8],
212 ctx: crate::DecodeContext<'_>,
213 ) -> Result<(), DecodeError> {
214 let mut cur: &'a [u8] = buf;
215 while !cur.is_empty() {
216 // Captured so unknown fields can preserve their raw byte span
217 // (`before_tag.len() - cur.len()` after the payload is consumed).
218 let before_tag = cur;
219 let tag = crate::encoding::Tag::decode(&mut cur)?;
220 cur = self.merge_view_field(tag, cur, before_tag, ctx)?;
221 }
222 Ok(())
223 }
224
225 /// Decode one field's payload into this view (generated per message).
226 ///
227 /// `cur` is the input positioned just past `tag`; the implementation
228 /// returns the remaining input after the field's payload. The
229 /// pass-by-value/return shape (rather than `&mut &'a [u8]`) keeps each
230 /// arm's `&mut` borrow of the slice local to that arm — sub-message
231 /// arms can hand `cur` slices to recursive decode calls without
232 /// fighting a long-lived outer `&mut` reborrow. `before_tag` is the
233 /// input including the tag bytes, for raw-span unknown-field capture.
234 ///
235 /// Hand-written views must supply this (it is the one method the
236 /// provided decode loop requires). A view that instead overrides both
237 /// [`decode_view`](Self::decode_view) and
238 /// [`decode_view_with_ctx`](Self::decode_view_with_ctx) to decode by hand
239 /// never reaches the provided loop, so it can satisfy the trait with a
240 /// one-line `Ok(cur)` stub. The canonical shape is a match on
241 /// `tag.field_number()`:
242 ///
243 /// ```rust,ignore
244 /// fn merge_view_field(
245 /// &mut self,
246 /// tag: buffa::encoding::Tag,
247 /// cur: &'a [u8],
248 /// _before_tag: &'a [u8],
249 /// ctx: buffa::DecodeContext<'_>,
250 /// ) -> Result<&'a [u8], buffa::DecodeError> {
251 /// let mut cur = cur;
252 /// match tag.field_number() {
253 /// 1 => self.id = buffa::types::decode_int32(&mut cur)?,
254 /// 2 => self.name = buffa::types::borrow_str(&mut cur)?,
255 /// _ => buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?,
256 /// }
257 /// Ok(cur)
258 /// }
259 /// ```
260 ///
261 /// Views that preserve unknown fields capture the raw span — tag
262 /// included — via `before_tag` (the span length is measured *after* the
263 /// payload is consumed) and store it with
264 /// [`UnknownFieldsView::push_record`], which charges the context's
265 /// unknown-field allowance per field (including fields nested in
266 /// unknown groups) so that [`to_owned_message`](Self::to_owned_message)
267 /// cannot exhaust it later; the provided loop stays message-agnostic:
268 ///
269 /// ```rust,ignore
270 /// _ => {
271 /// buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?;
272 /// let span_len = before_tag.len() - cur.len();
273 /// self.unknown_fields.push_record(before_tag, span_len, ctx)?;
274 /// }
275 /// ```
276 ///
277 /// The returned slice must be a suffix of `cur` (and hence of
278 /// `before_tag`): the provided loop continues from it, and the
279 /// unknown-field span is measured as `before_tag.len() - cur.len()`, which
280 /// underflows and panics if the returned slice is longer than the input.
281 ///
282 /// # Errors
283 ///
284 /// Returns a [`DecodeError`] on malformed payloads or wire-type
285 /// mismatches.
286 fn merge_view_field(
287 &mut self,
288 tag: crate::encoding::Tag,
289 cur: &'a [u8],
290 before_tag: &'a [u8],
291 ctx: crate::DecodeContext<'_>,
292 ) -> Result<&'a [u8], DecodeError>;
293
294 /// Convert this view to the owned message type.
295 ///
296 /// This allocates and copies all borrowed fields. Equivalent to
297 /// [`to_owned_from_source(None)`](Self::to_owned_from_source).
298 ///
299 /// For views produced by [`decode_view`](Self::decode_view) (or the
300 /// other wire-decoding entry points), this cannot fail: decoding
301 /// charged the unknown-field allowance with exactly the slots that
302 /// re-materializing preserved unknown fields consumes, every span was
303 /// parsed off the wire, and re-materialization replays under the field
304 /// budget and group-nesting depth recorded at decode time. The `Result`
305 /// remains for hand-written view impls and for views holding manually
306 /// pushed ([`UnknownFieldsView::push_raw`]) unknown-field spans.
307 ///
308 /// # Errors
309 ///
310 /// Returns an error if re-materializing preserved unknown fields fails —
311 /// possible only for views not produced by wire decoding, as described
312 /// above.
313 fn to_owned_message(&self) -> Result<Self::Owned, DecodeError>;
314
315 /// Convert this view to the owned message type, optionally slicing
316 /// `bytes::Bytes`-typed fields from `source` instead of copying.
317 ///
318 /// When `source` is the [`Bytes`] buffer this view was decoded from,
319 /// owned fields configured for `bytes::Bytes` (via the `bytes_fields`
320 /// codegen option) are produced via [`Bytes::slice_ref`] — a refcount
321 /// bump, no allocation or copy. Borrowed fields that fall outside
322 /// `source` (e.g. on a manually-constructed view) and the `None` case
323 /// fall back to [`Bytes::copy_from_slice`].
324 ///
325 /// Generated view types override this; the default delegates to
326 /// [`to_owned_message`](Self::to_owned_message) so hand-written impls
327 /// need only provide that method.
328 ///
329 /// # Errors
330 ///
331 /// Same contract as [`to_owned_message`](Self::to_owned_message).
332 fn to_owned_from_source(&self, source: Option<&Bytes>) -> Result<Self::Owned, DecodeError> {
333 let _ = source;
334 self.to_owned_message()
335 }
336}
337
338/// Exposes the real lifetime of an [`OwnedView`]'s borrows.
339///
340/// `OwnedView<V>` stores `V` with a `'static` lifetime — the actual borrows
341/// point into its internal [`Bytes`] buffer. `ViewReborrow` lets
342/// [`OwnedView::reborrow`] return a reference typed as `&'b V::Reborrowed<'b>`,
343/// tying the borrow to `&'b self` so the compiler can reason about it correctly.
344///
345/// Codegen emits `impl ViewReborrow` automatically for every generated view
346/// type. Hand-written view types must provide it manually if
347/// [`OwnedView::reborrow`] is needed.
348///
349/// # Soundness
350///
351/// `ViewReborrow` is a **safe** trait. Soundness is established mechanically
352/// by the compiler at each impl site: the [`reborrow`](Self::reborrow) method
353/// body coerces a `&'b Self` (where `Self = FooView<'static>`) to
354/// `&'b Self::Reborrowed<'b>` (= `&'b FooView<'b>`). Rust accepts this only
355/// when `FooView` is **covariant** in its lifetime parameter — a covariant
356/// `FooView<'static>` is a subtype of `FooView<'b>` and the coercion is a
357/// standard subtyping move. Invariant fields (`Cell<&'a T>`, `&'a mut T`,
358/// `fn(&'a T)`) make the type invariant in `'a`; the trait body then fails
359/// to compile and the impl is rejected — which is exactly what should
360/// happen, because narrowing the lifetime of an invariant view *would* be
361/// unsound.
362///
363/// Hand-written impls cannot accidentally introduce undefined behaviour
364/// without writing `unsafe` themselves: the canonical body is just `this`,
365/// which the type checker accepts iff the variance permits the coercion.
366#[rustversion::attr(
367 since(1.78),
368 diagnostic::on_unimplemented(
369 message = "`{Self}` does not implement `ViewReborrow` — required by `OwnedView::reborrow`",
370 note = "for a generated view type, this impl is emitted automatically by codegen",
371 note = "for a hand-written view type `MyView<'a>`, add:\n impl ViewReborrow for MyView<'static> {{\n type Reborrowed<'b> = MyView<'b>;\n fn reborrow<'b>(this: &'b Self) -> &'b Self::Reborrowed<'b> {{ this }}\n }}",
372 note = "your `MessageView` impl must be parametric over the lifetime — `impl<'a> MessageView<'a> for MyView<'a>` — so that both `Self: MessageView<'static>` and `Reborrowed<'b>: MessageView<'b>` hold",
373 note = "`MyView` must be covariant in its lifetime — fields like `&'a T` and `MessageFieldView<...>` are covariant; `Cell<&'a T>` and `&'a mut T` are not, and the trait body `{{ this }}` will fail to compile for invariant types"
374 )
375)]
376pub trait ViewReborrow: MessageView<'static> {
377 /// The same view type with its lifetime shortened to `'b`.
378 type Reborrowed<'b>: MessageView<'b, Owned = <Self as MessageView<'static>>::Owned>
379 where
380 Self: 'b;
381
382 /// Coerce `&'b Self` (= `&'b FooView<'static>`) to
383 /// `&'b Self::Reborrowed<'b>` (= `&'b FooView<'b>`). The canonical body
384 /// is just `this`; the compiler accepts it via standard lifetime
385 /// variance for covariant view types.
386 ///
387 /// Called by [`OwnedView::reborrow`]; users shouldn't need to call this
388 /// method directly.
389 fn reborrow<'b>(this: &'b Self) -> &'b Self::Reborrowed<'b>;
390}
391
392/// Implement [`ViewReborrow`] for a generated view type.
393///
394/// Emitted by generated code (one invocation per view struct); the trait's
395/// `on_unimplemented` note shows the equivalent expansion for hand-written
396/// views.
397///
398/// ```rust,ignore
399/// buffa::impl_view_reborrow!(MyMessageView);
400/// ```
401#[macro_export]
402macro_rules! impl_view_reborrow {
403 ($ty:ident) => {
404 impl $crate::ViewReborrow for $ty<'static> {
405 type Reborrowed<'b> = $ty<'b>;
406 fn reborrow<'b>(this: &'b Self) -> &'b Self::Reborrowed<'b> {
407 this
408 }
409 }
410 };
411}
412
413/// Links an owned message type to its generated zero-copy view types.
414///
415/// For a message `Foo`, generated code implements this trait as
416/// `View<'a> = FooView<'a>` (the borrowed view) and
417/// `ViewHandle = FooOwnedView` (the self-contained `'static` handle). The
418/// trait lets code that is generic over an owned message name those types —
419/// for example an RPC framework that decodes `M::View<'_>` from a request
420/// body it owns, or holds `M::ViewHandle` items in a stream — without
421/// per-message glue on the consumer's side.
422///
423/// The associated types intentionally carry only structural bounds:
424///
425/// - [`View<'a>`](Self::View) is the message's view, with
426/// [`Owned`](MessageView::Owned)` = Self`.
427/// - [`ViewHandle`](Self::ViewHandle) is convertible from, and exposes via
428/// [`AsRef`], the corresponding `OwnedView<Self::View<'static>>`, so
429/// generic code can reach [`reborrow`](OwnedView::reborrow),
430/// [`bytes`](OwnedView::bytes), and
431/// [`to_owned_message`](OwnedView::to_owned_message) without naming the
432/// concrete wrapper. The wrapper's per-field accessor methods remain
433/// inherent on the concrete type.
434///
435/// Generic code that wants to reborrow through the handle
436/// (`handle.as_ref().reborrow()`) adds `M::View<'static>: ViewReborrow` as a
437/// bound at the use site; every generated view satisfies it. (The bound
438/// cannot live on the trait itself: a `where Self::View<'static>:
439/// ViewReborrow` clause currently trips a GAT normalization error, E0308
440/// "expected `MessageView<'a>`, found `MessageView<'static>`".)
441///
442/// # Implementing
443///
444/// Implementations are generated alongside the view and owned-view wrapper
445/// (and are therefore gated with them). Hand-written implementations are only
446/// needed for hand-written view types and must follow the same shape.
447#[rustversion::attr(
448 since(1.78),
449 diagnostic::on_unimplemented(
450 message = "`{Self}` does not implement `HasMessageView` — its message-view family was not generated or is not enabled",
451 note = "the `HasMessageView` impl is emitted next to each message's view types: \
452 regenerate the crate that defines `{Self}` with buffa 0.7.0 or newer and \
453 views enabled — `generate_views(true)` (on by default) in a buffa-build / \
454 buffa-codegen config, or `views=true` for protoc-gen-buffa",
455 note = "if the defining crate feature-gates its generated impls, enabling its views \
456 feature is enough — no regeneration needed"
457 )
458)]
459pub trait HasMessageView: crate::Message + Sized {
460 /// The zero-copy view of `Self`, borrowing from a buffer with lifetime
461 /// `'a`.
462 type View<'a>: MessageView<'a, Owned = Self> + Send + Sync;
463
464 /// The generated `'static` owned-view handle for `Self`
465 /// (`FooOwnedView`).
466 type ViewHandle: From<OwnedView<Self::View<'static>>>
467 + AsRef<OwnedView<Self::View<'static>>>
468 + Send
469 + Sync
470 + 'static;
471
472 /// Decode a borrowed [`View`](Self::View) from a byte slice.
473 ///
474 /// Convenience for generic code: lets a caller bounded only on
475 /// `M: HasMessageView` write `M::decode_view(buf)` instead of the
476 /// associated-type path
477 /// `<M as HasMessageView>::View::decode_view(buf)`. The returned view
478 /// borrows from `buf`. Reading the returned view (e.g.
479 /// [`to_owned_message`](MessageView::to_owned_message)) requires
480 /// [`MessageView`] in scope.
481 ///
482 /// Like the underlying [`MessageView::decode_view`], this does not
483 /// enforce `max_message_size`; use
484 /// [`decode_view_with_options`](Self::decode_view_with_options) for that.
485 ///
486 /// # Errors
487 ///
488 /// Returns [`DecodeError`] if the buffer contains invalid protobuf data.
489 #[inline]
490 fn decode_view(buf: &[u8]) -> Result<Self::View<'_>, DecodeError> {
491 <Self::View<'_> as MessageView<'_>>::decode_view(buf)
492 }
493
494 /// Decode a borrowed [`View`](Self::View) under custom
495 /// [`DecodeOptions`](crate::DecodeOptions) (recursion limit, max message
496 /// size, unknown-field limit).
497 ///
498 /// Convenience for generic code; equivalent to
499 /// [`DecodeOptions::decode_view::<M::View<'_>>`](crate::DecodeOptions::decode_view).
500 ///
501 /// # Errors
502 ///
503 /// Returns [`DecodeError`] if the buffer is invalid or exceeds the
504 /// configured limits.
505 #[inline]
506 fn decode_view_with_options<'a>(
507 buf: &'a [u8],
508 opts: &crate::DecodeOptions,
509 ) -> Result<Self::View<'a>, DecodeError> {
510 opts.decode_view(buf)
511 }
512
513 /// Decode a [`ViewHandle`](Self::ViewHandle) from a [`Bytes`] buffer.
514 ///
515 /// Convenience for generic code; equivalent to decoding an
516 /// [`OwnedView<Self::View<'static>>`](OwnedView) and converting it with
517 /// `From`.
518 ///
519 /// # Errors
520 ///
521 /// Returns [`DecodeError`] if the buffer contains invalid protobuf data.
522 fn decode_view_handle(bytes: Bytes) -> Result<Self::ViewHandle, DecodeError> {
523 Ok(Self::ViewHandle::from(
524 OwnedView::<Self::View<'static>>::decode(bytes)?,
525 ))
526 }
527
528 /// Decode a [`ViewHandle`](Self::ViewHandle) with custom
529 /// [`DecodeOptions`](crate::DecodeOptions) (recursion limit, max message
530 /// size).
531 ///
532 /// # Errors
533 ///
534 /// Returns [`DecodeError`] if the buffer is invalid or exceeds the
535 /// configured limits.
536 fn decode_view_handle_with_options(
537 bytes: Bytes,
538 opts: &crate::DecodeOptions,
539 ) -> Result<Self::ViewHandle, DecodeError> {
540 Ok(Self::ViewHandle::from(
541 OwnedView::<Self::View<'static>>::decode_with_options(bytes, opts)?,
542 ))
543 }
544}
545
546/// Produce a [`Bytes`] for a borrowed slice, preferring a zero-copy
547/// [`Bytes::slice_ref`] into `source` when the slice lies within it.
548///
549/// Used by generated [`MessageView::to_owned_from_source`] for
550/// `bytes_fields`. Empty slices return [`Bytes::new`]; slices outside
551/// `source` (or `source = None`) fall back to [`Bytes::copy_from_slice`].
552#[doc(hidden)]
553#[inline]
554pub fn bytes_from_source(source: Option<&Bytes>, slice: &[u8]) -> Bytes {
555 if slice.is_empty() {
556 return Bytes::new();
557 }
558 if let Some(b) = source {
559 // Mirrors `slice_ref`'s own containment precondition so we fall back
560 // to copy (rather than panic) for slices outside `source`.
561 let b_start = b.as_ptr() as usize;
562 let s_start = slice.as_ptr() as usize;
563 if let (Some(b_end), Some(s_end)) = (
564 b_start.checked_add(b.len()),
565 s_start.checked_add(slice.len()),
566 ) {
567 if s_start >= b_start && s_end <= b_end {
568 return b.slice_ref(slice);
569 }
570 }
571 }
572 Bytes::copy_from_slice(slice)
573}
574
575/// Serialize a [`MessageView`] directly from its borrowed fields.
576///
577/// Symmetric with [`Message`](crate::Message)'s two-pass
578/// `compute_size` / `write_to` model, but the `&'a str` / `&'a [u8]` /
579/// [`MapView`] / [`RepeatedView`] fields are written by borrow — no
580/// owned-struct intermediary, no per-field `String`/`Vec<u8>` allocations.
581///
582/// Generated `*View<'a>` types implement this trait whenever views are
583/// generated (`generate_views(true)`, the default). Serialization state
584/// lives in the external [`SizeCache`](crate::SizeCache), not the view —
585/// view structs hold no interior mutability and remain `Send + Sync`.
586///
587/// ## When to use
588///
589/// Reach for `ViewEncode` when the source data is already in memory and
590/// you would otherwise allocate an owned message just to encode-then-drop
591/// it — e.g. an RPC handler serializing from app state. If you already
592/// hold the owned message, use [`Message::encode`](crate::Message::encode)
593/// instead; the wire output is identical.
594///
595/// ```rust,ignore
596/// let view = PersonView {
597/// name: "borrowed",
598/// tags: ["a", "b"].iter().copied().collect(),
599/// ..Default::default()
600/// };
601/// let bytes = view.encode_to_vec();
602/// ```
603#[rustversion::attr(
604 since(1.78),
605 diagnostic::on_unimplemented(
606 message = "`{Self}` does not implement `ViewEncode` — view types were not generated for this message",
607 note = "ViewEncode is implemented on every generated `*View<'a>` type; enable `generate_views(true)` (on by default) in your buffa-build / buffa-codegen config"
608 )
609)]
610pub trait ViewEncode<'a>: MessageView<'a> {
611 /// Compute the encoded byte size of this view, recording nested
612 /// sub-message sizes in `cache` for [`write_to`](Self::write_to)
613 /// to consume.
614 ///
615 /// Most callers should use [`encode`](Self::encode) instead, which runs
616 /// both passes with a fresh cache.
617 fn compute_size(&self, cache: &mut crate::SizeCache) -> u32;
618
619 /// Write this view's encoded bytes to a buffer, consuming
620 /// nested-message sizes from `cache` (populated by a prior
621 /// [`compute_size`](Self::compute_size) call on the same cache).
622 ///
623 /// Most callers should use [`encode`](Self::encode) instead.
624 fn write_to(&self, cache: &mut crate::SizeCache, buf: &mut impl BufMut);
625
626 /// Compute size, then write. Primary view-encode entry point.
627 fn encode(&self, buf: &mut impl BufMut) {
628 let mut cache = crate::SizeCache::new();
629 self.compute_size(&mut cache);
630 self.write_to(&mut cache, buf);
631 }
632
633 /// Encode using a caller-supplied [`SizeCache`](crate::SizeCache), for
634 /// reuse across many encodes in a hot loop. Clears the cache first.
635 fn encode_with_cache(&self, cache: &mut crate::SizeCache, buf: &mut impl BufMut) {
636 cache.clear();
637 self.compute_size(cache);
638 self.write_to(cache, buf);
639 }
640
641 /// Compute the encoded byte size of this view.
642 ///
643 /// Walks the view tree, discarding the intermediate
644 /// [`SizeCache`](crate::SizeCache). If you also intend to encode,
645 /// prefer [`encode`](Self::encode) or [`encode_to_vec`](Self::encode_to_vec)
646 /// — they do a single size pass and reuse the cache for the write.
647 #[must_use]
648 fn encoded_len(&self) -> u32 {
649 self.compute_size(&mut crate::SizeCache::new())
650 }
651
652 /// Encode this view as a length-delimited byte sequence.
653 fn encode_length_delimited(&self, buf: &mut impl BufMut) {
654 let mut cache = crate::SizeCache::new();
655 let len = self.compute_size(&mut cache);
656 crate::encoding::encode_varint(len as u64, buf);
657 self.write_to(&mut cache, buf);
658 }
659
660 /// Encode this view to a new `Vec<u8>`.
661 #[must_use]
662 fn encode_to_vec(&self) -> alloc::vec::Vec<u8> {
663 let mut cache = crate::SizeCache::new();
664 let size = self.compute_size(&mut cache) as usize;
665 let mut buf = alloc::vec::Vec::with_capacity(size);
666 self.write_to(&mut cache, &mut buf);
667 buf
668 }
669
670 /// Encode this view to a new [`bytes::Bytes`].
671 #[must_use]
672 fn encode_to_bytes(&self) -> Bytes {
673 let mut cache = crate::SizeCache::new();
674 let size = self.compute_size(&mut cache) as usize;
675 let mut buf = bytes::BytesMut::with_capacity(size);
676 self.write_to(&mut cache, &mut buf);
677 buf.freeze()
678 }
679}
680
681/// Provides access to a lazily-initialized default view instance.
682///
683/// View types implement this trait so that [`MessageFieldView`] can
684/// dereference to a default when unset, just as [`MessageField`](crate::MessageField)
685/// does for owned types via [`DefaultInstance`](crate::DefaultInstance).
686///
687/// Generated view types like `FooView<'a>` contain only covariant borrows
688/// (`&'a str`, `&'a [u8]`, etc.). A default view holds only `'static` data
689/// (`""`, `&[]`, `0`), so an implementation stores a single
690/// `&'static FooView<'static>` and returns it at the caller's lifetime via
691/// ordinary covariant subtyping — the compiler verifies covariance at the
692/// `impl` site, so no `unsafe` is required.
693///
694/// # Recommended implementation
695///
696/// The pattern codegen uses (and the recommended pattern for hand-written
697/// view types) stores the instance in a static
698/// [`once_cell::race::OnceBox`] (re-exported as
699/// `::buffa::__private::OnceBox`):
700///
701/// ```rust,ignore
702/// impl<'v> DefaultViewInstance for MyView<'v> {
703/// fn default_view_instance<'a>() -> &'a Self
704/// where
705/// Self: 'a,
706/// {
707/// static VALUE: ::buffa::__private::OnceBox<MyView<'static>>
708/// = ::buffa::__private::OnceBox::new();
709/// VALUE.get_or_init(|| Box::new(<MyView<'static>>::default()))
710/// }
711/// }
712/// ```
713///
714/// The return expression has type `&'static MyView<'static>`; the compiler
715/// coerces it to `&'a MyView<'v>` iff `MyView` is covariant in `'v` —
716/// non-covariant view types fail to compile here rather than risk an
717/// unsound cast.
718///
719/// # Non-covariant types are rejected
720///
721/// A type that is invariant in its lifetime parameter cannot satisfy the
722/// recommended pattern, because the `&'static T<'static> → &'a T<'v>`
723/// coercion is refused:
724///
725/// ```compile_fail
726/// # use core::marker::PhantomData;
727/// // `fn(&'v ()) -> &'v ()` is invariant in 'v, making `Invariant<'v>` invariant.
728/// struct Invariant<'v>(PhantomData<fn(&'v ()) -> &'v ()>);
729/// static INST: Invariant<'static> = Invariant(PhantomData);
730///
731/// impl<'v> buffa::view::DefaultViewInstance for Invariant<'v> {
732/// fn default_view_instance<'a>() -> &'a Self where Self: 'a {
733/// // error: lifetime may not live long enough
734/// // note: requirement occurs because of the type `Invariant<'_>`,
735/// // which makes the generic argument `'_` invariant
736/// &INST
737/// }
738/// }
739/// ```
740pub trait DefaultViewInstance {
741 /// Return a reference to the single default view instance.
742 ///
743 /// The lifetime `'a` is caller-chosen up to `Self: 'a`, so a
744 /// `FooView<'v>` can serve its `'static` default at any `'a ≤ 'v`.
745 fn default_view_instance<'a>() -> &'a Self
746 where
747 Self: 'a;
748}
749
750/// Implement [`DefaultViewInstance`] for a generated view type via a
751/// lazily-initialized `OnceBox<FooView<'static>>` singleton.
752///
753/// Emitted by generated code (one invocation per view struct). The static
754/// holds the `'static` instantiation; returning it at any shorter `'a` is
755/// sound because view lifetimes are covariant.
756///
757/// ```rust,ignore
758/// buffa::impl_default_view_instance!(MyMessageView);
759/// ```
760#[macro_export]
761macro_rules! impl_default_view_instance {
762 ($ty:ident) => {
763 impl<'v> $crate::DefaultViewInstance for $ty<'v> {
764 fn default_view_instance<'a>() -> &'a Self
765 where
766 Self: 'a,
767 {
768 static VALUE: $crate::__private::OnceBox<$ty<'static>> =
769 $crate::__private::OnceBox::new();
770 VALUE.get_or_init(|| {
771 $crate::alloc::boxed::Box::new(
772 <$ty<'static> as ::core::default::Default>::default(),
773 )
774 })
775 }
776 }
777 };
778}
779
780/// A borrowed view of an optional message field.
781///
782/// Analogous to [`MessageField<T>`](crate::MessageField) but for the view
783/// layer. Like `MessageField`, the inner view is **boxed** — recursive
784/// message types (`Foo { NestedMessage { corecursive: Foo } }`) would
785/// otherwise have infinite size. The box is API-transparent: `Deref`
786/// returns `&V`, and `set()` takes `V` by value.
787///
788/// When `V` implements [`DefaultViewInstance`], this type implements
789/// [`Deref<Target = V>`](core::ops::Deref), returning a reference to a
790/// static default instance when the field is unset — making view code
791/// identical to owned code for field access:
792///
793/// ```rust,ignore
794/// // Both work the same, regardless of whether `address` is set:
795/// let city = owned_msg.address.city; // MessageField<Address>
796/// let city = view_msg.address.city; // MessageFieldView<AddressView>
797/// ```
798///
799/// The lifetime of the contained view type `V` (e.g. `AddressView<'a>`)
800/// ties this to the input buffer — no separate lifetime parameter is
801/// needed here.
802#[derive(Clone, Debug)]
803pub struct MessageFieldView<V> {
804 inner: Option<alloc::boxed::Box<V>>,
805}
806
807impl<V> MessageFieldView<V> {
808 /// An unset field (the default).
809 #[inline]
810 pub const fn unset() -> Self {
811 Self { inner: None }
812 }
813
814 /// A set field with the given view value.
815 #[inline]
816 pub fn set(v: V) -> Self {
817 Self {
818 inner: Some(alloc::boxed::Box::new(v)),
819 }
820 }
821
822 /// Alias for [`set`](Self::set), mirroring owned
823 /// [`MessageField::some`](crate::MessageField::some).
824 #[inline]
825 pub fn some(v: V) -> Self {
826 Self::set(v)
827 }
828
829 /// Returns `true` if the field has a value.
830 #[inline]
831 pub const fn is_set(&self) -> bool {
832 self.inner.is_some()
833 }
834
835 /// Returns `true` if the field has no value.
836 #[inline]
837 pub const fn is_unset(&self) -> bool {
838 self.inner.is_none()
839 }
840
841 /// Get a reference to the inner view, or `None` if unset.
842 #[inline]
843 pub fn as_option(&self) -> Option<&V> {
844 self.inner.as_deref()
845 }
846
847 /// Get a mutable reference to the inner view, or `None` if unset.
848 ///
849 /// Used by generated decode code to merge a second occurrence of a
850 /// message field into an existing value (proto merge semantics).
851 #[inline]
852 pub fn as_mut(&mut self) -> Option<&mut V> {
853 self.inner.as_deref_mut()
854 }
855}
856
857impl<'a, V: ViewEncode<'a>> MessageFieldView<V> {
858 /// Forward to the inner view's [`compute_size`](ViewEncode::compute_size),
859 /// or `0` if unset. Generated `compute_size` calls this for nested-message
860 /// fields, mirroring [`MessageField`](crate::MessageField) on the owned side.
861 #[inline]
862 pub fn compute_size(&self, cache: &mut crate::SizeCache) -> u32 {
863 self.inner.as_deref().map_or(0, |v| v.compute_size(cache))
864 }
865
866 /// Forward to the inner view's [`write_to`](ViewEncode::write_to);
867 /// no-op if unset.
868 #[inline]
869 pub fn write_to(&self, cache: &mut crate::SizeCache, buf: &mut impl BufMut) {
870 if let Some(v) = self.inner.as_deref() {
871 v.write_to(cache, buf);
872 }
873 }
874}
875
876impl<V> Default for MessageFieldView<V> {
877 #[inline]
878 fn default() -> Self {
879 Self::unset()
880 }
881}
882
883impl<V> From<V> for MessageFieldView<V> {
884 #[inline]
885 fn from(v: V) -> Self {
886 Self::set(v)
887 }
888}
889
890impl<V: DefaultViewInstance> core::ops::Deref for MessageFieldView<V> {
891 type Target = V;
892
893 #[inline]
894 fn deref(&self) -> &V {
895 self.inner
896 .as_deref()
897 .unwrap_or_else(V::default_view_instance)
898 }
899}
900
901/// Wire-equivalent equality: `Unset` equals `Set(v)` when `v` equals the
902/// default instance.
903///
904/// This matches [`MessageField::eq`](crate::MessageField) on the owned side,
905/// so `view_a == view_b` agrees with
906/// `view_a.to_owned_message() == view_b.to_owned_message()`.
907///
908/// The comparison against the default routes through the
909/// [`Deref`](core::ops::Deref) impl.
910impl<V: PartialEq + DefaultViewInstance> PartialEq for MessageFieldView<V> {
911 fn eq(&self, other: &Self) -> bool {
912 match (&self.inner, &other.inner) {
913 // Short-circuit: two unset fields are equal regardless of whether
914 // V::PartialEq is reflexive (e.g. a view containing an f64 NaN).
915 (None, None) => true,
916 // At least one side is set. Deref handles None → default.
917 _ => {
918 <Self as core::ops::Deref>::deref(self) == <Self as core::ops::Deref>::deref(other)
919 }
920 }
921 }
922}
923
924impl<V: Eq + DefaultViewInstance> Eq for MessageFieldView<V> {}
925
926// ---------------------------------------------------------------------------
927// Lazy views (generated under the `lazy_views` codegen option)
928// ---------------------------------------------------------------------------
929
930/// The trait implemented by generated lazy view types (`FooLazyView<'a>`).
931///
932/// Lazy views are a separate, additive type family generated alongside the
933/// eager `FooView` family under the `lazy_views` codegen option. Where
934/// [`MessageView`]'s contract is "decode succeeded ⇒ the whole tree was
935/// validated", a lazy view's [`decode_lazy`](Self::decode_lazy) performs a
936/// single non-recursive scan over the message's own fields: scalar, string,
937/// and bytes fields are borrowed exactly as in the eager view, while nested
938/// and repeated message fields are *recorded* as undecoded byte ranges (see
939/// [`LazyMessageFieldView`] / [`LazyRepeatedView`]) and decoded only on
940/// access. Deferred validation is therefore visible in the type and trait
941/// bound — generic code over `MessageView` never silently inherits it.
942pub trait LazyMessageView<'a>: Sized {
943 /// The corresponding owned message type.
944 type Owned: crate::Message;
945
946 /// Decode a lazy view from `buf`: one scan over the message's own
947 /// fields, deferring nested message fields.
948 ///
949 /// # Errors
950 ///
951 /// Returns [`DecodeError`] if the message's *own* fields are malformed.
952 /// Deferred sub-message bytes are **not** validated here; they surface
953 /// errors on access.
954 fn decode_lazy(buf: &'a [u8]) -> Result<Self, DecodeError>;
955
956 /// Decode a lazy view under custom decode limits.
957 ///
958 /// Used by [`DecodeOptions::decode_lazy_view`](crate::DecodeOptions::decode_lazy_view).
959 /// The budgets remaining at each deferred field's position are recorded
960 /// and charged when that field is accessed, so custom limits flow through
961 /// deferred decoding. The default implementation delegates to
962 /// [`decode_lazy`](Self::decode_lazy) and **ignores the context**;
963 /// generated code always overrides it.
964 ///
965 /// # Errors
966 ///
967 /// Same contract as [`decode_lazy`](Self::decode_lazy), plus
968 /// [`DecodeError::RecursionLimitExceeded`] /
969 /// [`DecodeError::UnknownFieldLimitExceeded`] when `ctx`'s budgets are
970 /// exhausted by the message's own fields.
971 fn decode_lazy_with_ctx(
972 buf: &'a [u8],
973 ctx: crate::DecodeContext<'_>,
974 ) -> Result<Self, DecodeError> {
975 let _ = ctx;
976 Self::decode_lazy(buf)
977 }
978
979 /// Merge fields decoded from `buf` into this view (proto merge
980 /// semantics: singular scalars last-wins, repeated append, deferred
981 /// message fragments accumulate).
982 ///
983 /// Used by [`LazyMessageFieldView::get`] to reassemble a field whose
984 /// value was split across multiple wire occurrences — application code
985 /// rarely calls this directly.
986 ///
987 /// # Errors
988 ///
989 /// Same contract as [`decode_lazy_with_ctx`](Self::decode_lazy_with_ctx).
990 fn merge_lazy(
991 &mut self,
992 buf: &'a [u8],
993 ctx: crate::DecodeContext<'_>,
994 ) -> Result<(), DecodeError>;
995
996 /// Convert this view to the owned message type.
997 ///
998 /// This decodes every deferred sub-message, so it is where deferred
999 /// validation errors surface. Each deferred subtree decodes under its
1000 /// own replayed unknown-field allowance (see
1001 /// [`LazyMessageFieldView::get`]), so the conversion's total
1002 /// unknown-field records are bounded per subtree, not globally as in an
1003 /// eager decode.
1004 ///
1005 /// # Errors
1006 ///
1007 /// Returns the [`DecodeError`] that accessing a malformed or
1008 /// over-budget deferred field would have reported. Unlike
1009 /// [`MessageView::to_owned_message`], this conversion can genuinely
1010 /// fail for a wire-decoded lazy view: deferred subtrees were never
1011 /// validated (or charged against the unknown-field allowance) at
1012 /// decode time, so their errors surface here.
1013 fn to_owned_message(&self) -> Result<Self::Owned, DecodeError>;
1014}
1015
1016/// Fragments of one singular message field. `Many` only arises when an
1017/// encoder split the field across occurrences, keeping the common
1018/// single-occurrence path allocation-free.
1019#[derive(Clone)]
1020enum LazyFragments<'a> {
1021 None,
1022 One(&'a [u8]),
1023 Many(alloc::vec::Vec<&'a [u8]>),
1024}
1025
1026/// A deferred view of a singular message field on a lazy view.
1027///
1028/// Unlike [`MessageFieldView`] — which eagerly decodes (and boxes) the
1029/// sub-message during decode — this stores only the field's undecoded wire
1030/// bytes and decodes a fresh `V` on each [`get`](Self::get), so decoding the
1031/// enclosing message does not allocate or recurse into sub-messages the
1032/// caller never reads.
1033///
1034/// `get` returns a freshly-decoded view each call (views are thin borrows,
1035/// so this is cheap) and does not cache — bind the result when reading
1036/// several fields.
1037///
1038/// # Merge semantics
1039///
1040/// A singular message field may legally appear more than once on the wire;
1041/// decoders must merge the occurrences. This type stores each occurrence's
1042/// bytes as a separate fragment and [`get`](Self::get) replays them in order
1043/// (decode the first, [`LazyMessageView::merge_lazy`] the rest), so the
1044/// result matches the eager and owned decoders.
1045///
1046/// # Deferred validation and budgets
1047///
1048/// The fragment bytes are *not* validated when the enclosing view is
1049/// decoded; a malformed sub-message surfaces as a [`DecodeError`] from
1050/// [`get`](Self::get). The recursion budget and unknown-field allowance
1051/// remaining when the field was recorded are stored alongside the fragments,
1052/// and each access replays them as a fresh per-subtree budget (see
1053/// [`get`](Self::get) for the approximation this implies). Deep lazy chains
1054/// fail with [`DecodeError::RecursionLimitExceeded`] at the same boundary as
1055/// the eager decoder, and custom limits passed to the enclosing
1056/// [`decode_lazy_with_ctx`](LazyMessageView::decode_lazy_with_ctx) flow
1057/// through.
1058///
1059/// # Re-encoding
1060///
1061/// `ViewEncode` on the enclosing lazy view replays the recorded fragments
1062/// byte-for-byte **without validating them** — re-encoding a never-accessed
1063/// malformed field round-trips its bytes silently.
1064pub struct LazyMessageFieldView<'a, V> {
1065 raw: LazyFragments<'a>,
1066 depth: u32,
1067 allowance: usize,
1068 _marker: core::marker::PhantomData<fn() -> V>,
1069}
1070
1071impl<'a, V> LazyMessageFieldView<'a, V> {
1072 /// An unset field (the default).
1073 #[inline]
1074 pub const fn unset() -> Self {
1075 Self {
1076 raw: LazyFragments::None,
1077 // Sentinels: the first `push_fragment` lowers these to its
1078 // recorded budgets, so custom limits above the defaults aren't
1079 // clamped.
1080 depth: u32::MAX,
1081 allowance: usize::MAX,
1082 _marker: core::marker::PhantomData,
1083 }
1084 }
1085
1086 /// A set field carrying the sub-message's undecoded wire bytes, with the
1087 /// default recursion and unknown-field budgets for access.
1088 #[inline]
1089 pub const fn from_bytes(raw: &'a [u8]) -> Self {
1090 Self {
1091 raw: LazyFragments::One(raw),
1092 depth: crate::RECURSION_LIMIT,
1093 allowance: crate::DEFAULT_UNKNOWN_FIELD_LIMIT,
1094 _marker: core::marker::PhantomData,
1095 }
1096 }
1097
1098 /// Append one wire occurrence of the field (used by generated
1099 /// `decode_lazy`). Fragments accumulate in wire order; [`get`](Self::get)
1100 /// merges them. `ctx` carries the recursion budget and unknown-field
1101 /// allowance remaining at the record site; the smallest pushed budgets
1102 /// are charged on access.
1103 #[doc(hidden)]
1104 #[inline]
1105 pub fn push_fragment(&mut self, raw: &'a [u8], ctx: crate::DecodeContext<'_>) {
1106 self.depth = self.depth.min(ctx.depth());
1107 self.allowance = self.allowance.min(ctx.remaining_unknown_fields());
1108 self.raw = match core::mem::replace(&mut self.raw, LazyFragments::None) {
1109 LazyFragments::None => LazyFragments::One(raw),
1110 LazyFragments::One(first) => LazyFragments::Many(alloc::vec![first, raw]),
1111 LazyFragments::Many(mut frags) => {
1112 frags.push(raw);
1113 LazyFragments::Many(frags)
1114 }
1115 };
1116 }
1117
1118 /// Whether the field is present.
1119 #[inline]
1120 pub const fn is_set(&self) -> bool {
1121 !matches!(self.raw, LazyFragments::None)
1122 }
1123
1124 /// Whether the field has no value.
1125 #[inline]
1126 pub const fn is_unset(&self) -> bool {
1127 matches!(self.raw, LazyFragments::None)
1128 }
1129
1130 /// The undecoded wire fragments, in wire order (empty if unset).
1131 ///
1132 /// A singular message field that appeared exactly once on the wire — the
1133 /// common case — yields one fragment. Encoders that split the field
1134 /// across multiple occurrences yield one fragment per occurrence;
1135 /// [`get`](Self::get) merges them per proto semantics.
1136 #[inline]
1137 pub fn fragments(&self) -> &[&'a [u8]] {
1138 match &self.raw {
1139 LazyFragments::None => &[],
1140 LazyFragments::One(raw) => core::slice::from_ref(raw),
1141 LazyFragments::Many(frags) => frags,
1142 }
1143 }
1144}
1145
1146impl<'a, V: LazyMessageView<'a>> LazyMessageFieldView<'a, V> {
1147 /// Decode and return the sub-message view, or `None` if unset.
1148 ///
1149 /// Multiple wire fragments are merged per proto semantics (see the type
1150 /// docs). The view is re-decoded on every call; there is no cache — bind
1151 /// the result when reading several fields. Note the shape difference
1152 /// from [`LazyRepeatedView::get`], which returns `Option<Result<V, _>>`.
1153 ///
1154 /// Each access rebuilds a fresh decode context from the budgets recorded
1155 /// at decode time, so every deferred subtree independently gets the full
1156 /// recorded unknown-field allowance rather than sharing one pool with
1157 /// its siblings (the original decode call's shared allowance is gone by
1158 /// access time). The unknown-field limit is therefore a *per-subtree*
1159 /// bound on the lazy path, not the global decode-time cap the eager
1160 /// decoder enforces: a full traversal can materialize unknown-field
1161 /// records proportional to input size, where eager
1162 /// [`decode_view`](crate::DecodeOptions::decode_view) rejects such input
1163 /// up front. Prefer the eager path for untrusted input if that global
1164 /// bound matters.
1165 ///
1166 /// # Errors
1167 ///
1168 /// Returns [`DecodeError`] if the deferred bytes are not a valid
1169 /// encoding of `V` — validation happens here, not when the enclosing
1170 /// view was decoded — [`DecodeError::RecursionLimitExceeded`] when the
1171 /// recursion budget recorded at decode time is exhausted, or
1172 /// [`DecodeError::UnknownFieldLimitExceeded`] when the unknown-field
1173 /// allowance recorded at decode time is exhausted.
1174 #[inline]
1175 pub fn get(&self) -> Result<Option<V>, DecodeError> {
1176 let allowance = core::cell::Cell::new(self.allowance);
1177 let ctx = crate::DecodeContext::new(self.depth, &allowance);
1178 match &self.raw {
1179 LazyFragments::None => Ok(None),
1180 LazyFragments::One(raw) => V::decode_lazy_with_ctx(raw, ctx).map(Some),
1181 LazyFragments::Many(frags) => {
1182 // `Many` always holds ≥ 2 fragments (see `push_fragment`);
1183 // the guard is belt-and-suspenders.
1184 let mut iter = frags.iter();
1185 let Some(first) = iter.next() else {
1186 return Ok(None);
1187 };
1188 let mut view = V::decode_lazy_with_ctx(first, ctx)?;
1189 for frag in iter {
1190 view.merge_lazy(frag, ctx)?;
1191 }
1192 Ok(Some(view))
1193 }
1194 }
1195 }
1196
1197 /// Like [`get`](Self::get), but an unset field decodes to the default
1198 /// view — the lazy analogue of [`MessageFieldView`]'s deref-to-default,
1199 /// for the common read path:
1200 ///
1201 /// ```rust,ignore
1202 /// let city = view.address.get_or_default()?.city;
1203 /// ```
1204 ///
1205 /// # Errors
1206 ///
1207 /// Same as [`get`](Self::get).
1208 #[inline]
1209 pub fn get_or_default(&self) -> Result<V, DecodeError>
1210 where
1211 V: Default,
1212 {
1213 Ok(self.get()?.unwrap_or_default())
1214 }
1215}
1216
1217impl<V> Clone for LazyMessageFieldView<'_, V> {
1218 #[inline]
1219 fn clone(&self) -> Self {
1220 Self {
1221 raw: self.raw.clone(),
1222 depth: self.depth,
1223 allowance: self.allowance,
1224 _marker: core::marker::PhantomData,
1225 }
1226 }
1227}
1228impl<V> Default for LazyMessageFieldView<'_, V> {
1229 #[inline]
1230 fn default() -> Self {
1231 Self::unset()
1232 }
1233}
1234impl<V> core::fmt::Debug for LazyMessageFieldView<'_, V> {
1235 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1236 f.debug_struct("LazyMessageFieldView")
1237 .field("is_set", &self.is_set())
1238 .field("fragments", &self.fragments().len())
1239 .finish()
1240 }
1241}
1242
1243/// A deferred view of a repeated message field on a lazy view.
1244///
1245/// Holds the wire byte-slice of each element (cheap pointers) and decodes a
1246/// fresh element view on access ([`get`](Self::get)) or iteration
1247/// ([`iter`](Self::iter)), instead of eagerly decoding every element into a
1248/// `Vec` like [`RepeatedView`].
1249///
1250/// Element bytes are *not* validated when the enclosing view is decoded; a
1251/// malformed element surfaces as a [`DecodeError`] from `get`/`iter`. Unlike
1252/// [`RepeatedView`], this type is not slice-backed: there is no `Deref` or
1253/// indexing, use `get`/`iter`/`len`. Budgets and re-encoding behave as on
1254/// [`LazyMessageFieldView`].
1255pub struct LazyRepeatedView<'a, V> {
1256 elements: alloc::vec::Vec<&'a [u8]>,
1257 depth: u32,
1258 allowance: usize,
1259 _marker: core::marker::PhantomData<fn() -> V>,
1260}
1261
1262impl<'a, V> LazyRepeatedView<'a, V> {
1263 /// An empty repeated field.
1264 #[inline]
1265 pub fn new() -> Self {
1266 Self {
1267 elements: alloc::vec::Vec::new(),
1268 // Sentinels — see `LazyMessageFieldView::unset`.
1269 depth: u32::MAX,
1270 allowance: usize::MAX,
1271 _marker: core::marker::PhantomData,
1272 }
1273 }
1274
1275 /// Number of elements.
1276 #[inline]
1277 pub fn len(&self) -> usize {
1278 self.elements.len()
1279 }
1280
1281 /// Whether the field has no elements.
1282 #[inline]
1283 pub fn is_empty(&self) -> bool {
1284 self.elements.is_empty()
1285 }
1286
1287 /// The undecoded wire bytes of each element, in wire order.
1288 #[inline]
1289 pub fn raw_elements(&self) -> &[&'a [u8]] {
1290 &self.elements
1291 }
1292
1293 /// Append an element's undecoded bytes (used by generated `decode_lazy`).
1294 /// `ctx` carries the recursion budget and unknown-field allowance
1295 /// remaining at the record site; the smallest pushed budgets are charged
1296 /// on access.
1297 #[doc(hidden)]
1298 #[inline]
1299 pub fn push_bytes(&mut self, raw: &'a [u8], ctx: crate::DecodeContext<'_>) {
1300 self.depth = self.depth.min(ctx.depth());
1301 self.allowance = self.allowance.min(ctx.remaining_unknown_fields());
1302 self.elements.push(raw);
1303 }
1304}
1305
1306/// Decode one deferred element under a fresh context carrying the budgets
1307/// recorded at decode time. Each access decodes independently, so each gets
1308/// the full recorded allowance — a per-subtree bound, not the eager
1309/// decoder's shared global pool (see [`LazyMessageFieldView::get`]).
1310#[inline]
1311fn decode_deferred<'a, V: LazyMessageView<'a>>(
1312 raw: &'a [u8],
1313 depth: u32,
1314 allowance: usize,
1315) -> Result<V, DecodeError> {
1316 let cell = core::cell::Cell::new(allowance);
1317 V::decode_lazy_with_ctx(raw, crate::DecodeContext::new(depth, &cell))
1318}
1319
1320impl<'a, V: LazyMessageView<'a>> LazyRepeatedView<'a, V> {
1321 /// Decode the element at `index`, or `None` if out of range.
1322 ///
1323 /// Re-decodes on every call (no cache) — bind the result when reading
1324 /// multiple fields, and avoid calling it inside a tight loop over the
1325 /// same index. Note the shape difference from
1326 /// [`LazyMessageFieldView::get`], which returns `Result<Option<V>, _>`.
1327 #[inline]
1328 pub fn get(&self, index: usize) -> Option<Result<V, DecodeError>> {
1329 self.elements
1330 .get(index)
1331 .map(|b| decode_deferred(b, self.depth, self.allowance))
1332 }
1333
1334 /// Like [`get`](Self::get) with the layers flipped to match
1335 /// [`LazyMessageFieldView::get`]'s `Result<Option<_>, _>` shape:
1336 /// out-of-range yields `Ok(None)`.
1337 ///
1338 /// # Errors
1339 ///
1340 /// Same as [`get`](Self::get).
1341 #[inline]
1342 pub fn try_get(&self, index: usize) -> Result<Option<V>, DecodeError> {
1343 self.get(index).transpose()
1344 }
1345
1346 /// Iterate the elements, decoding each on the fly.
1347 ///
1348 /// Yields `Result<V, DecodeError>` — element bytes are validated here,
1349 /// not when the enclosing view was decoded. Each pass over the iterator
1350 /// re-decodes the elements (no cache).
1351 #[inline]
1352 pub fn iter(&self) -> LazyRepeatedIter<'_, 'a, V> {
1353 LazyRepeatedIter {
1354 inner: self.elements.iter(),
1355 depth: self.depth,
1356 allowance: self.allowance,
1357 _marker: core::marker::PhantomData,
1358 }
1359 }
1360}
1361
1362impl<'s, 'a, V: LazyMessageView<'a>> IntoIterator for &'s LazyRepeatedView<'a, V> {
1363 type Item = Result<V, DecodeError>;
1364 type IntoIter = LazyRepeatedIter<'s, 'a, V>;
1365
1366 #[inline]
1367 fn into_iter(self) -> Self::IntoIter {
1368 self.iter()
1369 }
1370}
1371
1372/// Iterator over a [`LazyRepeatedView`], decoding each element on `next`.
1373#[derive(Clone, Debug)]
1374pub struct LazyRepeatedIter<'s, 'a, V> {
1375 inner: core::slice::Iter<'s, &'a [u8]>,
1376 depth: u32,
1377 allowance: usize,
1378 _marker: core::marker::PhantomData<fn() -> V>,
1379}
1380
1381impl<'a, V: LazyMessageView<'a>> Iterator for LazyRepeatedIter<'_, 'a, V> {
1382 type Item = Result<V, DecodeError>;
1383
1384 #[inline]
1385 fn next(&mut self) -> Option<Self::Item> {
1386 self.inner
1387 .next()
1388 .map(|b| decode_deferred(b, self.depth, self.allowance))
1389 }
1390
1391 #[inline]
1392 fn size_hint(&self) -> (usize, Option<usize>) {
1393 self.inner.size_hint()
1394 }
1395}
1396
1397impl<'a, V: LazyMessageView<'a>> DoubleEndedIterator for LazyRepeatedIter<'_, 'a, V> {
1398 #[inline]
1399 fn next_back(&mut self) -> Option<Self::Item> {
1400 self.inner
1401 .next_back()
1402 .map(|b| decode_deferred(b, self.depth, self.allowance))
1403 }
1404}
1405
1406impl<'a, V: LazyMessageView<'a>> ExactSizeIterator for LazyRepeatedIter<'_, 'a, V> {}
1407
1408impl<V> Clone for LazyRepeatedView<'_, V> {
1409 #[inline]
1410 fn clone(&self) -> Self {
1411 Self {
1412 elements: self.elements.clone(),
1413 depth: self.depth,
1414 allowance: self.allowance,
1415 _marker: core::marker::PhantomData,
1416 }
1417 }
1418}
1419impl<V> Default for LazyRepeatedView<'_, V> {
1420 #[inline]
1421 fn default() -> Self {
1422 Self::new()
1423 }
1424}
1425impl<V> core::fmt::Debug for LazyRepeatedView<'_, V> {
1426 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1427 f.debug_struct("LazyRepeatedView")
1428 .field("len", &self.len())
1429 .finish()
1430 }
1431}
1432
1433/// A borrowed view of a repeated field.
1434///
1435/// For scalar repeated fields, this is backed by a decoded `Vec` (scalars
1436/// can't be zero-copy because they require varint decoding). For string and
1437/// bytes repeated fields, elements borrow from the input buffer.
1438#[derive(Clone, Debug, PartialEq, Eq)]
1439pub struct RepeatedView<'a, T> {
1440 elements: alloc::vec::Vec<T>,
1441 _marker: core::marker::PhantomData<&'a ()>,
1442}
1443
1444impl<'a, T> RepeatedView<'a, T> {
1445 /// Create from a vec of decoded elements.
1446 pub fn new(elements: alloc::vec::Vec<T>) -> Self {
1447 Self {
1448 elements,
1449 _marker: core::marker::PhantomData,
1450 }
1451 }
1452
1453 /// Returns the number of elements.
1454 pub fn len(&self) -> usize {
1455 self.elements.len()
1456 }
1457
1458 /// Returns `true` if the repeated field contains no elements.
1459 pub fn is_empty(&self) -> bool {
1460 self.elements.is_empty()
1461 }
1462
1463 /// Append an element (used by generated `decode_view` code).
1464 #[doc(hidden)]
1465 pub fn push(&mut self, elem: T) {
1466 self.elements.push(elem);
1467 }
1468
1469 /// Reserve capacity for at least `additional` more elements (used by
1470 /// generated `decode_view` code as a pre-allocation hint for packed
1471 /// repeated scalars). For varint elements the hint is an upper bound
1472 /// (every element occupies at least one byte on the wire); for fixed-
1473 /// size elements it is the exact remaining element count.
1474 #[doc(hidden)]
1475 pub fn reserve(&mut self, additional: usize) {
1476 self.elements.reserve(additional);
1477 }
1478
1479 /// Returns an iterator over the elements.
1480 pub fn iter(&self) -> core::slice::Iter<'_, T> {
1481 self.elements.iter()
1482 }
1483}
1484
1485impl<'a, T> Default for RepeatedView<'a, T> {
1486 fn default() -> Self {
1487 Self {
1488 elements: alloc::vec::Vec::new(),
1489 _marker: core::marker::PhantomData,
1490 }
1491 }
1492}
1493
1494impl<'a, T> core::ops::Deref for RepeatedView<'a, T> {
1495 type Target = [T];
1496
1497 fn deref(&self) -> &[T] {
1498 &self.elements
1499 }
1500}
1501
1502impl<'a, T> IntoIterator for RepeatedView<'a, T> {
1503 type Item = T;
1504 type IntoIter = alloc::vec::IntoIter<T>;
1505
1506 fn into_iter(self) -> Self::IntoIter {
1507 self.elements.into_iter()
1508 }
1509}
1510
1511impl<'b, 'a, T> IntoIterator for &'b RepeatedView<'a, T> {
1512 type Item = &'b T;
1513 type IntoIter = core::slice::Iter<'b, T>;
1514
1515 fn into_iter(self) -> Self::IntoIter {
1516 self.elements.iter()
1517 }
1518}
1519
1520impl<'a, T> From<alloc::vec::Vec<T>> for RepeatedView<'a, T> {
1521 fn from(elements: alloc::vec::Vec<T>) -> Self {
1522 Self::new(elements)
1523 }
1524}
1525
1526impl<'a, T> FromIterator<T> for RepeatedView<'a, T> {
1527 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1528 Self::new(iter.into_iter().collect())
1529 }
1530}
1531
1532/// A borrowed view of a map field.
1533///
1534/// Protobuf `map<K, V>` fields are encoded as repeated sub-messages, each
1535/// containing a key (field 1) and value (field 2). This type stores the
1536/// decoded entries in a `Vec<(K, V)>`, borrowing string and bytes keys/values
1537/// directly from the input buffer.
1538///
1539/// Lookup is O(n) linear scan, which is appropriate for the typically small
1540/// maps found in protobuf messages (metadata labels, headers, etc.).
1541/// If duplicate keys appear on the wire, [`get`](MapView::get) returns the
1542/// last occurrence (last-write-wins, per the protobuf spec).
1543///
1544/// For larger maps where O(1) lookup matters, collect into a `HashMap`:
1545///
1546/// ```ignore
1547/// use std::collections::HashMap;
1548/// let index: HashMap<&str, &str> = view.labels.into_iter().collect();
1549/// ```
1550///
1551/// Duplicate keys resolve last-write-wins in the collected map (matching
1552/// proto map semantics), since `HashMap::from_iter` keeps the last value.
1553///
1554/// # Allocation
1555///
1556/// Like [`RepeatedView`], the `Vec` backing store requires allocation.
1557/// The individual keys and values borrow from the input buffer where possible
1558/// (string keys as `&'a str`, bytes values as `&'a [u8]`).
1559#[derive(Clone, Debug, PartialEq, Eq)]
1560pub struct MapView<'a, K, V> {
1561 entries: alloc::vec::Vec<(K, V)>,
1562 _marker: core::marker::PhantomData<&'a ()>,
1563}
1564
1565impl<'a, K, V> MapView<'a, K, V> {
1566 /// Construct from a `Vec` of entries, for [`ViewEncode`] use.
1567 ///
1568 /// Duplicate keys are kept and all encoded — valid protobuf wire data
1569 /// (decoders apply last-write-wins). Mirrors [`RepeatedView::new`].
1570 pub fn new(entries: alloc::vec::Vec<(K, V)>) -> Self {
1571 Self {
1572 entries,
1573 _marker: core::marker::PhantomData,
1574 }
1575 }
1576
1577 /// Returns the number of entries (including duplicates).
1578 pub fn len(&self) -> usize {
1579 self.entries.len()
1580 }
1581
1582 /// Returns `true` if there are no entries.
1583 pub fn is_empty(&self) -> bool {
1584 self.entries.is_empty()
1585 }
1586
1587 /// Append a key-value pair (used by generated `decode_view` code).
1588 #[doc(hidden)]
1589 pub fn push(&mut self, key: K, value: V) {
1590 self.entries.push((key, value));
1591 }
1592
1593 /// Iterate over all entries in wire order.
1594 ///
1595 /// If duplicate keys exist, all occurrences are yielded.
1596 pub fn iter(&self) -> core::slice::Iter<'_, (K, V)> {
1597 self.entries.iter()
1598 }
1599
1600 /// Iterate over all keys in wire order.
1601 pub fn keys(&self) -> impl Iterator<Item = &K> {
1602 self.entries.iter().map(|(k, _)| k)
1603 }
1604
1605 /// Iterate over all values in wire order.
1606 pub fn values(&self) -> impl Iterator<Item = &V> {
1607 self.entries.iter().map(|(_, v)| v)
1608 }
1609
1610 /// Look up a value by key, returning the last occurrence (last-write-wins).
1611 ///
1612 /// Accepts any type that `K` can borrow as, so `map.get("key")` works
1613 /// when `K` is `&str`. O(n) scan.
1614 pub fn get<Q>(&self, key: &Q) -> Option<&V>
1615 where
1616 K: core::borrow::Borrow<Q>,
1617 Q: PartialEq + ?Sized,
1618 {
1619 self.entries
1620 .iter()
1621 .rev()
1622 .find(|(k, _)| k.borrow() == key)
1623 .map(|(_, v)| v)
1624 }
1625
1626 /// Returns `true` if an entry with the given key exists.
1627 pub fn contains_key<Q>(&self, key: &Q) -> bool
1628 where
1629 K: core::borrow::Borrow<Q>,
1630 Q: PartialEq + ?Sized,
1631 {
1632 self.entries.iter().any(|(k, _)| k.borrow() == key)
1633 }
1634
1635 /// Iterate over key-value pairs with duplicate keys removed.
1636 ///
1637 /// Each distinct key is yielded **exactly once, at the position of its
1638 /// last wire occurrence, carrying that occurrence's value** — i.e.
1639 /// last-write-wins, mirroring the merge semantics that an owned
1640 /// `HashMap` decode applies. Callers that need first-occurrence position
1641 /// should use [`iter`](Self::iter) and filter themselves.
1642 ///
1643 /// Used by the generated view `Serialize` impl: a JSON object cannot
1644 /// hold duplicate keys, but `MapView` preserves all wire entries
1645 /// (including malformed duplicates), so the JSON encode path must
1646 /// deduplicate. The implementation is allocation-free and O(n²) — for
1647 /// each entry, scan the remaining entries for a later occurrence of the
1648 /// same key. Duplicate map keys are invalid per the protobuf encoding
1649 /// spec and only arise in adversarial or conformance-test wire data, so
1650 /// `n` is effectively always small.
1651 pub fn iter_unique(&self) -> impl Iterator<Item = &(K, V)>
1652 where
1653 K: PartialEq,
1654 {
1655 let entries = &self.entries;
1656 entries.iter().enumerate().filter_map(move |(i, entry)| {
1657 if entries[i + 1..]
1658 .iter()
1659 .any(|(later_k, _)| *later_k == entry.0)
1660 {
1661 None
1662 } else {
1663 Some(entry)
1664 }
1665 })
1666 }
1667
1668 /// Count of distinct keys (`iter_unique().count()`).
1669 pub fn len_unique(&self) -> usize
1670 where
1671 K: PartialEq,
1672 {
1673 self.iter_unique().count()
1674 }
1675}
1676
1677impl<'a, K, V> From<alloc::vec::Vec<(K, V)>> for MapView<'a, K, V> {
1678 fn from(entries: alloc::vec::Vec<(K, V)>) -> Self {
1679 Self::new(entries)
1680 }
1681}
1682
1683/// Duplicate keys are kept and all encoded; see [`MapView::new`].
1684impl<'a, K, V> FromIterator<(K, V)> for MapView<'a, K, V> {
1685 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
1686 Self::new(iter.into_iter().collect())
1687 }
1688}
1689
1690impl<'a, K, V> Default for MapView<'a, K, V> {
1691 fn default() -> Self {
1692 Self {
1693 entries: alloc::vec::Vec::new(),
1694 _marker: core::marker::PhantomData,
1695 }
1696 }
1697}
1698
1699impl<'b, 'a, K, V> IntoIterator for &'b MapView<'a, K, V> {
1700 type Item = &'b (K, V);
1701 type IntoIter = core::slice::Iter<'b, (K, V)>;
1702
1703 fn into_iter(self) -> Self::IntoIter {
1704 self.entries.iter()
1705 }
1706}
1707
1708impl<'a, K, V> IntoIterator for MapView<'a, K, V> {
1709 type Item = (K, V);
1710 type IntoIter = alloc::vec::IntoIter<(K, V)>;
1711
1712 fn into_iter(self) -> Self::IntoIter {
1713 self.entries.into_iter()
1714 }
1715}
1716
1717/// A borrowed view of unknown fields.
1718///
1719/// Stores raw byte slices from the input buffer rather than decoded values,
1720/// enabling zero-copy round-tripping of unknown fields. Each stored span
1721/// holds **one or more consecutive** complete `(tag, value)` records:
1722/// adjacent unknown fields are coalesced into a single span, so a long run
1723/// of unknown fields costs one `Vec` slot rather than one per field.
1724/// Coalescing bounds the view's memory only — the decode-time
1725/// unknown-field allowance is still charged per field (see
1726/// [`push_record`](Self::push_record)).
1727#[derive(Clone, Default)]
1728pub struct UnknownFieldsView<'a> {
1729 /// Raw byte spans from the input buffer, each one or more complete
1730 /// `(tag, value)` records.
1731 raw_spans: alloc::vec::Vec<&'a [u8]>,
1732 /// The input-buffer tail starting at the first byte of the last span,
1733 /// kept so [`push_record`](Self::push_record) can extend that span over
1734 /// an adjacent record by re-slicing `last_tail` — never by widening the
1735 /// narrowed span reference, which would be provenance-unsound.
1736 last_tail: Option<&'a [u8]>,
1737 /// Total slots charged against the decode-time unknown-field allowance
1738 /// across every [`push_record`](Self::push_record) — exactly the number
1739 /// of `UnknownField`s [`to_owned`](Self::to_owned) re-materializes, so
1740 /// replay runs under precisely this budget and cannot exhaust it.
1741 to_owned_budget: usize,
1742 /// Deepest group nesting across all pushed records — the recursion
1743 /// depth [`to_owned`](Self::to_owned)'s replay needs, regardless of the
1744 /// (possibly larger) recursion limit the view was decoded under.
1745 to_owned_depth: u32,
1746 /// Set by [`push_raw`](Self::push_raw): the view holds spans that were
1747 /// never charged at decode time, so [`to_owned`](Self::to_owned) grants
1748 /// the default limits on top of the tracked budget and can fail.
1749 manual_spans: bool,
1750}
1751
1752// Manual impl: `last_tail` is an internal coalescing cursor that extends to
1753// the end of the input buffer — deriving Debug would dump the remaining
1754// message bytes on every `{:?}` print.
1755impl core::fmt::Debug for UnknownFieldsView<'_> {
1756 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1757 f.debug_struct("UnknownFieldsView")
1758 .field("raw_spans", &self.raw_spans)
1759 .finish_non_exhaustive()
1760 }
1761}
1762
1763impl<'a> UnknownFieldsView<'a> {
1764 /// Creates an empty view.
1765 pub fn new() -> Self {
1766 Self::default()
1767 }
1768
1769 #[doc(hidden)]
1770 pub fn push_raw(&mut self, span: &'a [u8]) {
1771 self.raw_spans.push(span);
1772 // A manually pushed span has no known position in the input buffer,
1773 // so coalescing must not extend it — and it was never charged
1774 // against a decode allowance, so to_owned falls back to the default
1775 // limits for it.
1776 self.last_tail = None;
1777 self.manual_spans = true;
1778 }
1779
1780 /// Record one unknown wire record of `span_len` bytes starting at the
1781 /// head of `tail`, where `tail` extends from the record's first byte to
1782 /// the end of the input buffer.
1783 ///
1784 /// Every record charges `ctx`'s unknown-field allowance with exactly the
1785 /// slots [`to_owned`](Self::to_owned) will re-materialize it into — one
1786 /// for the record's field plus, for group records, one per nested field.
1787 /// The charge total (and the deepest group nesting) is accumulated on
1788 /// the view as the conversion replay budget, so a view that decoded
1789 /// successfully always converts.
1790 ///
1791 /// If the record starts exactly where the previous one ended, the
1792 /// previous span is extended in place instead of pushing a new one —
1793 /// coalescing saves memory (no allocation, no `Vec` slot), not
1794 /// allowance.
1795 ///
1796 /// # Errors
1797 ///
1798 /// Returns [`DecodeError::UnknownFieldLimitExceeded`] when the allowance
1799 /// is exhausted, or [`DecodeError::UnexpectedEof`] if `span_len` exceeds
1800 /// `tail`.
1801 #[doc(hidden)]
1802 pub fn push_record(
1803 &mut self,
1804 tail: &'a [u8],
1805 span_len: usize,
1806 ctx: crate::DecodeContext<'_>,
1807 ) -> Result<(), crate::DecodeError> {
1808 if span_len > tail.len() {
1809 return Err(crate::DecodeError::UnexpectedEof);
1810 }
1811 let charge = crate::encoding::register_unknown_record(&tail[..span_len], ctx)?;
1812 self.to_owned_budget = self.to_owned_budget.saturating_add(charge.fields);
1813 self.to_owned_depth = self.to_owned_depth.max(charge.depth);
1814 if let (Some(last), Some(prev_tail)) = (self.raw_spans.last_mut(), self.last_tail) {
1815 let prev_len = last.len();
1816 // Contiguous if the new record begins exactly one past the end
1817 // of the previous span. Both checks are plain pointer/length
1818 // comparisons; the extension below re-slices `prev_tail`, whose
1819 // provenance covers the combined range.
1820 if prev_tail.len() >= prev_len + span_len
1821 && core::ptr::eq(prev_tail[prev_len..].as_ptr(), tail.as_ptr())
1822 {
1823 *last = &prev_tail[..prev_len + span_len];
1824 return Ok(());
1825 }
1826 }
1827 self.raw_spans.push(&tail[..span_len]);
1828 self.last_tail = Some(tail);
1829 Ok(())
1830 }
1831
1832 /// Returns `true` if no unknown fields were recorded.
1833 pub fn is_empty(&self) -> bool {
1834 self.raw_spans.is_empty()
1835 }
1836
1837 /// Total byte length of all unknown field data.
1838 pub fn encoded_len(&self) -> usize {
1839 self.raw_spans.iter().map(|s| s.len()).sum()
1840 }
1841
1842 /// Write all unknown-field bytes verbatim. Each span holds one or more
1843 /// complete `(tag, value)` records as they appeared on the wire, so
1844 /// concatenating the spans produces a valid encoding.
1845 pub fn write_to(&self, buf: &mut impl BufMut) {
1846 for span in &self.raw_spans {
1847 buf.put_slice(span);
1848 }
1849 }
1850
1851 /// Convert to an owned [`UnknownFields`](crate::UnknownFields) by parsing all stored raw byte spans.
1852 ///
1853 /// Each span holds one or more consecutive (tag + value) records as they
1854 /// appeared on the wire. Parsing uses
1855 /// [`crate::encoding::decode_unknown_field`] under exactly the budget
1856 /// [`push_record`](Self::push_record) charged at decode time — the same
1857 /// field count and group-nesting depth — so replay cannot exhaust
1858 /// either. Views holding manually pushed spans (via
1859 /// [`push_raw`](Self::push_raw)) additionally get
1860 /// [`DEFAULT_UNKNOWN_FIELD_LIMIT`](crate::DEFAULT_UNKNOWN_FIELD_LIMIT)
1861 /// slots and the full [`RECURSION_LIMIT`](crate::RECURSION_LIMIT), since
1862 /// those spans were never charged.
1863 /// A coalesced span re-materializes one owned `UnknownField` per
1864 /// record, so this conversion is where a long run of unknown fields
1865 /// actually allocates.
1866 ///
1867 /// # Errors
1868 ///
1869 /// Returns `Err` if a stored span is malformed or exceeds the replay
1870 /// budget. Neither can occur when the view was produced by wire
1871 /// decoding — every span was parsed off the wire, and the budget equals
1872 /// what decoding charged — so any view that decoded successfully
1873 /// converts successfully. Only views holding
1874 /// [`push_raw`](Self::push_raw) spans can fail here.
1875 pub fn to_owned(&self) -> Result<crate::UnknownFields, crate::DecodeError> {
1876 use crate::encoding::{decode_unknown_field, Tag};
1877
1878 let (budget, depth) = if self.manual_spans {
1879 (
1880 self.to_owned_budget
1881 .saturating_add(crate::DEFAULT_UNKNOWN_FIELD_LIMIT),
1882 self.to_owned_depth.max(crate::RECURSION_LIMIT),
1883 )
1884 } else {
1885 (self.to_owned_budget, self.to_owned_depth)
1886 };
1887 let limit = core::cell::Cell::new(budget);
1888 let ctx = crate::DecodeContext::new(depth, &limit);
1889 let mut out = crate::UnknownFields::new();
1890 for span in &self.raw_spans {
1891 let mut cur: &[u8] = span;
1892 while !cur.is_empty() {
1893 let tag = Tag::decode(&mut cur)?;
1894 let field = decode_unknown_field(tag, &mut cur, ctx)?;
1895 out.push(field);
1896 }
1897 }
1898 Ok(out)
1899 }
1900}
1901
1902/// An owned, `'static` container for a decoded message view.
1903///
1904/// `OwnedView` holds a [`Bytes`] buffer alongside the decoded view, ensuring
1905/// the view's borrows remain valid for the container's lifetime. The inner
1906/// view is reached through [`reborrow()`](OwnedView::reborrow), which returns
1907/// it with a lifetime tied to `&self`.
1908///
1909/// This type is `Send + Sync + 'static`, making it suitable for use across
1910/// async boundaries, in tower services, and anywhere a `'static` bound is
1911/// required.
1912///
1913/// # When to use
1914///
1915/// Use `OwnedView` when you need a zero-copy view that outlives the scope
1916/// where the buffer was received — for example, in an RPC handler where the
1917/// framework requires `'static` types:
1918///
1919/// ```rust,ignore
1920/// use buffa::view::OwnedView;
1921/// use bytes::Bytes;
1922///
1923/// let bytes: Bytes = receive_request_body().await;
1924/// let view = OwnedView::<PersonView>::decode(bytes)?;
1925///
1926/// // Field access through reborrow — the borrow is tied to `view`.
1927/// let person = view.reborrow();
1928/// println!("name: {}", person.name);
1929/// println!("id: {}", person.id);
1930///
1931/// // Convert to owned if you need to store or mutate
1932/// let owned: Person = view.to_owned_message()?;
1933/// ```
1934///
1935/// Generated code additionally provides a per-message `FooOwnedView` wrapper
1936/// around `OwnedView<FooView<'static>>` with per-field accessor methods
1937/// (`owned.name()`, `owned.id()`, …), so most handler code never touches
1938/// `OwnedView` or `reborrow` directly.
1939///
1940/// For scoped access where the buffer's lifetime is known, use
1941/// [`MessageView::decode_view`] directly — it has zero overhead beyond the
1942/// decode itself.
1943///
1944/// # Why field access goes through `reborrow`
1945///
1946/// `OwnedView` stores `V = FooView<'static>`: the view's borrows really point
1947/// into `self`'s [`Bytes`] buffer, and the `'static` is a synthetic lifetime
1948/// established by the constructor. Exposing `&V` directly (for example via a
1949/// `Deref` impl) would let borrowed fields *appear* `'static` to the
1950/// compiler and escape the `OwnedView`'s scope, dangling once it drops.
1951/// [`reborrow()`](OwnedView::reborrow) narrows the synthetic `'static` down
1952/// to the `OwnedView`'s real lifetime, so the borrow checker enforces the
1953/// actual validity of every field borrow:
1954///
1955/// ```no_run
1956/// # use buffa::view::OwnedView;
1957/// # use buffa::__doctest_fixtures::PersonView;
1958/// // Inline reads: reborrow once, then use plain field access.
1959/// fn log(owned: &OwnedView<PersonView<'static>>) {
1960/// let person = owned.reborrow();
1961/// println!("{}", person.name);
1962/// }
1963///
1964/// // Returning a borrowed field: the result is tied to the OwnedView.
1965/// fn name<'a>(owned: &'a OwnedView<PersonView<'static>>) -> &'a str {
1966/// owned.reborrow().name // &'a str tied to the OwnedView's lifetime
1967/// }
1968/// ```
1969///
1970/// View fields are not reachable directly on the handle — this fails to
1971/// compile rather than handing out a `'static` borrow into the buffer:
1972///
1973/// ```compile_fail,E0609
1974/// # use buffa::view::OwnedView;
1975/// # use buffa::__doctest_fixtures::PersonView;
1976/// fn field(owned: &OwnedView<PersonView<'static>>) -> &'static str {
1977/// owned.name // error[E0609]: no field `name` on type `&OwnedView<...>`
1978/// }
1979/// ```
1980///
1981/// # Safety
1982///
1983/// Internally, `OwnedView` extends the view's lifetime to `'static` via
1984/// `transmute` in its constructors. This is sound because:
1985///
1986/// 1. [`Bytes`] is reference-counted — its heap data pointer is stable across
1987/// moves. The view's borrows always point into valid memory.
1988/// 2. [`Bytes`] is immutable — the underlying data cannot be modified while
1989/// borrowed.
1990/// 3. A manual [`Drop`] impl explicitly drops the view before the bytes,
1991/// ensuring no dangling references during cleanup. The view field uses
1992/// [`ManuallyDrop`](core::mem::ManuallyDrop) to prevent the automatic
1993/// drop from running out of order.
1994///
1995/// [`reborrow`](OwnedView::reborrow) is a plain Rust subtype coercion (no
1996/// `unsafe`, no pointer cast): the [`ViewReborrow`] trait method coerces
1997/// `&'b FooView<'static>` into `&'b FooView<'b>` via standard lifetime
1998/// variance for covariant view types. See [`ViewReborrow`]'s docs for the
1999/// soundness argument.
2000pub struct OwnedView<V> {
2001 // INVARIANT: `view` borrows from `bytes`. The `Drop` impl ensures
2002 // `view` is dropped before `bytes`. `ManuallyDrop` prevents the compiler
2003 // from dropping `view` automatically — our `Drop` impl handles it.
2004 //
2005 // CONSTRUCTORS: any constructor added here MUST ensure the view's
2006 // borrows point into `self.bytes` (not into caller-owned memory).
2007 // The auto-`Send`/`Sync` derivation is only sound under that invariant
2008 // — there is no longer a `V: 'static` bound on `Send` to act as a
2009 // second gate. See the comment block above `send_sync_assertions` below.
2010 view: core::mem::ManuallyDrop<V>,
2011 bytes: Bytes,
2012}
2013
2014impl<V> Drop for OwnedView<V> {
2015 fn drop(&mut self) {
2016 // SAFETY: `view` borrows from `bytes`. We must drop the view before
2017 // bytes is dropped. `ManuallyDrop::drop` runs V's destructor in place
2018 // without moving it. After this, `bytes` drops automatically via the
2019 // compiler-generated drop glue.
2020 unsafe {
2021 core::mem::ManuallyDrop::drop(&mut self.view);
2022 }
2023 }
2024}
2025
2026impl<V> OwnedView<V>
2027where
2028 V: MessageView<'static>,
2029{
2030 /// Decode a view from a [`Bytes`] buffer.
2031 ///
2032 /// The view borrows directly from the buffer's data. Because [`Bytes`] is
2033 /// reference-counted and its data pointer is stable across moves, the
2034 /// view's borrows remain valid for the lifetime of this `OwnedView`.
2035 ///
2036 /// # Errors
2037 ///
2038 /// Returns [`DecodeError`] if the buffer contains invalid protobuf data.
2039 pub fn decode(bytes: Bytes) -> Result<Self, DecodeError> {
2040 // SAFETY: `Bytes` is StableDeref — its heap data never moves or is
2041 // freed while we hold the `Bytes` value. We hold it in `self.bytes`,
2042 // and drop order guarantees `view` drops first.
2043 let view = unsafe {
2044 let slice: &'static [u8] = core::mem::transmute::<&[u8], &'static [u8]>(&bytes);
2045 V::decode_view(slice)?
2046 };
2047 Ok(Self {
2048 view: core::mem::ManuallyDrop::new(view),
2049 bytes,
2050 })
2051 }
2052
2053 /// Decode a view with custom [`DecodeOptions`](crate::DecodeOptions)
2054 /// (recursion limit, max message size).
2055 ///
2056 /// # Errors
2057 ///
2058 /// Returns [`DecodeError`] if the buffer is invalid or exceeds the
2059 /// configured limits.
2060 pub fn decode_with_options(
2061 bytes: Bytes,
2062 opts: &crate::DecodeOptions,
2063 ) -> Result<Self, DecodeError> {
2064 // SAFETY: Same invariants as `decode` — see above.
2065 let view = unsafe {
2066 let slice: &'static [u8] = core::mem::transmute::<&[u8], &'static [u8]>(&bytes);
2067 opts.decode_view::<V>(slice)?
2068 };
2069 Ok(Self {
2070 view: core::mem::ManuallyDrop::new(view),
2071 bytes,
2072 })
2073 }
2074
2075 /// Create an `OwnedView` from an owned message by encoding then decoding.
2076 ///
2077 /// This performs a full **encode → decode** round-trip: the message is
2078 /// serialized to protobuf bytes, then a zero-copy view is decoded from
2079 /// those bytes. This is useful when the original wire bytes are not
2080 /// available (e.g., after JSON deserialization or programmatic construction),
2081 /// but note the cost: one allocation + O(n) encode + O(n) decode.
2082 ///
2083 /// For the common case where you already have wire bytes, prefer
2084 /// [`decode`](Self::decode) instead.
2085 ///
2086 /// # Errors
2087 ///
2088 /// Returns [`DecodeError`] if the re-encoded bytes are somehow invalid
2089 /// (should not happen for well-formed messages).
2090 pub fn from_owned(msg: &V::Owned) -> Result<Self, DecodeError> {
2091 let bytes = Bytes::from(msg.encode_to_vec());
2092 Self::decode(bytes)
2093 }
2094
2095 /// Convert the view to the corresponding owned message type.
2096 ///
2097 /// `bytes::Bytes`-typed fields are produced via [`Bytes::slice_ref`]
2098 /// into the retained buffer (zero-copy); other borrowed fields are
2099 /// allocated and copied.
2100 ///
2101 /// # Errors
2102 ///
2103 /// Returns an error if re-materializing preserved unknown fields fails
2104 /// (see [`MessageView::to_owned_message`]).
2105 pub fn to_owned_message(&self) -> Result<V::Owned, DecodeError> {
2106 self.view.to_owned_from_source(Some(&self.bytes))
2107 }
2108
2109 /// Get a reference to the underlying bytes buffer.
2110 pub fn bytes(&self) -> &Bytes {
2111 &self.bytes
2112 }
2113
2114 /// Create an `OwnedView` from a buffer and a pre-decoded view.
2115 ///
2116 /// This avoids re-decoding when you already hold a decoded view and want
2117 /// to wrap it for `'static` use.
2118 ///
2119 /// # Safety
2120 ///
2121 /// The caller must ensure that **all** borrows in `view` point into the
2122 /// data region of `bytes`. In practice, `view` must have been decoded
2123 /// from `bytes` (or a sub-slice that `bytes` fully contains). Violating
2124 /// this invariant causes undefined behavior (dangling references).
2125 pub unsafe fn from_parts(bytes: Bytes, view: V) -> Self {
2126 Self {
2127 view: core::mem::ManuallyDrop::new(view),
2128 bytes,
2129 }
2130 }
2131
2132 /// Consume the `OwnedView`, returning the underlying [`Bytes`] buffer.
2133 ///
2134 /// The view is dropped before the buffer is returned.
2135 pub fn into_bytes(mut self) -> Bytes {
2136 // SAFETY: Drop the view first (while bytes data is still alive),
2137 // then read bytes out via ptr::read, then forget self to prevent
2138 // the Drop impl from double-dropping the view.
2139 unsafe {
2140 core::mem::ManuallyDrop::drop(&mut self.view);
2141 let bytes = core::ptr::read(&self.bytes);
2142 core::mem::forget(self);
2143 bytes
2144 }
2145 }
2146
2147 /// Reborrow the view with a lifetime tied to `&'b self`.
2148 ///
2149 /// `OwnedView<V>` stores `V` with a `'static` lifetime — the actual borrows
2150 /// point into `self`'s internal [`Bytes`] buffer and are only valid while
2151 /// `self` is alive. `reborrow` makes that real lifetime visible to the borrow
2152 /// checker: the returned `&'b V::Reborrowed<'b>` cannot outlive `&'b self`.
2153 ///
2154 /// # Example
2155 ///
2156 /// ```no_run
2157 /// # use buffa::view::OwnedView;
2158 /// # use buffa::__doctest_fixtures::PersonView;
2159 /// fn handler<'a>(req: &'a OwnedView<PersonView<'static>>) -> &'a str {
2160 /// // The explicit annotation is for emphasis; inference works without it.
2161 /// // If you need to name the lifetime, store the reborrow in a `let` first.
2162 /// let req_view: &PersonView<'a> = req.reborrow();
2163 /// req_view.name // zero-copy from the OwnedView's buffer
2164 /// }
2165 /// ```
2166 ///
2167 /// The returned reference is tied to `&'b self` — the borrow checker
2168 /// prevents the reborrowed view from outliving the `OwnedView`:
2169 ///
2170 /// ```compile_fail,E0597
2171 /// # use buffa::view::OwnedView;
2172 /// # use buffa::__doctest_fixtures::PersonView;
2173 /// let name: &str;
2174 /// {
2175 /// // SAFETY: empty Bytes, no borrows — safe to construct directly.
2176 /// let owned = unsafe {
2177 /// OwnedView::<PersonView<'static>>::from_parts(
2178 /// ::buffa::bytes::Bytes::new(),
2179 /// PersonView::default(),
2180 /// )
2181 /// };
2182 /// name = owned.reborrow().name; // error[E0597]: `owned` does not live long enough
2183 /// }
2184 /// println!("{name}"); // name is dangling — borrow checker rejects this
2185 /// ```
2186 ///
2187 /// # How it works
2188 ///
2189 /// The trait method [`ViewReborrow::reborrow`] is a plain Rust subtype
2190 /// coercion: `&'b V` (where `V = FooView<'static>`) flows into the
2191 /// return slot `&'b V::Reborrowed<'b>` (= `&'b FooView<'b>`). Variance
2192 /// makes this safe — covariant view types narrow `'static` down to
2193 /// `'b` automatically. No `unsafe`, no pointer cast, no layout
2194 /// assertions. `OwnedView`'s own invariant (every borrow in `view`
2195 /// points into `self.bytes`, established by `decode` or upheld by the
2196 /// `unsafe from_parts` caller) guarantees the pointed-to data lives
2197 /// at least as long as `'b`.
2198 #[must_use = "reborrow returns a tied-lifetime view; discarding it is a no-op"]
2199 pub fn reborrow<'b>(&'b self) -> &'b V::Reborrowed<'b>
2200 where
2201 V: ViewReborrow,
2202 {
2203 V::reborrow(&self.view)
2204 }
2205}
2206
2207// Deliberately NO `Deref<Target = V>` impl: `V` is `FooView<'static>`, so a
2208// `&V` return would expose the synthetic `'static` on every borrowed field
2209// and let it escape the OwnedView's scope (dangling once the buffer drops).
2210// All access goes through `reborrow()`, which ties the borrow to `&self`.
2211
2212impl<V> core::fmt::Debug for OwnedView<V>
2213where
2214 V: core::fmt::Debug,
2215{
2216 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2217 (*self.view).fmt(f)
2218 }
2219}
2220
2221impl<V> Clone for OwnedView<V>
2222where
2223 V: Clone,
2224{
2225 fn clone(&self) -> Self {
2226 // SAFETY: `Bytes::clone()` is a refcount bump — both the original and
2227 // the clone share the same backing heap allocation. The cloned view's
2228 // `'static` references remain valid because they point into data that
2229 // is now kept alive by the cloned `Bytes` handle. This would be
2230 // unsound if `Bytes::clone()` performed a deep copy to a new address.
2231 Self {
2232 view: self.view.clone(),
2233 bytes: self.bytes.clone(),
2234 }
2235 }
2236}
2237
2238impl<V> PartialEq for OwnedView<V>
2239where
2240 V: PartialEq,
2241{
2242 fn eq(&self, other: &Self) -> bool {
2243 *self.view == *other.view
2244 }
2245}
2246
2247impl<V> Eq for OwnedView<V> where V: Eq {}
2248
2249/// Serialize an `OwnedView<V>` by delegating to the inner view's `Serialize`
2250/// impl.
2251///
2252/// Equivalent to serializing `owned_view.reborrow()` directly, so
2253/// `serde_json::to_string(&owned_view)` works on the handle itself. When
2254/// `V` is a buffa-generated view with `generate_json` enabled, this produces
2255/// protobuf JSON; the impl itself just forwards to whatever `V::serialize`
2256/// does.
2257///
2258/// Only available when the `json` feature is enabled.
2259#[cfg(feature = "json")]
2260impl<V: ::serde::Serialize> ::serde::Serialize for OwnedView<V> {
2261 fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
2262 ::serde::Serialize::serialize(&*self.view, s)
2263 }
2264}
2265
2266// `OwnedView<V>` is auto-`Send`/`Sync` when `V` is — `ManuallyDrop<V>` and
2267// `Bytes` both forward auto-traits. No manual `unsafe impl` is needed, and
2268// adding one with a `V: 'static` bound is actively harmful: it is precisely
2269// what triggers E0477 when `async fn` is used in a trait impl against an
2270// RPITIT `+ Send` return type (rust-lang/rust#128095). The RPITIT desugaring
2271// introduces a fresh lifetime for the `'static` in `FooView<'static>`, and
2272// then cannot prove that fresh lifetime satisfies `'static` to discharge the
2273// manual impl's bound.
2274//
2275// The bound was defensive — intended to prevent `OwnedView<FooView<'short>>`
2276// from being `Send` when the view borrows from something outside `self.bytes`.
2277// But that type is already unconstructible: `::decode()` and
2278// `::decode_with_options()` are gated on `V: MessageView<'static>`, and the
2279// fields are private. The short-lifetime case the bound guards against cannot
2280// exist in safe code.
2281//
2282// Auto-trait soundness: `Bytes` is `Send + Sync`. The view's `&'static [u8]`
2283// borrows point into `Bytes`'s heap allocation, which is immutable,
2284// `StableDeref`, and moves with the struct. Sending the whole pair to another
2285// thread preserves the invariant. The `'static` in `V` being a lie is about
2286// *where* the reference points, not about thread safety.
2287#[cfg(test)]
2288mod send_sync_assertions {
2289 use super::*;
2290 fn assert_send<T: Send>() {}
2291 fn assert_sync<T: Sync>() {}
2292
2293 // Any `V: Send + Sync` suffices — generated `FooView<'static>` types are
2294 // auto-`Send + Sync` via their `&'static str` / `&'static [u8]` fields.
2295 #[allow(dead_code)]
2296 fn owned_view_is_send_sync<V: Send + Sync>() {
2297 assert_send::<OwnedView<V>>();
2298 assert_sync::<OwnedView<V>>();
2299 }
2300
2301 // Concrete-type regression: `TinyView` is declared in the `tests` module
2302 // below and has the same shape as generated view types (one `&'a str`).
2303 #[allow(dead_code)]
2304 fn owned_tiny_view_is_send_sync() {
2305 assert_send::<OwnedView<super::tests::TinyView<'static>>>();
2306 assert_sync::<OwnedView<super::tests::TinyView<'static>>>();
2307 }
2308
2309 // `ViewReborrow::Reborrowed<'b>` must also be Send + Sync so that a
2310 // reborrowed view can be passed across threads (e.g. into a Tokio task).
2311 #[allow(dead_code)]
2312 fn reborrowed_view_is_send_sync<V>()
2313 where
2314 V: ViewReborrow + Send + Sync,
2315 for<'b> V::Reborrowed<'b>: Send + Sync,
2316 {
2317 assert_send::<OwnedView<V>>();
2318 assert_sync::<OwnedView<V>>();
2319 }
2320}
2321
2322#[cfg(test)]
2323mod tests {
2324 use super::*;
2325
2326 // ── MessageFieldView ─────────────────────────────────────────────────
2327
2328 #[test]
2329 fn message_field_view_default_is_unset() {
2330 let v: MessageFieldView<i32> = MessageFieldView::default();
2331 assert!(v.is_unset());
2332 assert!(!v.is_set());
2333 assert_eq!(v.as_option(), None);
2334 }
2335
2336 #[test]
2337 fn message_field_view_set_value() {
2338 let v = MessageFieldView::set(42);
2339 assert!(v.is_set());
2340 assert!(!v.is_unset());
2341 assert_eq!(v.as_option(), Some(&42));
2342 }
2343
2344 #[test]
2345 fn message_field_view_with_non_copy_type() {
2346 let v = MessageFieldView::set(alloc::string::String::from("hello"));
2347 assert!(v.is_set());
2348 assert_eq!(v.as_option().map(|s| s.as_str()), Some("hello"));
2349
2350 let unset: MessageFieldView<alloc::string::String> = MessageFieldView::unset();
2351 assert!(unset.is_unset());
2352 assert_eq!(unset.as_option(), None);
2353 }
2354
2355 // ── MessageFieldView Deref ─────────────────────────────────────────
2356
2357 /// A trivial view type for testing MessageFieldView Deref.
2358 #[derive(Clone, Debug, Default, PartialEq)]
2359 pub(super) struct TinyView<'a> {
2360 pub value: &'a str,
2361 }
2362
2363 // Via the exported macro, which doubles as its unit test (hygiene and
2364 // `$crate` path resolution).
2365 crate::impl_default_view_instance!(TinyView);
2366
2367 #[test]
2368 fn impl_default_view_instance_macro_returns_singleton() {
2369 let a: &TinyView<'_> = TinyView::default_view_instance();
2370 let b: &TinyView<'_> = TinyView::default_view_instance();
2371 assert!(core::ptr::eq(a, b), "singleton must be a single allocation");
2372 assert_eq!(a, &TinyView::default());
2373 }
2374
2375 #[test]
2376 fn message_field_view_deref_set() {
2377 let v = MessageFieldView::set(TinyView { value: "hello" });
2378 // Deref gives access to the inner view
2379 assert_eq!(v.value, "hello");
2380 }
2381
2382 #[test]
2383 fn message_field_view_deref_unset_returns_default() {
2384 let v: MessageFieldView<TinyView<'_>> = MessageFieldView::unset();
2385 // Deref transparently returns the default instance
2386 assert_eq!(v.value, "");
2387 }
2388
2389 #[test]
2390 fn message_field_view_deref_chained_access() {
2391 // Simulates accessing a nested field through an unset sub-message
2392 let v: MessageFieldView<TinyView<'_>> = MessageFieldView::unset();
2393 let len = v.value.len();
2394 assert_eq!(len, 0);
2395 }
2396
2397 // ── MessageFieldView PartialEq (wire-equivalent) ───────────────────
2398
2399 #[test]
2400 fn message_field_view_equality() {
2401 // None = Unset, Some(s) = Set(TinyView { value: s }).
2402 // TinyView::default() has value == "", so Some("") encodes Set(default).
2403 fn mk(c: Option<&str>) -> MessageFieldView<TinyView<'_>> {
2404 match c {
2405 None => MessageFieldView::unset(),
2406 Some(v) => MessageFieldView::set(TinyView { value: v }),
2407 }
2408 }
2409
2410 #[rustfmt::skip]
2411 let cases: &[(Option<&str>, Option<&str>, bool)] = &[
2412 // Wire-equivalent semantics: Unset == Set(default), matching
2413 // MessageField::PartialEq on the owned side.
2414 (None, None, true ), // Unset == Unset
2415 (None, Some(""), true ), // Unset == Set(default)
2416 (Some(""), None, true ), // Set(default) == Unset (symmetric)
2417 (Some(""), Some(""), true ), // Set(default) == Set(default)
2418 (None, Some("x"), false), // Unset != Set(nondefault)
2419 (Some("x"), None, false), // Set(nondefault) != Unset (symmetric)
2420 (Some("x"), Some("x"), true ), // Set == Set (same)
2421 (Some("x"), Some("y"), false), // Set != Set (different)
2422 ];
2423
2424 for &(l, r, expect) in cases {
2425 assert_eq!(
2426 mk(l) == mk(r),
2427 expect,
2428 "({l:?} == {r:?}) should be {expect}"
2429 );
2430 }
2431 }
2432
2433 // ── RepeatedView ─────────────────────────────────────────────────────
2434
2435 #[test]
2436 fn repeated_view_new_and_accessors() {
2437 let rv = RepeatedView::new(alloc::vec![10, 20, 30]);
2438 assert_eq!(rv.len(), 3);
2439 assert!(!rv.is_empty());
2440 assert_eq!(&*rv, &[10, 20, 30]);
2441 }
2442
2443 #[test]
2444 fn repeated_view_default_is_empty() {
2445 let rv: RepeatedView<'_, u8> = RepeatedView::default();
2446 assert!(rv.is_empty());
2447 assert_eq!(rv.len(), 0);
2448 }
2449
2450 #[test]
2451 fn repeated_view_push_and_iter() {
2452 let mut rv = RepeatedView::<i32>::default();
2453 rv.push(1);
2454 rv.push(2);
2455 let collected: alloc::vec::Vec<_> = rv.iter().copied().collect();
2456 assert_eq!(collected, alloc::vec![1, 2]);
2457 }
2458
2459 // ── UnknownFieldsView::push_record (coalescing + limit) ────────────
2460
2461 /// A test context at full depth with `n` unknown-field slots, leaking
2462 /// the cell so the context can outlive this helper.
2463 fn record_ctx(n: usize) -> crate::DecodeContext<'static> {
2464 let limit = alloc::boxed::Box::leak(alloc::boxed::Box::new(core::cell::Cell::new(n)));
2465 crate::DecodeContext::new(crate::RECURSION_LIMIT, limit)
2466 }
2467
2468 #[test]
2469 fn push_record_coalesces_adjacent_records() {
2470 // Buffer holds three consecutive 2-byte records: they coalesce into
2471 // a single span, but each still consumes one allowance slot.
2472 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02];
2473 let ctx = record_ctx(3);
2474 let mut ufv = UnknownFieldsView::new();
2475 ufv.push_record(&buf[0..], 2, ctx).unwrap();
2476 ufv.push_record(&buf[2..], 2, ctx).unwrap();
2477 ufv.push_record(&buf[4..], 2, ctx).unwrap();
2478 assert_eq!(ufv.encoded_len(), 6);
2479 assert_eq!(ufv.raw_spans.len(), 1, "coalesced into one span");
2480 let mut out = alloc::vec::Vec::new();
2481 ufv.write_to(&mut out);
2482 assert_eq!(out, buf);
2483 assert_eq!(ctx.remaining_unknown_fields(), 0, "one slot per record");
2484 }
2485
2486 #[test]
2487 fn push_record_non_adjacent_records_use_separate_slots() {
2488 let buf: &[u8] = &[0x08, 0x00, 0xFF, 0x08, 0x01];
2489 let ctx = record_ctx(2);
2490 let mut ufv = UnknownFieldsView::new();
2491 ufv.push_record(&buf[0..], 2, ctx).unwrap();
2492 // Skip buf[2] — the next record is not adjacent to the previous one.
2493 ufv.push_record(&buf[3..], 2, ctx).unwrap();
2494 assert_eq!(ufv.encoded_len(), 4);
2495 assert_eq!(ctx.remaining_unknown_fields(), 0, "two slots consumed");
2496 }
2497
2498 #[test]
2499 fn push_record_enforces_limit_per_record() {
2500 // Before the per-record accounting fix, a coalesced run consumed
2501 // one slot at decode and one slot per record at conversion, so an
2502 // over-limit contiguous run decoded as a view and then failed to
2503 // convert. Now it fails at push time.
2504 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02];
2505 let ctx = record_ctx(1);
2506 let mut ufv = UnknownFieldsView::new();
2507 ufv.push_record(&buf[0..], 2, ctx).unwrap();
2508 // Non-adjacent record (the one at buf[2..4] was skipped): new span.
2509 assert_eq!(
2510 ufv.push_record(&buf[4..], 2, ctx),
2511 Err(crate::DecodeError::UnknownFieldLimitExceeded)
2512 );
2513 // Coalescing saves a span slot, not allowance: at zero remaining
2514 // even an adjacent record is rejected, keeping the decode-time
2515 // count equal to the count to_owned re-materializes.
2516 assert_eq!(
2517 ufv.push_record(&buf[2..], 2, ctx),
2518 Err(crate::DecodeError::UnknownFieldLimitExceeded)
2519 );
2520 }
2521
2522 #[test]
2523 fn push_record_charges_group_records_per_nested_field() {
2524 // One group record (field 1) holding two nested varint fields:
2525 // to_owned materializes three UnknownFields (group + 2 nested), so
2526 // decode must charge three slots.
2527 let buf: &[u8] = &[0x0b, 0x08, 0x00, 0x08, 0x01, 0x0c];
2528 let ctx = record_ctx(2);
2529 let mut ufv = UnknownFieldsView::new();
2530 assert_eq!(
2531 ufv.push_record(buf, buf.len(), ctx),
2532 Err(crate::DecodeError::UnknownFieldLimitExceeded)
2533 );
2534
2535 let ctx = record_ctx(3);
2536 let mut ufv = UnknownFieldsView::new();
2537 ufv.push_record(buf, buf.len(), ctx).unwrap();
2538 assert_eq!(ctx.remaining_unknown_fields(), 0, "group + 2 nested");
2539 let owned = ufv.to_owned().expect("decode allowance covers replay");
2540 assert_eq!(owned.iter().count(), 1, "one top-level group field");
2541 }
2542
2543 #[test]
2544 fn push_record_charges_nested_groups_recursively() {
2545 // group 1 { varint; group 2 { varint } } — four materializable
2546 // fields, so four slots.
2547 let buf: &[u8] = &[0x0b, 0x08, 0x00, 0x13, 0x08, 0x01, 0x14, 0x0c];
2548 let ctx = record_ctx(3);
2549 let mut ufv = UnknownFieldsView::new();
2550 assert_eq!(
2551 ufv.push_record(buf, buf.len(), ctx),
2552 Err(crate::DecodeError::UnknownFieldLimitExceeded)
2553 );
2554
2555 let ctx = record_ctx(4);
2556 let mut ufv = UnknownFieldsView::new();
2557 ufv.push_record(buf, buf.len(), ctx).unwrap();
2558 assert_eq!(ctx.remaining_unknown_fields(), 0);
2559 ufv.to_owned().expect("decode allowance covers replay");
2560 }
2561
2562 #[test]
2563 fn push_raw_disables_coalescing_for_next_record() {
2564 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01];
2565 let ctx = record_ctx(2);
2566 let mut ufv = UnknownFieldsView::new();
2567 ufv.push_raw(&buf[0..2]);
2568 // Adjacent on the wire, but push_raw cleared the tail, so this must
2569 // open a fresh span (a manual span has no trusted buffer position).
2570 ufv.push_record(&buf[2..], 2, ctx).unwrap();
2571 assert_eq!(ctx.remaining_unknown_fields(), 1);
2572 assert_eq!(ufv.encoded_len(), 4);
2573 }
2574
2575 #[test]
2576 fn push_record_rejects_span_past_tail_end() {
2577 let buf: &[u8] = &[0x08, 0x00];
2578 let ctx = record_ctx(1);
2579 let mut ufv = UnknownFieldsView::new();
2580 assert_eq!(
2581 ufv.push_record(buf, 3, ctx),
2582 Err(crate::DecodeError::UnexpectedEof)
2583 );
2584 }
2585
2586 #[test]
2587 fn coalesced_span_to_owned_parses_every_record() {
2588 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02];
2589 let ctx = record_ctx(3);
2590 let mut ufv = UnknownFieldsView::new();
2591 for i in 0..3 {
2592 ufv.push_record(&buf[2 * i..], 2, ctx).unwrap();
2593 }
2594 let owned = ufv.to_owned().unwrap();
2595 assert_eq!(owned.iter().count(), 3, "all records parsed");
2596 }
2597
2598 #[test]
2599 fn decode_time_allowance_always_covers_to_owned() {
2600 // The invariant push_record's accounting exists for: any run that
2601 // decodes within the allowance converts within the captured
2602 // allowance. Here the record count exactly exhausts the limit and
2603 // the run coalesces into one span.
2604 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02];
2605 let ctx = record_ctx(3);
2606 let mut ufv = UnknownFieldsView::new();
2607 for i in 0..3 {
2608 ufv.push_record(&buf[2 * i..], 2, ctx).unwrap();
2609 }
2610 assert_eq!(ufv.raw_spans.len(), 1, "coalesced into one span");
2611 assert_eq!(ctx.remaining_unknown_fields(), 0, "limit exactly used");
2612 let owned = ufv.to_owned().expect("decode succeeded, so convert must");
2613 assert_eq!(owned.iter().count(), 3);
2614 }
2615
2616 #[test]
2617 fn to_owned_of_manual_view_uses_default_allowance() {
2618 // push_raw spans are never charged at decode time; to_owned grants
2619 // the default limit for them.
2620 let mut ufv = UnknownFieldsView::new();
2621 ufv.push_raw(&[0x08, 0x00]);
2622 let owned = ufv.to_owned().unwrap();
2623 assert_eq!(owned.iter().count(), 1);
2624 }
2625
2626 #[test]
2627 fn to_owned_covers_records_pushed_under_different_contexts() {
2628 // The replay budget is the accumulated charge total, not a snapshot
2629 // of any single context's remaining allowance — so a view merged
2630 // across decode passes with unrelated contexts still converts.
2631 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02];
2632 let mut ufv = UnknownFieldsView::new();
2633 let tight = record_ctx(1);
2634 ufv.push_record(&buf[0..], 2, tight).unwrap();
2635 let fresh = record_ctx(2);
2636 ufv.push_record(&buf[2..], 2, fresh).unwrap();
2637 ufv.push_record(&buf[4..], 2, fresh).unwrap();
2638 let owned = ufv.to_owned().expect("every push succeeded");
2639 assert_eq!(owned.iter().count(), 3);
2640 }
2641
2642 #[test]
2643 fn to_owned_replays_deep_groups_decoded_under_raised_recursion_limit() {
2644 // Replay depth comes from the nesting tracked at decode time, not
2645 // the fixed RECURSION_LIMIT — a group nested deeper than the
2646 // default (decodable only under a raised recursion limit) must
2647 // still convert.
2648 let deep = crate::RECURSION_LIMIT as usize + 20;
2649 let mut buf = alloc::vec![0x0bu8; deep]; // StartGroup ×deep
2650 buf.resize(2 * deep, 0x0c); // EndGroup ×deep
2651 let ctx = record_ctx(deep);
2652 let mut ufv = UnknownFieldsView::new();
2653 ufv.push_record(&buf, buf.len(), ctx).unwrap();
2654 assert_eq!(ctx.remaining_unknown_fields(), 0, "one slot per group");
2655 ufv.to_owned().expect("decode succeeded, so convert must");
2656 }
2657
2658 #[test]
2659 fn to_owned_of_malformed_manual_span_fails() {
2660 // The replay error path stays live for manually built views: a
2661 // push_raw span that is not a complete record fails to parse.
2662 let mut ufv = UnknownFieldsView::new();
2663 ufv.push_raw(&[0xFF]);
2664 assert!(ufv.to_owned().is_err());
2665 }
2666
2667 #[test]
2668 fn to_owned_of_manual_flood_over_default_limit_fails() {
2669 // The replay limit stays live for manually built views: push_raw
2670 // spans get the default allowance, no more — the memory-
2671 // amplification bound survives even though wire-decoded views can
2672 // no longer hit it.
2673 let n = crate::DEFAULT_UNKNOWN_FIELD_LIMIT + 1;
2674 let mut buf = alloc::vec::Vec::with_capacity(2 * n);
2675 for _ in 0..n {
2676 buf.extend_from_slice(&[0x08, 0x00]);
2677 }
2678 let mut ufv = UnknownFieldsView::new();
2679 ufv.push_raw(&buf);
2680 assert_eq!(
2681 ufv.to_owned(),
2682 Err(crate::DecodeError::UnknownFieldLimitExceeded)
2683 );
2684 }
2685
2686 #[test]
2687 fn repeated_view_reserve_grows_capacity() {
2688 let mut rv = RepeatedView::<u32>::default();
2689 rv.reserve(64);
2690 assert!(rv.elements.capacity() >= 64);
2691 // Reserve must not produce visible elements.
2692 assert!(rv.is_empty());
2693 // reserve(0) is a no-op and must not panic.
2694 rv.reserve(0);
2695 // Reserve after pushes adds capacity above current len.
2696 rv.push(1);
2697 rv.push(2);
2698 rv.reserve(100);
2699 assert_eq!(rv.len(), 2);
2700 assert!(rv.elements.capacity() >= 102);
2701 // Subsequent reserve calls must not corrupt the existing elements.
2702 let collected: alloc::vec::Vec<_> = rv.iter().copied().collect();
2703 assert_eq!(collected, alloc::vec![1, 2]);
2704 }
2705
2706 #[test]
2707 fn repeated_view_with_borrowed_str() {
2708 let data = alloc::string::String::from("hello world");
2709 let parts: alloc::vec::Vec<&str> = data.split_whitespace().collect();
2710 let rv = RepeatedView::new(parts);
2711 assert_eq!(rv.len(), 2);
2712 assert_eq!(rv[0], "hello");
2713 assert_eq!(rv[1], "world");
2714 }
2715
2716 #[test]
2717 fn repeated_view_into_iter_by_ref() {
2718 let rv = RepeatedView::new(alloc::vec![1, 2, 3]);
2719 let sum: i32 = (&rv).into_iter().sum();
2720 assert_eq!(sum, 6);
2721 // `for x in &rv` syntax works:
2722 let mut count = 0;
2723 for _ in &rv {
2724 count += 1;
2725 }
2726 assert_eq!(count, 3);
2727 }
2728
2729 #[test]
2730 fn repeated_view_into_iter_by_value() {
2731 let rv = RepeatedView::new(alloc::vec![
2732 alloc::string::String::from("a"),
2733 alloc::string::String::from("b"),
2734 ]);
2735 let collected: alloc::vec::Vec<_> = rv.into_iter().collect();
2736 assert_eq!(collected, alloc::vec!["a".to_string(), "b".to_string()]);
2737 }
2738
2739 // ── MapView ──────────────────────────────────────────────────────────
2740
2741 #[test]
2742 fn map_view_get_with_borrow() {
2743 let mut mv = MapView::<&str, i32>::default();
2744 mv.push("apples", 3);
2745 mv.push("bananas", 5);
2746
2747 // Ergonomic: get("key") works via Borrow<str> on &str
2748 assert_eq!(mv.get("apples"), Some(&3));
2749 assert_eq!(mv.get("bananas"), Some(&5));
2750 assert_eq!(mv.get("oranges"), None);
2751
2752 // Old style still works
2753 assert_eq!(mv.get(&"apples"), Some(&3));
2754 }
2755
2756 #[test]
2757 fn map_view_contains_key_with_borrow() {
2758 let mut mv = MapView::<&str, i32>::default();
2759 mv.push("key", 1);
2760
2761 assert!(mv.contains_key("key"));
2762 assert!(!mv.contains_key("missing"));
2763 }
2764
2765 #[test]
2766 fn map_view_get_last_write_wins() {
2767 let mut mv = MapView::<&str, i32>::default();
2768 mv.push("x", 1);
2769 mv.push("x", 2);
2770 assert_eq!(mv.get("x"), Some(&2));
2771 }
2772
2773 #[test]
2774 fn map_view_iter_unique_dedups_last_write_wins() {
2775 let mut mv = MapView::<&str, i32>::default();
2776 mv.push("a", 1);
2777 mv.push("b", 2);
2778 mv.push("a", 3); // duplicate key — only this entry survives for "a"
2779 mv.push("c", 4);
2780 mv.push("b", 5); // duplicate key — only this entry survives for "b"
2781
2782 assert_eq!(mv.len(), 5, "iter() preserves all wire entries");
2783 assert_eq!(mv.len_unique(), 3, "len_unique() counts distinct keys");
2784
2785 let unique: alloc::vec::Vec<_> = mv.iter_unique().collect();
2786 assert_eq!(unique, [&("a", 3), &("c", 4), &("b", 5)]);
2787 }
2788
2789 #[test]
2790 fn map_view_iter_unique_all_duplicates() {
2791 let mut mv = MapView::<&str, i32>::default();
2792 mv.push("a", 1);
2793 mv.push("a", 2);
2794 mv.push("a", 3);
2795 assert_eq!(mv.len_unique(), 1);
2796 assert_eq!(
2797 mv.iter_unique().collect::<alloc::vec::Vec<_>>(),
2798 [&("a", 3)]
2799 );
2800 }
2801
2802 #[test]
2803 fn map_view_iter_unique_no_duplicates() {
2804 let mut mv = MapView::<i32, &str>::default();
2805 mv.push(1, "x");
2806 mv.push(2, "y");
2807 assert_eq!(mv.len_unique(), 2);
2808 assert_eq!(
2809 mv.iter_unique().collect::<alloc::vec::Vec<_>>(),
2810 [&(1, "x"), &(2, "y")]
2811 );
2812 }
2813
2814 #[test]
2815 fn map_view_iter_unique_empty() {
2816 let mv = MapView::<&str, i32>::default();
2817 assert_eq!(mv.len_unique(), 0);
2818 assert_eq!(mv.iter_unique().count(), 0);
2819 }
2820
2821 #[test]
2822 fn map_view_keys_and_values() {
2823 let mut mv = MapView::<&str, i32>::default();
2824 mv.push("a", 1);
2825 mv.push("b", 2);
2826 mv.push("c", 3);
2827
2828 let keys: alloc::vec::Vec<_> = mv.keys().copied().collect();
2829 assert_eq!(keys, alloc::vec!["a", "b", "c"]);
2830
2831 let values: alloc::vec::Vec<_> = mv.values().copied().collect();
2832 assert_eq!(values, alloc::vec![1, 2, 3]);
2833 }
2834
2835 #[test]
2836 fn map_view_keys_and_values_empty() {
2837 let mv = MapView::<&str, i32>::default();
2838 assert_eq!(mv.keys().count(), 0);
2839 assert_eq!(mv.values().count(), 0);
2840 }
2841
2842 #[test]
2843 fn map_view_into_iter_collect_to_hashmap() {
2844 let mut mv = MapView::<&str, i32>::default();
2845 mv.push("a", 1);
2846 mv.push("b", 2);
2847 mv.push("a", 3); // duplicate — last-write-wins on collect
2848 let m: crate::__private::HashMap<&str, i32> = mv.into_iter().collect();
2849 assert_eq!(m.len(), 2);
2850 assert_eq!(m.get("a"), Some(&3)); // last value kept
2851 assert_eq!(m.get("b"), Some(&2));
2852 }
2853
2854 // ── bytes_from_source ────────────────────────────────────────────────
2855
2856 #[test]
2857 fn bytes_from_source_none_copies() {
2858 let data: &[u8] = b"hello";
2859 let out = bytes_from_source(None, data);
2860 assert_eq!(&out[..], data);
2861 assert_ne!(out.as_ptr(), data.as_ptr()); // distinct allocation
2862 }
2863
2864 #[test]
2865 fn bytes_from_source_some_within_is_slice_ref() {
2866 let parent = Bytes::copy_from_slice(b"hello world");
2867 let slice = &parent[6..11];
2868 let out = bytes_from_source(Some(&parent), slice);
2869 assert_eq!(&out[..], b"world");
2870 // slice_ref shares the same backing storage — same pointer.
2871 assert_eq!(out.as_ptr(), slice.as_ptr());
2872 }
2873
2874 #[test]
2875 fn bytes_from_source_some_outside_falls_back_to_copy() {
2876 let parent = Bytes::copy_from_slice(b"hello");
2877 let outside: &[u8] = b"world"; // static, not in `parent`
2878 let out = bytes_from_source(Some(&parent), outside);
2879 assert_eq!(&out[..], b"world");
2880 assert_ne!(out.as_ptr(), outside.as_ptr());
2881 }
2882
2883 #[test]
2884 fn bytes_from_source_empty_returns_new() {
2885 let parent = Bytes::copy_from_slice(b"hello");
2886 assert!(bytes_from_source(Some(&parent), &[]).is_empty());
2887 assert!(bytes_from_source(None, &[]).is_empty());
2888 }
2889
2890 #[test]
2891 fn bytes_from_source_full_range() {
2892 let parent = Bytes::copy_from_slice(b"hello");
2893 let out = bytes_from_source(Some(&parent), &parent[..]);
2894 assert_eq!(out.as_ptr(), parent.as_ptr());
2895 assert_eq!(out.len(), parent.len());
2896 }
2897
2898 // ── UnknownFieldsView ────────────────────────────────────────────────
2899
2900 #[test]
2901 fn unknown_fields_view_new_is_empty() {
2902 let uf = UnknownFieldsView::new();
2903 assert!(uf.is_empty());
2904 assert_eq!(uf.encoded_len(), 0);
2905 }
2906
2907 #[test]
2908 fn unknown_fields_view_push_raw_and_encoded_len() {
2909 let mut uf = UnknownFieldsView::new();
2910 uf.push_raw(&[0x08, 0x01]); // field 1, varint 1
2911 uf.push_raw(&[0x10, 0x02]); // field 2, varint 2
2912 assert!(!uf.is_empty());
2913 assert_eq!(uf.encoded_len(), 4);
2914 }
2915
2916 #[test]
2917 fn unknown_fields_view_to_owned_single_field() {
2918 // Build a valid unknown field: tag for field 99, varint wire type,
2919 // value 42. Tag = (99 << 3) | 0 = 792 = varint bytes [0x98, 0x06].
2920 let span: &[u8] = &[0x98, 0x06, 0x2A];
2921 let mut uf = UnknownFieldsView::new();
2922 uf.push_raw(span);
2923
2924 let owned = uf.to_owned().expect("valid wire data");
2925 assert_eq!(owned.len(), 1);
2926 let field = owned.iter().next().unwrap();
2927 assert_eq!(field.number, 99);
2928 assert_eq!(
2929 field.data,
2930 crate::unknown_fields::UnknownFieldData::Varint(42)
2931 );
2932 }
2933
2934 #[test]
2935 fn unknown_fields_view_to_owned_multiple_fields() {
2936 let mut uf = UnknownFieldsView::new();
2937 // Field 1, varint, value 7: tag = (1<<3)|0 = 0x08, value = 0x07
2938 uf.push_raw(&[0x08, 0x07]);
2939 // Field 2, fixed32, value 0x01020304:
2940 // tag = (2<<3)|5 = 0x15, then 4 LE bytes
2941 uf.push_raw(&[0x15, 0x04, 0x03, 0x02, 0x01]);
2942
2943 let owned = uf.to_owned().expect("valid wire data");
2944 assert_eq!(owned.len(), 2);
2945
2946 let mut it = owned.iter();
2947 let f1 = it.next().unwrap();
2948 assert_eq!(f1.number, 1);
2949 assert_eq!(f1.data, crate::unknown_fields::UnknownFieldData::Varint(7));
2950
2951 let f2 = it.next().unwrap();
2952 assert_eq!(f2.number, 2);
2953 assert_eq!(
2954 f2.data,
2955 crate::unknown_fields::UnknownFieldData::Fixed32(0x01020304)
2956 );
2957 }
2958
2959 #[test]
2960 fn unknown_fields_view_to_owned_malformed_returns_error() {
2961 // A truncated tag (high continuation bit, then EOF).
2962 let mut uf = UnknownFieldsView::new();
2963 uf.push_raw(&[0x80]);
2964 assert!(uf.to_owned().is_err());
2965 }
2966
2967 // ── OwnedView ──────────────────────────────────────────────────────
2968
2969 // Minimal types to test OwnedView without depending on generated code.
2970
2971 use crate::message::Message;
2972
2973 /// A trivial "message" for the owned side of the view contract.
2974 #[derive(Clone, Debug, Default, PartialEq)]
2975 struct SimpleMessage {
2976 pub id: i32,
2977 pub name: alloc::string::String,
2978 }
2979
2980 impl crate::DefaultInstance for SimpleMessage {
2981 fn default_instance() -> &'static Self {
2982 static INST: crate::__private::OnceBox<SimpleMessage> =
2983 crate::__private::OnceBox::new();
2984 INST.get_or_init(|| alloc::boxed::Box::new(SimpleMessage::default()))
2985 }
2986 }
2987
2988 impl crate::Message for SimpleMessage {
2989 fn compute_size(&self, _cache: &mut crate::SizeCache) -> u32 {
2990 let mut size = 0u32;
2991 if self.id != 0 {
2992 size += 1 + crate::types::int32_encoded_len(self.id) as u32;
2993 }
2994 if !self.name.is_empty() {
2995 size += 1 + crate::types::string_encoded_len(&self.name) as u32;
2996 }
2997 size
2998 }
2999
3000 fn write_to(&self, _cache: &mut crate::SizeCache, buf: &mut impl bytes::BufMut) {
3001 if self.id != 0 {
3002 crate::encoding::Tag::new(1, crate::encoding::WireType::Varint).encode(buf);
3003 crate::types::encode_int32(self.id, buf);
3004 }
3005 if !self.name.is_empty() {
3006 crate::encoding::Tag::new(2, crate::encoding::WireType::LengthDelimited)
3007 .encode(buf);
3008 crate::types::encode_string(&self.name, buf);
3009 }
3010 }
3011
3012 fn merge_field(
3013 &mut self,
3014 tag: crate::encoding::Tag,
3015 buf: &mut impl bytes::Buf,
3016 _ctx: crate::DecodeContext<'_>,
3017 ) -> Result<(), DecodeError> {
3018 match tag.field_number() {
3019 1 => self.id = crate::types::decode_int32(buf)?,
3020 2 => crate::types::merge_string(&mut self.name, buf)?,
3021 _ => crate::encoding::skip_field(tag, buf)?,
3022 }
3023 Ok(())
3024 }
3025
3026 fn clear(&mut self) {
3027 self.id = 0;
3028 self.name.clear();
3029 }
3030 }
3031
3032 /// A zero-copy view of `SimpleMessage`. Borrows `name` as `&str`.
3033 #[derive(Clone, Debug, Default, PartialEq)]
3034 struct SimpleMessageView<'a> {
3035 pub id: i32,
3036 pub name: &'a str,
3037 }
3038
3039 // Via the exported macro, which doubles as its unit test.
3040 crate::impl_view_reborrow!(SimpleMessageView);
3041
3042 impl<'a> MessageView<'a> for SimpleMessageView<'a> {
3043 type Owned = SimpleMessage;
3044 fn merge_view_field(
3045 &mut self,
3046 _tag: crate::encoding::Tag,
3047 cur: &'a [u8],
3048 _before_tag: &'a [u8],
3049 _ctx: crate::DecodeContext<'_>,
3050 ) -> Result<&'a [u8], DecodeError> {
3051 Ok(cur)
3052 }
3053
3054 fn decode_view(buf: &'a [u8]) -> Result<Self, DecodeError> {
3055 let mut view = SimpleMessageView::default();
3056 let mut cursor: &'a [u8] = buf;
3057 while !cursor.is_empty() {
3058 let tag = crate::encoding::Tag::decode(&mut cursor)?;
3059 match tag.field_number() {
3060 1 => view.id = crate::types::decode_int32(&mut cursor)?,
3061 2 => view.name = crate::types::borrow_str(&mut cursor)?,
3062 _ => crate::encoding::skip_field(tag, &mut cursor)?,
3063 }
3064 }
3065 Ok(view)
3066 }
3067
3068 fn to_owned_message(&self) -> Result<SimpleMessage, DecodeError> {
3069 Ok(SimpleMessage {
3070 id: self.id,
3071 name: self.name.into(),
3072 })
3073 }
3074 }
3075
3076 impl<'a> ViewEncode<'a> for SimpleMessageView<'a> {
3077 fn compute_size(&self, _cache: &mut crate::SizeCache) -> u32 {
3078 let mut size = 0u32;
3079 if self.id != 0 {
3080 size += 1 + crate::types::int32_encoded_len(self.id) as u32;
3081 }
3082 if !self.name.is_empty() {
3083 size += 1 + crate::types::string_encoded_len(self.name) as u32;
3084 }
3085 size
3086 }
3087
3088 fn write_to(&self, _cache: &mut crate::SizeCache, buf: &mut impl bytes::BufMut) {
3089 if self.id != 0 {
3090 crate::encoding::Tag::new(1, crate::encoding::WireType::Varint).encode(buf);
3091 crate::types::encode_int32(self.id, buf);
3092 }
3093 if !self.name.is_empty() {
3094 crate::encoding::Tag::new(2, crate::encoding::WireType::LengthDelimited)
3095 .encode(buf);
3096 crate::types::encode_string(self.name, buf);
3097 }
3098 }
3099 }
3100
3101 /// Encode a SimpleMessage to Bytes for testing.
3102 fn encode_simple(id: i32, name: &str) -> Bytes {
3103 let msg = SimpleMessage {
3104 id,
3105 name: name.into(),
3106 };
3107 Bytes::from(msg.encode_to_vec())
3108 }
3109
3110 #[test]
3111 fn owned_view_decode_and_reborrow() {
3112 let bytes = encode_simple(42, "hello");
3113 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3114
3115 // Field access via reborrow — the borrow is tied to `view`.
3116 assert_eq!(view.reborrow().id, 42);
3117 assert_eq!(view.reborrow().name, "hello");
3118 }
3119
3120 #[test]
3121 fn owned_view_to_owned_message() {
3122 let bytes = encode_simple(7, "world");
3123 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3124 let owned = view.to_owned_message().unwrap();
3125
3126 assert_eq!(owned.id, 7);
3127 assert_eq!(owned.name, "world");
3128 }
3129
3130 #[test]
3131 fn owned_view_debug_delegates_to_view() {
3132 let bytes = encode_simple(1, "test");
3133 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3134 let debug = alloc::format!("{:?}", view);
3135 assert!(debug.contains("test"));
3136 assert!(debug.contains("1"));
3137 }
3138
3139 #[test]
3140 fn owned_view_bytes_accessor() {
3141 let bytes = encode_simple(5, "data");
3142 let original_len = bytes.len();
3143 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3144
3145 assert_eq!(view.bytes().len(), original_len);
3146 }
3147
3148 #[test]
3149 fn owned_view_into_bytes_recovers_buffer() {
3150 let bytes = encode_simple(99, "recover");
3151 let expected = bytes.clone();
3152 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3153 let recovered = view.into_bytes();
3154
3155 assert_eq!(recovered, expected);
3156 }
3157
3158 #[test]
3159 fn owned_view_decode_invalid_data_returns_error() {
3160 // Truncated varint
3161 let bad = Bytes::from_static(&[0x08, 0x80]);
3162 let result = OwnedView::<SimpleMessageView<'static>>::decode(bad);
3163 assert!(result.is_err());
3164 }
3165
3166 #[test]
3167 fn owned_view_empty_message() {
3168 let bytes = Bytes::from_static(&[]);
3169 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3170 assert_eq!(view.reborrow().id, 0);
3171 assert_eq!(view.reborrow().name, "");
3172 }
3173
3174 #[test]
3175 fn owned_view_is_send_and_sync() {
3176 fn assert_send_sync<T: Send + Sync>() {}
3177 assert_send_sync::<OwnedView<SimpleMessageView<'static>>>();
3178 }
3179
3180 #[test]
3181 fn owned_view_from_owned_roundtrips() {
3182 let msg = SimpleMessage {
3183 id: 99,
3184 name: "roundtrip".into(),
3185 };
3186 let view = OwnedView::<SimpleMessageView<'static>>::from_owned(&msg).expect("from_owned");
3187 assert_eq!(view.reborrow().id, 99);
3188 assert_eq!(view.reborrow().name, "roundtrip");
3189
3190 let back = view.to_owned_message().unwrap();
3191 assert_eq!(back, msg);
3192 }
3193
3194 #[test]
3195 fn owned_view_decode_with_options() {
3196 let bytes = encode_simple(42, "opts");
3197 let opts = crate::DecodeOptions::new().with_max_message_size(1024);
3198 let view =
3199 OwnedView::<SimpleMessageView<'static>>::decode_with_options(bytes, &opts).unwrap();
3200 assert_eq!(view.reborrow().id, 42);
3201 assert_eq!(view.reborrow().name, "opts");
3202 }
3203
3204 #[test]
3205 fn owned_view_decode_with_options_rejects_oversized() {
3206 let bytes = encode_simple(42, "too large");
3207 let opts = crate::DecodeOptions::new().with_max_message_size(2);
3208 let result = OwnedView::<SimpleMessageView<'static>>::decode_with_options(bytes, &opts);
3209 assert!(result.is_err());
3210 }
3211
3212 #[test]
3213 fn owned_view_clone_survives_original_drop() {
3214 let bytes = encode_simple(42, "cloned");
3215 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3216 let cloned = view.clone();
3217 drop(view); // drop original — clone must still be valid
3218 assert_eq!(cloned.reborrow().id, 42);
3219 assert_eq!(cloned.reborrow().name, "cloned");
3220 }
3221
3222 #[test]
3223 fn owned_view_clone_equality() {
3224 let bytes = encode_simple(42, "eq");
3225 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3226 let cloned = view.clone();
3227 assert_eq!(view, cloned);
3228 }
3229
3230 #[test]
3231 fn owned_view_eq_same_data() {
3232 let a = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(1, "x")).unwrap();
3233 let b = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(1, "x")).unwrap();
3234 assert_eq!(a, b);
3235 }
3236
3237 #[test]
3238 fn owned_view_ne_different_data() {
3239 let a = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(1, "x")).unwrap();
3240 let b = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(2, "y")).unwrap();
3241 assert_ne!(a, b);
3242 }
3243
3244 #[test]
3245 fn owned_view_into_bytes_after_clone() {
3246 let bytes = encode_simple(42, "test");
3247 let expected = bytes.clone();
3248 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3249 let cloned = view.clone();
3250 drop(view); // drop original first
3251 let recovered = cloned.into_bytes();
3252 assert_eq!(recovered, expected);
3253 }
3254
3255 #[test]
3256 fn owned_view_drop_count() {
3257 use core::sync::atomic::{AtomicUsize, Ordering};
3258
3259 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
3260
3261 /// A wrapper view that counts drops.
3262 struct DropCountingView<'a> {
3263 inner: SimpleMessageView<'a>,
3264 }
3265
3266 impl Drop for DropCountingView<'_> {
3267 fn drop(&mut self) {
3268 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
3269 }
3270 }
3271
3272 impl<'a> MessageView<'a> for DropCountingView<'a> {
3273 type Owned = SimpleMessage;
3274 fn merge_view_field(
3275 &mut self,
3276 _tag: crate::encoding::Tag,
3277 cur: &'a [u8],
3278 _before_tag: &'a [u8],
3279 _ctx: crate::DecodeContext<'_>,
3280 ) -> Result<&'a [u8], DecodeError> {
3281 Ok(cur)
3282 }
3283
3284 fn decode_view(buf: &'a [u8]) -> Result<Self, DecodeError> {
3285 Ok(DropCountingView {
3286 inner: SimpleMessageView::decode_view(buf)?,
3287 })
3288 }
3289
3290 fn to_owned_message(&self) -> Result<SimpleMessage, DecodeError> {
3291 self.inner.to_owned_message()
3292 }
3293 }
3294
3295 // Test normal drop: view drops exactly once.
3296 DROP_COUNT.store(0, Ordering::SeqCst);
3297 {
3298 let bytes = encode_simple(1, "drop");
3299 let _view = OwnedView::<DropCountingView<'static>>::decode(bytes).unwrap();
3300 }
3301 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1, "normal drop");
3302
3303 // Test into_bytes: view drops exactly once.
3304 DROP_COUNT.store(0, Ordering::SeqCst);
3305 {
3306 let bytes = encode_simple(2, "into");
3307 let view = OwnedView::<DropCountingView<'static>>::decode(bytes).unwrap();
3308 let _bytes = view.into_bytes();
3309 }
3310 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1, "into_bytes drop");
3311 }
3312
3313 #[test]
3314 fn owned_view_name_borrows_from_bytes_buffer() {
3315 let bytes = encode_simple(42, "borrowed");
3316 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3317 let buf = view.bytes();
3318 let buf_start = buf.as_ptr() as usize;
3319 let buf_end = buf_start + buf.len();
3320 let name_ptr = view.reborrow().name.as_ptr() as usize;
3321 assert!(
3322 (buf_start..buf_end).contains(&name_ptr),
3323 "view name should point into the Bytes buffer"
3324 );
3325 }
3326
3327 #[test]
3328 fn owned_view_concurrent_read() {
3329 use alloc::sync::Arc;
3330
3331 let bytes = encode_simple(42, "concurrent");
3332 let view = Arc::new(OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap());
3333 let handles: alloc::vec::Vec<_> = (0..4)
3334 .map(|_| {
3335 let v = Arc::clone(&view);
3336 std::thread::spawn(move || {
3337 assert_eq!(v.reborrow().id, 42);
3338 assert_eq!(v.reborrow().name, "concurrent");
3339 })
3340 })
3341 .collect();
3342 for h in handles {
3343 h.join().unwrap();
3344 }
3345 }
3346
3347 #[test]
3348 fn owned_view_from_parts_roundtrip() {
3349 let bytes = encode_simple(42, "parts");
3350 // Decode a view from the bytes, then wrap via from_parts.
3351 // SAFETY: `view` was decoded from `bytes`.
3352 let view = unsafe {
3353 let slice: &'static [u8] = core::mem::transmute::<&[u8], &'static [u8]>(&bytes);
3354 let decoded = SimpleMessageView::decode_view(slice).unwrap();
3355 OwnedView::<SimpleMessageView<'static>>::from_parts(bytes, decoded)
3356 };
3357 assert_eq!(view.reborrow().id, 42);
3358 assert_eq!(view.reborrow().name, "parts");
3359 }
3360
3361 // ── ViewReborrow / OwnedView::reborrow ───────────────────────────────
3362
3363 #[test]
3364 fn reborrow_fields_match_original() {
3365 let bytes = encode_simple(7, "hello");
3366 let owned = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3367 let reborrowed: &SimpleMessageView<'_> = owned.reborrow();
3368 assert_eq!(reborrowed.id, 7);
3369 assert_eq!(reborrowed.name, "hello");
3370 // The reborrowed &str must point into the Bytes buffer, not a copy.
3371 let buf_start = owned.bytes().as_ptr() as usize;
3372 let buf_end = buf_start + owned.bytes().len();
3373 assert!((buf_start..buf_end).contains(&(reborrowed.name.as_ptr() as usize)));
3374 }
3375
3376 #[test]
3377 fn reborrow_does_not_consume_owned_view() {
3378 let bytes = encode_simple(1, "world");
3379 let owned = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3380 let r1: &SimpleMessageView<'_> = owned.reborrow();
3381 let r2: &SimpleMessageView<'_> = owned.reborrow();
3382 assert_eq!(r1.name, r2.name);
3383 // `owned` still usable here
3384 assert_eq!(owned.reborrow().name, "world");
3385 }
3386 // ── Lazy views ───────────────────────────────────────────────────────
3387
3388 /// Hand-written lazy view of `SimpleMessage`, shaped like generated
3389 /// `FooLazyView` code: scalars borrowed, one flat scan, fragment merge.
3390 #[derive(Clone, Debug, Default, PartialEq)]
3391 struct SimpleLazyView<'a> {
3392 pub id: i32,
3393 pub name: &'a str,
3394 }
3395
3396 impl<'a> LazyMessageView<'a> for SimpleLazyView<'a> {
3397 type Owned = SimpleMessage;
3398
3399 fn decode_lazy(buf: &'a [u8]) -> Result<Self, DecodeError> {
3400 let limit = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
3401 Self::decode_lazy_with_ctx(
3402 buf,
3403 crate::DecodeContext::new(crate::RECURSION_LIMIT, &limit),
3404 )
3405 }
3406
3407 fn decode_lazy_with_ctx(
3408 buf: &'a [u8],
3409 ctx: crate::DecodeContext<'_>,
3410 ) -> Result<Self, DecodeError> {
3411 let mut view = SimpleLazyView::default();
3412 view.merge_lazy(buf, ctx)?;
3413 Ok(view)
3414 }
3415
3416 fn merge_lazy(
3417 &mut self,
3418 buf: &'a [u8],
3419 ctx: crate::DecodeContext<'_>,
3420 ) -> Result<(), DecodeError> {
3421 let mut cursor: &'a [u8] = buf;
3422 while !cursor.is_empty() {
3423 let tag = crate::encoding::Tag::decode(&mut cursor)?;
3424 match tag.field_number() {
3425 1 => self.id = crate::types::decode_int32(&mut cursor)?,
3426 2 => self.name = crate::types::borrow_str(&mut cursor)?,
3427 _ => crate::encoding::skip_field_depth(tag, &mut cursor, ctx.depth())?,
3428 }
3429 }
3430 Ok(())
3431 }
3432
3433 fn to_owned_message(&self) -> Result<SimpleMessage, DecodeError> {
3434 Ok(SimpleMessage {
3435 id: self.id,
3436 name: self.name.into(),
3437 })
3438 }
3439 }
3440
3441 fn full_budget_ctx(cell: &core::cell::Cell<usize>) -> crate::DecodeContext<'_> {
3442 crate::DecodeContext::new(crate::RECURSION_LIMIT, cell)
3443 }
3444
3445 #[test]
3446 fn lazy_message_field_view_decodes_on_access() {
3447 let bytes = encode_simple(42, "lazy");
3448 let unset = LazyMessageFieldView::<SimpleLazyView<'_>>::unset();
3449 assert!(unset.is_unset());
3450 assert!(unset.fragments().is_empty());
3451 assert!(unset.get().unwrap().is_none());
3452 assert_eq!(unset.get_or_default().unwrap(), SimpleLazyView::default());
3453
3454 let lazy = LazyMessageFieldView::<SimpleLazyView<'_>>::from_bytes(&bytes);
3455 assert!(lazy.is_set());
3456 assert_eq!(lazy.fragments(), &[&bytes[..]]);
3457 let v = lazy.get().unwrap().expect("set");
3458 assert_eq!((v.id, v.name), (42, "lazy"));
3459 // Re-decodes each call (no cache).
3460 assert_eq!(lazy.get().unwrap().unwrap().id, 42);
3461 assert_eq!(v.to_owned_message().unwrap().name, "lazy");
3462 }
3463
3464 #[test]
3465 fn lazy_message_field_view_merges_fragments() {
3466 // A singular message field split across wire occurrences must merge:
3467 // fragment 1 sets `name`, fragment 2 sets `id`; the merged view has
3468 // both, matching the eager/owned decoders.
3469 let frag1 = encode_simple(0, "from-frag-1");
3470 let frag2 = encode_simple(7, "");
3471 let cell = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
3472
3473 let mut lazy = LazyMessageFieldView::<SimpleLazyView<'_>>::unset();
3474 lazy.push_fragment(&frag1, full_budget_ctx(&cell));
3475 assert_eq!(lazy.fragments().len(), 1);
3476 lazy.push_fragment(&frag2, full_budget_ctx(&cell));
3477 assert_eq!(lazy.fragments(), &[&frag1[..], &frag2[..]]);
3478
3479 let v = lazy.get().unwrap().expect("set");
3480 assert_eq!((v.id, v.name), (7, "from-frag-1"));
3481
3482 // Later fragments overwrite singular scalars (last-wins).
3483 let frag3 = encode_simple(9, "final");
3484 lazy.push_fragment(&frag3, full_budget_ctx(&cell));
3485 assert_eq!(lazy.fragments().len(), 3);
3486 let v = lazy.get().unwrap().expect("set");
3487 assert_eq!((v.id, v.name), (9, "final"));
3488 }
3489
3490 #[test]
3491 fn lazy_message_field_view_records_smallest_budgets() {
3492 // Budgets recorded across pushes are min-combined, and the recorded
3493 // allowance replays per access (capture-then-replay).
3494 let bytes = encode_simple(1, "x");
3495 let cell_big = core::cell::Cell::new(500);
3496 let cell_small = core::cell::Cell::new(3);
3497
3498 let mut lazy = LazyMessageFieldView::<SimpleLazyView<'_>>::unset();
3499 lazy.push_fragment(&bytes, crate::DecodeContext::new(80, &cell_big));
3500 lazy.push_fragment(&bytes, crate::DecodeContext::new(50, &cell_small));
3501 // Decoding succeeds — SimpleLazyView has no unknowns or nesting here;
3502 // the recorded budgets only bound what access may consume.
3503 assert!(lazy.get().unwrap().is_some());
3504 }
3505
3506 #[test]
3507 fn lazy_message_field_view_clone_default_debug() {
3508 let bytes = encode_simple(1, "x");
3509 let cell = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
3510 let mut lazy = LazyMessageFieldView::<SimpleLazyView<'_>>::default();
3511 assert!(lazy.is_unset());
3512 lazy.push_fragment(&bytes, full_budget_ctx(&cell));
3513 lazy.push_fragment(&bytes, full_budget_ctx(&cell));
3514 let cloned = lazy.clone();
3515 assert_eq!(cloned.fragments(), lazy.fragments());
3516 let dbg = alloc::format!("{lazy:?}");
3517 assert!(dbg.contains("is_set: true"), "{dbg}");
3518 assert!(dbg.contains("fragments: 2"), "{dbg}");
3519 }
3520
3521 #[test]
3522 fn lazy_message_field_view_malformed_errors_on_access() {
3523 // 0xFF starts a tag whose varint never terminates — invalid.
3524 let malformed = [0xFFu8; 3];
3525 let lazy = LazyMessageFieldView::<SimpleLazyView<'_>>::from_bytes(&malformed);
3526 // Deferred validation: construction succeeds, access fails.
3527 assert!(lazy.is_set());
3528 assert!(lazy.get().is_err());
3529 }
3530
3531 #[test]
3532 fn lazy_repeated_view_decodes_per_element() {
3533 let b0 = encode_simple(1, "a");
3534 let b1 = encode_simple(2, "b");
3535 let cell = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
3536 let mut rep = LazyRepeatedView::<SimpleLazyView<'_>>::new();
3537 assert!(rep.is_empty());
3538 rep.push_bytes(&b0, full_budget_ctx(&cell));
3539 rep.push_bytes(&b1, full_budget_ctx(&cell));
3540 assert_eq!(rep.len(), 2);
3541 assert_eq!(rep.raw_elements(), &[&b0[..], &b1[..]]);
3542 assert_eq!(rep.get(0).unwrap().unwrap().name, "a");
3543 assert_eq!(rep.get(1).unwrap().unwrap().id, 2);
3544 assert!(rep.get(2).is_none());
3545 }
3546
3547 #[test]
3548 fn lazy_repeated_view_iter() {
3549 let bufs: alloc::vec::Vec<Bytes> = (1..=3)
3550 .map(|i| encode_simple(i, core::str::from_utf8(&[b'a' + i as u8]).unwrap()))
3551 .collect();
3552 let cell = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
3553 let mut rep = LazyRepeatedView::<SimpleLazyView<'_>>::new();
3554 for b in &bufs {
3555 rep.push_bytes(b, full_budget_ctx(&cell));
3556 }
3557
3558 let iter = rep.iter();
3559 assert_eq!(iter.len(), 3);
3560 let ids: alloc::vec::Vec<i32> = iter.map(|r| r.unwrap().id).collect();
3561 assert_eq!(ids, [1, 2, 3]);
3562
3563 // IntoIterator for &LazyRepeatedView.
3564 let names: alloc::vec::Vec<&str> = (&rep).into_iter().map(|r| r.unwrap().name).collect();
3565 assert_eq!(names, ["b", "c", "d"]);
3566
3567 // DoubleEndedIterator.
3568 let rev_ids: alloc::vec::Vec<i32> = rep.iter().rev().map(|r| r.unwrap().id).collect();
3569 assert_eq!(rev_ids, [3, 2, 1]);
3570 }
3571
3572 #[test]
3573 fn lazy_repeated_view_iter_surfaces_element_errors() {
3574 let good = encode_simple(1, "ok");
3575 let malformed = [0xFFu8; 3];
3576 let cell = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
3577 let mut rep = LazyRepeatedView::<SimpleLazyView<'_>>::new();
3578 rep.push_bytes(&good, full_budget_ctx(&cell));
3579 rep.push_bytes(&malformed, full_budget_ctx(&cell));
3580 let results: alloc::vec::Vec<_> = rep.iter().collect();
3581 assert!(results[0].is_ok());
3582 assert!(results[1].is_err());
3583 let cloned = rep.clone();
3584 assert_eq!(cloned.len(), 2);
3585 }
3586}