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