Skip to main content

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}