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