Skip to main content

base64_ng/engine/
mod.rs

1use crate::{Alphabet, LineWrap, Profile, ct};
2
3/// A zero-sized Base64 engine parameterized by alphabet and padding policy.
4pub struct Engine<A, const PAD: bool> {
5    alphabet: core::marker::PhantomData<A>,
6}
7
8impl<A, const PAD: bool> Clone for Engine<A, PAD> {
9    fn clone(&self) -> Self {
10        *self
11    }
12}
13
14impl<A, const PAD: bool> Copy for Engine<A, PAD> {}
15
16impl<A, const PAD: bool> core::fmt::Debug for Engine<A, PAD> {
17    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
18        formatter
19            .debug_struct("Engine")
20            .field("padded", &PAD)
21            .finish()
22    }
23}
24
25impl<A, const PAD: bool> core::fmt::Display for Engine<A, PAD> {
26    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
27        write!(formatter, "padded={PAD}")
28    }
29}
30
31impl<A, const PAD: bool> Default for Engine<A, PAD> {
32    fn default() -> Self {
33        Self {
34            alphabet: core::marker::PhantomData,
35        }
36    }
37}
38
39impl<A, const PAD: bool> Eq for Engine<A, PAD> {}
40
41impl<A, const PAD: bool> PartialEq for Engine<A, PAD> {
42    fn eq(&self, _other: &Self) -> bool {
43        true
44    }
45}
46
47impl<A, const PAD: bool> Engine<A, PAD>
48where
49    A: Alphabet,
50{
51    /// Creates a new engine value.
52    #[must_use]
53    pub const fn new() -> Self {
54        Self {
55            alphabet: core::marker::PhantomData,
56        }
57    }
58
59    /// Returns whether this engine uses padded Base64.
60    #[must_use]
61    pub const fn is_padded(&self) -> bool {
62        PAD
63    }
64
65    /// Returns this engine as an unwrapped profile.
66    ///
67    /// Use [`Profile::new`] or [`Profile::checked_new`] when a strict
68    /// line-wrapping policy should travel with the profile.
69    #[must_use]
70    pub const fn profile(&self) -> Profile<A, PAD> {
71        Profile::new(*self, None)
72    }
73
74    /// Returns this engine as a profile with strict line wrapping.
75    ///
76    /// This is a convenience wrapper around [`Profile::new`] for protocol
77    /// presets that need a wrapping policy to travel with the engine.
78    ///
79    /// # Examples
80    ///
81    /// ```
82    /// use base64_ng::{LineEnding, LineWrap, STANDARD};
83    ///
84    /// let profile = STANDARD.profile_with_wrap(LineWrap::new(4, LineEnding::Lf));
85    /// let mut output = [0u8; 9];
86    /// let written = profile.encode_slice(b"hello", &mut output).unwrap();
87    ///
88    /// assert_eq!(&output[..written], b"aGVs\nbG8=");
89    /// ```
90    #[must_use]
91    pub const fn profile_with_wrap(&self, wrap: LineWrap) -> Profile<A, PAD> {
92        Profile::new(*self, Some(wrap))
93    }
94
95    /// Returns this engine as a wrapped profile, or `None` when the wrapping
96    /// policy is invalid.
97    ///
98    /// Use this helper when a wrapping policy comes from runtime
99    /// configuration or another untrusted source.
100    #[must_use]
101    pub const fn checked_profile_with_wrap(&self, wrap: LineWrap) -> Option<Profile<A, PAD>> {
102        Profile::checked_new(*self, Some(wrap))
103    }
104
105    /// Returns the matching constant-time-oriented decoder for this engine's
106    /// alphabet and padding policy.
107    ///
108    /// The returned decoder is still an explicit opt-in to the [`ct`] module's
109    /// slower, opaque-error, constant-time-oriented scalar path.
110    #[must_use]
111    pub const fn ct_decoder(&self) -> ct::CtEngine<A, PAD> {
112        ct::CtEngine::new()
113    }
114}
115
116mod decode;
117mod decode_const;
118mod decode_in_place;
119mod encode;
120mod encode_in_place;
121mod stream;
122mod validate;