qubit_codec/base64_codec.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! Base64 byte codec.
11
12use ::base64::Engine;
13use ::base64::engine::general_purpose::{
14 STANDARD,
15 STANDARD_NO_PAD,
16 URL_SAFE,
17 URL_SAFE_NO_PAD,
18};
19
20use crate::{
21 CodecError,
22 CodecResult,
23 Decoder,
24 Encoder,
25};
26
27/// Encodes and decodes Base64 byte strings.
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub struct Base64Codec {
30 url_safe: bool,
31 padding: bool,
32}
33
34impl Base64Codec {
35 /// Creates a standard Base64 codec with padding.
36 ///
37 /// # Returns
38 /// Standard Base64 codec.
39 pub fn standard() -> Self {
40 Self {
41 url_safe: false,
42 padding: true,
43 }
44 }
45
46 /// Creates a standard Base64 codec without padding.
47 ///
48 /// # Returns
49 /// Standard no-padding Base64 codec.
50 pub fn standard_no_pad() -> Self {
51 Self {
52 url_safe: false,
53 padding: false,
54 }
55 }
56
57 /// Creates a URL-safe Base64 codec with padding.
58 ///
59 /// # Returns
60 /// URL-safe Base64 codec.
61 pub fn url_safe() -> Self {
62 Self {
63 url_safe: true,
64 padding: true,
65 }
66 }
67
68 /// Creates a URL-safe Base64 codec without padding.
69 ///
70 /// # Returns
71 /// URL-safe no-padding Base64 codec.
72 pub fn url_safe_no_pad() -> Self {
73 Self {
74 url_safe: true,
75 padding: false,
76 }
77 }
78
79 /// Encodes bytes into Base64 text.
80 ///
81 /// # Parameters
82 /// - `bytes`: Bytes to encode.
83 ///
84 /// # Returns
85 /// Encoded Base64 text.
86 pub fn encode(&self, bytes: &[u8]) -> String {
87 self.engine().encode(bytes)
88 }
89
90 /// Decodes Base64 text into bytes.
91 ///
92 /// # Parameters
93 /// - `text`: Base64 text.
94 ///
95 /// # Returns
96 /// Decoded bytes.
97 ///
98 /// # Errors
99 /// Returns [`CodecError::InvalidBase64`] when `text` is malformed.
100 pub fn decode(&self, text: &str) -> CodecResult<Vec<u8>> {
101 self.engine().decode(text).map_err(CodecError::from)
102 }
103
104 /// Selects the concrete Base64 engine.
105 ///
106 /// # Returns
107 /// Base64 engine matching this codec's alphabet and padding settings.
108 fn engine(&self) -> &'static ::base64::engine::GeneralPurpose {
109 match (self.url_safe, self.padding) {
110 (false, true) => &STANDARD,
111 (false, false) => &STANDARD_NO_PAD,
112 (true, true) => &URL_SAFE,
113 (true, false) => &URL_SAFE_NO_PAD,
114 }
115 }
116}
117
118impl Default for Base64Codec {
119 /// Creates a standard Base64 codec with padding.
120 fn default() -> Self {
121 Self::standard()
122 }
123}
124
125impl Encoder<[u8]> for Base64Codec {
126 type Error = CodecError;
127 type Output = String;
128
129 /// Encodes bytes into Base64 text.
130 fn encode(&self, input: &[u8]) -> Result<Self::Output, Self::Error> {
131 Ok(Base64Codec::encode(self, input))
132 }
133}
134
135impl Decoder<str> for Base64Codec {
136 type Error = CodecError;
137 type Output = Vec<u8>;
138
139 /// Decodes Base64 text into bytes.
140 fn decode(&self, input: &str) -> Result<Self::Output, Self::Error> {
141 Base64Codec::decode(self, input)
142 }
143}