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::encode_sink::EncodeSink;
103use crate::error::DecodeError;
104use crate::message::Message as _;
105use bytes::Bytes;
106
107/// Trait for zero-copy borrowed message views.
108///
109/// View types borrow from the input buffer and provide read-only access
110/// to message fields without allocation. Each generated `MyMessageView<'a>`
111/// implements this trait.
112///
113/// The lifetime `'a` ties the view to the input buffer — the view cannot
114/// outlive the buffer it was decoded from.
115///
116/// Generated view structs may gain fields across releases; see the
117/// [struct evolution policy on `Message`](crate::Message#struct-evolution-policy).
118pub trait MessageView<'a>: Sized {
119 /// The corresponding owned message type.
120 type Owned: crate::Message;
121
122 /// Decode a view from a buffer, borrowing string/bytes fields directly.
123 ///
124 /// The returned view borrows from `buf`'s underlying bytes. The caller
125 /// must ensure the buffer is contiguous (e.g., `&[u8]` or `bytes::Bytes`).
126 ///
127 /// Decoding validates the whole message tree eagerly. For
128 /// decode-on-access of large sub-message trees, see the opt-in
129 /// [`LazyMessageView`] family (`lazy_views` codegen option).
130 ///
131 /// Generated impls construct a default [`DecodeContext`](crate::DecodeContext)
132 /// and delegate to [`decode_view_ctx`](Self::decode_view_ctx). (Kept
133 /// required, without a `Self: Default` bound, so generic callers stay
134 /// bound-free.)
135 ///
136 /// The default context carries the same three budgets
137 /// [`Message::decode`](crate::Message::decode) applies:
138 /// [`RECURSION_LIMIT`](crate::RECURSION_LIMIT),
139 /// [`DEFAULT_UNKNOWN_FIELD_LIMIT`](crate::DEFAULT_UNKNOWN_FIELD_LIMIT), and
140 /// [`DEFAULT_ELEMENT_MEMORY_LIMIT`](crate::DEFAULT_ELEMENT_MEMORY_LIMIT).
141 /// A view of a repeated field costs element memory just as the owned decode
142 /// does — each element occupies a `size_of::<FooView>()` slot in a `Vec`
143 /// even though its string and bytes contents stay borrowed.
144 fn decode_view(buf: &'a [u8]) -> Result<Self, DecodeError>;
145
146 /// Decode a view under custom decode limits.
147 ///
148 /// Used by [`DecodeOptions::decode_view`](crate::DecodeOptions::decode_view)
149 /// to pass a non-default recursion depth, unknown-field allowance, and
150 /// element-memory budget.
151 /// The default implementation delegates to
152 /// [`decode_view`](Self::decode_view) and **ignores the context** —
153 /// a hand-written `MessageView` that recurses or preserves unknown
154 /// fields must override this method to honor the limits configured on
155 /// `DecodeOptions`. Implementing
156 /// [`merge_view_field`](Self::merge_view_field) is **not sufficient**:
157 /// without this override, `DecodeOptions` limits never reach your
158 /// field arms. The one-line override is
159 /// `Self::decode_view_ctx(buf, ctx)` (when `Self: Default`). Generated
160 /// code always overrides it that way.
161 ///
162 /// Not to be confused with [`decode_view_ctx`](Self::decode_view_ctx),
163 /// which is the provided decoder that *honors* the context; this method
164 /// is the override point `DecodeOptions` calls.
165 fn decode_view_with_ctx(
166 buf: &'a [u8],
167 _ctx: crate::DecodeContext<'_>,
168 ) -> Result<Self, DecodeError> {
169 Self::decode_view(buf)
170 }
171
172 /// Decode a view under an explicit [`DecodeContext`](crate::DecodeContext)
173 /// (remaining recursion depth, unknown-field allowance, and element-memory
174 /// budget), driving the provided tag loop over
175 /// [`merge_view_field`](Self::merge_view_field).
176 ///
177 /// This is the bridge a hand-written impl uses to wire its required
178 /// `decode_view` to its required `merge_view_field`:
179 ///
180 /// ```rust,ignore
181 /// fn decode_view(buf: &'a [u8]) -> Result<Self, buffa::DecodeError> {
182 /// let limit = core::cell::Cell::new(buffa::DEFAULT_UNKNOWN_FIELD_LIMIT);
183 /// let elem = core::cell::Cell::new(buffa::DEFAULT_ELEMENT_MEMORY_LIMIT);
184 /// Self::decode_view_ctx(
185 /// buf,
186 /// buffa::DecodeContext::new(buffa::RECURSION_LIMIT, &limit)
187 /// .with_element_memory(&elem),
188 /// )
189 /// }
190 /// ```
191 ///
192 /// Attaching the element-memory budget is load-bearing, not decoration.
193 /// [`register_element_memory`](crate::DecodeContext::register_element_memory)
194 /// returns `Ok(())` when no budget is attached, so a context built without
195 /// [`with_element_memory`](crate::DecodeContext::with_element_memory)
196 /// turns every repeated-element charge in every field arm into a no-op.
197 ///
198 /// Also called by generated sub-message decode arms with a descended
199 /// context. Not to be confused with
200 /// [`decode_view_with_ctx`](Self::decode_view_with_ctx), the
201 /// `DecodeOptions` override point whose *default* ignores the context.
202 ///
203 /// # Errors
204 ///
205 /// Returns a [`DecodeError`] on malformed input, a wire-type mismatch, or
206 /// when a configured decode limit (recursion depth, unknown-field
207 /// allowance) is exceeded.
208 fn decode_view_ctx(buf: &'a [u8], ctx: crate::DecodeContext<'_>) -> Result<Self, DecodeError>
209 where
210 Self: Default,
211 {
212 let mut view = Self::default();
213 view.merge_into_view(buf, ctx)?;
214 Ok(view)
215 }
216
217 /// Merge fields from `buf` into this view (proto merge semantics):
218 /// repeated fields append, singular fields last-wins, singular message
219 /// fields merge recursively.
220 ///
221 /// The per-message work is the field `match` in
222 /// [`merge_view_field`](Self::merge_view_field); this provided method
223 /// owns the tag loop that every generated view previously restated.
224 /// Each iteration consumes the field's tag itself, so the loop makes
225 /// progress even if an arm consumes no payload bytes.
226 ///
227 /// # Errors
228 ///
229 /// Returns a [`DecodeError`] on malformed input, a wire-type mismatch, or
230 /// when a configured decode limit (recursion depth, unknown-field
231 /// allowance) is exceeded.
232 fn merge_into_view(
233 &mut self,
234 buf: &'a [u8],
235 ctx: crate::DecodeContext<'_>,
236 ) -> Result<(), DecodeError> {
237 let mut cur: &'a [u8] = buf;
238 while !cur.is_empty() {
239 // Captured so unknown fields can preserve their raw byte span
240 // (`before_tag.len() - cur.len()` after the payload is consumed).
241 let before_tag = cur;
242 let tag = crate::encoding::Tag::decode(&mut cur)?;
243 cur = self.merge_view_field(tag, cur, before_tag, ctx)?;
244 }
245 Ok(())
246 }
247
248 /// Decode one field's payload into this view (generated per message).
249 ///
250 /// `cur` is the input positioned just past `tag`; the implementation
251 /// returns the remaining input after the field's payload. The
252 /// pass-by-value/return shape (rather than `&mut &'a [u8]`) keeps each
253 /// arm's `&mut` borrow of the slice local to that arm — sub-message
254 /// arms can hand `cur` slices to recursive decode calls without
255 /// fighting a long-lived outer `&mut` reborrow. `before_tag` is the
256 /// input including the tag bytes, for raw-span unknown-field capture.
257 ///
258 /// Hand-written views must supply this (it is the one method the
259 /// provided decode loop requires). A view that instead overrides both
260 /// [`decode_view`](Self::decode_view) and
261 /// [`decode_view_with_ctx`](Self::decode_view_with_ctx) to decode by hand
262 /// never reaches the provided loop, so it can satisfy the trait with a
263 /// one-line `Ok(cur)` stub. The canonical shape is a match on
264 /// `tag.field_number()`. Mark the method `#[inline]`: the provided loop
265 /// calls it once per field across the crate boundary, so the hint lets the
266 /// optimizer fold the match into that loop.
267 ///
268 /// ```rust,ignore
269 /// #[inline]
270 /// fn merge_view_field(
271 /// &mut self,
272 /// tag: buffa::encoding::Tag,
273 /// cur: &'a [u8],
274 /// _before_tag: &'a [u8],
275 /// ctx: buffa::DecodeContext<'_>,
276 /// ) -> Result<&'a [u8], buffa::DecodeError> {
277 /// let mut cur = cur;
278 /// match tag.field_number() {
279 /// 1 => self.id = buffa::types::decode_int32(&mut cur)?,
280 /// 2 => self.name = buffa::types::borrow_str(&mut cur)?,
281 /// _ => buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?,
282 /// }
283 /// Ok(cur)
284 /// }
285 /// ```
286 ///
287 /// Views that preserve unknown fields capture the raw span — tag
288 /// included — via `before_tag` (the span length is measured *after* the
289 /// payload is consumed) and store it with
290 /// [`UnknownFieldsView::push_record`], which charges the context's
291 /// unknown-field allowance per field (including fields nested in
292 /// unknown groups) so that [`to_owned_message`](Self::to_owned_message)
293 /// cannot exhaust it later; the provided loop stays message-agnostic:
294 ///
295 /// ```rust,ignore
296 /// _ => {
297 /// buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?;
298 /// let span_len = before_tag.len() - cur.len();
299 /// self.unknown_fields.push_record(before_tag, span_len, ctx)?;
300 /// }
301 /// ```
302 ///
303 /// The returned slice must be a suffix of `cur` (and hence of
304 /// `before_tag`): the provided loop continues from it, and the
305 /// unknown-field span is measured as `before_tag.len() - cur.len()`, which
306 /// underflows and panics if the returned slice is longer than the input.
307 ///
308 /// # Errors
309 ///
310 /// Returns a [`DecodeError`] on malformed payloads or wire-type
311 /// mismatches.
312 fn merge_view_field(
313 &mut self,
314 tag: crate::encoding::Tag,
315 cur: &'a [u8],
316 before_tag: &'a [u8],
317 ctx: crate::DecodeContext<'_>,
318 ) -> Result<&'a [u8], DecodeError>;
319
320 /// Convert this view to the owned message type.
321 ///
322 /// This allocates and copies all borrowed fields. Equivalent to
323 /// [`to_owned_from_source(None)`](Self::to_owned_from_source).
324 ///
325 /// For views produced by [`decode_view`](Self::decode_view) (or the
326 /// other wire-decoding entry points), this cannot fail: decoding
327 /// charged the unknown-field allowance with exactly the slots that
328 /// re-materializing preserved unknown fields consumes, every span was
329 /// parsed off the wire, and re-materialization replays under the field
330 /// budget and group-nesting depth recorded at decode time. The `Result`
331 /// remains for hand-written view impls and for views holding manually
332 /// pushed ([`UnknownFieldsView::push_raw`]) unknown-field spans.
333 /// [`OwnedView`], which always holds a wire-decoded view, exposes this
334 /// conversion infallibly — see
335 /// [`OwnedView::to_owned_message`](OwnedView::to_owned_message) (and the
336 /// generated `FooOwnedView` wrappers likewise).
337 ///
338 /// # Errors
339 ///
340 /// Returns an error if re-materializing preserved unknown fields fails —
341 /// possible only for views not produced by wire decoding, as described
342 /// above.
343 fn to_owned_message(&self) -> Result<Self::Owned, DecodeError>;
344
345 /// Convert this view to the owned message type, optionally slicing
346 /// `bytes::Bytes`-typed fields from `source` instead of copying.
347 ///
348 /// When `source` is the [`Bytes`] buffer this view was decoded from,
349 /// owned fields configured for `bytes::Bytes` (via the `bytes_fields`
350 /// codegen option) are produced via [`Bytes::slice_ref`] — a refcount
351 /// bump, no allocation or copy. Borrowed fields that fall outside
352 /// `source` (e.g. on a manually-constructed view) and the `None` case
353 /// fall back to [`Bytes::copy_from_slice`].
354 ///
355 /// Generated view types override this; the default delegates to
356 /// [`to_owned_message`](Self::to_owned_message) so hand-written impls
357 /// need only provide that method.
358 ///
359 /// # Errors
360 ///
361 /// Same contract as [`to_owned_message`](Self::to_owned_message).
362 fn to_owned_from_source(&self, source: Option<&Bytes>) -> Result<Self::Owned, DecodeError> {
363 let _ = source;
364 self.to_owned_message()
365 }
366}
367
368/// Exposes the real lifetime of an [`OwnedView`]'s borrows.
369///
370/// `OwnedView<V>` stores `V` with a `'static` lifetime — the actual borrows
371/// point into its internal [`Bytes`] buffer. `ViewReborrow` lets
372/// [`OwnedView::reborrow`] return a reference typed as `&'b V::Reborrowed<'b>`,
373/// tying the borrow to `&'b self` so the compiler can reason about it correctly.
374///
375/// Codegen emits `impl ViewReborrow` automatically for every generated view
376/// type. Hand-written view types must provide it manually if
377/// [`OwnedView::reborrow`] is needed.
378///
379/// # Soundness
380///
381/// `ViewReborrow` is a **safe** trait. Soundness is established mechanically
382/// by the compiler at each impl site: the [`reborrow`](Self::reborrow) method
383/// body coerces a `&'b Self` (where `Self = FooView<'static>`) to
384/// `&'b Self::Reborrowed<'b>` (= `&'b FooView<'b>`). Rust accepts this only
385/// when `FooView` is **covariant** in its lifetime parameter — a covariant
386/// `FooView<'static>` is a subtype of `FooView<'b>` and the coercion is a
387/// standard subtyping move. Invariant fields (`Cell<&'a T>`, `&'a mut T`,
388/// `fn(&'a T)`) make the type invariant in `'a`; the trait body then fails
389/// to compile and the impl is rejected — which is exactly what should
390/// happen, because narrowing the lifetime of an invariant view *would* be
391/// unsound.
392///
393/// Hand-written impls cannot accidentally introduce undefined behaviour
394/// without writing `unsafe` themselves: the canonical body is just `this`,
395/// which the type checker accepts iff the variance permits the coercion.
396#[rustversion::attr(
397 since(1.78),
398 diagnostic::on_unimplemented(
399 message = "`{Self}` does not implement `ViewReborrow` — required by `OwnedView::reborrow`",
400 note = "for a generated view type, this impl is emitted automatically by codegen",
401 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 }}",
402 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",
403 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"
404 )
405)]
406pub trait ViewReborrow: MessageView<'static> {
407 /// The same view type with its lifetime shortened to `'b`.
408 type Reborrowed<'b>: MessageView<'b, Owned = <Self as MessageView<'static>>::Owned>
409 where
410 Self: 'b;
411
412 /// Coerce `&'b Self` (= `&'b FooView<'static>`) to
413 /// `&'b Self::Reborrowed<'b>` (= `&'b FooView<'b>`). The canonical body
414 /// is just `this`; the compiler accepts it via standard lifetime
415 /// variance for covariant view types.
416 ///
417 /// Called by [`OwnedView::reborrow`]; users shouldn't need to call this
418 /// method directly.
419 fn reborrow<'b>(this: &'b Self) -> &'b Self::Reborrowed<'b>;
420}
421
422/// Implement [`ViewReborrow`] for a generated view type.
423///
424/// Emitted by generated code (one invocation per view struct); the trait's
425/// `on_unimplemented` note shows the equivalent expansion for hand-written
426/// views.
427///
428/// ```rust,ignore
429/// buffa::impl_view_reborrow!(MyMessageView);
430/// ```
431#[macro_export]
432macro_rules! impl_view_reborrow {
433 ($ty:ident) => {
434 impl $crate::ViewReborrow for $ty<'static> {
435 type Reborrowed<'b> = $ty<'b>;
436 fn reborrow<'b>(this: &'b Self) -> &'b Self::Reborrowed<'b> {
437 this
438 }
439 }
440 };
441}
442
443/// Links an owned message type to its generated zero-copy view types.
444///
445/// For a message `Foo`, generated code implements this trait as
446/// `View<'a> = FooView<'a>` (the borrowed view) and
447/// `ViewHandle = FooOwnedView` (the self-contained `'static` handle). The
448/// trait lets code that is generic over an owned message name those types —
449/// for example an RPC framework that decodes `M::View<'_>` from a request
450/// body it owns, or holds `M::ViewHandle` items in a stream — without
451/// per-message glue on the consumer's side.
452///
453/// The associated types intentionally carry only structural bounds:
454///
455/// - [`View<'a>`](Self::View) is the message's view, with
456/// [`Owned`](MessageView::Owned)` = Self`.
457/// - [`ViewHandle`](Self::ViewHandle) is convertible from, and exposes via
458/// [`AsRef`], the corresponding `OwnedView<Self::View<'static>>`, so
459/// generic code can reach [`reborrow`](OwnedView::reborrow),
460/// [`bytes`](OwnedView::bytes), and
461/// [`to_owned_message`](OwnedView::to_owned_message) without naming the
462/// concrete wrapper. The wrapper's per-field accessor methods remain
463/// inherent on the concrete type.
464///
465/// Generic code that wants to reborrow through the handle
466/// (`handle.as_ref().reborrow()`) adds `M::View<'static>: ViewReborrow` as a
467/// bound at the use site; every generated view satisfies it. (The bound
468/// cannot live on the trait itself: a `where Self::View<'static>:
469/// ViewReborrow` clause currently trips a GAT normalization error, E0308
470/// "expected `MessageView<'a>`, found `MessageView<'static>`".)
471///
472/// # Implementing
473///
474/// Implementations are generated alongside the view and owned-view wrapper
475/// (and are therefore gated with them). Hand-written implementations are only
476/// needed for hand-written view types and must follow the same shape.
477#[rustversion::attr(
478 since(1.78),
479 diagnostic::on_unimplemented(
480 message = "`{Self}` does not implement `HasMessageView` — its message-view family was not generated or is not enabled",
481 note = "the `HasMessageView` impl is emitted next to each message's view types: \
482 regenerate the crate that defines `{Self}` with buffa 0.7.0 or newer and \
483 views enabled — `generate_views(true)` (on by default) in a buffa-build / \
484 buffa-codegen config, or `views=true` for protoc-gen-buffa",
485 note = "if the defining crate feature-gates its generated impls, enabling its views \
486 feature is enough — no regeneration needed"
487 )
488)]
489pub trait HasMessageView: crate::Message + Sized {
490 /// The zero-copy view of `Self`, borrowing from a buffer with lifetime
491 /// `'a`.
492 type View<'a>: MessageView<'a, Owned = Self> + Send + Sync;
493
494 /// The generated `'static` owned-view handle for `Self`
495 /// (`FooOwnedView`).
496 type ViewHandle: From<OwnedView<Self::View<'static>>>
497 + AsRef<OwnedView<Self::View<'static>>>
498 + Send
499 + Sync
500 + 'static;
501
502 /// Decode a borrowed [`View`](Self::View) from a byte slice.
503 ///
504 /// Convenience for generic code: lets a caller bounded only on
505 /// `M: HasMessageView` write `M::decode_view(buf)` instead of the
506 /// associated-type path
507 /// `<M as HasMessageView>::View::decode_view(buf)`. The returned view
508 /// borrows from `buf`. Reading the returned view (e.g.
509 /// [`to_owned_message`](MessageView::to_owned_message)) requires
510 /// [`MessageView`] in scope.
511 ///
512 /// Like the underlying [`MessageView::decode_view`], this does not
513 /// enforce `max_message_size`; use
514 /// [`decode_view_with_options`](Self::decode_view_with_options) for that.
515 ///
516 /// # Errors
517 ///
518 /// Returns [`DecodeError`] if the buffer contains invalid protobuf data.
519 #[inline]
520 fn decode_view(buf: &[u8]) -> Result<Self::View<'_>, DecodeError> {
521 <Self::View<'_> as MessageView<'_>>::decode_view(buf)
522 }
523
524 /// Decode a borrowed [`View`](Self::View) under custom
525 /// [`DecodeOptions`](crate::DecodeOptions) (recursion limit, max message
526 /// size, unknown-field limit).
527 ///
528 /// Convenience for generic code; equivalent to
529 /// [`DecodeOptions::decode_view::<M::View<'_>>`](crate::DecodeOptions::decode_view).
530 ///
531 /// # Errors
532 ///
533 /// Returns [`DecodeError`] if the buffer is invalid or exceeds the
534 /// configured limits.
535 #[inline]
536 fn decode_view_with_options<'a>(
537 buf: &'a [u8],
538 opts: &crate::DecodeOptions,
539 ) -> Result<Self::View<'a>, DecodeError> {
540 opts.decode_view(buf)
541 }
542
543 /// Decode a [`ViewHandle`](Self::ViewHandle) from a [`Bytes`] buffer.
544 ///
545 /// Convenience for generic code; equivalent to decoding an
546 /// [`OwnedView<Self::View<'static>>`](OwnedView) and converting it with
547 /// `From`.
548 ///
549 /// # Errors
550 ///
551 /// Returns [`DecodeError`] if the buffer contains invalid protobuf data.
552 fn decode_view_handle(bytes: Bytes) -> Result<Self::ViewHandle, DecodeError> {
553 Ok(Self::ViewHandle::from(
554 OwnedView::<Self::View<'static>>::decode(bytes)?,
555 ))
556 }
557
558 /// Decode a [`ViewHandle`](Self::ViewHandle) with custom
559 /// [`DecodeOptions`](crate::DecodeOptions) (recursion limit, max message
560 /// size).
561 ///
562 /// # Errors
563 ///
564 /// Returns [`DecodeError`] if the buffer is invalid or exceeds the
565 /// configured limits.
566 fn decode_view_handle_with_options(
567 bytes: Bytes,
568 opts: &crate::DecodeOptions,
569 ) -> Result<Self::ViewHandle, DecodeError> {
570 Ok(Self::ViewHandle::from(
571 OwnedView::<Self::View<'static>>::decode_with_options(bytes, opts)?,
572 ))
573 }
574}
575
576/// Produce a [`Bytes`] for a borrowed slice, preferring a zero-copy
577/// [`Bytes::slice_ref`] into `source` when the slice lies within it.
578///
579/// Used by generated [`MessageView::to_owned_from_source`] for
580/// `bytes_fields`. Empty slices return [`Bytes::new`]; slices outside
581/// `source` (or `source = None`) fall back to [`Bytes::copy_from_slice`].
582#[doc(hidden)]
583#[inline]
584pub fn bytes_from_source(source: Option<&Bytes>, slice: &[u8]) -> Bytes {
585 if slice.is_empty() {
586 return Bytes::new();
587 }
588 if let Some(b) = source {
589 if let Some(shared) = try_slice_ref(b, slice) {
590 return shared;
591 }
592 }
593 Bytes::copy_from_slice(slice)
594}
595
596/// Zero-copy [`Bytes::slice_ref`] guarded by `slice_ref`'s own containment
597/// precondition: returns `Some` only when `slice` lies entirely within
598/// `backing`, so callers fall back to a copy rather than panic for slices
599/// from elsewhere. Shared by [`bytes_from_source`] and the
600/// [`Rope`](crate::Rope) backing-buffer capture.
601///
602/// The caller is responsible for excluding empty slices when an empty
603/// result is not wanted (an empty slice's dangling pointer can spuriously
604/// fall inside any range).
605#[inline]
606pub(crate) fn try_slice_ref(backing: &Bytes, slice: &[u8]) -> Option<Bytes> {
607 let b_start = backing.as_ptr() as usize;
608 let s_start = slice.as_ptr() as usize;
609 let b_end = b_start.checked_add(backing.len())?;
610 let s_end = s_start.checked_add(slice.len())?;
611 (s_start >= b_start && s_end <= b_end).then(|| backing.slice_ref(slice))
612}
613
614/// Serialize a [`MessageView`] directly from its borrowed fields.
615///
616/// Symmetric with [`Message`](crate::Message)'s two-pass
617/// `compute_size` / `write_to` model, but the `&'a str` / `&'a [u8]` /
618/// [`MapView`] / [`RepeatedView`] fields are written by borrow — no
619/// owned-struct intermediary, no per-field `String`/`Vec<u8>` allocations.
620///
621/// Generated `*View<'a>` types implement this trait whenever views are
622/// generated (`generate_views(true)`, the default). Serialization state
623/// lives in the external [`SizeCache`](crate::SizeCache), not the view —
624/// view structs hold no interior mutability and remain `Send + Sync`.
625///
626/// ## When to use
627///
628/// Reach for `ViewEncode` when the source data is already in memory and
629/// you would otherwise allocate an owned message just to encode-then-drop
630/// it — e.g. an RPC handler serializing from app state. If you already
631/// hold the owned message, use [`Message::encode`](crate::Message::encode)
632/// instead; the wire output is identical.
633///
634/// ```rust,ignore
635/// let view = PersonView {
636/// name: "borrowed",
637/// tags: ["a", "b"].iter().copied().collect(),
638/// ..Default::default()
639/// };
640/// let bytes = view.encode_to_vec();
641/// ```
642#[rustversion::attr(
643 since(1.78),
644 diagnostic::on_unimplemented(
645 message = "`{Self}` does not implement `ViewEncode` — view types were not generated for this message",
646 note = "ViewEncode is implemented on every generated `*View<'a>` type; enable `generate_views(true)` (on by default) in your buffa-build / buffa-codegen config"
647 )
648)]
649pub trait ViewEncode<'a>: MessageView<'a> {
650 /// Compute the encoded byte size of this view, recording nested
651 /// sub-message sizes in `cache` for [`write_to`](Self::write_to)
652 /// to consume.
653 ///
654 /// Most callers should use [`encode`](Self::encode) instead, which runs
655 /// both passes with a fresh cache.
656 fn compute_size(&self, cache: &mut crate::SizeCache) -> u32;
657
658 /// Write this view's encoded bytes to a buffer, consuming
659 /// nested-message sizes from `cache` (populated by a prior
660 /// [`compute_size`](Self::compute_size) call on the same cache).
661 ///
662 /// Most callers should use [`encode`](Self::encode) instead. This is a
663 /// low-level primitive: the 2 GiB size check
664 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)) lives in the
665 /// provided encode entry points, so callers driving `compute_size` /
666 /// `write_to` directly must validate the size themselves (via
667 /// [`checked_encode_size`](crate::checked_encode_size)).
668 fn write_to(&self, cache: &mut crate::SizeCache, buf: &mut impl EncodeSink);
669
670 /// Compute size, then write. Primary view-encode entry point.
671 ///
672 /// The sink can be any [`BufMut`](bytes::BufMut) (contiguous output) or
673 /// a [`Rope`](crate::Rope); a rope constructed with
674 /// [`with_backing`](crate::Rope::with_backing) on the view's source
675 /// buffer re-encodes large borrowed fields zero-copy.
676 ///
677 /// # Panics
678 ///
679 /// Panics if the encoded size exceeds the 2 GiB protobuf limit
680 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)) — see
681 /// [`try_encode`](Self::try_encode) for the error-returning variant.
682 #[inline]
683 fn encode(&self, buf: &mut impl EncodeSink) {
684 self.try_encode(buf)
685 .unwrap_or_else(|_| crate::message::encode_size_overflow())
686 }
687
688 /// Encode, returning an error instead of panicking if the encoded size
689 /// exceeds the 2 GiB protobuf limit
690 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)).
691 ///
692 /// On `Err`, nothing is written to `buf`.
693 ///
694 /// # Errors
695 ///
696 /// Returns [`EncodeError::MessageTooLarge`](crate::EncodeError::MessageTooLarge)
697 /// if the encoded size exceeds the limit.
698 fn try_encode(&self, buf: &mut impl EncodeSink) -> Result<(), crate::EncodeError> {
699 let mut cache = crate::SizeCache::new();
700 crate::message::checked_encode_size(self.compute_size(&mut cache))?;
701 self.write_to(&mut cache, buf);
702 Ok(())
703 }
704
705 /// Encode using a caller-supplied [`SizeCache`](crate::SizeCache), for
706 /// reuse across many encodes in a hot loop. Clears the cache first.
707 ///
708 /// # Panics
709 ///
710 /// Panics if the encoded size exceeds the 2 GiB protobuf limit
711 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)) — see
712 /// [`try_encode_with_cache`](Self::try_encode_with_cache) for the
713 /// error-returning variant.
714 #[inline]
715 fn encode_with_cache(&self, cache: &mut crate::SizeCache, buf: &mut impl EncodeSink) {
716 self.try_encode_with_cache(cache, buf)
717 .unwrap_or_else(|_| crate::message::encode_size_overflow())
718 }
719
720 /// Encode with a caller-supplied [`SizeCache`](crate::SizeCache),
721 /// returning an error instead of panicking if the encoded size exceeds
722 /// the 2 GiB protobuf limit ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)).
723 /// Clears the cache first.
724 ///
725 /// On `Err`, nothing is written to `buf`.
726 ///
727 /// # Errors
728 ///
729 /// Returns [`EncodeError::MessageTooLarge`](crate::EncodeError::MessageTooLarge)
730 /// if the encoded size exceeds the limit.
731 fn try_encode_with_cache(
732 &self,
733 cache: &mut crate::SizeCache,
734 buf: &mut impl EncodeSink,
735 ) -> Result<(), crate::EncodeError> {
736 cache.clear();
737 crate::message::checked_encode_size(self.compute_size(cache))?;
738 self.write_to(cache, buf);
739 Ok(())
740 }
741
742 /// Encode this view into `buf` only if its encoded size fits within
743 /// `max_bytes`, using a single size pass that is then reused for the write.
744 ///
745 /// This avoids the double tree-walk that `try_encoded_len` + `encode`
746 /// would require: one `compute_size` pass populates the
747 /// [`SizeCache`](crate::SizeCache); the budget check happens before
748 /// `write_to` runs, so on `Err` nothing is written to `buf`.
749 ///
750 /// Returns the encoded body length on success (excludes any length prefix
751 /// you add for framing) — useful for metrics or frame sizing. Note that
752 /// this return type is `u32`, unlike `try_encode`'s `()`. `max_bytes` is
753 /// also `u32`; callers with a `usize` budget can cast with
754 /// `u32::try_from(budget).unwrap_or(u32::MAX)`.
755 ///
756 /// # Errors
757 ///
758 /// - [`EncodeError::MessageTooLarge`](crate::EncodeError::MessageTooLarge)
759 /// if the encoded size exceeds the 2 GiB protobuf limit
760 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)).
761 /// `MessageTooLarge` takes precedence if both limits are exceeded.
762 /// - [`EncodeError::ExceedsBudget`](crate::EncodeError::ExceedsBudget)
763 /// if the encoded size is within the protobuf limit but exceeds
764 /// `max_bytes`.
765 fn try_encode_bounded(
766 &self,
767 max_bytes: u32,
768 buf: &mut impl EncodeSink,
769 ) -> Result<u32, crate::EncodeError> {
770 let mut cache = crate::SizeCache::new();
771 self.try_encode_bounded_with_cache(max_bytes, &mut cache, buf)
772 }
773
774 /// Like [`try_encode_bounded`](Self::try_encode_bounded) but reuses an
775 /// existing [`SizeCache`](crate::SizeCache), clearing it first.
776 ///
777 /// Prefer
778 /// [`SizeCachePool::try_encode_view_bounded`](crate::SizeCachePool::try_encode_view_bounded)
779 /// for hot-loop use — the pool amortizes the cache's spill allocation.
780 ///
781 /// # Errors
782 ///
783 /// Same as [`try_encode_bounded`](Self::try_encode_bounded).
784 fn try_encode_bounded_with_cache(
785 &self,
786 max_bytes: u32,
787 cache: &mut crate::SizeCache,
788 buf: &mut impl EncodeSink,
789 ) -> Result<u32, crate::EncodeError> {
790 cache.clear();
791 let len = crate::message::checked_encode_size(self.compute_size(cache))?;
792 if len > max_bytes {
793 return Err(crate::EncodeError::ExceedsBudget { len, max_bytes });
794 }
795 self.write_to(cache, buf);
796 Ok(len)
797 }
798
799 /// Compute the encoded byte size of this view.
800 ///
801 /// Walks the view tree, discarding the intermediate
802 /// [`SizeCache`](crate::SizeCache). If you also intend to encode,
803 /// prefer [`encode`](Self::encode) or [`encode_to_vec`](Self::encode_to_vec)
804 /// — they do a single size pass and reuse the cache for the write.
805 ///
806 /// # Panics
807 ///
808 /// Panics if the encoded size exceeds the 2 GiB protobuf limit
809 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)) — see
810 /// [`try_encoded_len`](Self::try_encoded_len) for the error-returning
811 /// variant.
812 #[inline]
813 #[must_use]
814 fn encoded_len(&self) -> u32 {
815 self.try_encoded_len()
816 .unwrap_or_else(|_| crate::message::encode_size_overflow())
817 }
818
819 /// Compute the encoded byte size, returning an error instead of
820 /// panicking if it exceeds the 2 GiB protobuf limit
821 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)).
822 ///
823 /// # Errors
824 ///
825 /// Returns [`EncodeError::MessageTooLarge`](crate::EncodeError::MessageTooLarge)
826 /// if the encoded size exceeds the limit.
827 fn try_encoded_len(&self) -> Result<u32, crate::EncodeError> {
828 crate::message::checked_encode_size(self.compute_size(&mut crate::SizeCache::new()))
829 }
830
831 /// Encode this view as a length-delimited byte sequence.
832 ///
833 /// # Panics
834 ///
835 /// Panics if the encoded size exceeds the 2 GiB protobuf limit
836 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)); the check runs
837 /// before the length prefix is written, so nothing reaches `buf` on
838 /// failure. See
839 /// [`try_encode_length_delimited`](Self::try_encode_length_delimited)
840 /// for the error-returning variant.
841 #[inline]
842 fn encode_length_delimited(&self, buf: &mut impl EncodeSink) {
843 self.try_encode_length_delimited(buf)
844 .unwrap_or_else(|_| crate::message::encode_size_overflow())
845 }
846
847 /// Encode as a length-delimited byte sequence, returning an error
848 /// instead of panicking if the encoded size exceeds the 2 GiB protobuf
849 /// limit ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)).
850 ///
851 /// On `Err`, nothing is written to `buf`.
852 ///
853 /// # Errors
854 ///
855 /// Returns [`EncodeError::MessageTooLarge`](crate::EncodeError::MessageTooLarge)
856 /// if the encoded size exceeds the limit.
857 fn try_encode_length_delimited(
858 &self,
859 buf: &mut impl EncodeSink,
860 ) -> Result<(), crate::EncodeError> {
861 let mut cache = crate::SizeCache::new();
862 let len = crate::message::checked_encode_size(self.compute_size(&mut cache))?;
863 crate::encoding::encode_varint(len as u64, buf);
864 self.write_to(&mut cache, buf);
865 Ok(())
866 }
867
868 /// Encode this view to a new `Vec<u8>`.
869 ///
870 /// # Panics
871 ///
872 /// Panics if the encoded size exceeds the 2 GiB protobuf limit
873 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)) — see
874 /// [`try_encode_to_vec`](Self::try_encode_to_vec) for the
875 /// error-returning variant. In debug builds, also panics if a manual
876 /// implementation's `write_to` produces a different byte count than
877 /// its `compute_size` declared.
878 // Direct body rather than delegating to try_encode_to_vec — the
879 // Result<Vec<u8>> niche survives inlining and costs measurably in
880 // callers; see Message::encode_to_vec for the measurement.
881 #[inline]
882 #[must_use]
883 fn encode_to_vec(&self) -> alloc::vec::Vec<u8> {
884 let mut cache = crate::SizeCache::new();
885 let size = match crate::message::checked_encode_size(self.compute_size(&mut cache)) {
886 Ok(size) => size as usize,
887 Err(_) => crate::message::encode_size_overflow(),
888 };
889 let mut buf = alloc::vec::Vec::with_capacity(size);
890 self.write_to(&mut cache, &mut buf);
891 crate::message::debug_assert_two_pass(buf.len(), size);
892 buf
893 }
894
895 /// Encode to a new `Vec<u8>`, returning an error instead of panicking
896 /// if the encoded size exceeds the 2 GiB protobuf limit
897 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)).
898 ///
899 /// # Errors
900 ///
901 /// Returns [`EncodeError::MessageTooLarge`](crate::EncodeError::MessageTooLarge)
902 /// if the encoded size exceeds the limit.
903 ///
904 /// # Panics
905 ///
906 /// In debug builds, panics if a manual implementation's `write_to`
907 /// produces a different byte count than its `compute_size` declared.
908 fn try_encode_to_vec(&self) -> Result<alloc::vec::Vec<u8>, crate::EncodeError> {
909 let mut cache = crate::SizeCache::new();
910 let size = crate::message::checked_encode_size(self.compute_size(&mut cache))? as usize;
911 let mut buf = alloc::vec::Vec::with_capacity(size);
912 self.write_to(&mut cache, &mut buf);
913 crate::message::debug_assert_two_pass(buf.len(), size);
914 Ok(buf)
915 }
916
917 /// Encode this view to a new [`bytes::Bytes`].
918 ///
919 /// # Panics
920 ///
921 /// Panics if the encoded size exceeds the 2 GiB protobuf limit
922 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)) — see
923 /// [`try_encode_to_bytes`](Self::try_encode_to_bytes) for the
924 /// error-returning variant. In debug builds, also panics if a manual
925 /// implementation's `write_to` produces a different byte count than
926 /// its `compute_size` declared.
927 // Direct body — see Message::encode_to_vec for why the fat-payload
928 // entry points do not delegate to their try_ twins.
929 #[inline]
930 #[must_use]
931 fn encode_to_bytes(&self) -> Bytes {
932 let mut cache = crate::SizeCache::new();
933 let size = match crate::message::checked_encode_size(self.compute_size(&mut cache)) {
934 Ok(size) => size as usize,
935 Err(_) => crate::message::encode_size_overflow(),
936 };
937 let mut buf = bytes::BytesMut::with_capacity(size);
938 self.write_to(&mut cache, &mut buf);
939 crate::message::debug_assert_two_pass(buf.len(), size);
940 buf.freeze()
941 }
942
943 /// Encode to a new [`bytes::Bytes`], returning an error instead of
944 /// panicking if the encoded size exceeds the 2 GiB protobuf limit
945 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)).
946 ///
947 /// # Errors
948 ///
949 /// Returns [`EncodeError::MessageTooLarge`](crate::EncodeError::MessageTooLarge)
950 /// if the encoded size exceeds the limit.
951 ///
952 /// # Panics
953 ///
954 /// In debug builds, panics if a manual implementation's `write_to`
955 /// produces a different byte count than its `compute_size` declared.
956 fn try_encode_to_bytes(&self) -> Result<Bytes, crate::EncodeError> {
957 let mut cache = crate::SizeCache::new();
958 let size = crate::message::checked_encode_size(self.compute_size(&mut cache))? as usize;
959 let mut buf = bytes::BytesMut::with_capacity(size);
960 self.write_to(&mut cache, &mut buf);
961 crate::message::debug_assert_two_pass(buf.len(), size);
962 Ok(buf.freeze())
963 }
964}
965
966/// Provides access to a lazily-initialized default view instance.
967///
968/// View types implement this trait so that [`MessageFieldView`] can
969/// dereference to a default when unset, just as [`MessageField`](crate::MessageField)
970/// does for owned types via [`DefaultInstance`](crate::DefaultInstance).
971///
972/// Generated view types like `FooView<'a>` contain only covariant borrows
973/// (`&'a str`, `&'a [u8]`, etc.). A default view holds only `'static` data
974/// (`""`, `&[]`, `0`), so an implementation stores a single
975/// `&'static FooView<'static>` and returns it at the caller's lifetime via
976/// ordinary covariant subtyping — the compiler verifies covariance at the
977/// `impl` site, so no `unsafe` is required.
978///
979/// # Recommended implementation
980///
981/// The pattern codegen uses (and the recommended pattern for hand-written
982/// view types) stores the instance in a static
983/// [`once_cell::race::OnceBox`] (re-exported as
984/// `::buffa::__private::OnceBox`):
985///
986/// ```rust,ignore
987/// impl<'v> DefaultViewInstance for MyView<'v> {
988/// fn default_view_instance<'a>() -> &'a Self
989/// where
990/// Self: 'a,
991/// {
992/// static VALUE: ::buffa::__private::OnceBox<MyView<'static>>
993/// = ::buffa::__private::OnceBox::new();
994/// VALUE.get_or_init(|| Box::new(<MyView<'static>>::default()))
995/// }
996/// }
997/// ```
998///
999/// The return expression has type `&'static MyView<'static>`; the compiler
1000/// coerces it to `&'a MyView<'v>` iff `MyView` is covariant in `'v` —
1001/// non-covariant view types fail to compile here rather than risk an
1002/// unsound cast.
1003///
1004/// # Non-covariant types are rejected
1005///
1006/// A type that is invariant in its lifetime parameter cannot satisfy the
1007/// recommended pattern, because the `&'static T<'static> → &'a T<'v>`
1008/// coercion is refused:
1009///
1010/// ```compile_fail
1011/// # use core::marker::PhantomData;
1012/// // `fn(&'v ()) -> &'v ()` is invariant in 'v, making `Invariant<'v>` invariant.
1013/// struct Invariant<'v>(PhantomData<fn(&'v ()) -> &'v ()>);
1014/// static INST: Invariant<'static> = Invariant(PhantomData);
1015///
1016/// impl<'v> buffa::view::DefaultViewInstance for Invariant<'v> {
1017/// fn default_view_instance<'a>() -> &'a Self where Self: 'a {
1018/// // error: lifetime may not live long enough
1019/// // note: requirement occurs because of the type `Invariant<'_>`,
1020/// // which makes the generic argument `'_` invariant
1021/// &INST
1022/// }
1023/// }
1024/// ```
1025pub trait DefaultViewInstance {
1026 /// Return a reference to the single default view instance.
1027 ///
1028 /// The lifetime `'a` is caller-chosen up to `Self: 'a`, so a
1029 /// `FooView<'v>` can serve its `'static` default at any `'a ≤ 'v`.
1030 fn default_view_instance<'a>() -> &'a Self
1031 where
1032 Self: 'a;
1033}
1034
1035/// Implement [`DefaultViewInstance`] for a generated view type via a
1036/// lazily-initialized `OnceBox<FooView<'static>>` singleton.
1037///
1038/// Emitted by generated code (one invocation per view struct). The static
1039/// holds the `'static` instantiation; returning it at any shorter `'a` is
1040/// sound because view lifetimes are covariant.
1041///
1042/// ```rust,ignore
1043/// buffa::impl_default_view_instance!(MyMessageView);
1044/// ```
1045#[macro_export]
1046macro_rules! impl_default_view_instance {
1047 ($ty:ident) => {
1048 impl<'v> $crate::DefaultViewInstance for $ty<'v> {
1049 fn default_view_instance<'a>() -> &'a Self
1050 where
1051 Self: 'a,
1052 {
1053 static VALUE: $crate::__private::OnceBox<$ty<'static>> =
1054 $crate::__private::OnceBox::new();
1055 VALUE.get_or_init(|| {
1056 $crate::alloc::boxed::Box::new(
1057 <$ty<'static> as ::core::default::Default>::default(),
1058 )
1059 })
1060 }
1061 }
1062 };
1063}
1064
1065/// A borrowed view of an optional message field.
1066///
1067/// Analogous to [`MessageField<T>`](crate::MessageField) but for the view
1068/// layer. Like `MessageField`, the inner view is **boxed** — recursive
1069/// message types (`Foo { NestedMessage { corecursive: Foo } }`) would
1070/// otherwise have infinite size. The box is API-transparent: `Deref`
1071/// returns `&V`, and `set()` takes `V` by value.
1072///
1073/// When `V` implements [`DefaultViewInstance`], this type implements
1074/// [`Deref<Target = V>`](core::ops::Deref), returning a reference to a
1075/// static default instance when the field is unset — making view code
1076/// identical to owned code for field access:
1077///
1078/// ```rust,ignore
1079/// // Both work the same, regardless of whether `address` is set:
1080/// let city = owned_msg.address.city; // MessageField<Address>
1081/// let city = view_msg.address.city; // MessageFieldView<AddressView>
1082/// ```
1083///
1084/// The lifetime of the contained view type `V` (e.g. `AddressView<'a>`)
1085/// ties this to the input buffer — no separate lifetime parameter is
1086/// needed here.
1087#[derive(Clone, Debug)]
1088pub struct MessageFieldView<V> {
1089 inner: Option<alloc::boxed::Box<V>>,
1090}
1091
1092impl<V> MessageFieldView<V> {
1093 /// An unset field (the default).
1094 #[inline]
1095 pub const fn unset() -> Self {
1096 Self { inner: None }
1097 }
1098
1099 /// A set field with the given view value.
1100 #[inline]
1101 pub fn set(v: V) -> Self {
1102 Self {
1103 inner: Some(alloc::boxed::Box::new(v)),
1104 }
1105 }
1106
1107 /// Alias for [`set`](Self::set), mirroring owned
1108 /// [`MessageField::some`](crate::MessageField::some).
1109 #[inline]
1110 pub fn some(v: V) -> Self {
1111 Self::set(v)
1112 }
1113
1114 /// Returns `true` if the field has a value.
1115 #[inline]
1116 pub const fn is_set(&self) -> bool {
1117 self.inner.is_some()
1118 }
1119
1120 /// Returns `true` if the field has no value.
1121 #[inline]
1122 pub const fn is_unset(&self) -> bool {
1123 self.inner.is_none()
1124 }
1125
1126 /// Get a reference to the inner view, or `None` if unset.
1127 #[inline]
1128 pub fn as_option(&self) -> Option<&V> {
1129 self.inner.as_deref()
1130 }
1131
1132 /// Get a mutable reference to the inner view, or `None` if unset.
1133 ///
1134 /// Used by generated decode code to merge a second occurrence of a
1135 /// message field into an existing value (proto merge semantics).
1136 #[inline]
1137 pub fn as_mut(&mut self) -> Option<&mut V> {
1138 self.inner.as_deref_mut()
1139 }
1140}
1141
1142impl<'a, V: ViewEncode<'a>> MessageFieldView<V> {
1143 /// Forward to the inner view's [`compute_size`](ViewEncode::compute_size),
1144 /// or `0` if unset. Generated `compute_size` calls this for nested-message
1145 /// fields, mirroring [`MessageField`](crate::MessageField) on the owned side.
1146 #[inline]
1147 pub fn compute_size(&self, cache: &mut crate::SizeCache) -> u32 {
1148 self.inner.as_deref().map_or(0, |v| v.compute_size(cache))
1149 }
1150
1151 /// Forward to the inner view's [`write_to`](ViewEncode::write_to);
1152 /// no-op if unset.
1153 #[inline]
1154 pub fn write_to(&self, cache: &mut crate::SizeCache, buf: &mut impl EncodeSink) {
1155 if let Some(v) = self.inner.as_deref() {
1156 v.write_to(cache, buf);
1157 }
1158 }
1159}
1160
1161impl<V> Default for MessageFieldView<V> {
1162 #[inline]
1163 fn default() -> Self {
1164 Self::unset()
1165 }
1166}
1167
1168impl<V> From<V> for MessageFieldView<V> {
1169 #[inline]
1170 fn from(v: V) -> Self {
1171 Self::set(v)
1172 }
1173}
1174
1175impl<V: DefaultViewInstance> core::ops::Deref for MessageFieldView<V> {
1176 type Target = V;
1177
1178 #[inline]
1179 fn deref(&self) -> &V {
1180 self.inner
1181 .as_deref()
1182 .unwrap_or_else(V::default_view_instance)
1183 }
1184}
1185
1186/// Wire-equivalent equality: `Unset` equals `Set(v)` when `v` equals the
1187/// default instance.
1188///
1189/// This matches [`MessageField::eq`](crate::MessageField) on the owned side,
1190/// so `view_a == view_b` agrees with
1191/// `view_a.to_owned_message() == view_b.to_owned_message()`.
1192///
1193/// The comparison against the default routes through the
1194/// [`Deref`](core::ops::Deref) impl.
1195impl<V: PartialEq + DefaultViewInstance> PartialEq for MessageFieldView<V> {
1196 fn eq(&self, other: &Self) -> bool {
1197 match (&self.inner, &other.inner) {
1198 // Short-circuit: two unset fields are equal regardless of whether
1199 // V::PartialEq is reflexive (e.g. a view containing an f64 NaN).
1200 (None, None) => true,
1201 // At least one side is set. Deref handles None → default.
1202 _ => {
1203 <Self as core::ops::Deref>::deref(self) == <Self as core::ops::Deref>::deref(other)
1204 }
1205 }
1206 }
1207}
1208
1209impl<V: Eq + DefaultViewInstance> Eq for MessageFieldView<V> {}
1210
1211// ---------------------------------------------------------------------------
1212// Lazy views (generated under the `lazy_views` codegen option)
1213// ---------------------------------------------------------------------------
1214
1215/// The trait implemented by generated lazy view types (`FooLazyView<'a>`).
1216///
1217/// Lazy views are a separate, additive type family generated alongside the
1218/// eager `FooView` family under the `lazy_views` codegen option. Where
1219/// [`MessageView`]'s contract is "decode succeeded ⇒ the whole tree was
1220/// validated", a lazy view's [`decode_lazy`](Self::decode_lazy) performs a
1221/// single non-recursive scan over the message's own fields: scalar, string,
1222/// and bytes fields are borrowed exactly as in the eager view, while nested
1223/// and repeated message fields are *recorded* as undecoded byte ranges (see
1224/// [`LazyMessageFieldView`] / [`LazyRepeatedView`]) and decoded only on
1225/// access. Deferred validation is therefore visible in the type and trait
1226/// bound — generic code over `MessageView` never silently inherits it.
1227///
1228/// Generated lazy-view structs may gain fields across releases; see the
1229/// [struct evolution policy on `Message`](crate::Message#struct-evolution-policy).
1230pub trait LazyMessageView<'a>: Sized {
1231 /// The corresponding owned message type.
1232 type Owned: crate::Message;
1233
1234 /// Decode a lazy view from `buf`: one scan over the message's own
1235 /// fields, deferring nested message fields.
1236 ///
1237 /// # Errors
1238 ///
1239 /// Returns [`DecodeError`] if the message's *own* fields are malformed,
1240 /// or [`DecodeError::ElementMemoryLimitExceeded`] if recording its
1241 /// repeated elements exceeds the default element-memory budget — the
1242 /// `Vec` of deferred byte ranges is real memory even though the elements
1243 /// themselves are not decoded yet. Deferred sub-message bytes are
1244 /// **not** validated here; they surface errors on access.
1245 fn decode_lazy(buf: &'a [u8]) -> Result<Self, DecodeError>;
1246
1247 /// Decode a lazy view under custom decode limits.
1248 ///
1249 /// Used by [`DecodeOptions::decode_lazy_view`](crate::DecodeOptions::decode_lazy_view).
1250 /// The budgets remaining at each deferred field's position are recorded
1251 /// and charged when that field is accessed, so custom limits flow through
1252 /// deferred decoding. The default implementation delegates to
1253 /// [`decode_lazy`](Self::decode_lazy) and **ignores the context**;
1254 /// generated code always overrides it.
1255 ///
1256 /// # Errors
1257 ///
1258 /// Same contract as [`decode_lazy`](Self::decode_lazy), plus
1259 /// [`DecodeError::RecursionLimitExceeded`],
1260 /// [`DecodeError::UnknownFieldLimitExceeded`], or
1261 /// [`DecodeError::ElementMemoryLimitExceeded`] when `ctx`'s budgets are
1262 /// exhausted by the message's own fields.
1263 fn decode_lazy_with_ctx(
1264 buf: &'a [u8],
1265 ctx: crate::DecodeContext<'_>,
1266 ) -> Result<Self, DecodeError> {
1267 let _ = ctx;
1268 Self::decode_lazy(buf)
1269 }
1270
1271 /// Merge fields decoded from `buf` into this view (proto merge
1272 /// semantics: singular scalars last-wins, repeated append, deferred
1273 /// message fragments accumulate).
1274 ///
1275 /// Used by [`LazyMessageFieldView::get`] to reassemble a field whose
1276 /// value was split across multiple wire occurrences — application code
1277 /// rarely calls this directly.
1278 ///
1279 /// # Errors
1280 ///
1281 /// Same contract as [`decode_lazy_with_ctx`](Self::decode_lazy_with_ctx).
1282 fn merge_lazy(
1283 &mut self,
1284 buf: &'a [u8],
1285 ctx: crate::DecodeContext<'_>,
1286 ) -> Result<(), DecodeError>;
1287
1288 /// Convert this view to the owned message type.
1289 ///
1290 /// This decodes every deferred sub-message, so it is where deferred
1291 /// validation errors surface. Each deferred subtree decodes under its
1292 /// own replayed unknown-field allowance (see
1293 /// [`LazyMessageFieldView::get`]), so the conversion's total
1294 /// unknown-field records are bounded per subtree, not globally as in an
1295 /// eager decode.
1296 ///
1297 /// # Errors
1298 ///
1299 /// Returns the [`DecodeError`] that accessing a malformed or
1300 /// over-budget deferred field would have reported. Unlike
1301 /// [`MessageView::to_owned_message`], this conversion can genuinely
1302 /// fail for a wire-decoded lazy view: deferred subtrees were never
1303 /// validated (or charged against the unknown-field allowance) at
1304 /// decode time, so their errors surface here.
1305 fn to_owned_message(&self) -> Result<Self::Owned, DecodeError>;
1306}
1307
1308/// Fragments of one singular message field. `Many` only arises when an
1309/// encoder split the field across occurrences, keeping the common
1310/// single-occurrence path allocation-free.
1311#[derive(Clone)]
1312enum LazyFragments<'a> {
1313 None,
1314 One(&'a [u8]),
1315 Many(alloc::vec::Vec<&'a [u8]>),
1316}
1317
1318/// A deferred view of a singular message field on a lazy view.
1319///
1320/// Unlike [`MessageFieldView`] — which eagerly decodes (and boxes) the
1321/// sub-message during decode — this stores only the field's undecoded wire
1322/// bytes and decodes a fresh `V` on each [`get`](Self::get), so decoding the
1323/// enclosing message does not allocate or recurse into sub-messages the
1324/// caller never reads.
1325///
1326/// `get` returns a freshly-decoded view each call (views are thin borrows,
1327/// so this is cheap) and does not cache — bind the result when reading
1328/// several fields.
1329///
1330/// # Merge semantics
1331///
1332/// A singular message field may legally appear more than once on the wire;
1333/// decoders must merge the occurrences. This type stores each occurrence's
1334/// bytes as a separate fragment and [`get`](Self::get) replays them in order
1335/// (decode the first, [`LazyMessageView::merge_lazy`] the rest), so the
1336/// result matches the eager and owned decoders.
1337///
1338/// # Deferred validation and budgets
1339///
1340/// The fragment bytes are *not* validated when the enclosing view is
1341/// decoded; a malformed sub-message surfaces as a [`DecodeError`] from
1342/// [`get`](Self::get). The recursion budget, unknown-field allowance, and
1343/// element-memory budget remaining when the field was recorded are stored
1344/// alongside the fragments,
1345/// and each access replays them as a fresh per-subtree budget (see
1346/// [`get`](Self::get) for the approximation this implies). Deep lazy chains
1347/// fail with [`DecodeError::RecursionLimitExceeded`] at the same boundary as
1348/// the eager decoder, and custom limits passed to the enclosing
1349/// [`decode_lazy_with_ctx`](LazyMessageView::decode_lazy_with_ctx) flow
1350/// through.
1351///
1352/// # Re-encoding
1353///
1354/// `ViewEncode` on the enclosing lazy view replays the recorded fragments
1355/// byte-for-byte **without validating them** — re-encoding a never-accessed
1356/// malformed field round-trips its bytes silently.
1357pub struct LazyMessageFieldView<'a, V> {
1358 raw: LazyFragments<'a>,
1359 depth: u32,
1360 allowance: usize,
1361 elem_allowance: usize,
1362 _marker: core::marker::PhantomData<fn() -> V>,
1363}
1364
1365impl<'a, V> LazyMessageFieldView<'a, V> {
1366 /// An unset field (the default).
1367 #[inline]
1368 pub const fn unset() -> Self {
1369 Self {
1370 raw: LazyFragments::None,
1371 // Sentinels: the first `push_fragment` lowers these to its
1372 // recorded budgets, so custom limits above the defaults aren't
1373 // clamped.
1374 depth: u32::MAX,
1375 allowance: usize::MAX,
1376 elem_allowance: usize::MAX,
1377 _marker: core::marker::PhantomData,
1378 }
1379 }
1380
1381 /// A set field carrying the sub-message's undecoded wire bytes, with the
1382 /// default recursion, unknown-field, and element-memory budgets for
1383 /// access.
1384 #[inline]
1385 pub const fn from_bytes(raw: &'a [u8]) -> Self {
1386 Self {
1387 raw: LazyFragments::One(raw),
1388 depth: crate::RECURSION_LIMIT,
1389 allowance: crate::DEFAULT_UNKNOWN_FIELD_LIMIT,
1390 elem_allowance: crate::DEFAULT_ELEMENT_MEMORY_LIMIT,
1391 _marker: core::marker::PhantomData,
1392 }
1393 }
1394
1395 /// Append one wire occurrence of the field (used by generated
1396 /// `decode_lazy`). Fragments accumulate in wire order; [`get`](Self::get)
1397 /// merges them. `ctx` carries the recursion budget and unknown-field
1398 /// allowance remaining at the record site; the smallest pushed budgets
1399 /// are charged on access.
1400 #[doc(hidden)]
1401 #[inline]
1402 pub fn push_fragment(&mut self, raw: &'a [u8], ctx: crate::DecodeContext<'_>) {
1403 self.depth = self.depth.min(ctx.depth());
1404 self.allowance = self.allowance.min(ctx.remaining_unknown_fields());
1405 if let Some(remaining) = ctx.remaining_element_memory() {
1406 self.elem_allowance = self.elem_allowance.min(remaining);
1407 }
1408 self.raw = match core::mem::replace(&mut self.raw, LazyFragments::None) {
1409 LazyFragments::None => LazyFragments::One(raw),
1410 LazyFragments::One(first) => LazyFragments::Many(alloc::vec![first, raw]),
1411 LazyFragments::Many(mut frags) => {
1412 frags.push(raw);
1413 LazyFragments::Many(frags)
1414 }
1415 };
1416 }
1417
1418 /// Whether the field is present.
1419 #[inline]
1420 pub const fn is_set(&self) -> bool {
1421 !matches!(self.raw, LazyFragments::None)
1422 }
1423
1424 /// Whether the field has no value.
1425 #[inline]
1426 pub const fn is_unset(&self) -> bool {
1427 matches!(self.raw, LazyFragments::None)
1428 }
1429
1430 /// The undecoded wire fragments, in wire order (empty if unset).
1431 ///
1432 /// A singular message field that appeared exactly once on the wire — the
1433 /// common case — yields one fragment. Encoders that split the field
1434 /// across multiple occurrences yield one fragment per occurrence;
1435 /// [`get`](Self::get) merges them per proto semantics.
1436 #[inline]
1437 pub fn fragments(&self) -> &[&'a [u8]] {
1438 match &self.raw {
1439 LazyFragments::None => &[],
1440 LazyFragments::One(raw) => core::slice::from_ref(raw),
1441 LazyFragments::Many(frags) => frags,
1442 }
1443 }
1444}
1445
1446impl<'a, V: LazyMessageView<'a>> LazyMessageFieldView<'a, V> {
1447 /// Decode and return the sub-message view, or `None` if unset.
1448 ///
1449 /// Multiple wire fragments are merged per proto semantics (see the type
1450 /// docs). The view is re-decoded on every call; there is no cache — bind
1451 /// the result when reading several fields. Note the shape difference
1452 /// from [`LazyRepeatedView::get`], which returns `Option<Result<V, _>>`.
1453 ///
1454 /// Each access rebuilds a fresh decode context from the budgets recorded
1455 /// at decode time, so every deferred subtree independently gets the full
1456 /// recorded unknown-field allowance and element-memory budget rather than
1457 /// sharing one pool with its siblings (the original decode call's shared
1458 /// budgets are gone by access time). Both are therefore *per-subtree*
1459 /// bounds on the lazy path, not the global decode-time caps the eager
1460 /// decoder enforces: a full traversal can materialize records
1461 /// proportional to input size, where eager
1462 /// [`decode_view`](crate::DecodeOptions::decode_view) rejects such input
1463 /// up front. Prefer the eager path for untrusted input if that global
1464 /// bound matters.
1465 ///
1466 /// # Errors
1467 ///
1468 /// Returns [`DecodeError`] if the deferred bytes are not a valid
1469 /// encoding of `V` — validation happens here, not when the enclosing
1470 /// view was decoded — [`DecodeError::RecursionLimitExceeded`] when the
1471 /// recursion budget recorded at decode time is exhausted,
1472 /// [`DecodeError::UnknownFieldLimitExceeded`] when the unknown-field
1473 /// allowance is, or [`DecodeError::ElementMemoryLimitExceeded`] when the
1474 /// element-memory budget is.
1475 #[inline]
1476 pub fn get(&self) -> Result<Option<V>, DecodeError> {
1477 let allowance = core::cell::Cell::new(self.allowance);
1478 let elem = core::cell::Cell::new(self.elem_allowance);
1479 let ctx = crate::DecodeContext::new(self.depth, &allowance).with_element_memory(&elem);
1480 match &self.raw {
1481 LazyFragments::None => Ok(None),
1482 LazyFragments::One(raw) => V::decode_lazy_with_ctx(raw, ctx).map(Some),
1483 LazyFragments::Many(frags) => {
1484 // `Many` always holds ≥ 2 fragments (see `push_fragment`);
1485 // the guard is belt-and-suspenders.
1486 let mut iter = frags.iter();
1487 let Some(first) = iter.next() else {
1488 return Ok(None);
1489 };
1490 let mut view = V::decode_lazy_with_ctx(first, ctx)?;
1491 for frag in iter {
1492 view.merge_lazy(frag, ctx)?;
1493 }
1494 Ok(Some(view))
1495 }
1496 }
1497 }
1498
1499 /// Like [`get`](Self::get), but an unset field decodes to the default
1500 /// view — the lazy analogue of [`MessageFieldView`]'s deref-to-default,
1501 /// for the common read path:
1502 ///
1503 /// ```rust,ignore
1504 /// let city = view.address.get_or_default()?.city;
1505 /// ```
1506 ///
1507 /// # Errors
1508 ///
1509 /// Same as [`get`](Self::get).
1510 #[inline]
1511 pub fn get_or_default(&self) -> Result<V, DecodeError>
1512 where
1513 V: Default,
1514 {
1515 Ok(self.get()?.unwrap_or_default())
1516 }
1517}
1518
1519impl<V> Clone for LazyMessageFieldView<'_, V> {
1520 #[inline]
1521 fn clone(&self) -> Self {
1522 Self {
1523 raw: self.raw.clone(),
1524 depth: self.depth,
1525 allowance: self.allowance,
1526 elem_allowance: self.elem_allowance,
1527 _marker: core::marker::PhantomData,
1528 }
1529 }
1530}
1531impl<V> Default for LazyMessageFieldView<'_, V> {
1532 #[inline]
1533 fn default() -> Self {
1534 Self::unset()
1535 }
1536}
1537impl<V> core::fmt::Debug for LazyMessageFieldView<'_, V> {
1538 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1539 f.debug_struct("LazyMessageFieldView")
1540 .field("is_set", &self.is_set())
1541 .field("fragments", &self.fragments().len())
1542 .finish()
1543 }
1544}
1545
1546/// A deferred view of a repeated message field on a lazy view.
1547///
1548/// Holds the wire byte-slice of each element (cheap pointers) and decodes a
1549/// fresh element view on access ([`get`](Self::get)) or iteration
1550/// ([`iter`](Self::iter)), instead of eagerly decoding every element into a
1551/// `Vec` like [`RepeatedView`].
1552///
1553/// Element bytes are *not* validated when the enclosing view is decoded; a
1554/// malformed element surfaces as a [`DecodeError`] from `get`/`iter`. Unlike
1555/// [`RepeatedView`], this type is not slice-backed: there is no `Deref` or
1556/// indexing, use `get`/`iter`/`len`. Budgets and re-encoding behave as on
1557/// [`LazyMessageFieldView`].
1558pub struct LazyRepeatedView<'a, V> {
1559 elements: alloc::vec::Vec<&'a [u8]>,
1560 depth: u32,
1561 allowance: usize,
1562 elem_allowance: usize,
1563 _marker: core::marker::PhantomData<fn() -> V>,
1564}
1565
1566impl<'a, V> LazyRepeatedView<'a, V> {
1567 /// An empty repeated field.
1568 #[inline]
1569 pub fn new() -> Self {
1570 Self {
1571 elements: alloc::vec::Vec::new(),
1572 // Sentinels — see `LazyMessageFieldView::unset`.
1573 depth: u32::MAX,
1574 allowance: usize::MAX,
1575 elem_allowance: usize::MAX,
1576 _marker: core::marker::PhantomData,
1577 }
1578 }
1579
1580 /// Number of elements.
1581 #[inline]
1582 pub fn len(&self) -> usize {
1583 self.elements.len()
1584 }
1585
1586 /// Whether the field has no elements.
1587 #[inline]
1588 pub fn is_empty(&self) -> bool {
1589 self.elements.is_empty()
1590 }
1591
1592 /// The undecoded wire bytes of each element, in wire order.
1593 #[inline]
1594 pub fn raw_elements(&self) -> &[&'a [u8]] {
1595 &self.elements
1596 }
1597
1598 /// Append an element's undecoded bytes (used by generated `decode_lazy`).
1599 /// `ctx` carries the recursion budget, unknown-field allowance, and
1600 /// element-memory budget remaining at the record site; the smallest
1601 /// pushed budgets are charged on access.
1602 #[doc(hidden)]
1603 #[inline]
1604 pub fn push_bytes(&mut self, raw: &'a [u8], ctx: crate::DecodeContext<'_>) {
1605 self.depth = self.depth.min(ctx.depth());
1606 self.allowance = self.allowance.min(ctx.remaining_unknown_fields());
1607 if let Some(remaining) = ctx.remaining_element_memory() {
1608 self.elem_allowance = self.elem_allowance.min(remaining);
1609 }
1610 self.elements.push(raw);
1611 }
1612}
1613
1614/// Decode one deferred element under a fresh context carrying the budgets
1615/// recorded at decode time. Each access decodes independently, so each gets
1616/// the full recorded allowance — a per-subtree bound, not the eager
1617/// decoder's shared global pool (see [`LazyMessageFieldView::get`]).
1618#[inline]
1619fn decode_deferred<'a, V: LazyMessageView<'a>>(
1620 raw: &'a [u8],
1621 depth: u32,
1622 allowance: usize,
1623 elem_allowance: usize,
1624) -> Result<V, DecodeError> {
1625 let cell = core::cell::Cell::new(allowance);
1626 let elem = core::cell::Cell::new(elem_allowance);
1627 V::decode_lazy_with_ctx(
1628 raw,
1629 crate::DecodeContext::new(depth, &cell).with_element_memory(&elem),
1630 )
1631}
1632
1633impl<'a, V: LazyMessageView<'a>> LazyRepeatedView<'a, V> {
1634 /// Decode the element at `index`, or `None` if out of range.
1635 ///
1636 /// Re-decodes on every call (no cache) — bind the result when reading
1637 /// multiple fields, and avoid calling it inside a tight loop over the
1638 /// same index. Note the shape difference from
1639 /// [`LazyMessageFieldView::get`], which returns `Result<Option<V>, _>`.
1640 #[inline]
1641 pub fn get(&self, index: usize) -> Option<Result<V, DecodeError>> {
1642 self.elements
1643 .get(index)
1644 .map(|b| decode_deferred(b, self.depth, self.allowance, self.elem_allowance))
1645 }
1646
1647 /// Like [`get`](Self::get) with the layers flipped to match
1648 /// [`LazyMessageFieldView::get`]'s `Result<Option<_>, _>` shape:
1649 /// out-of-range yields `Ok(None)`.
1650 ///
1651 /// # Errors
1652 ///
1653 /// Same as [`get`](Self::get).
1654 #[inline]
1655 pub fn try_get(&self, index: usize) -> Result<Option<V>, DecodeError> {
1656 self.get(index).transpose()
1657 }
1658
1659 /// Iterate the elements, decoding each on the fly.
1660 ///
1661 /// Yields `Result<V, DecodeError>` — element bytes are validated here,
1662 /// not when the enclosing view was decoded. Each pass over the iterator
1663 /// re-decodes the elements (no cache).
1664 #[inline]
1665 pub fn iter(&self) -> LazyRepeatedIter<'_, 'a, V> {
1666 LazyRepeatedIter {
1667 inner: self.elements.iter(),
1668 depth: self.depth,
1669 allowance: self.allowance,
1670 elem_allowance: self.elem_allowance,
1671 _marker: core::marker::PhantomData,
1672 }
1673 }
1674}
1675
1676impl<'s, 'a, V: LazyMessageView<'a>> IntoIterator for &'s LazyRepeatedView<'a, V> {
1677 type Item = Result<V, DecodeError>;
1678 type IntoIter = LazyRepeatedIter<'s, 'a, V>;
1679
1680 #[inline]
1681 fn into_iter(self) -> Self::IntoIter {
1682 self.iter()
1683 }
1684}
1685
1686/// Iterator over a [`LazyRepeatedView`], decoding each element on `next`.
1687#[derive(Clone, Debug)]
1688pub struct LazyRepeatedIter<'s, 'a, V> {
1689 inner: core::slice::Iter<'s, &'a [u8]>,
1690 depth: u32,
1691 allowance: usize,
1692 elem_allowance: usize,
1693 _marker: core::marker::PhantomData<fn() -> V>,
1694}
1695
1696impl<'a, V: LazyMessageView<'a>> Iterator for LazyRepeatedIter<'_, 'a, V> {
1697 type Item = Result<V, DecodeError>;
1698
1699 #[inline]
1700 fn next(&mut self) -> Option<Self::Item> {
1701 self.inner
1702 .next()
1703 .map(|b| decode_deferred(b, self.depth, self.allowance, self.elem_allowance))
1704 }
1705
1706 #[inline]
1707 fn size_hint(&self) -> (usize, Option<usize>) {
1708 self.inner.size_hint()
1709 }
1710}
1711
1712impl<'a, V: LazyMessageView<'a>> DoubleEndedIterator for LazyRepeatedIter<'_, 'a, V> {
1713 #[inline]
1714 fn next_back(&mut self) -> Option<Self::Item> {
1715 self.inner
1716 .next_back()
1717 .map(|b| decode_deferred(b, self.depth, self.allowance, self.elem_allowance))
1718 }
1719}
1720
1721impl<'a, V: LazyMessageView<'a>> ExactSizeIterator for LazyRepeatedIter<'_, 'a, V> {}
1722
1723impl<V> Clone for LazyRepeatedView<'_, V> {
1724 #[inline]
1725 fn clone(&self) -> Self {
1726 Self {
1727 elements: self.elements.clone(),
1728 depth: self.depth,
1729 allowance: self.allowance,
1730 elem_allowance: self.elem_allowance,
1731 _marker: core::marker::PhantomData,
1732 }
1733 }
1734}
1735impl<V> Default for LazyRepeatedView<'_, V> {
1736 #[inline]
1737 fn default() -> Self {
1738 Self::new()
1739 }
1740}
1741impl<V> core::fmt::Debug for LazyRepeatedView<'_, V> {
1742 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1743 f.debug_struct("LazyRepeatedView")
1744 .field("len", &self.len())
1745 .finish()
1746 }
1747}
1748
1749/// A borrowed view of a repeated field.
1750///
1751/// For scalar repeated fields, this is backed by a decoded `Vec` (scalars
1752/// can't be zero-copy because they require varint decoding). For string and
1753/// bytes repeated fields, elements borrow from the input buffer.
1754#[derive(Clone, Debug, PartialEq, Eq)]
1755pub struct RepeatedView<'a, T> {
1756 elements: alloc::vec::Vec<T>,
1757 _marker: core::marker::PhantomData<&'a ()>,
1758}
1759
1760impl<'a, T> RepeatedView<'a, T> {
1761 /// Create from a vec of decoded elements.
1762 pub fn new(elements: alloc::vec::Vec<T>) -> Self {
1763 Self {
1764 elements,
1765 _marker: core::marker::PhantomData,
1766 }
1767 }
1768
1769 /// Returns the number of elements.
1770 pub fn len(&self) -> usize {
1771 self.elements.len()
1772 }
1773
1774 /// Returns `true` if the repeated field contains no elements.
1775 pub fn is_empty(&self) -> bool {
1776 self.elements.is_empty()
1777 }
1778
1779 /// Append an element (used by generated `decode_view` code).
1780 #[doc(hidden)]
1781 pub fn push(&mut self, elem: T) {
1782 self.elements.push(elem);
1783 }
1784
1785 /// Reserve capacity for at least `additional` more elements (used by
1786 /// generated `decode_view` code as a pre-allocation hint for packed
1787 /// repeated scalars). For varint elements the hint is an upper bound
1788 /// (every element occupies at least one byte on the wire); for fixed-
1789 /// size elements it is the exact remaining element count.
1790 #[doc(hidden)]
1791 pub fn reserve(&mut self, additional: usize) {
1792 self.elements.reserve(additional);
1793 }
1794
1795 /// Mutable access to the backing vec (used by generated `decode_view`
1796 /// code to decode packed fixed-width payloads in one bulk call).
1797 #[doc(hidden)]
1798 pub fn as_mut_vec(&mut self) -> &mut alloc::vec::Vec<T> {
1799 &mut self.elements
1800 }
1801
1802 /// Returns an iterator over the elements.
1803 pub fn iter(&self) -> core::slice::Iter<'_, T> {
1804 self.elements.iter()
1805 }
1806}
1807
1808impl<'a, T> Default for RepeatedView<'a, T> {
1809 fn default() -> Self {
1810 Self {
1811 elements: alloc::vec::Vec::new(),
1812 _marker: core::marker::PhantomData,
1813 }
1814 }
1815}
1816
1817impl<'a, T> core::ops::Deref for RepeatedView<'a, T> {
1818 type Target = [T];
1819
1820 fn deref(&self) -> &[T] {
1821 &self.elements
1822 }
1823}
1824
1825impl<'a, T> IntoIterator for RepeatedView<'a, T> {
1826 type Item = T;
1827 type IntoIter = alloc::vec::IntoIter<T>;
1828
1829 fn into_iter(self) -> Self::IntoIter {
1830 self.elements.into_iter()
1831 }
1832}
1833
1834impl<'b, 'a, T> IntoIterator for &'b RepeatedView<'a, T> {
1835 type Item = &'b T;
1836 type IntoIter = core::slice::Iter<'b, T>;
1837
1838 fn into_iter(self) -> Self::IntoIter {
1839 self.elements.iter()
1840 }
1841}
1842
1843impl<'a, T> From<alloc::vec::Vec<T>> for RepeatedView<'a, T> {
1844 fn from(elements: alloc::vec::Vec<T>) -> Self {
1845 Self::new(elements)
1846 }
1847}
1848
1849impl<'a, T> FromIterator<T> for RepeatedView<'a, T> {
1850 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1851 Self::new(iter.into_iter().collect())
1852 }
1853}
1854
1855/// A borrowed view of a map field.
1856///
1857/// Protobuf `map<K, V>` fields are encoded as repeated sub-messages, each
1858/// containing a key (field 1) and value (field 2). This type stores the
1859/// decoded entries in a `Vec<(K, V)>`, borrowing string and bytes keys/values
1860/// directly from the input buffer.
1861///
1862/// Lookup is O(n) linear scan, which is appropriate for the typically small
1863/// maps found in protobuf messages (metadata labels, headers, etc.).
1864/// If duplicate keys appear on the wire, [`get`](MapView::get) returns the
1865/// last occurrence (last-write-wins, per the protobuf spec). That rule is
1866/// about whole entries; *within* one entry, a repeated scalar key or value
1867/// also last-wins, while a repeated message value merges — the same as the
1868/// owned decoder.
1869///
1870/// For larger maps where O(1) lookup matters, collect into a `HashMap`:
1871///
1872/// ```ignore
1873/// use std::collections::HashMap;
1874/// let index: HashMap<&str, &str> = view.labels.into_iter().collect();
1875/// ```
1876///
1877/// Duplicate keys resolve last-write-wins in the collected map (matching
1878/// proto map semantics), since `HashMap::from_iter` keeps the last value.
1879///
1880/// # Allocation
1881///
1882/// Like [`RepeatedView`], the `Vec` backing store requires allocation.
1883/// The individual keys and values borrow from the input buffer where possible
1884/// (string keys as `&'a str`, bytes values as `&'a [u8]`).
1885#[derive(Clone, Debug, PartialEq, Eq)]
1886pub struct MapView<'a, K, V> {
1887 entries: alloc::vec::Vec<(K, V)>,
1888 _marker: core::marker::PhantomData<&'a ()>,
1889}
1890
1891impl<'a, K, V> MapView<'a, K, V> {
1892 /// Construct from a `Vec` of entries, for [`ViewEncode`] use.
1893 ///
1894 /// Duplicate keys are kept and all encoded — valid protobuf wire data
1895 /// (decoders apply last-write-wins). Mirrors [`RepeatedView::new`].
1896 pub fn new(entries: alloc::vec::Vec<(K, V)>) -> Self {
1897 Self {
1898 entries,
1899 _marker: core::marker::PhantomData,
1900 }
1901 }
1902
1903 /// Returns the number of entries (including duplicates).
1904 pub fn len(&self) -> usize {
1905 self.entries.len()
1906 }
1907
1908 /// Returns `true` if there are no entries.
1909 pub fn is_empty(&self) -> bool {
1910 self.entries.is_empty()
1911 }
1912
1913 /// Append a key-value pair (used by generated `decode_view` code).
1914 #[doc(hidden)]
1915 pub fn push(&mut self, key: K, value: V) {
1916 self.entries.push((key, value));
1917 }
1918
1919 /// Iterate over all entries in wire order.
1920 ///
1921 /// If duplicate keys exist, all occurrences are yielded.
1922 pub fn iter(&self) -> core::slice::Iter<'_, (K, V)> {
1923 self.entries.iter()
1924 }
1925
1926 /// Iterate over all keys in wire order.
1927 pub fn keys(&self) -> impl Iterator<Item = &K> {
1928 self.entries.iter().map(|(k, _)| k)
1929 }
1930
1931 /// Iterate over all values in wire order.
1932 pub fn values(&self) -> impl Iterator<Item = &V> {
1933 self.entries.iter().map(|(_, v)| v)
1934 }
1935
1936 /// Look up a value by key, returning the last occurrence (last-write-wins).
1937 ///
1938 /// Accepts any type that `K` can borrow as, so `map.get("key")` works
1939 /// when `K` is `&str`. O(n) scan.
1940 pub fn get<Q>(&self, key: &Q) -> Option<&V>
1941 where
1942 K: core::borrow::Borrow<Q>,
1943 Q: PartialEq + ?Sized,
1944 {
1945 self.entries
1946 .iter()
1947 .rev()
1948 .find(|(k, _)| k.borrow() == key)
1949 .map(|(_, v)| v)
1950 }
1951
1952 /// Returns `true` if an entry with the given key exists.
1953 pub fn contains_key<Q>(&self, key: &Q) -> bool
1954 where
1955 K: core::borrow::Borrow<Q>,
1956 Q: PartialEq + ?Sized,
1957 {
1958 self.entries.iter().any(|(k, _)| k.borrow() == key)
1959 }
1960
1961 /// Iterate over key-value pairs with duplicate keys removed.
1962 ///
1963 /// Each distinct key is yielded **exactly once, at the position of its
1964 /// last wire occurrence, carrying that occurrence's value** — i.e.
1965 /// last-write-wins, mirroring the merge semantics that an owned
1966 /// `HashMap` decode applies. Callers that need first-occurrence position
1967 /// should use [`iter`](Self::iter) and filter themselves.
1968 ///
1969 /// Used by the generated view `Serialize` impl: a JSON object cannot
1970 /// hold duplicate keys, but `MapView` preserves all wire entries
1971 /// (including malformed duplicates), so the JSON encode path must
1972 /// deduplicate. The implementation is allocation-free and O(n²) — for
1973 /// each entry, scan the remaining entries for a later occurrence of the
1974 /// same key. Duplicate map keys are invalid per the protobuf encoding
1975 /// spec and only arise in adversarial or conformance-test wire data, so
1976 /// `n` is effectively always small.
1977 pub fn iter_unique(&self) -> impl Iterator<Item = &(K, V)>
1978 where
1979 K: PartialEq,
1980 {
1981 let entries = &self.entries;
1982 entries.iter().enumerate().filter_map(move |(i, entry)| {
1983 if entries[i + 1..]
1984 .iter()
1985 .any(|(later_k, _)| *later_k == entry.0)
1986 {
1987 None
1988 } else {
1989 Some(entry)
1990 }
1991 })
1992 }
1993
1994 /// Count of distinct keys (`iter_unique().count()`).
1995 pub fn len_unique(&self) -> usize
1996 where
1997 K: PartialEq,
1998 {
1999 self.iter_unique().count()
2000 }
2001}
2002
2003impl<'a, K, V> From<alloc::vec::Vec<(K, V)>> for MapView<'a, K, V> {
2004 fn from(entries: alloc::vec::Vec<(K, V)>) -> Self {
2005 Self::new(entries)
2006 }
2007}
2008
2009/// Duplicate keys are kept and all encoded; see [`MapView::new`].
2010impl<'a, K, V> FromIterator<(K, V)> for MapView<'a, K, V> {
2011 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
2012 Self::new(iter.into_iter().collect())
2013 }
2014}
2015
2016impl<'a, K, V> Default for MapView<'a, K, V> {
2017 fn default() -> Self {
2018 Self {
2019 entries: alloc::vec::Vec::new(),
2020 _marker: core::marker::PhantomData,
2021 }
2022 }
2023}
2024
2025impl<'b, 'a, K, V> IntoIterator for &'b MapView<'a, K, V> {
2026 type Item = &'b (K, V);
2027 type IntoIter = core::slice::Iter<'b, (K, V)>;
2028
2029 fn into_iter(self) -> Self::IntoIter {
2030 self.entries.iter()
2031 }
2032}
2033
2034impl<'a, K, V> IntoIterator for MapView<'a, K, V> {
2035 type Item = (K, V);
2036 type IntoIter = alloc::vec::IntoIter<(K, V)>;
2037
2038 fn into_iter(self) -> Self::IntoIter {
2039 self.entries.into_iter()
2040 }
2041}
2042
2043/// One unknown-field wire record: either a span borrowed from the input
2044/// buffer, or synthetic bytes for a value with no borrowable source span.
2045#[derive(Clone, Debug)]
2046enum UnknownFieldsViewRecord<'a> {
2047 Borrowed(&'a [u8]),
2048 Owned(alloc::vec::Vec<u8>),
2049}
2050
2051impl UnknownFieldsViewRecord<'_> {
2052 fn as_slice(&self) -> &[u8] {
2053 match self {
2054 Self::Borrowed(span) => span,
2055 Self::Owned(bytes) => bytes,
2056 }
2057 }
2058}
2059
2060/// A borrowed view of unknown fields.
2061///
2062/// Stores unknown fields as wire records rather than decoded values, enabling
2063/// zero-copy round-tripping for borrowable input spans. Borrowed spans may
2064/// hold **one or more consecutive** complete `(tag, value)` records: adjacent
2065/// unknown fields are coalesced into a single span, so a long run of unknown
2066/// fields costs one `Vec` slot rather than one per field. Synthetic records
2067/// cover cases where the view decoder must preserve a value that has no
2068/// borrowable source span.
2069/// Coalescing bounds the view's memory only — the decode-time
2070/// unknown-field allowance is still charged per field (see
2071/// [`push_record`](Self::push_record)).
2072#[derive(Clone, Default)]
2073pub struct UnknownFieldsView<'a> {
2074 // Boxed, so this type is one pointer wide and holds no inline heap owner.
2075 // Every generated view embeds one by value; with the records inline, the
2076 // view becomes an owning aggregate that the compiler moves with
2077 // out-of-line `memcpy` calls instead of inline vector stores, which costs
2078 // view-decode throughput on message-dense shapes even when no unknown
2079 // field is ever pushed. The allocation happens on the first push.
2080 state: Option<alloc::boxed::Box<UnknownFieldsState<'a>>>,
2081}
2082
2083/// The records and replay accounting, allocated once a view turns out to
2084/// carry an unknown field.
2085#[derive(Clone, Default)]
2086struct UnknownFieldsState<'a> {
2087 /// Unknown wire records in decode order. Borrowed records may each hold
2088 /// one or more complete `(tag, value)` records; owned records are
2089 /// synthetic wire bytes for values that have no borrowable source span.
2090 records: alloc::vec::Vec<UnknownFieldsViewRecord<'a>>,
2091 /// The input-buffer tail starting at the first byte of the last span,
2092 /// kept so [`push_record`](Self::push_record) can extend that span over
2093 /// an adjacent record by re-slicing `last_tail` — never by widening the
2094 /// narrowed span reference, which would be provenance-unsound.
2095 last_tail: Option<&'a [u8]>,
2096 /// Total slots charged against the decode-time unknown-field allowance
2097 /// across every [`push_record`](Self::push_record) — exactly the number
2098 /// of `UnknownField`s [`to_owned`](Self::to_owned) re-materializes, so
2099 /// replay runs under precisely this budget and cannot exhaust it.
2100 to_owned_budget: usize,
2101 /// Deepest group nesting across all pushed records — the recursion
2102 /// depth [`to_owned`](Self::to_owned)'s replay needs, regardless of the
2103 /// (possibly larger) recursion limit the view was decoded under.
2104 to_owned_depth: u32,
2105 /// Set by [`push_raw`](Self::push_raw): the view holds spans that were
2106 /// never charged at decode time, so [`to_owned`](Self::to_owned) grants
2107 /// the default limits on top of the tracked budget and can fail.
2108 manual_spans: bool,
2109}
2110
2111// Manual impl: `last_tail` is an internal coalescing cursor that extends to
2112// the end of the input buffer — deriving Debug would dump the remaining
2113// message bytes on every `{:?}` print.
2114impl core::fmt::Debug for UnknownFieldsView<'_> {
2115 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2116 f.debug_struct("UnknownFieldsView")
2117 .field("records", &self.records_slice())
2118 .finish_non_exhaustive()
2119 }
2120}
2121
2122impl<'a> UnknownFieldsView<'a> {
2123 /// The state, created on first use.
2124 ///
2125 /// The `Some` test inlines and only the allocation is out of line, so a
2126 /// run of unknown records pays the branch once per record rather than a
2127 /// call: every push after the first finds the state already there.
2128 #[inline]
2129 fn state_mut(&mut self) -> &mut UnknownFieldsState<'a> {
2130 self.state.get_or_insert_with(Self::alloc_state)
2131 }
2132
2133 /// Out of line: this runs once, when a message turns out to carry an
2134 /// unknown field at all.
2135 #[cold]
2136 fn alloc_state() -> alloc::boxed::Box<UnknownFieldsState<'a>> {
2137 alloc::boxed::Box::default()
2138 }
2139
2140 /// The records, or an empty slice when nothing was ever pushed.
2141 #[inline]
2142 fn records_slice(&self) -> &[UnknownFieldsViewRecord<'a>] {
2143 self.state.as_ref().map_or(&[], |st| st.records.as_slice())
2144 }
2145
2146 /// Creates an empty view.
2147 pub fn new() -> Self {
2148 Self::default()
2149 }
2150
2151 #[doc(hidden)]
2152 pub fn push_raw(&mut self, span: &'a [u8]) {
2153 let st = self.state_mut();
2154 st.records.push(UnknownFieldsViewRecord::Borrowed(span));
2155 // A manually pushed span has no known position in the input buffer,
2156 // so coalescing must not extend it — and it was never charged
2157 // against a decode allowance, so to_owned falls back to the default
2158 // limits for it.
2159 st.last_tail = None;
2160 st.manual_spans = true;
2161 }
2162
2163 /// Record one unknown wire record of `span_len` bytes starting at the
2164 /// head of `tail`, where `tail` extends from the record's first byte to
2165 /// the end of the input buffer.
2166 ///
2167 /// Every record charges `ctx`'s unknown-field allowance with exactly the
2168 /// slots [`to_owned`](Self::to_owned) will re-materialize it into — one
2169 /// for the record's field plus, for group records, one per nested field.
2170 /// The charge total (and the deepest group nesting) is accumulated on
2171 /// the view as the conversion replay budget, so a view that decoded
2172 /// successfully always converts.
2173 ///
2174 /// If the record starts exactly where the previous one ended, the
2175 /// previous span is extended in place instead of pushing a new one —
2176 /// coalescing saves memory (no allocation, no `Vec` slot), not
2177 /// allowance.
2178 ///
2179 /// Marked `#[cold]`: every caller is an exceptional-value route — the
2180 /// unrecognized-field arm of a generated view merge, and the arms that
2181 /// preserve an unrecognized value of a closed enum (singular and map
2182 /// entry). None runs when the payload matches the schema, so the loop
2183 /// that inlines around them is laid out as though they never do.
2184 /// Decoding from a newer producer does take these routes, once per field
2185 /// it added, and pays for that choice.
2186 ///
2187 /// # Errors
2188 ///
2189 /// Returns [`DecodeError::UnknownFieldLimitExceeded`] when the allowance
2190 /// is exhausted, or [`DecodeError::UnexpectedEof`] if `span_len` exceeds
2191 /// `tail`.
2192 #[doc(hidden)]
2193 #[cold]
2194 pub fn push_record(
2195 &mut self,
2196 tail: &'a [u8],
2197 span_len: usize,
2198 ctx: crate::DecodeContext<'_>,
2199 ) -> Result<(), crate::DecodeError> {
2200 if span_len > tail.len() {
2201 return Err(crate::DecodeError::UnexpectedEof);
2202 }
2203 let charge = crate::encoding::register_unknown_record(&tail[..span_len], ctx)?;
2204 let st = self.state_mut();
2205 st.to_owned_budget = st.to_owned_budget.saturating_add(charge.fields);
2206 st.to_owned_depth = st.to_owned_depth.max(charge.depth);
2207 if let (Some(UnknownFieldsViewRecord::Borrowed(last)), Some(prev_tail)) =
2208 (st.records.last_mut(), st.last_tail)
2209 {
2210 let prev_len = last.len();
2211 // Contiguous if the new record begins exactly one past the end
2212 // of the previous span. Both checks are plain pointer/length
2213 // comparisons; the extension below re-slices `prev_tail`, whose
2214 // provenance covers the combined range.
2215 if prev_tail.len() >= prev_len + span_len
2216 && core::ptr::eq(prev_tail[prev_len..].as_ptr(), tail.as_ptr())
2217 {
2218 *last = &prev_tail[..prev_len + span_len];
2219 return Ok(());
2220 }
2221 }
2222 st.records
2223 .push(UnknownFieldsViewRecord::Borrowed(&tail[..span_len]));
2224 st.last_tail = Some(tail);
2225 Ok(())
2226 }
2227
2228 /// Preserve one unrecognized value of a closed enum as synthetic varint
2229 /// wire bytes.
2230 ///
2231 /// Marked `#[cold]`: the sole caller is the per-element route for a closed
2232 /// enum whose wire value names no variant — reached from a *recognized*
2233 /// field, including inside a packed element loop, so it can run more than
2234 /// once per message against a newer producer's data. It builds a `Vec` per
2235 /// value regardless, which dwarfs what the size-optimized body this
2236 /// attribute asks for costs.
2237 #[doc(hidden)]
2238 #[cold]
2239 pub fn push_varint(
2240 &mut self,
2241 field_number: u32,
2242 value: u64,
2243 ctx: crate::DecodeContext<'_>,
2244 ) -> Result<(), crate::DecodeError> {
2245 use crate::encoding::{encode_varint, Tag, WireType};
2246
2247 ctx.register_unknown_field()?;
2248 let st = self.state_mut();
2249 st.to_owned_budget = st.to_owned_budget.saturating_add(1);
2250
2251 let mut bytes = alloc::vec::Vec::new();
2252 Tag::new(field_number, WireType::Varint).encode(&mut bytes);
2253 encode_varint(value, &mut bytes);
2254 st.records.push(UnknownFieldsViewRecord::Owned(bytes));
2255 // Synthetic bytes have no position in the input buffer, so a later
2256 // borrowed record must start a fresh span.
2257 st.last_tail = None;
2258 Ok(())
2259 }
2260
2261 /// Returns `true` if no unknown fields were recorded.
2262 pub fn is_empty(&self) -> bool {
2263 self.records_slice().is_empty()
2264 }
2265
2266 /// Total byte length of all unknown field data.
2267 pub fn encoded_len(&self) -> usize {
2268 self.records_slice()
2269 .iter()
2270 .map(|record| record.as_slice().len())
2271 .sum()
2272 }
2273
2274 /// Write all unknown-field bytes in decode order. Each record holds one
2275 /// or more complete `(tag, value)` records, so concatenating them
2276 /// produces a valid encoding.
2277 pub fn write_to(&self, buf: &mut impl EncodeSink) {
2278 for record in self.records_slice() {
2279 buf.put_slice(record.as_slice());
2280 }
2281 }
2282
2283 /// Convert to an owned [`UnknownFields`](crate::UnknownFields) by parsing all stored wire records.
2284 ///
2285 /// Each record holds one or more consecutive (tag + value) records as
2286 /// they should be re-emitted. Parsing uses
2287 /// [`crate::encoding::decode_unknown_field`] under exactly the budget
2288 /// [`push_record`](Self::push_record) and [`push_varint`](Self::push_varint)
2289 /// charged at decode time — the same field count and group-nesting depth —
2290 /// so replay cannot exhaust either. Views holding manually pushed spans
2291 /// (via [`push_raw`](Self::push_raw)) additionally get
2292 /// [`DEFAULT_UNKNOWN_FIELD_LIMIT`](crate::DEFAULT_UNKNOWN_FIELD_LIMIT)
2293 /// slots and the full [`RECURSION_LIMIT`](crate::RECURSION_LIMIT), since
2294 /// those spans were never charged.
2295 /// A coalesced borrowed span re-materializes one owned `UnknownField` per
2296 /// wire record, so this conversion is where a long run of unknown fields
2297 /// actually allocates.
2298 ///
2299 /// # Errors
2300 ///
2301 /// Returns `Err` if a stored record is malformed or exceeds the replay
2302 /// budget. Neither can occur when the view was produced by wire decoding
2303 /// — every borrowed record was parsed off the wire, and the budget equals
2304 /// what decoding charged — so any such view converts successfully. Only
2305 /// views holding [`push_raw`](Self::push_raw) spans can fail here.
2306 pub fn to_owned(&self) -> Result<crate::UnknownFields, crate::DecodeError> {
2307 use crate::encoding::{decode_unknown_field, Tag};
2308
2309 let Some(state) = self.state.as_deref() else {
2310 return Ok(crate::UnknownFields::new());
2311 };
2312 let (budget, depth) = if state.manual_spans {
2313 (
2314 state
2315 .to_owned_budget
2316 .saturating_add(crate::DEFAULT_UNKNOWN_FIELD_LIMIT),
2317 state.to_owned_depth.max(crate::RECURSION_LIMIT),
2318 )
2319 } else {
2320 (state.to_owned_budget, state.to_owned_depth)
2321 };
2322 let limit = core::cell::Cell::new(budget);
2323 let ctx = crate::DecodeContext::new(depth, &limit);
2324 let mut out = crate::UnknownFields::new();
2325 for record in &state.records {
2326 let mut cur = record.as_slice();
2327 while !cur.is_empty() {
2328 let tag = Tag::decode(&mut cur)?;
2329 let field = decode_unknown_field(tag, &mut cur, ctx)?;
2330 out.push(field);
2331 }
2332 }
2333 Ok(out)
2334 }
2335}
2336
2337/// An owned, `'static` container for a decoded message view.
2338///
2339/// `OwnedView` holds a [`Bytes`] buffer alongside the decoded view, ensuring
2340/// the view's borrows remain valid for the container's lifetime. The inner
2341/// view is reached through [`reborrow()`](OwnedView::reborrow), which returns
2342/// it with a lifetime tied to `&self`.
2343///
2344/// This type is `Send + Sync + 'static`, making it suitable for use across
2345/// async boundaries, in tower services, and anywhere a `'static` bound is
2346/// required.
2347///
2348/// # When to use
2349///
2350/// Use `OwnedView` when you need a zero-copy view that outlives the scope
2351/// where the buffer was received — for example, in an RPC handler where the
2352/// framework requires `'static` types:
2353///
2354/// ```rust,ignore
2355/// use buffa::view::OwnedView;
2356/// use bytes::Bytes;
2357///
2358/// let bytes: Bytes = receive_request_body().await;
2359/// let view = OwnedView::<PersonView>::decode(bytes)?;
2360///
2361/// // Field access through reborrow — the borrow is tied to `view`.
2362/// let person = view.reborrow();
2363/// println!("name: {}", person.name);
2364/// println!("id: {}", person.id);
2365///
2366/// // Convert to owned if you need to store or mutate — infallible, since
2367/// // an OwnedView always holds a wire-decoded view.
2368/// let owned: Person = view.to_owned_message();
2369/// ```
2370///
2371/// Generated code additionally provides a per-message `FooOwnedView` wrapper
2372/// around `OwnedView<FooView<'static>>` with per-field accessor methods
2373/// (`owned.name()`, `owned.id()`, …), so most handler code never touches
2374/// `OwnedView` or `reborrow` directly.
2375///
2376/// For scoped access where the buffer's lifetime is known, use
2377/// [`MessageView::decode_view`] directly — it has zero overhead beyond the
2378/// decode itself.
2379///
2380/// # Why field access goes through `reborrow`
2381///
2382/// `OwnedView` stores `V = FooView<'static>`: the view's borrows really point
2383/// into `self`'s [`Bytes`] buffer, and the `'static` is a synthetic lifetime
2384/// established by the constructor. Exposing `&V` directly (for example via a
2385/// `Deref` impl) would let borrowed fields *appear* `'static` to the
2386/// compiler and escape the `OwnedView`'s scope, dangling once it drops.
2387/// [`reborrow()`](OwnedView::reborrow) narrows the synthetic `'static` down
2388/// to the `OwnedView`'s real lifetime, so the borrow checker enforces the
2389/// actual validity of every field borrow:
2390///
2391/// ```no_run
2392/// # use buffa::view::OwnedView;
2393/// # use buffa::__doctest_fixtures::PersonView;
2394/// // Inline reads: reborrow once, then use plain field access.
2395/// fn log(owned: &OwnedView<PersonView<'static>>) {
2396/// let person = owned.reborrow();
2397/// println!("{}", person.name);
2398/// }
2399///
2400/// // Returning a borrowed field: the result is tied to the OwnedView.
2401/// fn name<'a>(owned: &'a OwnedView<PersonView<'static>>) -> &'a str {
2402/// owned.reborrow().name // &'a str tied to the OwnedView's lifetime
2403/// }
2404/// ```
2405///
2406/// View fields are not reachable directly on the handle — this fails to
2407/// compile rather than handing out a `'static` borrow into the buffer:
2408///
2409/// ```compile_fail,E0609
2410/// # use buffa::view::OwnedView;
2411/// # use buffa::__doctest_fixtures::PersonView;
2412/// fn field(owned: &OwnedView<PersonView<'static>>) -> &'static str {
2413/// owned.name // error[E0609]: no field `name` on type `&OwnedView<...>`
2414/// }
2415/// ```
2416///
2417/// # Safety
2418///
2419/// Internally, `OwnedView` extends the view's lifetime to `'static` via
2420/// `transmute` in its constructors. This is sound because:
2421///
2422/// 1. [`Bytes`] is reference-counted — its heap data pointer is stable across
2423/// moves. The view's borrows always point into valid memory.
2424/// 2. [`Bytes`] is immutable — the underlying data cannot be modified while
2425/// borrowed.
2426/// 3. The view is declared before the buffer, and the compiler's drop glue
2427/// drops fields in declaration order, so the view is always gone before
2428/// the buffer it borrows from is released — on a normal drop and during
2429/// an unwind; [`into_bytes`](OwnedView::into_bytes) drops it explicitly
2430/// before handing the buffer back.
2431/// 4. The view is stored in a private `MaybeDangling` wrapper (an in-tree
2432/// stand-in for RFC 3336), which tells the aliasing model that its forged
2433/// `'static` borrows carry no validity guarantees of their own while an
2434/// `OwnedView` is moved around by value.
2435///
2436/// [`reborrow`](OwnedView::reborrow) is a plain Rust subtype coercion (no
2437/// `unsafe`, no pointer cast): the [`ViewReborrow`] trait method coerces
2438/// `&'b FooView<'static>` into `&'b FooView<'b>` via standard lifetime
2439/// variance for covariant view types. See [`ViewReborrow`]'s docs for the
2440/// soundness argument.
2441pub struct OwnedView<V> {
2442 // INVARIANT: `view` borrows from `bytes`. FIELD ORDER IS LOAD-BEARING:
2443 // drop glue runs in declaration order, so `view` must stay declared
2444 // before `bytes` for the view to be dropped while its buffer is still
2445 // alive. There is deliberately no `Drop` impl on `OwnedView` — with one,
2446 // `into_bytes` could not move `bytes` out, and a panic in `V::drop`
2447 // could unwind into it and drop the view a second time (#377).
2448 //
2449 // CONSTRUCTORS: any constructor added here MUST ensure the view's
2450 // borrows point into `self.bytes` (not into caller-owned memory).
2451 // The auto-`Send`/`Sync` derivation is only sound under that invariant
2452 // — there is no longer a `V: 'static` bound on `Send` to act as a
2453 // second gate. See the comment block above `send_sync_assertions` below.
2454 view: MaybeDangling<V>,
2455 bytes: Bytes,
2456}
2457
2458/// An in-tree stand-in for the `MaybeDangling<T>` proposed in [RFC 3336],
2459/// modelled on `yoke`'s `KindaSortaDangling` (minus the `into_inner` and
2460/// `DerefMut` this crate has no caller for).
2461///
2462/// The view inside an [`OwnedView`] carries `&'static` borrows that really
2463/// point into the sibling `Bytes` buffer. Storing it behind a
2464/// [`MaybeUninit`](core::mem::MaybeUninit) tells the aliasing model that the
2465/// value has no memory-dependent validity properties (`dereferenceable`,
2466/// `noalias`) of its own. Without the wrapper, Miri's field retagging puts a
2467/// protector on each forged `&'static` whenever an `OwnedView` is passed by
2468/// value, and freeing the buffer inside that call — a plain `drop(owned)` in
2469/// the callee, or the unwind path of [`OwnedView::into_bytes`] — is reported
2470/// as undefined behaviour. [icu4x #3696] is the `yoke` test case for exactly
2471/// this.
2472///
2473/// Once RFC 3336 lands this can become the standard library type.
2474///
2475/// [RFC 3336]: https://github.com/rust-lang/rfcs/pull/3336
2476/// [icu4x #3696]: https://github.com/unicode-org/icu4x/issues/3696
2477#[repr(transparent)]
2478struct MaybeDangling<T> {
2479 /// INVARIANT: always holds an initialized `T`. Its drop glue runs from
2480 /// [`Drop::drop`] below rather than from `MaybeUninit` (which has none),
2481 /// so nothing may treat `inner` as initialized after that point — and
2482 /// nothing does, because the only code that runs afterwards is the
2483 /// empty drop glue of `MaybeUninit`.
2484 inner: core::mem::MaybeUninit<T>,
2485}
2486
2487impl<T> MaybeDangling<T> {
2488 #[inline]
2489 const fn new(value: T) -> Self {
2490 Self {
2491 inner: core::mem::MaybeUninit::new(value),
2492 }
2493 }
2494}
2495
2496impl<T> core::ops::Deref for MaybeDangling<T> {
2497 type Target = T;
2498 #[inline]
2499 fn deref(&self) -> &T {
2500 // SAFETY: `inner` is initialized (the type invariant); `deref` is
2501 // never reachable once `Drop::drop` has run.
2502 unsafe { self.inner.assume_init_ref() }
2503 }
2504}
2505
2506impl<T> Drop for MaybeDangling<T> {
2507 #[inline]
2508 fn drop(&mut self) {
2509 // SAFETY: `inner` is initialized (the type invariant) and is dropped
2510 // exactly once here — `MaybeUninit` has no drop glue, so nothing runs
2511 // it again afterwards. `drop_in_place` rather than
2512 // `assume_init_read` so the `T` is never moved into an unwrapped
2513 // local, which would reassert the validity properties this wrapper
2514 // exists to suppress.
2515 unsafe { self.inner.as_mut_ptr().drop_in_place() }
2516 }
2517}
2518
2519/// Panic path for [`OwnedView::to_owned_message`], hoisted out of the
2520/// generic method so the format machinery is emitted once rather than per
2521/// monomorphization — the branch is unreachable for generated view types.
2522#[cold]
2523#[inline(never)]
2524fn convert_contract_violated(e: DecodeError) -> ! {
2525 panic!(
2526 "OwnedView conversion failed ({e:?}): the wrapped MessageView \
2527 impl violates the wire-decode => convert contract"
2528 )
2529}
2530
2531impl<V> OwnedView<V>
2532where
2533 V: MessageView<'static>,
2534{
2535 /// Decode a view from a [`Bytes`] buffer.
2536 ///
2537 /// The view borrows directly from the buffer's data. Because [`Bytes`] is
2538 /// reference-counted and its data pointer is stable across moves, the
2539 /// view's borrows remain valid for the lifetime of this `OwnedView`.
2540 ///
2541 /// # Errors
2542 ///
2543 /// Returns [`DecodeError`] if the buffer contains invalid protobuf data.
2544 pub fn decode(bytes: Bytes) -> Result<Self, DecodeError> {
2545 // SAFETY: `Bytes` is StableDeref — its heap data never moves or is
2546 // freed while we hold the `Bytes` value. We hold it in `self.bytes`,
2547 // and declaration-order drop glue (`OwnedView` has no `Drop` impl)
2548 // guarantees `view` drops first.
2549 let view = unsafe {
2550 let slice: &'static [u8] = core::mem::transmute::<&[u8], &'static [u8]>(&bytes);
2551 V::decode_view(slice)?
2552 };
2553 Ok(Self {
2554 view: MaybeDangling::new(view),
2555 bytes,
2556 })
2557 }
2558
2559 /// Decode a view with custom [`DecodeOptions`](crate::DecodeOptions)
2560 /// (recursion limit, max message size).
2561 ///
2562 /// # Errors
2563 ///
2564 /// Returns [`DecodeError`] if the buffer is invalid or exceeds the
2565 /// configured limits.
2566 pub fn decode_with_options(
2567 bytes: Bytes,
2568 opts: &crate::DecodeOptions,
2569 ) -> Result<Self, DecodeError> {
2570 // SAFETY: Same invariants as `decode` — see above.
2571 let view = unsafe {
2572 let slice: &'static [u8] = core::mem::transmute::<&[u8], &'static [u8]>(&bytes);
2573 opts.decode_view::<V>(slice)?
2574 };
2575 Ok(Self {
2576 view: MaybeDangling::new(view),
2577 bytes,
2578 })
2579 }
2580
2581 /// Create an `OwnedView` from an owned message by encoding then decoding.
2582 ///
2583 /// This performs a full **encode → decode** round-trip: the message is
2584 /// serialized to protobuf bytes, then a zero-copy view is decoded from
2585 /// those bytes. This is useful when the original wire bytes are not
2586 /// available (e.g., after JSON deserialization or programmatic construction),
2587 /// but note the cost: one allocation + O(n) encode + O(n) decode.
2588 ///
2589 /// For the common case where you already have wire bytes, prefer
2590 /// [`decode`](Self::decode) instead.
2591 ///
2592 /// # Errors
2593 ///
2594 /// Returns [`DecodeError::MessageTooLarge`] if the message's encoded
2595 /// size exceeds the 2 GiB protobuf limit
2596 /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)), or another
2597 /// [`DecodeError`] if the re-encoded bytes are somehow invalid (should
2598 /// not happen for well-formed messages).
2599 pub fn from_owned(msg: &V::Owned) -> Result<Self, DecodeError> {
2600 let bytes = Bytes::from(
2601 msg.try_encode_to_vec()
2602 .map_err(|_| DecodeError::MessageTooLarge)?,
2603 );
2604 Self::decode(bytes)
2605 }
2606
2607 /// Convert the view to the corresponding owned message type.
2608 ///
2609 /// `bytes::Bytes`-typed fields are produced via [`Bytes::slice_ref`]
2610 /// into the retained buffer (zero-copy); other borrowed fields are
2611 /// allocated and copied.
2612 ///
2613 /// Infallible: every `OwnedView` constructor wire-decodes its view
2614 /// ([`decode`](Self::decode), [`decode_with_options`](Self::decode_with_options),
2615 /// [`from_owned`](Self::from_owned)) or requires wire-decode provenance
2616 /// as part of its safety contract ([`from_parts`](Self::from_parts)),
2617 /// and a view produced by wire decoding always converts (see
2618 /// [`MessageView::to_owned_message`]).
2619 ///
2620 /// # Panics
2621 ///
2622 /// Panics if `V`'s [`MessageView`] implementation violates the
2623 /// wire-decode ⇒ convert contract. Generated view types cannot trigger
2624 /// this; only a buggy hand-written impl (or a
2625 /// [`from_parts`](Self::from_parts) view that breaches its safety
2626 /// contract) can.
2627 #[must_use]
2628 pub fn to_owned_message(&self) -> V::Owned {
2629 self.view
2630 .to_owned_from_source(Some(&self.bytes))
2631 .unwrap_or_else(|e| convert_contract_violated(e))
2632 }
2633
2634 /// Get a reference to the underlying bytes buffer.
2635 pub fn bytes(&self) -> &Bytes {
2636 &self.bytes
2637 }
2638
2639 /// Create an `OwnedView` from a buffer and a pre-decoded view.
2640 ///
2641 /// This avoids re-decoding when you already hold a decoded view and want
2642 /// to wrap it for `'static` use.
2643 ///
2644 /// # Safety
2645 ///
2646 /// The caller must ensure that `view` was produced by **wire-decoding**
2647 /// `bytes` (or a sub-slice that `bytes` fully contains) — e.g. via
2648 /// [`MessageView::decode_view`]. This guarantees both that all borrows
2649 /// in `view` point into the data region of `bytes` (violating that
2650 /// causes undefined behavior — dangling references) and that
2651 /// [`to_owned_message`](Self::to_owned_message)'s infallible-conversion
2652 /// contract holds (a manually assembled view merely borrowing from
2653 /// `bytes` satisfies the borrow requirement but can make conversion
2654 /// panic).
2655 pub unsafe fn from_parts(bytes: Bytes, view: V) -> Self {
2656 Self {
2657 view: MaybeDangling::new(view),
2658 bytes,
2659 }
2660 }
2661
2662 /// Consume the `OwnedView`, returning the underlying [`Bytes`] buffer.
2663 ///
2664 /// The view is dropped before the buffer is returned.
2665 ///
2666 /// # Panics
2667 ///
2668 /// Propagates a panic from `V`'s destructor; the buffer is then released
2669 /// by the unwind instead of being returned.
2670 pub fn into_bytes(self) -> Bytes {
2671 // Destructuring is only legal because `OwnedView` has no `Drop` impl
2672 // of its own. Moving the `Bytes` handle out first is fine: the heap
2673 // data the view borrows stays put (`Bytes` is `StableDeref`), and
2674 // the local keeps it alive. Dropping the view explicitly before
2675 // `bytes` moves into the return slot keeps the buffer a plain local
2676 // while `V::drop` runs: if that panics, the unwind frees `bytes` (a
2677 // value already in the return slot would be leaked instead), and
2678 // `view` has been moved into `drop`, so nothing can drop it twice.
2679 let Self { view, bytes } = self;
2680 drop(view);
2681 bytes
2682 }
2683
2684 /// Reborrow the view with a lifetime tied to `&'b self`.
2685 ///
2686 /// `OwnedView<V>` stores `V` with a `'static` lifetime — the actual borrows
2687 /// point into `self`'s internal [`Bytes`] buffer and are only valid while
2688 /// `self` is alive. `reborrow` makes that real lifetime visible to the borrow
2689 /// checker: the returned `&'b V::Reborrowed<'b>` cannot outlive `&'b self`.
2690 ///
2691 /// # Example
2692 ///
2693 /// ```no_run
2694 /// # use buffa::view::OwnedView;
2695 /// # use buffa::__doctest_fixtures::PersonView;
2696 /// fn handler<'a>(req: &'a OwnedView<PersonView<'static>>) -> &'a str {
2697 /// // The explicit annotation is for emphasis; inference works without it.
2698 /// // If you need to name the lifetime, store the reborrow in a `let` first.
2699 /// let req_view: &PersonView<'a> = req.reborrow();
2700 /// req_view.name // zero-copy from the OwnedView's buffer
2701 /// }
2702 /// ```
2703 ///
2704 /// The returned reference is tied to `&'b self` — the borrow checker
2705 /// prevents the reborrowed view from outliving the `OwnedView`:
2706 ///
2707 /// ```compile_fail,E0597
2708 /// # use buffa::view::OwnedView;
2709 /// # use buffa::__doctest_fixtures::PersonView;
2710 /// let name: &str;
2711 /// {
2712 /// // SAFETY: empty Bytes, no borrows — safe to construct directly.
2713 /// let owned = unsafe {
2714 /// OwnedView::<PersonView<'static>>::from_parts(
2715 /// ::buffa::bytes::Bytes::new(),
2716 /// PersonView::default(),
2717 /// )
2718 /// };
2719 /// name = owned.reborrow().name; // error[E0597]: `owned` does not live long enough
2720 /// }
2721 /// println!("{name}"); // name is dangling — borrow checker rejects this
2722 /// ```
2723 ///
2724 /// # How it works
2725 ///
2726 /// The trait method [`ViewReborrow::reborrow`] is a plain Rust subtype
2727 /// coercion: `&'b V` (where `V = FooView<'static>`) flows into the
2728 /// return slot `&'b V::Reborrowed<'b>` (= `&'b FooView<'b>`). Variance
2729 /// makes this safe — covariant view types narrow `'static` down to
2730 /// `'b` automatically. No `unsafe`, no pointer cast, no layout
2731 /// assertions. `OwnedView`'s own invariant (every borrow in `view`
2732 /// points into `self.bytes`, established by `decode` or upheld by the
2733 /// `unsafe from_parts` caller) guarantees the pointed-to data lives
2734 /// at least as long as `'b`.
2735 #[must_use = "reborrow returns a tied-lifetime view; discarding it is a no-op"]
2736 pub fn reborrow<'b>(&'b self) -> &'b V::Reborrowed<'b>
2737 where
2738 V: ViewReborrow,
2739 {
2740 V::reborrow(&self.view)
2741 }
2742}
2743
2744// Deliberately NO `Deref<Target = V>` impl: `V` is `FooView<'static>`, so a
2745// `&V` return would expose the synthetic `'static` on every borrowed field
2746// and let it escape the OwnedView's scope (dangling once the buffer drops).
2747// All access goes through `reborrow()`, which ties the borrow to `&self`.
2748
2749impl<V> core::fmt::Debug for OwnedView<V>
2750where
2751 V: core::fmt::Debug,
2752{
2753 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2754 (*self.view).fmt(f)
2755 }
2756}
2757
2758impl<V> Clone for OwnedView<V>
2759where
2760 V: Clone,
2761{
2762 fn clone(&self) -> Self {
2763 // SAFETY: `Bytes::clone()` is a refcount bump — both the original and
2764 // the clone share the same backing heap allocation. The cloned view's
2765 // `'static` references remain valid because they point into data that
2766 // is now kept alive by the cloned `Bytes` handle. This would be
2767 // unsound if `Bytes::clone()` performed a deep copy to a new address.
2768 Self {
2769 view: MaybeDangling::new((*self.view).clone()),
2770 bytes: self.bytes.clone(),
2771 }
2772 }
2773}
2774
2775impl<V> PartialEq for OwnedView<V>
2776where
2777 V: PartialEq,
2778{
2779 fn eq(&self, other: &Self) -> bool {
2780 *self.view == *other.view
2781 }
2782}
2783
2784impl<V> Eq for OwnedView<V> where V: Eq {}
2785
2786/// Serialize an `OwnedView<V>` by delegating to the inner view's `Serialize`
2787/// impl.
2788///
2789/// Equivalent to serializing `owned_view.reborrow()` directly, so
2790/// `serde_json::to_string(&owned_view)` works on the handle itself. When
2791/// `V` is a buffa-generated view with `generate_json` enabled, this produces
2792/// protobuf JSON; the impl itself just forwards to whatever `V::serialize`
2793/// does.
2794///
2795/// Only available when the `json` feature is enabled.
2796#[cfg(feature = "json")]
2797impl<V: ::serde::Serialize> ::serde::Serialize for OwnedView<V> {
2798 fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
2799 ::serde::Serialize::serialize(&*self.view, s)
2800 }
2801}
2802
2803// `OwnedView<V>` is auto-`Send`/`Sync` when `V` is — `MaybeDangling<V>` (a
2804// `MaybeUninit<V>`) and `Bytes` both forward auto-traits. No manual
2805// `unsafe impl` is needed, and adding one with a `V: 'static` bound is
2806// actively harmful: it is precisely what triggers E0477 when `async fn` is
2807// used in a trait impl against an RPITIT `+ Send` return type
2808// (rust-lang/rust#128095). The RPITIT desugaring introduces a fresh lifetime
2809// for the `'static` in `FooView<'static>`, and then cannot prove that fresh
2810// lifetime satisfies `'static` to discharge the manual impl's bound.
2811//
2812// The bound was defensive — intended to prevent `OwnedView<FooView<'short>>`
2813// from being `Send` when the view borrows from something outside `self.bytes`.
2814// But that type is already unconstructible: `::decode()` and
2815// `::decode_with_options()` are gated on `V: MessageView<'static>`, and the
2816// fields are private. The short-lifetime case the bound guards against cannot
2817// exist in safe code.
2818//
2819// Auto-trait soundness: `Bytes` is `Send + Sync`. The view's `&'static [u8]`
2820// borrows point into `Bytes`'s heap allocation, which is immutable,
2821// `StableDeref`, and moves with the struct. Sending the whole pair to another
2822// thread preserves the invariant. The `'static` in `V` being a lie is about
2823// *where* the reference points, not about thread safety.
2824#[cfg(test)]
2825mod send_sync_assertions {
2826 use super::*;
2827 fn assert_send<T: Send>() {}
2828 fn assert_sync<T: Sync>() {}
2829
2830 // Any `V: Send + Sync` suffices — generated `FooView<'static>` types are
2831 // auto-`Send + Sync` via their `&'static str` / `&'static [u8]` fields.
2832 #[allow(dead_code)]
2833 fn owned_view_is_send_sync<V: Send + Sync>() {
2834 assert_send::<OwnedView<V>>();
2835 assert_sync::<OwnedView<V>>();
2836 }
2837
2838 // `OwnedView<FooView<'static>>` must keep coercing to
2839 // `OwnedView<FooView<'a>>`: `MaybeUninit<V>` is covariant in `V` like the
2840 // `ManuallyDrop<V>` it replaced, but that is a derived property of the
2841 // union, not a documented guarantee, so pin it here.
2842 #[allow(dead_code)]
2843 fn owned_view_is_covariant<'a>(
2844 v: OwnedView<super::tests::TinyView<'static>>,
2845 ) -> OwnedView<super::tests::TinyView<'a>> {
2846 v
2847 }
2848
2849 // Concrete-type regression: `TinyView` is declared in the `tests` module
2850 // below and has the same shape as generated view types (one `&'a str`).
2851 #[allow(dead_code)]
2852 fn owned_tiny_view_is_send_sync() {
2853 assert_send::<OwnedView<super::tests::TinyView<'static>>>();
2854 assert_sync::<OwnedView<super::tests::TinyView<'static>>>();
2855 }
2856
2857 // `ViewReborrow::Reborrowed<'b>` must also be Send + Sync so that a
2858 // reborrowed view can be passed across threads (e.g. into a Tokio task).
2859 #[allow(dead_code)]
2860 fn reborrowed_view_is_send_sync<V>()
2861 where
2862 V: ViewReborrow + Send + Sync,
2863 for<'b> V::Reborrowed<'b>: Send + Sync,
2864 {
2865 assert_send::<OwnedView<V>>();
2866 assert_sync::<OwnedView<V>>();
2867 }
2868}
2869
2870#[cfg(test)]
2871mod tests {
2872 use super::*;
2873
2874 // ── MessageFieldView ─────────────────────────────────────────────────
2875
2876 #[test]
2877 fn message_field_view_default_is_unset() {
2878 let v: MessageFieldView<i32> = MessageFieldView::default();
2879 assert!(v.is_unset());
2880 assert!(!v.is_set());
2881 assert_eq!(v.as_option(), None);
2882 }
2883
2884 #[test]
2885 fn message_field_view_set_value() {
2886 let v = MessageFieldView::set(42);
2887 assert!(v.is_set());
2888 assert!(!v.is_unset());
2889 assert_eq!(v.as_option(), Some(&42));
2890 }
2891
2892 #[test]
2893 fn message_field_view_with_non_copy_type() {
2894 let v = MessageFieldView::set(alloc::string::String::from("hello"));
2895 assert!(v.is_set());
2896 assert_eq!(v.as_option().map(|s| s.as_str()), Some("hello"));
2897
2898 let unset: MessageFieldView<alloc::string::String> = MessageFieldView::unset();
2899 assert!(unset.is_unset());
2900 assert_eq!(unset.as_option(), None);
2901 }
2902
2903 // ── MessageFieldView Deref ─────────────────────────────────────────
2904
2905 /// A trivial view type for testing MessageFieldView Deref.
2906 #[derive(Clone, Debug, Default, PartialEq)]
2907 pub(super) struct TinyView<'a> {
2908 pub value: &'a str,
2909 }
2910
2911 // Via the exported macro, which doubles as its unit test (hygiene and
2912 // `$crate` path resolution).
2913 crate::impl_default_view_instance!(TinyView);
2914
2915 #[test]
2916 fn impl_default_view_instance_macro_returns_singleton() {
2917 let a: &TinyView<'_> = TinyView::default_view_instance();
2918 let b: &TinyView<'_> = TinyView::default_view_instance();
2919 assert!(core::ptr::eq(a, b), "singleton must be a single allocation");
2920 assert_eq!(a, &TinyView::default());
2921 }
2922
2923 #[test]
2924 fn message_field_view_deref_set() {
2925 let v = MessageFieldView::set(TinyView { value: "hello" });
2926 // Deref gives access to the inner view
2927 assert_eq!(v.value, "hello");
2928 }
2929
2930 #[test]
2931 fn message_field_view_deref_unset_returns_default() {
2932 let v: MessageFieldView<TinyView<'_>> = MessageFieldView::unset();
2933 // Deref transparently returns the default instance
2934 assert_eq!(v.value, "");
2935 }
2936
2937 #[test]
2938 fn message_field_view_deref_chained_access() {
2939 // Simulates accessing a nested field through an unset sub-message
2940 let v: MessageFieldView<TinyView<'_>> = MessageFieldView::unset();
2941 let len = v.value.len();
2942 assert_eq!(len, 0);
2943 }
2944
2945 // ── MessageFieldView PartialEq (wire-equivalent) ───────────────────
2946
2947 #[test]
2948 fn message_field_view_equality() {
2949 // None = Unset, Some(s) = Set(TinyView { value: s }).
2950 // TinyView::default() has value == "", so Some("") encodes Set(default).
2951 fn mk(c: Option<&str>) -> MessageFieldView<TinyView<'_>> {
2952 match c {
2953 None => MessageFieldView::unset(),
2954 Some(v) => MessageFieldView::set(TinyView { value: v }),
2955 }
2956 }
2957
2958 #[rustfmt::skip]
2959 let cases: &[(Option<&str>, Option<&str>, bool)] = &[
2960 // Wire-equivalent semantics: Unset == Set(default), matching
2961 // MessageField::PartialEq on the owned side.
2962 (None, None, true ), // Unset == Unset
2963 (None, Some(""), true ), // Unset == Set(default)
2964 (Some(""), None, true ), // Set(default) == Unset (symmetric)
2965 (Some(""), Some(""), true ), // Set(default) == Set(default)
2966 (None, Some("x"), false), // Unset != Set(nondefault)
2967 (Some("x"), None, false), // Set(nondefault) != Unset (symmetric)
2968 (Some("x"), Some("x"), true ), // Set == Set (same)
2969 (Some("x"), Some("y"), false), // Set != Set (different)
2970 ];
2971
2972 for &(l, r, expect) in cases {
2973 assert_eq!(
2974 mk(l) == mk(r),
2975 expect,
2976 "({l:?} == {r:?}) should be {expect}"
2977 );
2978 }
2979 }
2980
2981 // ── RepeatedView ─────────────────────────────────────────────────────
2982
2983 #[test]
2984 fn repeated_view_new_and_accessors() {
2985 let rv = RepeatedView::new(alloc::vec![10, 20, 30]);
2986 assert_eq!(rv.len(), 3);
2987 assert!(!rv.is_empty());
2988 assert_eq!(&*rv, &[10, 20, 30]);
2989 }
2990
2991 #[test]
2992 fn repeated_view_default_is_empty() {
2993 let rv: RepeatedView<'_, u8> = RepeatedView::default();
2994 assert!(rv.is_empty());
2995 assert_eq!(rv.len(), 0);
2996 }
2997
2998 #[test]
2999 fn repeated_view_push_and_iter() {
3000 let mut rv = RepeatedView::<i32>::default();
3001 rv.push(1);
3002 rv.push(2);
3003 let collected: alloc::vec::Vec<_> = rv.iter().copied().collect();
3004 assert_eq!(collected, alloc::vec![1, 2]);
3005 }
3006
3007 // ── UnknownFieldsView::push_record (coalescing + limit) ────────────
3008
3009 /// A test context at full depth with `n` unknown-field slots, leaking
3010 /// the cell so the context can outlive this helper.
3011 fn record_ctx(n: usize) -> crate::DecodeContext<'static> {
3012 let limit = alloc::boxed::Box::leak(alloc::boxed::Box::new(core::cell::Cell::new(n)));
3013 crate::DecodeContext::new(crate::RECURSION_LIMIT, limit)
3014 }
3015
3016 #[test]
3017 fn push_record_coalesces_adjacent_records() {
3018 // Buffer holds three consecutive 2-byte records: they coalesce into
3019 // a single span, but each still consumes one allowance slot.
3020 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02];
3021 let ctx = record_ctx(3);
3022 let mut ufv = UnknownFieldsView::new();
3023 ufv.push_record(&buf[0..], 2, ctx).unwrap();
3024 ufv.push_record(&buf[2..], 2, ctx).unwrap();
3025 ufv.push_record(&buf[4..], 2, ctx).unwrap();
3026 assert_eq!(ufv.encoded_len(), 6);
3027 assert_eq!(ufv.records_slice().len(), 1, "coalesced into one span");
3028 let mut out = alloc::vec::Vec::new();
3029 ufv.write_to(&mut out);
3030 assert_eq!(out, buf);
3031 assert_eq!(ctx.remaining_unknown_fields(), 0, "one slot per record");
3032 }
3033
3034 #[test]
3035 fn push_record_non_adjacent_records_use_separate_slots() {
3036 let buf: &[u8] = &[0x08, 0x00, 0xFF, 0x08, 0x01];
3037 let ctx = record_ctx(2);
3038 let mut ufv = UnknownFieldsView::new();
3039 ufv.push_record(&buf[0..], 2, ctx).unwrap();
3040 // Skip buf[2] — the next record is not adjacent to the previous one.
3041 ufv.push_record(&buf[3..], 2, ctx).unwrap();
3042 assert_eq!(ufv.encoded_len(), 4);
3043 assert_eq!(ctx.remaining_unknown_fields(), 0, "two slots consumed");
3044 }
3045
3046 #[test]
3047 fn push_record_enforces_limit_per_record() {
3048 // Before the per-record accounting fix, a coalesced run consumed
3049 // one slot at decode and one slot per record at conversion, so an
3050 // over-limit contiguous run decoded as a view and then failed to
3051 // convert. Now it fails at push time.
3052 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02];
3053 let ctx = record_ctx(1);
3054 let mut ufv = UnknownFieldsView::new();
3055 ufv.push_record(&buf[0..], 2, ctx).unwrap();
3056 // Non-adjacent record (the one at buf[2..4] was skipped): new span.
3057 assert_eq!(
3058 ufv.push_record(&buf[4..], 2, ctx),
3059 Err(crate::DecodeError::UnknownFieldLimitExceeded)
3060 );
3061 // Coalescing saves a span slot, not allowance: at zero remaining
3062 // even an adjacent record is rejected, keeping the decode-time
3063 // count equal to the count to_owned re-materializes.
3064 assert_eq!(
3065 ufv.push_record(&buf[2..], 2, ctx),
3066 Err(crate::DecodeError::UnknownFieldLimitExceeded)
3067 );
3068 }
3069
3070 #[test]
3071 fn push_record_charges_group_records_per_nested_field() {
3072 // One group record (field 1) holding two nested varint fields:
3073 // to_owned materializes three UnknownFields (group + 2 nested), so
3074 // decode must charge three slots.
3075 let buf: &[u8] = &[0x0b, 0x08, 0x00, 0x08, 0x01, 0x0c];
3076 let ctx = record_ctx(2);
3077 let mut ufv = UnknownFieldsView::new();
3078 assert_eq!(
3079 ufv.push_record(buf, buf.len(), ctx),
3080 Err(crate::DecodeError::UnknownFieldLimitExceeded)
3081 );
3082
3083 let ctx = record_ctx(3);
3084 let mut ufv = UnknownFieldsView::new();
3085 ufv.push_record(buf, buf.len(), ctx).unwrap();
3086 assert_eq!(ctx.remaining_unknown_fields(), 0, "group + 2 nested");
3087 let owned = ufv.to_owned().expect("decode allowance covers replay");
3088 assert_eq!(owned.iter().count(), 1, "one top-level group field");
3089 }
3090
3091 #[test]
3092 fn push_record_charges_nested_groups_recursively() {
3093 // group 1 { varint; group 2 { varint } } — four materializable
3094 // fields, so four slots.
3095 let buf: &[u8] = &[0x0b, 0x08, 0x00, 0x13, 0x08, 0x01, 0x14, 0x0c];
3096 let ctx = record_ctx(3);
3097 let mut ufv = UnknownFieldsView::new();
3098 assert_eq!(
3099 ufv.push_record(buf, buf.len(), ctx),
3100 Err(crate::DecodeError::UnknownFieldLimitExceeded)
3101 );
3102
3103 let ctx = record_ctx(4);
3104 let mut ufv = UnknownFieldsView::new();
3105 ufv.push_record(buf, buf.len(), ctx).unwrap();
3106 assert_eq!(ctx.remaining_unknown_fields(), 0);
3107 ufv.to_owned().expect("decode allowance covers replay");
3108 }
3109
3110 #[test]
3111 fn push_raw_disables_coalescing_for_next_record() {
3112 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01];
3113 let ctx = record_ctx(2);
3114 let mut ufv = UnknownFieldsView::new();
3115 ufv.push_raw(&buf[0..2]);
3116 // Adjacent on the wire, but push_raw cleared the tail, so this must
3117 // open a fresh span (a manual span has no trusted buffer position).
3118 ufv.push_record(&buf[2..], 2, ctx).unwrap();
3119 assert_eq!(ctx.remaining_unknown_fields(), 1);
3120 assert_eq!(ufv.encoded_len(), 4);
3121 }
3122
3123 #[test]
3124 fn push_record_rejects_span_past_tail_end() {
3125 let buf: &[u8] = &[0x08, 0x00];
3126 let ctx = record_ctx(1);
3127 let mut ufv = UnknownFieldsView::new();
3128 assert_eq!(
3129 ufv.push_record(buf, 3, ctx),
3130 Err(crate::DecodeError::UnexpectedEof)
3131 );
3132 }
3133
3134 #[test]
3135 fn coalesced_span_to_owned_parses_every_record() {
3136 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02];
3137 let ctx = record_ctx(3);
3138 let mut ufv = UnknownFieldsView::new();
3139 for i in 0..3 {
3140 ufv.push_record(&buf[2 * i..], 2, ctx).unwrap();
3141 }
3142 let owned = ufv.to_owned().unwrap();
3143 assert_eq!(owned.iter().count(), 3, "all records parsed");
3144 }
3145
3146 #[test]
3147 fn decode_time_allowance_always_covers_to_owned() {
3148 // The invariant push_record's accounting exists for: any run that
3149 // decodes within the allowance converts within the captured
3150 // allowance. Here the record count exactly exhausts the limit and
3151 // the run coalesces into one span.
3152 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02];
3153 let ctx = record_ctx(3);
3154 let mut ufv = UnknownFieldsView::new();
3155 for i in 0..3 {
3156 ufv.push_record(&buf[2 * i..], 2, ctx).unwrap();
3157 }
3158 assert_eq!(ufv.records_slice().len(), 1, "coalesced into one span");
3159 assert_eq!(ctx.remaining_unknown_fields(), 0, "limit exactly used");
3160 let owned = ufv.to_owned().expect("decode succeeded, so convert must");
3161 assert_eq!(owned.iter().count(), 3);
3162 }
3163
3164 #[test]
3165 fn to_owned_of_manual_view_uses_default_allowance() {
3166 // push_raw spans are never charged at decode time; to_owned grants
3167 // the default limit for them.
3168 let mut ufv = UnknownFieldsView::new();
3169 ufv.push_raw(&[0x08, 0x00]);
3170 let owned = ufv.to_owned().unwrap();
3171 assert_eq!(owned.iter().count(), 1);
3172 }
3173
3174 #[test]
3175 fn to_owned_covers_records_pushed_under_different_contexts() {
3176 // The replay budget is the accumulated charge total, not a snapshot
3177 // of any single context's remaining allowance — so a view merged
3178 // across decode passes with unrelated contexts still converts.
3179 let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02];
3180 let mut ufv = UnknownFieldsView::new();
3181 let tight = record_ctx(1);
3182 ufv.push_record(&buf[0..], 2, tight).unwrap();
3183 let fresh = record_ctx(2);
3184 ufv.push_record(&buf[2..], 2, fresh).unwrap();
3185 ufv.push_record(&buf[4..], 2, fresh).unwrap();
3186 let owned = ufv.to_owned().expect("every push succeeded");
3187 assert_eq!(owned.iter().count(), 3);
3188 }
3189
3190 #[test]
3191 fn to_owned_replays_deep_groups_decoded_under_raised_recursion_limit() {
3192 // Replay depth comes from the nesting tracked at decode time, not
3193 // the fixed RECURSION_LIMIT — a group nested deeper than the
3194 // default (decodable only under a raised recursion limit) must
3195 // still convert.
3196 let deep = crate::RECURSION_LIMIT as usize + 20;
3197 let mut buf = alloc::vec![0x0bu8; deep]; // StartGroup ×deep
3198 buf.resize(2 * deep, 0x0c); // EndGroup ×deep
3199 let ctx = record_ctx(deep);
3200 let mut ufv = UnknownFieldsView::new();
3201 ufv.push_record(&buf, buf.len(), ctx).unwrap();
3202 assert_eq!(ctx.remaining_unknown_fields(), 0, "one slot per group");
3203 ufv.to_owned().expect("decode succeeded, so convert must");
3204 }
3205
3206 #[test]
3207 fn to_owned_of_malformed_manual_span_fails() {
3208 // The replay error path stays live for manually built views: a
3209 // push_raw span that is not a complete record fails to parse.
3210 let mut ufv = UnknownFieldsView::new();
3211 ufv.push_raw(&[0xFF]);
3212 assert!(ufv.to_owned().is_err());
3213 }
3214
3215 #[test]
3216 fn to_owned_of_manual_flood_over_default_limit_fails() {
3217 // The replay limit stays live for manually built views: push_raw
3218 // spans get the default allowance, no more — the memory-
3219 // amplification bound survives even though wire-decoded views
3220 // cannot hit it (decode charges the allowance up front).
3221 let n = crate::DEFAULT_UNKNOWN_FIELD_LIMIT + 1;
3222 let mut buf = alloc::vec::Vec::with_capacity(2 * n);
3223 for _ in 0..n {
3224 buf.extend_from_slice(&[0x08, 0x00]);
3225 }
3226 let mut ufv = UnknownFieldsView::new();
3227 ufv.push_raw(&buf);
3228 assert_eq!(
3229 ufv.to_owned(),
3230 Err(crate::DecodeError::UnknownFieldLimitExceeded)
3231 );
3232 }
3233
3234 #[test]
3235 fn repeated_view_reserve_grows_capacity() {
3236 let mut rv = RepeatedView::<u32>::default();
3237 rv.reserve(64);
3238 assert!(rv.elements.capacity() >= 64);
3239 // Reserve must not produce visible elements.
3240 assert!(rv.is_empty());
3241 // reserve(0) is a no-op and must not panic.
3242 rv.reserve(0);
3243 // Reserve after pushes adds capacity above current len.
3244 rv.push(1);
3245 rv.push(2);
3246 rv.reserve(100);
3247 assert_eq!(rv.len(), 2);
3248 assert!(rv.elements.capacity() >= 102);
3249 // Subsequent reserve calls must not corrupt the existing elements.
3250 let collected: alloc::vec::Vec<_> = rv.iter().copied().collect();
3251 assert_eq!(collected, alloc::vec![1, 2]);
3252 }
3253
3254 #[test]
3255 fn repeated_view_with_borrowed_str() {
3256 let data = alloc::string::String::from("hello world");
3257 let parts: alloc::vec::Vec<&str> = data.split_whitespace().collect();
3258 let rv = RepeatedView::new(parts);
3259 assert_eq!(rv.len(), 2);
3260 assert_eq!(rv[0], "hello");
3261 assert_eq!(rv[1], "world");
3262 }
3263
3264 #[test]
3265 fn repeated_view_into_iter_by_ref() {
3266 let rv = RepeatedView::new(alloc::vec![1, 2, 3]);
3267 let sum: i32 = (&rv).into_iter().sum();
3268 assert_eq!(sum, 6);
3269 // `for x in &rv` syntax works:
3270 let mut count = 0;
3271 for _ in &rv {
3272 count += 1;
3273 }
3274 assert_eq!(count, 3);
3275 }
3276
3277 #[test]
3278 fn repeated_view_into_iter_by_value() {
3279 let rv = RepeatedView::new(alloc::vec![
3280 alloc::string::String::from("a"),
3281 alloc::string::String::from("b"),
3282 ]);
3283 let collected: alloc::vec::Vec<_> = rv.into_iter().collect();
3284 assert_eq!(collected, alloc::vec!["a".to_string(), "b".to_string()]);
3285 }
3286
3287 // ── MapView ──────────────────────────────────────────────────────────
3288
3289 #[test]
3290 fn map_view_get_with_borrow() {
3291 let mut mv = MapView::<&str, i32>::default();
3292 mv.push("apples", 3);
3293 mv.push("bananas", 5);
3294
3295 // Ergonomic: get("key") works via Borrow<str> on &str
3296 assert_eq!(mv.get("apples"), Some(&3));
3297 assert_eq!(mv.get("bananas"), Some(&5));
3298 assert_eq!(mv.get("oranges"), None);
3299
3300 // Old style still works
3301 assert_eq!(mv.get(&"apples"), Some(&3));
3302 }
3303
3304 #[test]
3305 fn map_view_contains_key_with_borrow() {
3306 let mut mv = MapView::<&str, i32>::default();
3307 mv.push("key", 1);
3308
3309 assert!(mv.contains_key("key"));
3310 assert!(!mv.contains_key("missing"));
3311 }
3312
3313 #[test]
3314 fn map_view_get_last_write_wins() {
3315 let mut mv = MapView::<&str, i32>::default();
3316 mv.push("x", 1);
3317 mv.push("x", 2);
3318 assert_eq!(mv.get("x"), Some(&2));
3319 }
3320
3321 #[test]
3322 fn map_view_iter_unique_dedups_last_write_wins() {
3323 let mut mv = MapView::<&str, i32>::default();
3324 mv.push("a", 1);
3325 mv.push("b", 2);
3326 mv.push("a", 3); // duplicate key — only this entry survives for "a"
3327 mv.push("c", 4);
3328 mv.push("b", 5); // duplicate key — only this entry survives for "b"
3329
3330 assert_eq!(mv.len(), 5, "iter() preserves all wire entries");
3331 assert_eq!(mv.len_unique(), 3, "len_unique() counts distinct keys");
3332
3333 let unique: alloc::vec::Vec<_> = mv.iter_unique().collect();
3334 assert_eq!(unique, [&("a", 3), &("c", 4), &("b", 5)]);
3335 }
3336
3337 #[test]
3338 fn map_view_iter_unique_all_duplicates() {
3339 let mut mv = MapView::<&str, i32>::default();
3340 mv.push("a", 1);
3341 mv.push("a", 2);
3342 mv.push("a", 3);
3343 assert_eq!(mv.len_unique(), 1);
3344 assert_eq!(
3345 mv.iter_unique().collect::<alloc::vec::Vec<_>>(),
3346 [&("a", 3)]
3347 );
3348 }
3349
3350 #[test]
3351 fn map_view_iter_unique_no_duplicates() {
3352 let mut mv = MapView::<i32, &str>::default();
3353 mv.push(1, "x");
3354 mv.push(2, "y");
3355 assert_eq!(mv.len_unique(), 2);
3356 assert_eq!(
3357 mv.iter_unique().collect::<alloc::vec::Vec<_>>(),
3358 [&(1, "x"), &(2, "y")]
3359 );
3360 }
3361
3362 #[test]
3363 fn map_view_iter_unique_empty() {
3364 let mv = MapView::<&str, i32>::default();
3365 assert_eq!(mv.len_unique(), 0);
3366 assert_eq!(mv.iter_unique().count(), 0);
3367 }
3368
3369 #[test]
3370 fn map_view_keys_and_values() {
3371 let mut mv = MapView::<&str, i32>::default();
3372 mv.push("a", 1);
3373 mv.push("b", 2);
3374 mv.push("c", 3);
3375
3376 let keys: alloc::vec::Vec<_> = mv.keys().copied().collect();
3377 assert_eq!(keys, alloc::vec!["a", "b", "c"]);
3378
3379 let values: alloc::vec::Vec<_> = mv.values().copied().collect();
3380 assert_eq!(values, alloc::vec![1, 2, 3]);
3381 }
3382
3383 #[test]
3384 fn map_view_keys_and_values_empty() {
3385 let mv = MapView::<&str, i32>::default();
3386 assert_eq!(mv.keys().count(), 0);
3387 assert_eq!(mv.values().count(), 0);
3388 }
3389
3390 #[test]
3391 fn map_view_into_iter_collect_to_hashmap() {
3392 let mut mv = MapView::<&str, i32>::default();
3393 mv.push("a", 1);
3394 mv.push("b", 2);
3395 mv.push("a", 3); // duplicate — last-write-wins on collect
3396 let m: crate::__private::HashMap<&str, i32> = mv.into_iter().collect();
3397 assert_eq!(m.len(), 2);
3398 assert_eq!(m.get("a"), Some(&3)); // last value kept
3399 assert_eq!(m.get("b"), Some(&2));
3400 }
3401
3402 // ── bytes_from_source ────────────────────────────────────────────────
3403
3404 #[test]
3405 fn bytes_from_source_none_copies() {
3406 let data: &[u8] = b"hello";
3407 let out = bytes_from_source(None, data);
3408 assert_eq!(&out[..], data);
3409 assert_ne!(out.as_ptr(), data.as_ptr()); // distinct allocation
3410 }
3411
3412 #[test]
3413 fn bytes_from_source_some_within_is_slice_ref() {
3414 let parent = Bytes::copy_from_slice(b"hello world");
3415 let slice = &parent[6..11];
3416 let out = bytes_from_source(Some(&parent), slice);
3417 assert_eq!(&out[..], b"world");
3418 // slice_ref shares the same backing storage — same pointer.
3419 assert_eq!(out.as_ptr(), slice.as_ptr());
3420 }
3421
3422 #[test]
3423 fn bytes_from_source_some_outside_falls_back_to_copy() {
3424 let parent = Bytes::copy_from_slice(b"hello");
3425 let outside: &[u8] = b"world"; // static, not in `parent`
3426 let out = bytes_from_source(Some(&parent), outside);
3427 assert_eq!(&out[..], b"world");
3428 assert_ne!(out.as_ptr(), outside.as_ptr());
3429 }
3430
3431 #[test]
3432 fn bytes_from_source_empty_returns_new() {
3433 let parent = Bytes::copy_from_slice(b"hello");
3434 assert!(bytes_from_source(Some(&parent), &[]).is_empty());
3435 assert!(bytes_from_source(None, &[]).is_empty());
3436 }
3437
3438 #[test]
3439 fn bytes_from_source_full_range() {
3440 let parent = Bytes::copy_from_slice(b"hello");
3441 let out = bytes_from_source(Some(&parent), &parent[..]);
3442 assert_eq!(out.as_ptr(), parent.as_ptr());
3443 assert_eq!(out.len(), parent.len());
3444 }
3445
3446 // ── UnknownFieldsView ────────────────────────────────────────────────
3447
3448 #[test]
3449 fn unknown_fields_view_new_is_empty() {
3450 let uf = UnknownFieldsView::new();
3451 assert!(uf.is_empty());
3452 assert_eq!(uf.encoded_len(), 0);
3453 }
3454
3455 #[test]
3456 fn unknown_fields_view_push_raw_and_encoded_len() {
3457 let mut uf = UnknownFieldsView::new();
3458 uf.push_raw(&[0x08, 0x01]); // field 1, varint 1
3459 uf.push_raw(&[0x10, 0x02]); // field 2, varint 2
3460 assert!(!uf.is_empty());
3461 assert_eq!(uf.encoded_len(), 4);
3462 }
3463
3464 #[test]
3465 fn unknown_fields_view_to_owned_single_field() {
3466 // Build a valid unknown field: tag for field 99, varint wire type,
3467 // value 42. Tag = (99 << 3) | 0 = 792 = varint bytes [0x98, 0x06].
3468 let span: &[u8] = &[0x98, 0x06, 0x2A];
3469 let mut uf = UnknownFieldsView::new();
3470 uf.push_raw(span);
3471
3472 let owned = uf.to_owned().expect("valid wire data");
3473 assert_eq!(owned.len(), 1);
3474 let field = owned.iter().next().unwrap();
3475 assert_eq!(field.number, 99);
3476 assert_eq!(
3477 field.data,
3478 crate::unknown_fields::UnknownFieldData::Varint(42)
3479 );
3480 }
3481
3482 #[test]
3483 fn unknown_fields_view_to_owned_multiple_fields() {
3484 let mut uf = UnknownFieldsView::new();
3485 // Field 1, varint, value 7: tag = (1<<3)|0 = 0x08, value = 0x07
3486 uf.push_raw(&[0x08, 0x07]);
3487 // Field 2, fixed32, value 0x01020304:
3488 // tag = (2<<3)|5 = 0x15, then 4 LE bytes
3489 uf.push_raw(&[0x15, 0x04, 0x03, 0x02, 0x01]);
3490
3491 let owned = uf.to_owned().expect("valid wire data");
3492 assert_eq!(owned.len(), 2);
3493
3494 let mut it = owned.iter();
3495 let f1 = it.next().unwrap();
3496 assert_eq!(f1.number, 1);
3497 assert_eq!(f1.data, crate::unknown_fields::UnknownFieldData::Varint(7));
3498
3499 let f2 = it.next().unwrap();
3500 assert_eq!(f2.number, 2);
3501 assert_eq!(
3502 f2.data,
3503 crate::unknown_fields::UnknownFieldData::Fixed32(0x01020304)
3504 );
3505 }
3506
3507 #[test]
3508 fn unknown_fields_view_to_owned_malformed_returns_error() {
3509 // A truncated tag (high continuation bit, then EOF).
3510 let mut uf = UnknownFieldsView::new();
3511 uf.push_raw(&[0x80]);
3512 assert!(uf.to_owned().is_err());
3513 }
3514
3515 #[test]
3516 fn unknown_fields_view_to_owned_includes_synthetic_varint_records() {
3517 let ctx = record_ctx(1);
3518 let mut uf = UnknownFieldsView::new();
3519 uf.push_varint(3, 99, ctx).unwrap();
3520 assert_eq!(ctx.remaining_unknown_fields(), 0);
3521
3522 let owned = uf.to_owned().expect("owned unknown field");
3523 let fields: Vec<_> = owned.iter().collect();
3524 assert_eq!(fields.len(), 1);
3525 assert_eq!(fields[0].number, 3);
3526 assert!(matches!(
3527 fields[0].data,
3528 crate::UnknownFieldData::Varint(99)
3529 ));
3530 }
3531
3532 // ── OwnedView ──────────────────────────────────────────────────────
3533
3534 // Minimal types to test OwnedView without depending on generated code.
3535
3536 use crate::message::Message;
3537
3538 /// A trivial "message" for the owned side of the view contract.
3539 #[derive(Clone, Debug, Default, PartialEq)]
3540 struct SimpleMessage {
3541 pub id: i32,
3542 pub name: alloc::string::String,
3543 }
3544
3545 impl crate::DefaultInstance for SimpleMessage {
3546 fn default_instance() -> &'static Self {
3547 static INST: crate::__private::OnceBox<SimpleMessage> =
3548 crate::__private::OnceBox::new();
3549 INST.get_or_init(|| alloc::boxed::Box::new(SimpleMessage::default()))
3550 }
3551 }
3552
3553 impl crate::Message for SimpleMessage {
3554 fn compute_size(&self, _cache: &mut crate::SizeCache) -> u32 {
3555 let mut size = 0u32;
3556 if self.id != 0 {
3557 size += 1 + crate::types::int32_encoded_len(self.id) as u32;
3558 }
3559 if !self.name.is_empty() {
3560 size += 1 + crate::types::string_encoded_len(&self.name) as u32;
3561 }
3562 size
3563 }
3564
3565 fn write_to(&self, _cache: &mut crate::SizeCache, buf: &mut impl crate::EncodeSink) {
3566 if self.id != 0 {
3567 crate::encoding::Tag::new(1, crate::encoding::WireType::Varint).encode(buf);
3568 crate::types::encode_int32(self.id, buf);
3569 }
3570 if !self.name.is_empty() {
3571 crate::encoding::Tag::new(2, crate::encoding::WireType::LengthDelimited)
3572 .encode(buf);
3573 crate::types::encode_string(&self.name, buf);
3574 }
3575 }
3576
3577 fn merge_field(
3578 &mut self,
3579 tag: crate::encoding::Tag,
3580 buf: &mut impl bytes::Buf,
3581 _ctx: crate::DecodeContext<'_>,
3582 ) -> Result<(), DecodeError> {
3583 match tag.field_number() {
3584 1 => self.id = crate::types::decode_int32(buf)?,
3585 2 => crate::types::merge_string(&mut self.name, buf)?,
3586 _ => crate::encoding::skip_field(tag, buf)?,
3587 }
3588 Ok(())
3589 }
3590
3591 fn clear(&mut self) {
3592 self.id = 0;
3593 self.name.clear();
3594 }
3595 }
3596
3597 /// A zero-copy view of `SimpleMessage`. Borrows `name` as `&str`.
3598 #[derive(Clone, Debug, Default, PartialEq)]
3599 struct SimpleMessageView<'a> {
3600 pub id: i32,
3601 pub name: &'a str,
3602 }
3603
3604 // Via the exported macro, which doubles as its unit test.
3605 crate::impl_view_reborrow!(SimpleMessageView);
3606
3607 impl<'a> MessageView<'a> for SimpleMessageView<'a> {
3608 type Owned = SimpleMessage;
3609 fn merge_view_field(
3610 &mut self,
3611 _tag: crate::encoding::Tag,
3612 cur: &'a [u8],
3613 _before_tag: &'a [u8],
3614 _ctx: crate::DecodeContext<'_>,
3615 ) -> Result<&'a [u8], DecodeError> {
3616 Ok(cur)
3617 }
3618
3619 fn decode_view(buf: &'a [u8]) -> Result<Self, DecodeError> {
3620 let mut view = SimpleMessageView::default();
3621 let mut cursor: &'a [u8] = buf;
3622 while !cursor.is_empty() {
3623 let tag = crate::encoding::Tag::decode(&mut cursor)?;
3624 match tag.field_number() {
3625 1 => view.id = crate::types::decode_int32(&mut cursor)?,
3626 2 => view.name = crate::types::borrow_str(&mut cursor)?,
3627 _ => crate::encoding::skip_field(tag, &mut cursor)?,
3628 }
3629 }
3630 Ok(view)
3631 }
3632
3633 fn to_owned_message(&self) -> Result<SimpleMessage, DecodeError> {
3634 Ok(SimpleMessage {
3635 id: self.id,
3636 name: self.name.into(),
3637 })
3638 }
3639 }
3640
3641 impl<'a> ViewEncode<'a> for SimpleMessageView<'a> {
3642 fn compute_size(&self, _cache: &mut crate::SizeCache) -> u32 {
3643 let mut size = 0u32;
3644 if self.id != 0 {
3645 size += 1 + crate::types::int32_encoded_len(self.id) as u32;
3646 }
3647 if !self.name.is_empty() {
3648 size += 1 + crate::types::string_encoded_len(self.name) as u32;
3649 }
3650 size
3651 }
3652
3653 fn write_to(&self, _cache: &mut crate::SizeCache, buf: &mut impl crate::EncodeSink) {
3654 if self.id != 0 {
3655 crate::encoding::Tag::new(1, crate::encoding::WireType::Varint).encode(buf);
3656 crate::types::encode_int32(self.id, buf);
3657 }
3658 if !self.name.is_empty() {
3659 crate::encoding::Tag::new(2, crate::encoding::WireType::LengthDelimited)
3660 .encode(buf);
3661 crate::types::encode_string(self.name, buf);
3662 }
3663 }
3664 }
3665
3666 /// Encode a SimpleMessage to Bytes for testing.
3667 fn encode_simple(id: i32, name: &str) -> Bytes {
3668 let msg = SimpleMessage {
3669 id,
3670 name: name.into(),
3671 };
3672 Bytes::from(msg.encode_to_vec())
3673 }
3674
3675 #[test]
3676 fn owned_view_decode_and_reborrow() {
3677 let bytes = encode_simple(42, "hello");
3678 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3679
3680 // Field access via reborrow — the borrow is tied to `view`.
3681 assert_eq!(view.reborrow().id, 42);
3682 assert_eq!(view.reborrow().name, "hello");
3683 }
3684
3685 #[test]
3686 fn owned_view_to_owned_message() {
3687 let bytes = encode_simple(7, "world");
3688 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3689 let owned = view.to_owned_message();
3690
3691 assert_eq!(owned.id, 7);
3692 assert_eq!(owned.name, "world");
3693 }
3694
3695 /// A view whose `to_owned_message` breaks the wire-decode ⇒ convert
3696 /// contract, standing in for a buggy hand-written impl.
3697 #[derive(Clone, Debug, Default, PartialEq)]
3698 struct ContractBreakingView<'a>(core::marker::PhantomData<&'a ()>);
3699
3700 crate::impl_view_reborrow!(ContractBreakingView);
3701
3702 impl<'a> MessageView<'a> for ContractBreakingView<'a> {
3703 type Owned = SimpleMessage;
3704 fn merge_view_field(
3705 &mut self,
3706 _tag: crate::encoding::Tag,
3707 cur: &'a [u8],
3708 _before_tag: &'a [u8],
3709 _ctx: crate::DecodeContext<'_>,
3710 ) -> Result<&'a [u8], DecodeError> {
3711 Ok(cur)
3712 }
3713 fn decode_view(_buf: &'a [u8]) -> Result<Self, DecodeError> {
3714 Ok(Self(core::marker::PhantomData))
3715 }
3716 fn to_owned_message(&self) -> Result<SimpleMessage, DecodeError> {
3717 Err(DecodeError::UnknownFieldLimitExceeded)
3718 }
3719 }
3720
3721 #[test]
3722 #[should_panic(expected = "wire-decode => convert contract")]
3723 fn owned_view_panics_when_impl_breaks_convert_contract() {
3724 // The infallible signature rests on the decode ⇒ convert invariant;
3725 // an impl that violates it must fail loudly, not silently.
3726 let view = OwnedView::<ContractBreakingView<'static>>::decode(Bytes::new()).unwrap();
3727 let _ = view.to_owned_message();
3728 }
3729
3730 #[test]
3731 fn owned_view_debug_delegates_to_view() {
3732 let bytes = encode_simple(1, "test");
3733 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3734 let debug = alloc::format!("{:?}", view);
3735 assert!(debug.contains("test"));
3736 assert!(debug.contains("1"));
3737 }
3738
3739 #[test]
3740 fn owned_view_bytes_accessor() {
3741 let bytes = encode_simple(5, "data");
3742 let original_len = bytes.len();
3743 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3744
3745 assert_eq!(view.bytes().len(), original_len);
3746 }
3747
3748 #[test]
3749 fn owned_view_into_bytes_recovers_buffer() {
3750 let bytes = encode_simple(99, "recover");
3751 let expected = bytes.clone();
3752 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3753 let recovered = view.into_bytes();
3754
3755 assert_eq!(recovered, expected);
3756 }
3757
3758 #[test]
3759 fn owned_view_decode_invalid_data_returns_error() {
3760 // Truncated varint
3761 let bad = Bytes::from_static(&[0x08, 0x80]);
3762 let result = OwnedView::<SimpleMessageView<'static>>::decode(bad);
3763 assert!(result.is_err());
3764 }
3765
3766 #[test]
3767 fn owned_view_empty_message() {
3768 let bytes = Bytes::from_static(&[]);
3769 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3770 assert_eq!(view.reborrow().id, 0);
3771 assert_eq!(view.reborrow().name, "");
3772 }
3773
3774 #[test]
3775 fn owned_view_is_send_and_sync() {
3776 fn assert_send_sync<T: Send + Sync>() {}
3777 assert_send_sync::<OwnedView<SimpleMessageView<'static>>>();
3778 }
3779
3780 #[test]
3781 fn owned_view_from_owned_roundtrips() {
3782 let msg = SimpleMessage {
3783 id: 99,
3784 name: "roundtrip".into(),
3785 };
3786 let view = OwnedView::<SimpleMessageView<'static>>::from_owned(&msg).expect("from_owned");
3787 assert_eq!(view.reborrow().id, 99);
3788 assert_eq!(view.reborrow().name, "roundtrip");
3789
3790 let back = view.to_owned_message();
3791 assert_eq!(back, msg);
3792 }
3793
3794 #[test]
3795 fn owned_view_decode_with_options() {
3796 let bytes = encode_simple(42, "opts");
3797 let opts = crate::DecodeOptions::new().with_max_message_size(1024);
3798 let view =
3799 OwnedView::<SimpleMessageView<'static>>::decode_with_options(bytes, &opts).unwrap();
3800 assert_eq!(view.reborrow().id, 42);
3801 assert_eq!(view.reborrow().name, "opts");
3802 }
3803
3804 #[test]
3805 fn owned_view_decode_with_options_rejects_oversized() {
3806 let bytes = encode_simple(42, "too large");
3807 let opts = crate::DecodeOptions::new().with_max_message_size(2);
3808 let result = OwnedView::<SimpleMessageView<'static>>::decode_with_options(bytes, &opts);
3809 assert!(result.is_err());
3810 }
3811
3812 #[test]
3813 fn owned_view_clone_survives_original_drop() {
3814 let bytes = encode_simple(42, "cloned");
3815 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3816 let cloned = view.clone();
3817 drop(view); // drop original — clone must still be valid
3818 assert_eq!(cloned.reborrow().id, 42);
3819 assert_eq!(cloned.reborrow().name, "cloned");
3820 }
3821
3822 #[test]
3823 fn owned_view_clone_equality() {
3824 let bytes = encode_simple(42, "eq");
3825 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3826 let cloned = view.clone();
3827 assert_eq!(view, cloned);
3828 }
3829
3830 #[test]
3831 fn owned_view_eq_same_data() {
3832 let a = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(1, "x")).unwrap();
3833 let b = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(1, "x")).unwrap();
3834 assert_eq!(a, b);
3835 }
3836
3837 #[test]
3838 fn owned_view_ne_different_data() {
3839 let a = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(1, "x")).unwrap();
3840 let b = OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(2, "y")).unwrap();
3841 assert_ne!(a, b);
3842 }
3843
3844 #[test]
3845 fn owned_view_into_bytes_after_clone() {
3846 let bytes = encode_simple(42, "test");
3847 let expected = bytes.clone();
3848 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3849 let cloned = view.clone();
3850 drop(view); // drop original first
3851 let recovered = cloned.into_bytes();
3852 assert_eq!(recovered, expected);
3853 }
3854
3855 // The `owned_view_drop*` and `owned_view_into_bytes*` names below are
3856 // the filter for the `Miri (OwnedView soundness)` CI step; a renamed or
3857 // differently named test silently leaves that gate.
3858 #[test]
3859 fn owned_view_drop_count() {
3860 use core::sync::atomic::{AtomicUsize, Ordering};
3861
3862 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
3863
3864 /// A wrapper view that counts drops.
3865 struct DropCountingView<'a> {
3866 inner: SimpleMessageView<'a>,
3867 }
3868
3869 impl Drop for DropCountingView<'_> {
3870 fn drop(&mut self) {
3871 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
3872 }
3873 }
3874
3875 impl<'a> MessageView<'a> for DropCountingView<'a> {
3876 type Owned = SimpleMessage;
3877 fn merge_view_field(
3878 &mut self,
3879 _tag: crate::encoding::Tag,
3880 cur: &'a [u8],
3881 _before_tag: &'a [u8],
3882 _ctx: crate::DecodeContext<'_>,
3883 ) -> Result<&'a [u8], DecodeError> {
3884 Ok(cur)
3885 }
3886
3887 fn decode_view(buf: &'a [u8]) -> Result<Self, DecodeError> {
3888 Ok(DropCountingView {
3889 inner: SimpleMessageView::decode_view(buf)?,
3890 })
3891 }
3892
3893 fn to_owned_message(&self) -> Result<SimpleMessage, DecodeError> {
3894 self.inner.to_owned_message()
3895 }
3896 }
3897
3898 // Test normal drop: view drops exactly once.
3899 DROP_COUNT.store(0, Ordering::SeqCst);
3900 {
3901 let bytes = encode_simple(1, "drop");
3902 let _view = OwnedView::<DropCountingView<'static>>::decode(bytes).unwrap();
3903 }
3904 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1, "normal drop");
3905
3906 // Test into_bytes: view drops exactly once.
3907 DROP_COUNT.store(0, Ordering::SeqCst);
3908 {
3909 let bytes = encode_simple(2, "into");
3910 let view = OwnedView::<DropCountingView<'static>>::decode(bytes).unwrap();
3911 let _bytes = view.into_bytes();
3912 }
3913 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1, "into_bytes drop");
3914 }
3915
3916 /// Dropping an `OwnedView` that arrived as a by-value argument frees the
3917 /// buffer inside a call that still holds the view's forged `'static`
3918 /// borrows. Under Miri's field retagging that is UB unless the view is
3919 /// behind `MaybeDangling`, so this is a Miri regression test (it cannot
3920 /// fail under plain `cargo test`).
3921 #[test]
3922 fn owned_view_drop_by_value_argument() {
3923 fn consume<V>(v: OwnedView<V>) {
3924 drop(v);
3925 }
3926 let view =
3927 OwnedView::<SimpleMessageView<'static>>::decode(encode_simple(4, "arg")).unwrap();
3928 consume(view);
3929 }
3930
3931 /// A `V::drop` that panics during `into_bytes` must not drop the view a
3932 /// second time on the way out.
3933 #[cfg(feature = "std")]
3934 #[test]
3935 fn owned_view_into_bytes_unwinding_view_drop_runs_once() {
3936 use core::sync::atomic::{AtomicUsize, Ordering};
3937
3938 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
3939
3940 /// Panics on its first drop only: a re-entrant second drop must not
3941 /// panic again, or the unwind would abort the process instead of
3942 /// reaching the assertion below.
3943 struct PanicOnFirstDropView<'a> {
3944 inner: SimpleMessageView<'a>,
3945 /// A heap allocation, so that a regression to dropping the view
3946 /// twice is a real double free (which Miri flags), not just a
3947 /// count of two.
3948 _owned: alloc::string::String,
3949 }
3950
3951 impl Drop for PanicOnFirstDropView<'_> {
3952 fn drop(&mut self) {
3953 if DROP_COUNT.fetch_add(1, Ordering::SeqCst) == 0 {
3954 panic!("first drop");
3955 }
3956 }
3957 }
3958
3959 impl<'a> MessageView<'a> for PanicOnFirstDropView<'a> {
3960 type Owned = SimpleMessage;
3961 fn merge_view_field(
3962 &mut self,
3963 _tag: crate::encoding::Tag,
3964 cur: &'a [u8],
3965 _before_tag: &'a [u8],
3966 _ctx: crate::DecodeContext<'_>,
3967 ) -> Result<&'a [u8], DecodeError> {
3968 Ok(cur)
3969 }
3970
3971 fn decode_view(buf: &'a [u8]) -> Result<Self, DecodeError> {
3972 Ok(PanicOnFirstDropView {
3973 inner: SimpleMessageView::decode_view(buf)?,
3974 _owned: alloc::string::String::from("owned"),
3975 })
3976 }
3977
3978 fn to_owned_message(&self) -> Result<SimpleMessage, DecodeError> {
3979 self.inner.to_owned_message()
3980 }
3981 }
3982
3983 DROP_COUNT.store(0, Ordering::SeqCst);
3984 let bytes = encode_simple(3, "unwind");
3985 let view = OwnedView::<PanicOnFirstDropView<'static>>::decode(bytes).unwrap();
3986 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| view.into_bytes()));
3987 assert!(result.is_err(), "the view's panic must propagate");
3988 assert_eq!(
3989 DROP_COUNT.load(Ordering::SeqCst),
3990 1,
3991 "view dropped exactly once"
3992 );
3993 }
3994
3995 #[test]
3996 fn owned_view_name_borrows_from_bytes_buffer() {
3997 let bytes = encode_simple(42, "borrowed");
3998 let view = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
3999 let buf = view.bytes();
4000 let buf_start = buf.as_ptr() as usize;
4001 let buf_end = buf_start + buf.len();
4002 let name_ptr = view.reborrow().name.as_ptr() as usize;
4003 assert!(
4004 (buf_start..buf_end).contains(&name_ptr),
4005 "view name should point into the Bytes buffer"
4006 );
4007 }
4008
4009 #[test]
4010 fn owned_view_concurrent_read() {
4011 use alloc::sync::Arc;
4012
4013 let bytes = encode_simple(42, "concurrent");
4014 let view = Arc::new(OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap());
4015 let handles: alloc::vec::Vec<_> = (0..4)
4016 .map(|_| {
4017 let v = Arc::clone(&view);
4018 std::thread::spawn(move || {
4019 assert_eq!(v.reborrow().id, 42);
4020 assert_eq!(v.reborrow().name, "concurrent");
4021 })
4022 })
4023 .collect();
4024 for h in handles {
4025 h.join().unwrap();
4026 }
4027 }
4028
4029 #[test]
4030 fn owned_view_from_parts_roundtrip() {
4031 let bytes = encode_simple(42, "parts");
4032 // Decode a view from the bytes, then wrap via from_parts.
4033 // SAFETY: `view` was decoded from `bytes`.
4034 let view = unsafe {
4035 let slice: &'static [u8] = core::mem::transmute::<&[u8], &'static [u8]>(&bytes);
4036 let decoded = SimpleMessageView::decode_view(slice).unwrap();
4037 OwnedView::<SimpleMessageView<'static>>::from_parts(bytes, decoded)
4038 };
4039 assert_eq!(view.reborrow().id, 42);
4040 assert_eq!(view.reborrow().name, "parts");
4041 }
4042
4043 // ── ViewReborrow / OwnedView::reborrow ───────────────────────────────
4044
4045 #[test]
4046 fn reborrow_fields_match_original() {
4047 let bytes = encode_simple(7, "hello");
4048 let owned = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
4049 let reborrowed: &SimpleMessageView<'_> = owned.reborrow();
4050 assert_eq!(reborrowed.id, 7);
4051 assert_eq!(reborrowed.name, "hello");
4052 // The reborrowed &str must point into the Bytes buffer, not a copy.
4053 let buf_start = owned.bytes().as_ptr() as usize;
4054 let buf_end = buf_start + owned.bytes().len();
4055 assert!((buf_start..buf_end).contains(&(reborrowed.name.as_ptr() as usize)));
4056 }
4057
4058 #[test]
4059 fn reborrow_does_not_consume_owned_view() {
4060 let bytes = encode_simple(1, "world");
4061 let owned = OwnedView::<SimpleMessageView<'static>>::decode(bytes).unwrap();
4062 let r1: &SimpleMessageView<'_> = owned.reborrow();
4063 let r2: &SimpleMessageView<'_> = owned.reborrow();
4064 assert_eq!(r1.name, r2.name);
4065 // `owned` still usable here
4066 assert_eq!(owned.reborrow().name, "world");
4067 }
4068 // ── Lazy views ───────────────────────────────────────────────────────
4069
4070 /// Hand-written lazy view of `SimpleMessage`, shaped like generated
4071 /// `FooLazyView` code: scalars borrowed, one flat scan, fragment merge.
4072 #[derive(Clone, Debug, Default, PartialEq)]
4073 struct SimpleLazyView<'a> {
4074 pub id: i32,
4075 pub name: &'a str,
4076 }
4077
4078 impl<'a> LazyMessageView<'a> for SimpleLazyView<'a> {
4079 type Owned = SimpleMessage;
4080
4081 fn decode_lazy(buf: &'a [u8]) -> Result<Self, DecodeError> {
4082 let limit = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
4083 Self::decode_lazy_with_ctx(
4084 buf,
4085 crate::DecodeContext::new(crate::RECURSION_LIMIT, &limit),
4086 )
4087 }
4088
4089 fn decode_lazy_with_ctx(
4090 buf: &'a [u8],
4091 ctx: crate::DecodeContext<'_>,
4092 ) -> Result<Self, DecodeError> {
4093 let mut view = SimpleLazyView::default();
4094 view.merge_lazy(buf, ctx)?;
4095 Ok(view)
4096 }
4097
4098 fn merge_lazy(
4099 &mut self,
4100 buf: &'a [u8],
4101 ctx: crate::DecodeContext<'_>,
4102 ) -> Result<(), DecodeError> {
4103 let mut cursor: &'a [u8] = buf;
4104 while !cursor.is_empty() {
4105 let tag = crate::encoding::Tag::decode(&mut cursor)?;
4106 match tag.field_number() {
4107 1 => self.id = crate::types::decode_int32(&mut cursor)?,
4108 2 => self.name = crate::types::borrow_str(&mut cursor)?,
4109 _ => crate::encoding::skip_field_depth(tag, &mut cursor, ctx.depth())?,
4110 }
4111 }
4112 Ok(())
4113 }
4114
4115 fn to_owned_message(&self) -> Result<SimpleMessage, DecodeError> {
4116 Ok(SimpleMessage {
4117 id: self.id,
4118 name: self.name.into(),
4119 })
4120 }
4121 }
4122
4123 fn full_budget_ctx(cell: &core::cell::Cell<usize>) -> crate::DecodeContext<'_> {
4124 crate::DecodeContext::new(crate::RECURSION_LIMIT, cell)
4125 }
4126
4127 #[test]
4128 fn lazy_message_field_view_decodes_on_access() {
4129 let bytes = encode_simple(42, "lazy");
4130 let unset = LazyMessageFieldView::<SimpleLazyView<'_>>::unset();
4131 assert!(unset.is_unset());
4132 assert!(unset.fragments().is_empty());
4133 assert!(unset.get().unwrap().is_none());
4134 assert_eq!(unset.get_or_default().unwrap(), SimpleLazyView::default());
4135
4136 let lazy = LazyMessageFieldView::<SimpleLazyView<'_>>::from_bytes(&bytes);
4137 assert!(lazy.is_set());
4138 assert_eq!(lazy.fragments(), &[&bytes[..]]);
4139 let v = lazy.get().unwrap().expect("set");
4140 assert_eq!((v.id, v.name), (42, "lazy"));
4141 // Re-decodes each call (no cache).
4142 assert_eq!(lazy.get().unwrap().unwrap().id, 42);
4143 assert_eq!(v.to_owned_message().unwrap().name, "lazy");
4144 }
4145
4146 #[test]
4147 fn lazy_message_field_view_merges_fragments() {
4148 // A singular message field split across wire occurrences must merge:
4149 // fragment 1 sets `name`, fragment 2 sets `id`; the merged view has
4150 // both, matching the eager/owned decoders.
4151 let frag1 = encode_simple(0, "from-frag-1");
4152 let frag2 = encode_simple(7, "");
4153 let cell = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
4154
4155 let mut lazy = LazyMessageFieldView::<SimpleLazyView<'_>>::unset();
4156 lazy.push_fragment(&frag1, full_budget_ctx(&cell));
4157 assert_eq!(lazy.fragments().len(), 1);
4158 lazy.push_fragment(&frag2, full_budget_ctx(&cell));
4159 assert_eq!(lazy.fragments(), &[&frag1[..], &frag2[..]]);
4160
4161 let v = lazy.get().unwrap().expect("set");
4162 assert_eq!((v.id, v.name), (7, "from-frag-1"));
4163
4164 // Later fragments overwrite singular scalars (last-wins).
4165 let frag3 = encode_simple(9, "final");
4166 lazy.push_fragment(&frag3, full_budget_ctx(&cell));
4167 assert_eq!(lazy.fragments().len(), 3);
4168 let v = lazy.get().unwrap().expect("set");
4169 assert_eq!((v.id, v.name), (9, "final"));
4170 }
4171
4172 #[test]
4173 fn lazy_message_field_view_records_smallest_budgets() {
4174 // Budgets recorded across pushes are min-combined, and the recorded
4175 // allowance replays per access (capture-then-replay).
4176 let bytes = encode_simple(1, "x");
4177 let cell_big = core::cell::Cell::new(500);
4178 let cell_small = core::cell::Cell::new(3);
4179
4180 let mut lazy = LazyMessageFieldView::<SimpleLazyView<'_>>::unset();
4181 lazy.push_fragment(&bytes, crate::DecodeContext::new(80, &cell_big));
4182 lazy.push_fragment(&bytes, crate::DecodeContext::new(50, &cell_small));
4183 // Decoding succeeds — SimpleLazyView has no unknowns or nesting here;
4184 // the recorded budgets only bound what access may consume.
4185 assert!(lazy.get().unwrap().is_some());
4186 }
4187
4188 #[test]
4189 fn lazy_message_field_view_clone_default_debug() {
4190 let bytes = encode_simple(1, "x");
4191 let cell = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
4192 let mut lazy = LazyMessageFieldView::<SimpleLazyView<'_>>::default();
4193 assert!(lazy.is_unset());
4194 lazy.push_fragment(&bytes, full_budget_ctx(&cell));
4195 lazy.push_fragment(&bytes, full_budget_ctx(&cell));
4196 let cloned = lazy.clone();
4197 assert_eq!(cloned.fragments(), lazy.fragments());
4198 let dbg = alloc::format!("{lazy:?}");
4199 assert!(dbg.contains("is_set: true"), "{dbg}");
4200 assert!(dbg.contains("fragments: 2"), "{dbg}");
4201 }
4202
4203 #[test]
4204 fn lazy_message_field_view_malformed_errors_on_access() {
4205 // 0xFF starts a tag whose varint never terminates — invalid.
4206 let malformed = [0xFFu8; 3];
4207 let lazy = LazyMessageFieldView::<SimpleLazyView<'_>>::from_bytes(&malformed);
4208 // Deferred validation: construction succeeds, access fails.
4209 assert!(lazy.is_set());
4210 assert!(lazy.get().is_err());
4211 }
4212
4213 #[test]
4214 fn lazy_repeated_view_decodes_per_element() {
4215 let b0 = encode_simple(1, "a");
4216 let b1 = encode_simple(2, "b");
4217 let cell = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
4218 let mut rep = LazyRepeatedView::<SimpleLazyView<'_>>::new();
4219 assert!(rep.is_empty());
4220 rep.push_bytes(&b0, full_budget_ctx(&cell));
4221 rep.push_bytes(&b1, full_budget_ctx(&cell));
4222 assert_eq!(rep.len(), 2);
4223 assert_eq!(rep.raw_elements(), &[&b0[..], &b1[..]]);
4224 assert_eq!(rep.get(0).unwrap().unwrap().name, "a");
4225 assert_eq!(rep.get(1).unwrap().unwrap().id, 2);
4226 assert!(rep.get(2).is_none());
4227 }
4228
4229 #[test]
4230 fn lazy_repeated_view_iter() {
4231 let bufs: alloc::vec::Vec<Bytes> = (1..=3)
4232 .map(|i| encode_simple(i, core::str::from_utf8(&[b'a' + i as u8]).unwrap()))
4233 .collect();
4234 let cell = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
4235 let mut rep = LazyRepeatedView::<SimpleLazyView<'_>>::new();
4236 for b in &bufs {
4237 rep.push_bytes(b, full_budget_ctx(&cell));
4238 }
4239
4240 let iter = rep.iter();
4241 assert_eq!(iter.len(), 3);
4242 let ids: alloc::vec::Vec<i32> = iter.map(|r| r.unwrap().id).collect();
4243 assert_eq!(ids, [1, 2, 3]);
4244
4245 // IntoIterator for &LazyRepeatedView.
4246 let names: alloc::vec::Vec<&str> = (&rep).into_iter().map(|r| r.unwrap().name).collect();
4247 assert_eq!(names, ["b", "c", "d"]);
4248
4249 // DoubleEndedIterator.
4250 let rev_ids: alloc::vec::Vec<i32> = rep.iter().rev().map(|r| r.unwrap().id).collect();
4251 assert_eq!(rev_ids, [3, 2, 1]);
4252 }
4253
4254 #[test]
4255 fn lazy_repeated_view_iter_surfaces_element_errors() {
4256 let good = encode_simple(1, "ok");
4257 let malformed = [0xFFu8; 3];
4258 let cell = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT);
4259 let mut rep = LazyRepeatedView::<SimpleLazyView<'_>>::new();
4260 rep.push_bytes(&good, full_budget_ctx(&cell));
4261 rep.push_bytes(&malformed, full_budget_ctx(&cell));
4262 let results: alloc::vec::Vec<_> = rep.iter().collect();
4263 assert!(results[0].is_ok());
4264 assert!(results[1].is_err());
4265 let cloned = rep.clone();
4266 assert_eq!(cloned.len(), 2);
4267 }
4268
4269 // ── Encode-side 2 GiB guard tests ──────────────────────────────────
4270
4271 /// Test double whose `compute_size` reports a caller-chosen value and
4272 /// whose `write_to` writes nothing — exercises the over-limit paths
4273 /// without materializing gigabytes.
4274 #[derive(Clone, Debug, Default, PartialEq)]
4275 struct SizedView {
4276 reported_size: u32,
4277 }
4278
4279 impl<'a> MessageView<'a> for SizedView {
4280 type Owned = SimpleMessage;
4281 fn merge_view_field(
4282 &mut self,
4283 _tag: crate::encoding::Tag,
4284 cur: &'a [u8],
4285 _before_tag: &'a [u8],
4286 _ctx: crate::DecodeContext<'_>,
4287 ) -> Result<&'a [u8], DecodeError> {
4288 Ok(cur)
4289 }
4290 fn decode_view(_buf: &'a [u8]) -> Result<Self, DecodeError> {
4291 Ok(Self::default())
4292 }
4293 fn to_owned_message(&self) -> Result<SimpleMessage, DecodeError> {
4294 Ok(SimpleMessage::default())
4295 }
4296 }
4297
4298 impl<'a> ViewEncode<'a> for SizedView {
4299 fn compute_size(&self, _cache: &mut crate::SizeCache) -> u32 {
4300 self.reported_size
4301 }
4302 fn write_to(&self, _cache: &mut crate::SizeCache, _buf: &mut impl EncodeSink) {}
4303 }
4304
4305 const OVER_LIMIT: u32 = crate::MAX_MESSAGE_BYTES + 1;
4306
4307 /// View double over the shared [`SizedMsg`](crate::test_doubles::SizedMsg)
4308 /// owned double, so `OwnedView::from_owned` can hit the over-limit
4309 /// encode path without materializing gigabytes.
4310 #[derive(Clone, Debug, Default, PartialEq)]
4311 struct SizedOwnedView;
4312
4313 impl<'a> MessageView<'a> for SizedOwnedView {
4314 type Owned = crate::test_doubles::SizedMsg;
4315 fn merge_view_field(
4316 &mut self,
4317 _tag: crate::encoding::Tag,
4318 cur: &'a [u8],
4319 _before_tag: &'a [u8],
4320 _ctx: crate::DecodeContext<'_>,
4321 ) -> Result<&'a [u8], DecodeError> {
4322 Ok(cur)
4323 }
4324 fn decode_view(_buf: &'a [u8]) -> Result<Self, DecodeError> {
4325 Ok(Self)
4326 }
4327 fn to_owned_message(&self) -> Result<crate::test_doubles::SizedMsg, DecodeError> {
4328 Ok(crate::test_doubles::SizedMsg::default())
4329 }
4330 }
4331
4332 #[test]
4333 fn owned_view_from_owned_over_limit_errs_not_panics() {
4334 // from_owned is a Result-returning API: an over-limit message must
4335 // surface as Err(MessageTooLarge), never a panic from the interior
4336 // encode.
4337 let msg = crate::test_doubles::SizedMsg {
4338 reported_size: OVER_LIMIT,
4339 };
4340 let res = OwnedView::<SizedOwnedView>::from_owned(&msg);
4341 assert!(matches!(res, Err(DecodeError::MessageTooLarge)));
4342 }
4343
4344 #[test]
4345 #[should_panic(expected = "2 GiB protobuf limit")]
4346 fn view_encode_over_limit_panics() {
4347 let view = SizedView {
4348 reported_size: OVER_LIMIT,
4349 };
4350 let mut buf = alloc::vec::Vec::new();
4351 view.encode(&mut buf);
4352 }
4353
4354 #[test]
4355 #[should_panic(expected = "2 GiB protobuf limit")]
4356 fn view_encoded_len_over_limit_panics() {
4357 let view = SizedView {
4358 reported_size: OVER_LIMIT,
4359 };
4360 let _ = view.encoded_len();
4361 }
4362
4363 #[test]
4364 #[should_panic(expected = "2 GiB protobuf limit")]
4365 fn view_encode_length_delimited_over_limit_panics() {
4366 let view = SizedView {
4367 reported_size: OVER_LIMIT,
4368 };
4369 let mut buf = alloc::vec::Vec::new();
4370 view.encode_length_delimited(&mut buf);
4371 }
4372
4373 #[test]
4374 #[should_panic(expected = "2 GiB protobuf limit")]
4375 fn view_encode_to_vec_over_limit_panics() {
4376 let view = SizedView {
4377 reported_size: OVER_LIMIT,
4378 };
4379 let _ = view.encode_to_vec();
4380 }
4381
4382 #[test]
4383 #[should_panic(expected = "2 GiB protobuf limit")]
4384 fn view_encode_to_bytes_over_limit_panics() {
4385 let view = SizedView {
4386 reported_size: OVER_LIMIT,
4387 };
4388 let _ = view.encode_to_bytes();
4389 }
4390
4391 #[test]
4392 #[should_panic(expected = "2 GiB protobuf limit")]
4393 fn view_encode_with_cache_over_limit_panics() {
4394 let view = SizedView {
4395 reported_size: OVER_LIMIT,
4396 };
4397 let mut cache = crate::SizeCache::new();
4398 let mut buf = alloc::vec::Vec::new();
4399 view.encode_with_cache(&mut cache, &mut buf);
4400 }
4401
4402 #[cfg(debug_assertions)]
4403 #[test]
4404 #[should_panic(expected = "two-pass traversal mismatch")]
4405 fn view_encode_to_vec_ledger_catches_size_write_disagreement() {
4406 // An under-limit reported size with a no-op write_to: the guard
4407 // passes, then the debug ledger flags the two-pass divergence.
4408 let view = SizedView { reported_size: 3 };
4409 let _ = view.encode_to_vec();
4410 }
4411
4412 #[test]
4413 fn view_try_encode_over_limit_errors_and_writes_nothing() {
4414 let view = SizedView {
4415 reported_size: OVER_LIMIT,
4416 };
4417 let mut buf = alloc::vec::Vec::new();
4418 assert_eq!(
4419 view.try_encode(&mut buf),
4420 Err(crate::EncodeError::MessageTooLarge)
4421 );
4422 assert!(buf.is_empty(), "no bytes may reach the buffer on Err");
4423 let mut cache = crate::SizeCache::new();
4424 assert_eq!(
4425 view.try_encode_with_cache(&mut cache, &mut buf),
4426 Err(crate::EncodeError::MessageTooLarge)
4427 );
4428 assert!(buf.is_empty(), "no bytes may reach the buffer on Err");
4429 assert_eq!(
4430 view.try_encode_length_delimited(&mut buf),
4431 Err(crate::EncodeError::MessageTooLarge)
4432 );
4433 assert!(buf.is_empty(), "not even the length prefix");
4434 assert_eq!(
4435 view.try_encode_to_vec(),
4436 Err(crate::EncodeError::MessageTooLarge)
4437 );
4438 assert_eq!(
4439 view.try_encode_to_bytes(),
4440 Err(crate::EncodeError::MessageTooLarge)
4441 );
4442 assert_eq!(
4443 view.try_encoded_len(),
4444 Err(crate::EncodeError::MessageTooLarge)
4445 );
4446 }
4447
4448 #[test]
4449 fn view_try_encode_matches_encode_for_normal_views() {
4450 let view = SimpleMessageView {
4451 id: 42,
4452 name: "hello",
4453 };
4454 let mut expected = alloc::vec::Vec::new();
4455 view.encode(&mut expected);
4456 let mut actual = alloc::vec::Vec::new();
4457 view.try_encode(&mut actual).unwrap();
4458 assert_eq!(actual, expected);
4459 assert_eq!(view.try_encode_to_vec().unwrap(), expected);
4460 assert_eq!(view.try_encode_to_bytes().unwrap(), expected);
4461 assert_eq!(view.try_encoded_len().unwrap(), expected.len() as u32);
4462 }
4463
4464 #[test]
4465 fn view_try_encode_bounded_within_budget_encodes_and_returns_len() {
4466 let view = SimpleMessageView {
4467 id: 42,
4468 name: "hello",
4469 };
4470 let mut expected = alloc::vec::Vec::new();
4471 view.encode(&mut expected);
4472 let budget = expected.len() as u32;
4473
4474 let mut buf = alloc::vec::Vec::new();
4475 let len = view.try_encode_bounded(budget, &mut buf).unwrap();
4476 assert_eq!(buf, expected);
4477 assert_eq!(len, budget);
4478
4479 // with_cache variant agrees
4480 let mut cache = crate::SizeCache::new();
4481 let mut buf2 = alloc::vec::Vec::new();
4482 let len2 = view
4483 .try_encode_bounded_with_cache(budget, &mut cache, &mut buf2)
4484 .unwrap();
4485 assert_eq!(buf2, expected);
4486 assert_eq!(len2, budget);
4487 }
4488
4489 #[test]
4490 fn view_try_encode_bounded_over_budget_errors_and_writes_nothing() {
4491 let view = SimpleMessageView {
4492 id: 42,
4493 name: "hello",
4494 };
4495 let len = view.encoded_len();
4496 let budget = len - 1;
4497
4498 let mut buf = alloc::vec::Vec::new();
4499 assert_eq!(
4500 view.try_encode_bounded(budget, &mut buf),
4501 Err(crate::EncodeError::ExceedsBudget {
4502 len,
4503 max_bytes: budget
4504 })
4505 );
4506 assert!(buf.is_empty(), "nothing written on budget exceeded");
4507 }
4508
4509 #[test]
4510 fn view_try_encode_bounded_over_protobuf_limit_errors_as_too_large() {
4511 let view = SizedView {
4512 reported_size: OVER_LIMIT,
4513 };
4514 let mut buf = alloc::vec::Vec::new();
4515 assert_eq!(
4516 view.try_encode_bounded(u32::MAX, &mut buf),
4517 Err(crate::EncodeError::MessageTooLarge)
4518 );
4519 assert!(buf.is_empty());
4520 }
4521
4522 #[test]
4523 fn pool_try_encode_view_bounded_within_budget_encodes_and_returns_len() {
4524 let view = SimpleMessageView {
4525 id: 7,
4526 name: "pooled",
4527 };
4528 let mut expected = alloc::vec::Vec::new();
4529 view.encode(&mut expected);
4530 let budget = expected.len() as u32;
4531
4532 let mut pool = crate::SizeCachePool::sequential(64);
4533 let mut buf = alloc::vec::Vec::new();
4534 let len = pool
4535 .try_encode_view_bounded(&view, budget, &mut buf)
4536 .unwrap();
4537 assert_eq!(buf, expected);
4538 assert_eq!(len, budget);
4539 }
4540
4541 #[test]
4542 fn pool_try_encode_view_bounded_over_budget_errors_and_buffer_returned() {
4543 let view = SimpleMessageView {
4544 id: 7,
4545 name: "pooled",
4546 };
4547 let len = view.encoded_len();
4548 let budget = len - 1;
4549
4550 let mut pool = crate::SizeCachePool::sequential(64);
4551 let mut buf = alloc::vec::Vec::new();
4552 assert_eq!(
4553 pool.try_encode_view_bounded(&view, budget, &mut buf),
4554 Err(crate::EncodeError::ExceedsBudget {
4555 len,
4556 max_bytes: budget
4557 })
4558 );
4559 assert!(buf.is_empty());
4560 // Pool buffer must be returned on Err — a subsequent call must succeed.
4561 assert_eq!(
4562 pool.try_encode_view_bounded(&view, len, &mut buf).unwrap(),
4563 len
4564 );
4565 }
4566}
4567
4568#[cfg(test)]
4569mod unknown_fields_view_repr {
4570 use super::UnknownFieldsView;
4571
4572 // Every generated view embeds this by value, so it must stay pointer-sized
4573 // and hold no inline heap owner; otherwise views regress to being moved by
4574 // out-of-line `memcpy` rather than inline vector stores.
4575 #[test]
4576 fn handle_is_pointer_sized() {
4577 assert_eq!(
4578 core::mem::size_of::<UnknownFieldsView<'_>>(),
4579 core::mem::size_of::<usize>()
4580 );
4581 }
4582
4583 // `UnknownFieldsView` is reachable from every generated view, so it is part
4584 // of the public surface downstream code puts in its own types.
4585 #[test]
4586 fn is_send_and_sync() {
4587 fn assert_send<T: Send>() {}
4588 fn assert_sync<T: Sync>() {}
4589 assert_send::<UnknownFieldsView<'_>>();
4590 assert_sync::<UnknownFieldsView<'_>>();
4591 }
4592
4593 // The manual `Debug` impl exists to keep `last_tail` — which runs to the end
4594 // of the input buffer — out of the output, while still showing the records.
4595 #[test]
4596 fn debug_shows_records_and_hides_the_coalescing_cursor() {
4597 let mut ufv = UnknownFieldsView::new();
4598 assert!(format!("{ufv:?}").contains("records: []"));
4599
4600 ufv.push_raw(&[0x08, 0x2a]);
4601 let rendered = format!("{ufv:?}");
4602 assert!(rendered.contains("records: [Borrowed("), "{rendered}");
4603 assert!(!rendered.contains("last_tail"), "{rendered}");
4604 }
4605}