qubit_codec/codec/codec.rs
1// =============================================================================
2// Copyright (c) 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Low-level value codec trait.
9
10use core::num::NonZeroUsize;
11
12use super::decode_failure::DecodeFailure;
13
14/// Encodes and decodes one value or codec quantum against a unit buffer.
15///
16/// `Codec` is the lowest-level abstraction in the codec stack. It is intended
17/// for hot paths that have already validated buffer capacity and want to avoid
18/// constructing subslices for every value. Higher-level transcoders and
19/// convenience APIs are responsible for checked buffer management and owned
20/// output allocation.
21///
22/// `MIN_UNITS_PER_VALUE` and `MAX_DECODE_UNITS_PER_VALUE` describe the readable
23/// representation-width bounds for one decoded value. If fewer than the
24/// minimum units are available, no complete value can exist, so a streaming
25/// caller can request more input or report an incomplete EOF tail. The minimum
26/// is also the smallest safety precondition checked callers must satisfy before
27/// entering [`decode`](Self::decode). The decode maximum bounds successful
28/// consumption and incomplete-input requirements for one value.
29///
30/// `MAX_ENCODE_UNITS_PER_VALUE` is the independent value-agnostic upper bound
31/// for main-phase encode output. Reserving that many units makes encoding safe
32/// for every encodable value. Once a value and encode state are known, callers
33/// may instead reserve the exact [`encode_len`](Self::encode_len), which must
34/// not exceed the encode maximum. Complete-lifecycle adapters that still need
35/// to run [`encode_reset`](Self::encode_reset) must reserve the maximum first
36/// because reset may change the exact width.
37///
38/// A codec may keep decode-side and encode-side stream state. That state is an
39/// implementation detail owned by the codec. Callers do not snapshot or restore
40/// it; implementations must keep their own state internally consistent across
41/// every public operation. A failed decode attempt must not advance decode
42/// state, so callers can retry the same input after refilling their buffer or
43/// applying an invalid-input policy.
44///
45/// Decode operations see only the currently supplied input slice and codec
46/// state. [`decode`](Self::decode) treats that slice as an open stream segment;
47/// [`decode_eof`](Self::decode_eof) receives the same preconditions after the
48/// caller has established that no more units will arrive. Returning
49/// [`DecodeFailure::Incomplete`] from `decode` requests more input for the
50/// current value; it is not itself an EOF error. Codecs that need EOF-aware
51/// maximal-munch parsing or reinterpretation of a trailing prefix can override
52/// `decode_eof` without changing their streaming behavior.
53/// An incomplete failure may also retain codec-specific context through
54/// [`DecodeFailure::incomplete_with_source`]; stream drivers may ignore that
55/// context while retrying and use it for detailed EOF diagnostics.
56///
57/// # Associated Types
58///
59/// - `Value`: Logical value decoded from or encoded into the buffer. This may
60/// be a scalar such as `u8`, `u16`, `u64`, a `char`, a fixed quantum such as
61/// `[u8; 3]`, or an owned value such as `String`/`Vec<u8>`. Adapters that
62/// need scratch initialization add their own bounds at the use site.
63/// - `Unit`: Buffer unit used by the encoded representation. Implementations
64/// are typically scalar storage units such as `u8`, `u16`, or `char`.
65/// Adapters that allocate owned output add their own initialization bounds at
66/// the use site.
67///
68/// Implementors must uphold the safety contract documented by
69/// [`decode`](Self::decode), [`encode`](Self::encode),
70/// [`encode_reset`](Self::encode_reset), and
71/// [`decode_finish`](Self::decode_finish). Unchecked implementations must not
72/// read or write outside the caller-provided ranges. Implementations should use
73/// `debug_assert!` to state the expected buffer bounds at the unchecked entry
74/// point.
75///
76/// Implementations must also guarantee that
77/// [`MIN_UNITS_PER_VALUE`](Self::MIN_UNITS_PER_VALUE) is non-zero and no larger
78/// than [`MAX_DECODE_UNITS_PER_VALUE`](Self::MAX_DECODE_UNITS_PER_VALUE), which
79/// must also be non-zero. `MAX_ENCODE_UNITS_PER_VALUE` may be zero for a codec
80/// that always buffers each accepted value instead of immediately emitting
81/// units. Checked adapters enforce the decode-bound invariants with
82/// compile-time assertions before using codec-provided bounds.
83///
84/// # Why the low-level methods are unchecked
85///
86/// The `unsafe` entry points are intentional: checked adapters validate the
87/// index and capacity preconditions once, then call [`encode`](Self::encode)
88/// and [`decode`](Self::decode) without rebuilding subslices or repeating
89/// bounds checks for every value. The `safe_vs_unchecked` benchmark in
90/// `benches/transcode.rs` compares the same 64 KiB copy loop in release mode.
91/// Its result is workload- and toolchain-specific, so callers should use
92/// checked adapters unless they can establish the documented preconditions at
93/// a trusted boundary. Measure representative codec workloads before choosing
94/// an unchecked entry point. Codec implementations should keep the unchecked
95/// methods small and use `debug_assert!` for those assumptions.
96///
97/// # Examples
98///
99/// A minimal identity codec exposes its bounds and decodes one byte:
100///
101/// ```
102/// use core::convert::Infallible;
103/// use core::num::NonZeroUsize;
104///
105/// use qubit_codec::Codec;
106/// use qubit_codec::DecodeFailure;
107///
108/// struct Identity;
109/// impl Identity {
110/// fn new() -> Self { Self }
111/// }
112/// impl Codec for Identity {
113/// type Value = u8;
114/// type Unit = u8;
115/// type DecodeError = Infallible;
116/// type EncodeError = Infallible;
117/// const MIN_UNITS_PER_VALUE: usize = 1;
118/// const MAX_DECODE_UNITS_PER_VALUE: usize = 1;
119/// const MAX_ENCODE_UNITS_PER_VALUE: usize = 1;
120///
121/// unsafe fn decode(&mut self, input: &[u8], index: usize)
122/// -> Result<(u8, NonZeroUsize), DecodeFailure<Infallible>> {
123/// Ok((input[index], NonZeroUsize::MIN))
124/// }
125///
126/// unsafe fn encode(&mut self, value: &u8, output: &mut [u8], index: usize)
127/// -> Result<usize, Infallible> {
128/// output[index] = *value;
129/// Ok(1)
130/// }
131/// }
132///
133/// let mut codec = Identity::new();
134/// assert_eq!(codec.encode_len(&42), 1);
135/// // SAFETY: the input contains the one readable unit required by Identity.
136/// let (value, consumed) = unsafe { codec.decode(&[42], 0) }.unwrap();
137/// assert_eq!((value, consumed.get()), (42, 1));
138/// ```
139pub trait Codec {
140 /// The type of logical values decoded from or encoded into the buffer.
141 type Value;
142
143 /// The type of buffer units used by the encoded representation.
144 type Unit;
145
146 /// The type of errors reported when decoding malformed units.
147 type DecodeError;
148
149 /// The type of errors reported when encoding an unsupported value.
150 type EncodeError;
151
152 /// The minimum possible non-zero readable unit count for one decoded value.
153 ///
154 /// This is a lower bound used by checked callers for planning and fast
155 /// impossibility checks. If a streaming decoder has fewer than this many
156 /// readable units, no complete value can be present at the current
157 /// position. It is also the denominator used by default decode hooks when
158 /// estimating the maximum number of values that can be produced from an
159 /// input unit count.
160 const MIN_UNITS_PER_VALUE: usize;
161
162 /// The maximum unit count emitted when encoding one value.
163 ///
164 /// This is a value-independent upper bound for the main encode phase. When
165 /// no concrete value is available, reserving this many writable units is
166 /// sufficient for any encodable value, without first calling
167 /// [`encode_len`](Self::encode_len). For a known value, callers may reserve
168 /// only the exact length returned by `encode_len` instead. This bound does
169 /// not include output produced by encode reset or finish phases.
170 ///
171 /// This is also the multiplier used by default encode hooks when estimating
172 /// the maximum number of output units needed for an input value count.
173 ///
174 /// The bound may be zero for a codec that buffers every accepted value and
175 /// emits retained output only during a later lifecycle phase.
176 const MAX_ENCODE_UNITS_PER_VALUE: usize;
177
178 /// The maximum non-zero unit count consumed to decode one value.
179 ///
180 /// This is a value-independent upper bound for one complete encoded value
181 /// or codec quantum on the decode side. Successful decode consumption and
182 /// the `required_total` carried by [`DecodeFailure::Incomplete`] must not
183 /// exceed this bound.
184 const MAX_DECODE_UNITS_PER_VALUE: usize;
185
186 /// The maximum unit count emitted when resetting encode state.
187 ///
188 /// This bound covers only output written by
189 /// [`encode_reset`](Self::encode_reset). It does not include hook-owned
190 /// reset output or any ordinary encoded input values. It must cover every
191 /// reachable pre-reset encode state. Stateless codecs should use the
192 /// default `0`.
193 const MAX_ENCODE_RESET_UNITS: usize = 0;
194
195 /// The maximum unit count emitted when finishing encode state at EOF.
196 ///
197 /// This bound covers only output written by
198 /// [`encode_finish`](Self::encode_finish). It does not include hook-owned
199 /// finish output and must cover every reachable encode state, even when the
200 /// current stream has no pending finish output. Stateless codecs should use
201 /// the default `0`. Codecs that emit a stream trailer (padding, checksum,
202 /// or end-of-stream marker) should override this with the exact maximum
203 /// unit count.
204 const MAX_ENCODE_FINISH_UNITS: usize = 0;
205
206 /// The maximum value count emitted when resetting decode state.
207 ///
208 /// This bound covers only values written by
209 /// [`decode_reset`](Self::decode_reset). It does not include hook-owned
210 /// reset output or values decoded from source units. It must cover every
211 /// reachable pre-reset decode state. Stateless codecs should use the
212 /// default `0`. Codecs that emit a stream-start sentinel or BOM on reset
213 /// should override this.
214 const MAX_DECODE_RESET_VALUES: usize = 0;
215
216 /// The maximum value count emitted when finishing decode state.
217 ///
218 /// This bound covers only values written by
219 /// [`decode_finish`](Self::decode_finish). It does not include hook-owned
220 /// finish output and must cover every reachable decode state, even when the
221 /// current stream has no pending finish output. Stateless codecs should use
222 /// the default `0`.
223 const MAX_DECODE_FINISH_VALUES: usize = 0;
224
225 /// Returns whether `value` is in this codec's encodable value domain.
226 ///
227 /// The default implementation returns `true`, which is correct for codecs
228 /// whose [`Value`](Self::Value) type contains only values they can encode.
229 /// Codecs whose logical value type is broader than their representation
230 /// domain, such as an ASCII codec with `Value = char`, must override this
231 /// method.
232 ///
233 /// Checked encoder adapters call this method in the same codec state used
234 /// to query [`encode_len`](Self::encode_len) and enter the unsafe
235 /// [`encode`](Self::encode) method. Complete-lifecycle adapters do so after
236 /// [`encode_reset`](Self::encode_reset). Direct unsafe callers must uphold
237 /// the same ordering.
238 ///
239 /// # Parameters
240 ///
241 /// - `value`: Value whose encodability is queried.
242 ///
243 /// # Returns
244 ///
245 /// Returns `true` when `value` may be passed to
246 /// [`encode_len`](Self::encode_len) and [`encode`](Self::encode).
247 #[inline]
248 #[must_use]
249 fn can_encode_value(&self, _value: &Self::Value) -> bool {
250 true
251 }
252
253 /// Returns the exact unit count this codec will write when encoding
254 /// `value`.
255 ///
256 /// The default implementation returns
257 /// [`MAX_ENCODE_UNITS_PER_VALUE`](Self::MAX_ENCODE_UNITS_PER_VALUE). This
258 /// default is correct only when every successful main encode writes exactly
259 /// that many units in the relevant codec state, as fixed-width codecs
260 /// normally do.
261 ///
262 /// Variable-width, buffering, or otherwise state-dependent codecs must
263 /// override this method to report the true encoded length for encodable
264 /// `value`s. The return value is never an estimate or an "unknown" marker:
265 /// it must equal the unit count [`encode`](Self::encode) subsequently
266 /// writes for the same `value` under the same codec state. It must also
267 /// never exceed
268 /// [`MAX_ENCODE_UNITS_PER_VALUE`](Self::MAX_ENCODE_UNITS_PER_VALUE).
269 /// Callers that do not yet have a concrete value should use
270 /// `MAX_ENCODE_UNITS_PER_VALUE` directly instead of calling this method.
271 ///
272 /// Default codec-backed encoders use this exact value for per-value output
273 /// capacity. The contract requires callers to use this method only when
274 /// [`can_encode_value`](Self::can_encode_value) returned `true` for the
275 /// same `value`.
276 ///
277 /// # Parameters
278 ///
279 /// - `value`: Value whose encoded length is queried.
280 ///
281 /// # Returns
282 ///
283 /// Returns the unit count [`encode`](Self::encode) will write for an
284 /// encodable `value`.
285 ///
286 /// A return value of `0` is valid for stateful encoders that accept a
287 /// value into internal state without immediately emitting units. Examples
288 /// include codecs that aggregate values into fixed-size quanta, shift-state
289 /// encodings, or framing layers that defer output until enough values have
290 /// been seen or EOF is finalized. Stateless and directly value-to-unit
291 /// codecs should continue returning a positive length.
292 #[inline]
293 #[must_use]
294 fn encode_len(&self, _value: &Self::Value) -> usize {
295 Self::MAX_ENCODE_UNITS_PER_VALUE
296 }
297
298 /// Emits stream-start output and resets encode-side state.
299 ///
300 /// # Parameters
301 ///
302 /// - `output`: Destination unit buffer.
303 /// - `output_index`: Start index in `output`.
304 ///
305 /// # Returns
306 ///
307 /// Returns the number of reset units written.
308 ///
309 /// # Errors
310 ///
311 /// Returns `Self::EncodeError` when reset output cannot be emitted.
312 /// Implementations must leave encode state unchanged when returning an
313 /// error.
314 ///
315 /// # Safety
316 ///
317 /// The caller must guarantee that the implementation can write up to
318 /// [`MAX_ENCODE_RESET_UNITS`](Self::MAX_ENCODE_RESET_UNITS) units starting
319 /// at `output_index`.
320 #[inline]
321 #[must_use = "reset output and reset errors must be handled"]
322 unsafe fn encode_reset(
323 &mut self,
324 _output: &mut [Self::Unit],
325 _output_index: usize,
326 ) -> Result<usize, Self::EncodeError> {
327 Ok(0)
328 }
329
330 /// Encodes one borrowed value into `output` starting at `output_index`.
331 ///
332 /// # Parameters
333 ///
334 /// - `value`: Value to encode.
335 /// - `output`: Destination unit buffer.
336 /// - `output_index`: Start index in `output`.
337 ///
338 /// # Returns
339 ///
340 /// Returns the number of written units.
341 ///
342 /// A successful encode may return `0` when the codec accepted `value` into
343 /// internal encode-side state but intentionally deferred output. This is
344 /// the normal shape for accumulative encoders such as base64-byte
345 /// aggregators, shift-state encodings, or frame builders. In that case
346 /// [`encode_len`](Self::encode_len) for the same `value` and state must
347 /// also return `0`, and the retained output must be emitted by a later
348 /// successful [`encode`](Self::encode),
349 /// [`encode_finish`](Self::encode_finish), or codec-specific facade.
350 ///
351 /// # Errors
352 ///
353 /// Returns `Self::EncodeError` for encode-side state or representation
354 /// failures other than a value being outside the codec's encodable domain.
355 /// Checked callers reject values for which
356 /// [`can_encode_value`](Self::can_encode_value) returns `false` before
357 /// entering this unsafe method. Implementations must leave their internal
358 /// state consistent when returning an error.
359 ///
360 /// # Safety
361 ///
362 /// The caller must guarantee that
363 /// [`can_encode_value`](Self::can_encode_value) returned `true` for
364 /// `value`. Starting at `output_index`, the caller must also provide either
365 /// at least
366 /// [`MAX_ENCODE_UNITS_PER_VALUE`](Self::MAX_ENCODE_UNITS_PER_VALUE)
367 /// writable
368 /// units, which is sufficient for every encodable value, or at least the
369 /// exact [`encode_len`](Self::encode_len) for the same `value` and codec
370 /// state. On success, implementations must return that exact written unit
371 /// count, including `0` for deliberate buffering, and the count must be no
372 /// larger than `MAX_ENCODE_UNITS_PER_VALUE`. Implementations must not write
373 /// beyond the exact `encode_len` capacity on either the success or error
374 /// path.
375 #[must_use = "encoded length and encode errors must be handled"]
376 unsafe fn encode(
377 &mut self,
378 value: &Self::Value,
379 output: &mut [Self::Unit],
380 output_index: usize,
381 ) -> Result<usize, Self::EncodeError>;
382
383 /// Emits EOF trailer output and finishes encode-side state.
384 ///
385 /// This is the encode-side counterpart of
386 /// [`decode_finish`](Self::decode_finish). Codecs that append stream
387 /// trailers (padding, checksums, end-of-stream markers) emit them here.
388 /// Stateless codecs use the default no-op.
389 ///
390 /// # Parameters
391 ///
392 /// - `output`: Destination unit buffer.
393 /// - `output_index`: Start index in `output`.
394 ///
395 /// # Returns
396 ///
397 /// Returns the number of finish units written.
398 ///
399 /// # Errors
400 ///
401 /// Returns `Self::EncodeError` when finish output cannot be emitted.
402 /// Implementations must leave their internal state consistent when
403 /// returning an error.
404 ///
405 /// # Safety
406 ///
407 /// The caller must guarantee that the implementation can write up to
408 /// [`MAX_ENCODE_FINISH_UNITS`](Self::MAX_ENCODE_FINISH_UNITS) units
409 /// starting at `output_index`.
410 #[inline]
411 #[must_use = "finish output and finish errors must be handled"]
412 unsafe fn encode_finish(
413 &mut self,
414 _output: &mut [Self::Unit],
415 _output_index: usize,
416 ) -> Result<usize, Self::EncodeError> {
417 Ok(0)
418 }
419
420 /// Emits stream-start values and resets decode-side state.
421 ///
422 /// This is the decode-side counterpart of
423 /// [`encode_reset`](Self::encode_reset). Codecs that emit a
424 /// stream-start marker or BOM before decoding a new stream emit them
425 /// here. Stateless codecs use the default no-op.
426 ///
427 /// # Parameters
428 ///
429 /// - `output`: Destination value buffer.
430 /// - `output_index`: Start index in `output`.
431 ///
432 /// # Returns
433 ///
434 /// Returns the number of reset values written.
435 ///
436 /// # Errors
437 ///
438 /// Returns `Self::DecodeError` when reset output cannot be emitted.
439 /// Implementations must leave their internal state consistent when
440 /// returning an error.
441 ///
442 /// # Safety
443 ///
444 /// The caller must guarantee that the implementation can write up to
445 /// [`MAX_DECODE_RESET_VALUES`](Self::MAX_DECODE_RESET_VALUES) values
446 /// starting at `output_index`.
447 #[inline]
448 #[must_use = "reset output and reset errors must be handled"]
449 unsafe fn decode_reset(
450 &mut self,
451 _output: &mut [Self::Value],
452 _output_index: usize,
453 ) -> Result<usize, Self::DecodeError> {
454 Ok(0)
455 }
456
457 /// Decodes one value from `input` starting at `input_index`.
458 ///
459 /// # Parameters
460 ///
461 /// - `input`: Source unit buffer.
462 /// - `input_index`: Start index in `input`.
463 ///
464 /// # Returns
465 ///
466 /// Returns the decoded value and the non-zero number of consumed units.
467 ///
468 /// # Errors
469 ///
470 /// Returns [`DecodeFailure::Incomplete`] when the visible input is a
471 /// valid prefix but more units are needed to decide or complete a value.
472 /// This reports a streaming boundary, not a final EOF condition; the
473 /// caller or higher-level adapter decides what an incomplete tail means
474 /// when the upstream source is closed. Codec-specific context may be
475 /// retained in the failure's optional `source` field.
476 /// Returns [`DecodeFailure::Invalid`] when the units are malformed,
477 /// non-canonical, unmappable, or otherwise invalid for this codec and the
478 /// span is known or unknown. Unknown span is represented as
479 /// [`DecodeFailure::Invalid`] with an unknown consumed-unit hint.
480 /// Implementations must leave their internal state consistent when
481 /// returning an error.
482 ///
483 /// # Safety
484 ///
485 /// The caller must guarantee that `input_index` is a valid boundary in
486 /// `input` and that at least
487 /// [`MIN_UNITS_PER_VALUE`](Self::MIN_UNITS_PER_VALUE)
488 /// units are readable from `input_index`. Implementations must not read
489 /// beyond the currently available units under that precondition. They
490 /// may return [`DecodeFailure::Incomplete`] when those units are a
491 /// valid but incomplete prefix.
492 ///
493 /// On success, implementations must return a consumed unit count no larger
494 /// than either the available input or
495 /// [`MAX_DECODE_UNITS_PER_VALUE`](Self::MAX_DECODE_UNITS_PER_VALUE). An
496 /// incomplete result's `required_total` must also not exceed that maximum.
497 /// The return type guarantees that successful decoding always consumes at
498 /// least one unit. Implementations should use `debug_assert!` to state
499 /// these unchecked entry-point assumptions.
500 #[must_use = "decoded value, consumed length, and decode errors must be handled"]
501 unsafe fn decode(
502 &mut self,
503 input: &[Self::Unit],
504 input_index: usize,
505 ) -> Result<(Self::Value, NonZeroUsize), DecodeFailure<Self::DecodeError>>;
506
507 /// Decodes one value after the caller has established end of input.
508 ///
509 /// This method has the same safety and state guarantees as
510 /// [`decode`](Self::decode), but may resolve an otherwise incomplete
511 /// trailing prefix using EOF-aware format rules. The default preserves the
512 /// open-stream behavior by delegating to [`decode`](Self::decode).
513 ///
514 /// # Parameters
515 ///
516 /// - `input`: Final source unit buffer; no more units will arrive.
517 /// - `input_index`: Start index of the value in `input`.
518 ///
519 /// # Returns
520 ///
521 /// Returns the decoded value and the non-zero number of consumed units.
522 ///
523 /// # Errors
524 ///
525 /// Returns [`DecodeFailure::Incomplete`] for an unresolved final prefix,
526 /// or [`DecodeFailure::Invalid`] for malformed input, as in
527 /// [`decode`](Self::decode). An override may resolve a prefix at EOF.
528 ///
529 /// # Safety
530 ///
531 /// The caller must satisfy the same input-index and minimum-readable-unit
532 /// preconditions as [`decode`](Self::decode). Implementations must not
533 /// read beyond the currently available units.
534 #[inline]
535 #[must_use = "decoded value, consumed length, and decode errors must be handled"]
536 unsafe fn decode_eof(
537 &mut self,
538 input: &[Self::Unit],
539 input_index: usize,
540 ) -> Result<(Self::Value, NonZeroUsize), DecodeFailure<Self::DecodeError>> {
541 // SAFETY: `decode_eof` has the same preconditions as `decode`.
542 unsafe { self.decode(input, input_index) }
543 }
544
545 /// Finishes decode-side EOF state into `output`.
546 ///
547 /// `decode_finish` receives no source input. Callers must have already
548 /// handled any tail reported by [`DecodeFailure::Incomplete`] before
549 /// finishing decode state. Implementations may emit retained values or
550 /// validate internal EOF state, but they must not depend on re-reading the
551 /// incomplete source tail.
552 ///
553 /// # Parameters
554 ///
555 /// - `output`: Destination value buffer.
556 /// - `output_index`: Start index in `output`.
557 ///
558 /// # Returns
559 ///
560 /// Returns the number of finished values written.
561 ///
562 /// # Errors
563 ///
564 /// Returns `Self::DecodeError` when retained decode state is invalid at
565 /// EOF. Implementations must leave their internal state consistent when
566 /// returning an error.
567 ///
568 /// # Safety
569 ///
570 /// The caller must guarantee that the implementation can write up to
571 /// [`MAX_DECODE_FINISH_VALUES`](Self::MAX_DECODE_FINISH_VALUES) values
572 /// starting at `output_index`.
573 #[inline]
574 #[must_use = "finish output length and finish errors must be handled"]
575 unsafe fn decode_finish(
576 &mut self,
577 _output: &mut [Self::Value],
578 _output_index: usize,
579 ) -> Result<usize, Self::DecodeError> {
580 Ok(0)
581 }
582}
583
584/// Compile-time asserts the public unit-bound invariants required by [`Codec`].
585///
586/// # Type Parameters
587///
588/// - `C`: Codec implementation to validate.
589///
590/// # Returns
591///
592/// Returns unit `()`.
593///
594/// # Panics
595///
596/// Panics at compile time when either decode width bound is zero or when
597/// [`Codec::MIN_UNITS_PER_VALUE`] is greater than
598/// [`Codec::MAX_DECODE_UNITS_PER_VALUE`], because these invariants must hold
599/// for any well-formed [`Codec`] implementation and violating them is always a
600/// bug.
601#[inline]
602pub(crate) fn assert_unit_bounds<C>()
603where
604 C: Codec,
605{
606 const {
607 assert!(
608 C::MIN_UNITS_PER_VALUE > 0,
609 "Codec::MIN_UNITS_PER_VALUE must be non-zero",
610 );
611 assert!(
612 C::MAX_DECODE_UNITS_PER_VALUE > 0,
613 "Codec::MAX_DECODE_UNITS_PER_VALUE must be non-zero",
614 );
615 assert!(
616 C::MIN_UNITS_PER_VALUE <= C::MAX_DECODE_UNITS_PER_VALUE,
617 "Codec::MIN_UNITS_PER_VALUE must not exceed Codec::MAX_DECODE_UNITS_PER_VALUE",
618 );
619 }
620}