use base64::{
display::Base64Display,
encoded_len,
engine::general_purpose::{GeneralPurpose, STANDARD},
};
use core::fmt::{self, Write};
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Base64Slice([u8]);
impl Base64Slice {
#[inline]
#[must_use]
pub const fn new(bytes: &[u8]) -> &Self {
unsafe { &*(bytes as *const [u8] as *const Self) }
}
#[inline]
#[must_use]
pub const fn as_bytes(&self) -> &[u8] {
&self.0
}
}
fn base64_display(bytes: &[u8]) -> Base64Display<'_, 'static, GeneralPurpose> {
Base64Display::new(bytes, &STANDARD)
}
pub(crate) struct QuotedBase64<'a>(pub(crate) &'a [u8]);
impl fmt::Debug for QuotedBase64<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('"')?;
fmt::Display::fmt(&base64_display(self.0), f)?;
f.write_char('"')
}
}
struct Truncate<'a, 'b> {
inner: &'a mut fmt::Formatter<'b>,
remaining: usize,
}
impl Write for Truncate<'_, '_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
let take = s.len().min(self.remaining);
self.remaining -= take;
self.inner.write_str(&s[..take])
}
}
impl fmt::Debug for Base64Slice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Base64Slice").field(&QuotedBase64(&self.0)).finish()
}
}
impl fmt::Display for Base64Slice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let encoded_len = encoded_len(self.0.len(), true)
.expect("base64 length of an in-memory slice fits in usize");
let content_len = match f.precision() {
Some(precision) => precision.min(encoded_len),
None => encoded_len,
};
let padding = match f.width() {
Some(width) => width.saturating_sub(content_len),
None => 0,
};
let (pre, post) = match f.align() {
Some(fmt::Alignment::Left) | None => (0, padding),
Some(fmt::Alignment::Right) => (padding, 0),
Some(fmt::Alignment::Center) => {
(padding / 2, padding - padding / 2)
}
};
let fill = f.fill();
for _ in 0..pre {
f.write_char(fill)?;
}
if content_len == encoded_len {
fmt::Display::fmt(&base64_display(&self.0), f)?;
} else {
let mut truncate = Truncate { inner: f, remaining: content_len };
write!(truncate, "{}", base64_display(&self.0))?;
}
for _ in 0..post {
f.write_char(fill)?;
}
Ok(())
}
}
impl core::ops::Deref for Base64Slice {
type Target = [u8];
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl AsRef<[u8]> for Base64Slice {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl AsRef<Base64Slice> for Base64Slice {
#[inline]
fn as_ref(&self) -> &Base64Slice {
self
}
}
#[cfg(feature = "serde")]
mod serde_impls {
use super::{Base64Slice, base64_display};
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
impl serde_core::Serialize for Base64Slice {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde_core::Serializer,
{
if serializer.is_human_readable() {
serializer.collect_str(&base64_display(&self.0))
} else {
serializer.serialize_bytes(&self.0)
}
}
}
}