Skip to main content

qubit_codec_misc/
base64_codec.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//! Base64 byte codec.
9
10use ::base64::Engine;
11use ::base64::engine::general_purpose::{
12    STANDARD,
13    STANDARD_NO_PAD,
14    URL_SAFE,
15    URL_SAFE_NO_PAD,
16};
17
18use crate::{
19    MiscCodecError,
20    MiscCodecResult,
21    ValueDecoder,
22    ValueEncoder,
23};
24
25/// Encodes and decodes Base64 byte strings.
26///
27/// This facade intentionally remains a whole-value codec backed by the
28/// `base64` crate. Final partial quantum handling and optional `=` padding are
29/// facade/transcoder responsibilities, not part of the low-level quantum codec.
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub struct Base64Codec {
32    url_safe: bool,
33    padding: bool,
34}
35
36impl Base64Codec {
37    /// Creates a standard Base64 codec with padding.
38    ///
39    /// # Returns
40    /// Standard Base64 codec.
41    #[inline]
42    pub fn standard() -> Self {
43        Self {
44            url_safe: false,
45            padding: true,
46        }
47    }
48
49    /// Creates a standard Base64 codec without padding.
50    ///
51    /// # Returns
52    /// Standard no-padding Base64 codec.
53    #[inline]
54    pub fn standard_no_pad() -> Self {
55        Self {
56            url_safe: false,
57            padding: false,
58        }
59    }
60
61    /// Creates a URL-safe Base64 codec with padding.
62    ///
63    /// # Returns
64    /// URL-safe Base64 codec.
65    #[inline]
66    pub fn url_safe() -> Self {
67        Self {
68            url_safe: true,
69            padding: true,
70        }
71    }
72
73    /// Creates a URL-safe Base64 codec without padding.
74    ///
75    /// # Returns
76    /// URL-safe no-padding Base64 codec.
77    #[inline]
78    pub fn url_safe_no_pad() -> Self {
79        Self {
80            url_safe: true,
81            padding: false,
82        }
83    }
84
85    /// Encodes bytes into Base64 text.
86    ///
87    /// # Parameters
88    /// - `bytes`: Bytes to encode.
89    ///
90    /// # Returns
91    /// Encoded Base64 text.
92    #[inline]
93    pub fn encode(&self, bytes: &[u8]) -> String {
94        self.engine().encode(bytes)
95    }
96
97    /// Decodes Base64 text into bytes.
98    ///
99    /// # Parameters
100    /// - `text`: Base64 text.
101    ///
102    /// # Returns
103    /// Decoded bytes.
104    ///
105    /// # Errors
106    /// Returns [`MiscCodecError::InvalidInput`] when `text` is malformed.
107    #[inline]
108    pub fn decode(&self, text: &str) -> MiscCodecResult<Vec<u8>> {
109        self.engine().decode(text).map_err(|source| {
110            MiscCodecError::InvalidInput {
111                codec: "base64",
112                reason: source.to_string(),
113            }
114        })
115    }
116
117    /// Selects the concrete Base64 engine.
118    ///
119    /// # Returns
120    /// Base64 engine matching this codec's alphabet and padding settings.
121    #[inline(always)]
122    fn engine(&self) -> &'static ::base64::engine::GeneralPurpose {
123        match (self.url_safe, self.padding) {
124            (false, true) => &STANDARD,
125            (false, false) => &STANDARD_NO_PAD,
126            (true, true) => &URL_SAFE,
127            (true, false) => &URL_SAFE_NO_PAD,
128        }
129    }
130}
131
132impl Default for Base64Codec {
133    /// Creates a standard Base64 codec with padding.
134    #[inline]
135    fn default() -> Self {
136        Self::standard()
137    }
138}
139
140impl ValueEncoder<[u8]> for Base64Codec {
141    type Error = MiscCodecError;
142    type Output = String;
143
144    /// Encodes bytes into Base64 text.
145    #[inline]
146    fn encode(&self, input: &[u8]) -> Result<Self::Output, Self::Error> {
147        Ok(Base64Codec::encode(self, input))
148    }
149}
150
151impl ValueDecoder<str> for Base64Codec {
152    type Error = MiscCodecError;
153    type Output = Vec<u8>;
154
155    /// Decodes Base64 text into bytes.
156    #[inline]
157    fn decode(&self, input: &str) -> Result<Self::Output, Self::Error> {
158        Base64Codec::decode(self, input)
159    }
160}