#![cfg_attr(not(any(feature = "std", test)), no_std)]
#![cfg_attr(feature = "unstable", feature(aarch64_target_feature))]
#![cfg_attr(feature = "unstable", feature(arm_target_feature))]
#![deny(
clippy::all,
clippy::cargo,
missing_debug_implementations,
missing_docs
)]
#![warn(clippy::todo)]
#[cfg(feature = "alloc")]
extern crate alloc;
pub use simd_abstraction::tools::OutBuf;
mod error;
pub use self::error::Error;
pub(crate) use self::error::ERROR;
mod utils;
#[cfg(test)]
mod tests;
pub mod fallback;
#[macro_use]
mod generic;
mod polyfill;
pub mod arch;
mod auto;
mod ext;
#[derive(Debug)]
enum Base64Kind {
Standard,
UrlSafe,
}
#[derive(Debug)]
pub struct Base64 {
kind: Base64Kind,
padding: bool,
}
impl Base64 {
const PAD: u8 = b'=';
pub const STANDARD: Self = Self {
kind: Base64Kind::Standard,
padding: true,
};
pub const STANDARD_NO_PAD: Self = Self {
kind: Base64Kind::Standard,
padding: false,
};
pub const URL_SAFE: Self = Self {
kind: Base64Kind::UrlSafe,
padding: true,
};
pub const URL_SAFE_NO_PAD: Self = Self {
kind: Base64Kind::UrlSafe,
padding: false,
};
const unsafe fn encoded_length_unchecked(n: usize, padding: bool) -> usize {
let extra = n % 3;
if extra == 0 {
n / 3 * 4
} else if padding {
n / 3 * 4 + 4
} else {
n / 3 * 4 + extra + 1
}
}
unsafe fn decoded_length_unchecked(src: &[u8], padding: bool) -> Result<(usize, usize), Error> {
let n = {
let len = src.len();
if padding {
if len % 4 != 0 {
return Err(ERROR);
}
let last1 = *src.get_unchecked(len - 1);
let last2 = *src.get_unchecked(len - 2);
let count = (last1 == Base64::PAD) as usize + (last2 == Base64::PAD) as usize;
len - count
} else {
len
}
};
let m = match n % 4 {
0 => n / 4 * 3,
1 => return Err(ERROR),
2 => n / 4 * 3 + 1,
3 => n / 4 * 3 + 2,
_ => core::hint::unreachable_unchecked(),
};
Ok((n, m))
}
pub const fn encoded_length(&self, n: usize) -> usize {
assert!(n < usize::MAX / 2);
unsafe { Self::encoded_length_unchecked(n, self.padding) }
}
}