byte_wrapper/
base64_slice.rs1use base64::{
7 display::Base64Display,
8 encoded_len,
9 engine::general_purpose::{GeneralPurpose, STANDARD},
10};
11use core::fmt::{self, Write};
12
13#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
35#[repr(transparent)]
36pub struct Base64Slice([u8]);
37
38impl Base64Slice {
39 #[inline]
41 #[must_use]
42 pub const fn new(bytes: &[u8]) -> &Self {
43 unsafe { &*(bytes as *const [u8] as *const Self) }
52 }
53
54 #[inline]
56 #[must_use]
57 pub const fn as_bytes(&self) -> &[u8] {
58 &self.0
59 }
60}
61
62fn base64_display(bytes: &[u8]) -> Base64Display<'_, 'static, GeneralPurpose> {
63 Base64Display::new(bytes, &STANDARD)
64}
65
66pub(crate) struct QuotedBase64<'a>(pub(crate) &'a [u8]);
70
71impl fmt::Debug for QuotedBase64<'_> {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 f.write_char('"')?;
74 fmt::Display::fmt(&base64_display(self.0), f)?;
75 f.write_char('"')
76 }
77}
78
79struct Truncate<'a, 'b> {
83 inner: &'a mut fmt::Formatter<'b>,
84 remaining: usize,
85}
86
87impl Write for Truncate<'_, '_> {
88 fn write_str(&mut self, s: &str) -> fmt::Result {
89 let take = s.len().min(self.remaining);
90 self.remaining -= take;
91 self.inner.write_str(&s[..take])
92 }
93}
94
95impl fmt::Debug for Base64Slice {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 f.debug_tuple("Base64Slice").field(&QuotedBase64(&self.0)).finish()
98 }
99}
100
101impl fmt::Display for Base64Slice {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 let encoded_len = encoded_len(self.0.len(), true)
107 .expect("base64 length of an in-memory slice fits in usize");
108 let content_len = match f.precision() {
109 Some(precision) => precision.min(encoded_len),
110 None => encoded_len,
111 };
112 let padding = match f.width() {
113 Some(width) => width.saturating_sub(content_len),
114 None => 0,
115 };
116 let (pre, post) = match f.align() {
117 Some(fmt::Alignment::Left) | None => (0, padding),
118 Some(fmt::Alignment::Right) => (padding, 0),
119 Some(fmt::Alignment::Center) => {
120 (padding / 2, padding - padding / 2)
121 }
122 };
123
124 let fill = f.fill();
125 for _ in 0..pre {
126 f.write_char(fill)?;
127 }
128 if content_len == encoded_len {
129 fmt::Display::fmt(&base64_display(&self.0), f)?;
130 } else {
131 let mut truncate = Truncate { inner: f, remaining: content_len };
132 write!(truncate, "{}", base64_display(&self.0))?;
133 }
134 for _ in 0..post {
135 f.write_char(fill)?;
136 }
137 Ok(())
138 }
139}
140
141impl core::ops::Deref for Base64Slice {
142 type Target = [u8];
143
144 #[inline]
145 fn deref(&self) -> &Self::Target {
146 &self.0
147 }
148}
149
150impl AsRef<[u8]> for Base64Slice {
151 #[inline]
152 fn as_ref(&self) -> &[u8] {
153 &self.0
154 }
155}
156
157impl AsRef<Base64Slice> for Base64Slice {
158 #[inline]
159 fn as_ref(&self) -> &Base64Slice {
160 self
161 }
162}
163
164#[cfg(feature = "serde")]
165mod serde_impls {
166 use super::{Base64Slice, base64_display};
167
168 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
169 impl serde_core::Serialize for Base64Slice {
170 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
171 where
172 S: serde_core::Serializer,
173 {
174 if serializer.is_human_readable() {
175 serializer.collect_str(&base64_display(&self.0))
176 } else {
177 serializer.serialize_bytes(&self.0)
178 }
179 }
180 }
181}