qubit_codec/codec/decode_failure.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//! Failures returned by low-level codec decode operations.
9
10use core::num::NonZeroUsize;
11
12/// Failure reported by [`crate::Codec::decode`].
13///
14/// This type separates stream-control failures from codec-domain failures.
15/// [`Incomplete`](Self::Incomplete) tells buffered adapters to preserve the
16/// current input tail and request more units. [`Invalid`](Self::Invalid)
17/// carries the codec-specific malformed, non-canonical, or otherwise invalid
18/// input error.
19///
20/// # Type Parameters
21///
22/// - `E`: Codec-specific invalid-input error type.
23#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
24pub enum DecodeFailure<E> {
25 /// The visible input is a valid prefix but not enough to decode a value.
26 Incomplete {
27 /// Non-zero total units required from the current value start.
28 required_total: NonZeroUsize,
29 },
30
31 /// The input is invalid for the codec.
32 Invalid {
33 /// Codec-specific invalid-input error.
34 source: E,
35 /// Invalid units that may be consumed by a non-strict policy.
36 consumed: Option<NonZeroUsize>,
37 },
38}
39
40impl<E> DecodeFailure<E> {
41 /// Creates an incomplete-input decode failure.
42 ///
43 /// # Parameters
44 ///
45 /// - `required_total`: Non-zero total units required from the current value
46 /// start.
47 ///
48 /// # Returns
49 ///
50 /// Returns an incomplete decode failure.
51 #[inline(always)]
52 #[must_use]
53 pub const fn incomplete(required_total: NonZeroUsize) -> Self {
54 Self::Incomplete { required_total }
55 }
56
57 /// Creates an invalid-input decode failure with a consumption hint.
58 ///
59 /// # Parameters
60 ///
61 /// - `source`: Codec-specific invalid-input error.
62 /// - `consumed`: Invalid input units that may be consumed.
63 ///
64 /// # Returns
65 ///
66 /// Returns an invalid decode failure.
67 #[inline(always)]
68 #[must_use]
69 pub const fn invalid(source: E, consumed: NonZeroUsize) -> Self {
70 Self::Invalid {
71 source,
72 consumed: Some(consumed),
73 }
74 }
75
76 /// Creates an invalid-input decode failure without a consumption hint.
77 ///
78 /// # Parameters
79 ///
80 /// - `source`: Codec-specific invalid-input error.
81 ///
82 /// # Returns
83 ///
84 /// Returns an invalid decode failure.
85 #[inline(always)]
86 #[must_use]
87 pub const fn invalid_without_consumed(source: E) -> Self {
88 Self::Invalid {
89 source,
90 consumed: None,
91 }
92 }
93
94 /// Returns the total input units required for an incomplete prefix.
95 ///
96 /// # Returns
97 ///
98 /// Returns `Some(required_total)` for incomplete failures, or `None` for
99 /// invalid-input failures.
100 #[inline(always)]
101 #[must_use]
102 pub const fn required_total(&self) -> Option<NonZeroUsize> {
103 match self {
104 Self::Incomplete { required_total } => Some(*required_total),
105 Self::Invalid { .. } => None,
106 }
107 }
108
109 /// Borrows the codec-specific invalid-input error.
110 ///
111 /// # Returns
112 ///
113 /// Returns `Some(source)` for invalid-input failures, or `None` for
114 /// incomplete failures.
115 #[inline(always)]
116 #[must_use]
117 pub const fn invalid_source(&self) -> Option<&E> {
118 match self {
119 Self::Invalid { source, .. } => Some(source),
120 Self::Incomplete { .. } => None,
121 }
122 }
123
124 /// Returns invalid units that may be consumed by a non-strict policy.
125 ///
126 /// # Returns
127 ///
128 /// Returns `Some(consumed)` when the invalid failure carries a consumption
129 /// hint, or `None` otherwise.
130 #[inline(always)]
131 #[must_use]
132 pub const fn consumed_units(&self) -> Option<NonZeroUsize> {
133 match self {
134 Self::Invalid { consumed, .. } => *consumed,
135 Self::Incomplete { .. } => None,
136 }
137 }
138}