#[cfg(any(feature = "alloc", feature = "std", test))]
use crate::chunked_encoder;
use crate::{
encode::{encode_with_padding, EncodeSliceError},
encoded_len, DecodeError, DecodeSliceError,
};
#[cfg(any(feature = "alloc", feature = "std", test))]
use alloc::vec::Vec;
#[cfg(any(feature = "alloc", feature = "std", test))]
use alloc::{string::String, vec};
pub mod general_purpose;
#[cfg(test)]
mod naive;
#[cfg(test)]
mod tests;
pub use general_purpose::{GeneralPurpose, GeneralPurposeConfig};
pub trait Engine: Send + Sync {
type Config: Config;
type DecodeEstimate: DecodeEstimate;
#[doc(hidden)]
fn internal_encode(&self, input: &[u8], output: &mut [u8]) -> usize;
#[doc(hidden)]
fn internal_decoded_len_estimate(&self, input_len: usize) -> Self::DecodeEstimate;
#[doc(hidden)]
fn internal_decode(
&self,
input: &[u8],
output: &mut [u8],
decode_estimate: Self::DecodeEstimate,
) -> Result<usize, DecodeError>;
fn config(&self) -> &Self::Config;
#[cfg(any(feature = "alloc", feature = "std", test))]
fn encode<T: AsRef<[u8]>>(&self, input: T) -> String {
let encoded_size = encoded_len(input.as_ref().len(), self.config().encode_padding())
.expect("integer overflow when calculating buffer size");
let mut buf = vec![0; encoded_size];
encode_with_padding(input.as_ref(), &mut buf[..], self, encoded_size);
String::from_utf8(buf).expect("Invalid UTF8")
}
#[cfg(any(feature = "alloc", feature = "std", test))]
fn encode_string<T: AsRef<[u8]>>(&self, input: T, output_buf: &mut String) {
let input_bytes = input.as_ref();
{
let mut sink = chunked_encoder::StringSink::new(output_buf);
chunked_encoder::ChunkedEncoder::new(self)
.encode(input_bytes, &mut sink)
.expect("Writing to a String shouldn't fail");
}
}
fn encode_slice<T: AsRef<[u8]>>(
&self,
input: T,
output_buf: &mut [u8],
) -> Result<usize, EncodeSliceError> {
let input_bytes = input.as_ref();
let encoded_size = encoded_len(input_bytes.len(), self.config().encode_padding())
.expect("usize overflow when calculating buffer size");
if output_buf.len() < encoded_size {
return Err(EncodeSliceError::OutputSliceTooSmall);
}
let b64_output = &mut output_buf[0..encoded_size];
encode_with_padding(input_bytes, b64_output, self, encoded_size);
Ok(encoded_size)
}
#[cfg(any(feature = "alloc", feature = "std", test))]
fn decode<T: AsRef<[u8]>>(&self, input: T) -> Result<Vec<u8>, DecodeError> {
let input_bytes = input.as_ref();
let estimate = self.internal_decoded_len_estimate(input_bytes.len());
let mut buffer = vec![0; estimate.decoded_len_estimate()];
let bytes_written = self.internal_decode(input_bytes, &mut buffer, estimate)?;
buffer.truncate(bytes_written);
Ok(buffer)
}
#[cfg(any(feature = "alloc", feature = "std", test))]
fn decode_vec<T: AsRef<[u8]>>(
&self,
input: T,
buffer: &mut Vec<u8>,
) -> Result<(), DecodeError> {
let input_bytes = input.as_ref();
let starting_output_len = buffer.len();
let estimate = self.internal_decoded_len_estimate(input_bytes.len());
let total_len_estimate = estimate
.decoded_len_estimate()
.checked_add(starting_output_len)
.expect("Overflow when calculating output buffer length");
buffer.resize(total_len_estimate, 0);
let buffer_slice = &mut buffer.as_mut_slice()[starting_output_len..];
let bytes_written = self.internal_decode(input_bytes, buffer_slice, estimate)?;
buffer.truncate(starting_output_len + bytes_written);
Ok(())
}
fn decode_slice<T: AsRef<[u8]>>(
&self,
input: T,
output: &mut [u8],
) -> Result<usize, DecodeSliceError> {
let input_bytes = input.as_ref();
let estimate = self.internal_decoded_len_estimate(input_bytes.len());
if output.len() < estimate.decoded_len_estimate() {
return Err(DecodeSliceError::OutputSliceTooSmall);
}
self.internal_decode(input_bytes, output, estimate)
.map_err(|e| e.into())
}
fn decode_slice_unchecked<T: AsRef<[u8]>>(
&self,
input: T,
output: &mut [u8],
) -> Result<usize, DecodeError> {
let input_bytes = input.as_ref();
self.internal_decode(
input_bytes,
output,
self.internal_decoded_len_estimate(input_bytes.len()),
)
}
}
pub trait Config {
fn encode_padding(&self) -> bool;
}
pub trait DecodeEstimate {
fn decoded_len_estimate(&self) -> usize;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DecodePaddingMode {
Indifferent,
RequireCanonical,
RequireNone,
}