base64_ng/engine/validate.rs
1use crate::{
2 Alphabet, DecodeError, EncodeError, Engine, LineWrap, checked_encoded_len,
3 checked_wrapped_encoded_len, decoded_len, encoded_len, validate_decode, validate_legacy_decode,
4 validate_wrapped_decode, wrapped_encoded_len,
5};
6
7impl<A, const PAD: bool> Engine<A, PAD>
8where
9 A: Alphabet,
10{
11 /// Returns the encoded length for this engine's padding policy.
12 pub const fn encoded_len(&self, input_len: usize) -> Result<usize, EncodeError> {
13 encoded_len(input_len, PAD)
14 }
15
16 /// Returns the encoded length for this engine, or `None` on overflow.
17 #[must_use]
18 pub const fn checked_encoded_len(&self, input_len: usize) -> Option<usize> {
19 checked_encoded_len(input_len, PAD)
20 }
21
22 /// Returns the encoded length after applying a line wrapping policy.
23 ///
24 /// The returned length includes inserted line endings but does not include
25 /// a trailing line ending after the final encoded line.
26 pub const fn wrapped_encoded_len(
27 &self,
28 input_len: usize,
29 wrap: LineWrap,
30 ) -> Result<usize, EncodeError> {
31 wrapped_encoded_len(input_len, PAD, wrap)
32 }
33
34 /// Returns the encoded length after line wrapping, or `None` on overflow or
35 /// invalid line wrapping.
36 #[must_use]
37 pub const fn checked_wrapped_encoded_len(
38 &self,
39 input_len: usize,
40 wrap: LineWrap,
41 ) -> Option<usize> {
42 checked_wrapped_encoded_len(input_len, PAD, wrap)
43 }
44
45 /// Returns the exact decoded length implied by input length and padding.
46 ///
47 /// This validates padding placement and impossible lengths, but it does not
48 /// validate alphabet membership or non-canonical trailing bits.
49 pub fn decoded_len(&self, input: &[u8]) -> Result<usize, DecodeError> {
50 decoded_len(input, PAD)
51 }
52
53 /// Returns the exact decoded length for the explicit legacy profile.
54 ///
55 /// The legacy profile ignores ASCII space, tab, carriage return, and line
56 /// feed bytes before applying the same alphabet, padding, and canonical-bit
57 /// checks as strict decoding.
58 pub fn decoded_len_legacy(&self, input: &[u8]) -> Result<usize, DecodeError> {
59 validate_legacy_decode::<A, PAD>(input)
60 }
61
62 /// Returns the exact decoded length for a line-wrapped profile.
63 ///
64 /// The wrapped profile accepts only the configured line ending. Non-final
65 /// lines must contain exactly `wrap.line_len` encoded bytes; the final line
66 /// may be shorter. A single trailing line ending after the final line is
67 /// accepted.
68 pub fn decoded_len_wrapped(&self, input: &[u8], wrap: LineWrap) -> Result<usize, DecodeError> {
69 validate_wrapped_decode::<A, PAD>(input, wrap)
70 }
71
72 /// Validates strict Base64 input without writing decoded bytes.
73 ///
74 /// This applies the same alphabet, padding, and canonical-bit checks as
75 /// [`Self::decode_slice`]. Use this method when malformed-input
76 /// diagnostics matter; use [`Self::validate`] when a boolean is enough.
77 /// This default validator is not constant-time; use
78 /// [`crate::ct::CtEngine::validate_result`] through [`Self::ct_decoder`]
79 /// for secret-bearing payloads where timing posture matters.
80 ///
81 /// # Examples
82 ///
83 /// ```
84 /// use base64_ng::STANDARD;
85 ///
86 /// STANDARD.validate_result(b"aGVsbG8=").unwrap();
87 /// assert!(STANDARD.validate_result(b"aGVsbG8").is_err());
88 /// ```
89 pub fn validate_result(&self, input: &[u8]) -> Result<(), DecodeError> {
90 validate_decode::<A, PAD>(input).map(|_| ())
91 }
92
93 /// Returns whether `input` is valid strict Base64 for this engine.
94 ///
95 /// This is a convenience wrapper around [`Self::validate_result`] and is
96 /// not constant-time. Use [`crate::ct::CtEngine::validate`] through
97 /// [`Self::ct_decoder`] for secret-bearing payloads where timing posture
98 /// matters.
99 ///
100 /// # Examples
101 ///
102 /// ```
103 /// use base64_ng::URL_SAFE_NO_PAD;
104 ///
105 /// assert!(URL_SAFE_NO_PAD.validate(b"-_8"));
106 /// assert!(!URL_SAFE_NO_PAD.validate(b"+/8"));
107 /// ```
108 #[must_use]
109 pub fn validate(&self, input: &[u8]) -> bool {
110 self.validate_result(input).is_ok()
111 }
112
113 /// Validates input using the explicit legacy whitespace profile.
114 ///
115 /// ASCII space, tab, carriage return, and line feed bytes are ignored
116 /// before applying the same alphabet, padding, and canonical-bit checks as
117 /// strict decoding.
118 ///
119 /// # Examples
120 ///
121 /// ```
122 /// use base64_ng::STANDARD;
123 ///
124 /// STANDARD.validate_legacy_result(b" aG\r\nVsbG8= ").unwrap();
125 /// assert!(STANDARD.validate_legacy_result(b" aG-=").is_err());
126 /// ```
127 pub fn validate_legacy_result(&self, input: &[u8]) -> Result<(), DecodeError> {
128 validate_legacy_decode::<A, PAD>(input).map(|_| ())
129 }
130
131 /// Returns whether `input` is valid for the explicit legacy whitespace
132 /// profile.
133 ///
134 /// This is a convenience wrapper around [`Self::validate_legacy_result`].
135 ///
136 /// # Examples
137 ///
138 /// ```
139 /// use base64_ng::STANDARD;
140 ///
141 /// assert!(STANDARD.validate_legacy(b" aG\r\nVsbG8= "));
142 /// assert!(!STANDARD.validate_legacy(b"aG-V"));
143 /// ```
144 #[must_use]
145 pub fn validate_legacy(&self, input: &[u8]) -> bool {
146 self.validate_legacy_result(input).is_ok()
147 }
148
149 /// Validates input using a strict line-wrapped profile.
150 ///
151 /// This is stricter than [`Self::validate_legacy_result`]: it accepts only
152 /// the configured line ending and enforces the configured line length for
153 /// every non-final line.
154 ///
155 /// # Examples
156 ///
157 /// ```
158 /// use base64_ng::{LineEnding, LineWrap, STANDARD};
159 ///
160 /// let wrap = LineWrap::new(4, LineEnding::Lf);
161 /// STANDARD.validate_wrapped_result(b"aGVs\nbG8=", wrap).unwrap();
162 /// assert!(STANDARD.validate_wrapped_result(b"aG\nVsbG8=", wrap).is_err());
163 /// ```
164 pub fn validate_wrapped_result(&self, input: &[u8], wrap: LineWrap) -> Result<(), DecodeError> {
165 validate_wrapped_decode::<A, PAD>(input, wrap).map(|_| ())
166 }
167
168 /// Returns whether `input` is valid for a strict line-wrapped profile.
169 ///
170 /// This is a convenience wrapper around [`Self::validate_wrapped_result`].
171 ///
172 /// # Examples
173 ///
174 /// ```
175 /// use base64_ng::{LineEnding, LineWrap, STANDARD};
176 ///
177 /// let wrap = LineWrap::new(4, LineEnding::Lf);
178 /// assert!(STANDARD.validate_wrapped(b"aGVs\nbG8=", wrap));
179 /// assert!(!STANDARD.validate_wrapped(b"aG\nVsbG8=", wrap));
180 /// ```
181 #[must_use]
182 pub fn validate_wrapped(&self, input: &[u8], wrap: LineWrap) -> bool {
183 self.validate_wrapped_result(input, wrap).is_ok()
184 }
185}