lib_unknown/types/bytes.rs
1//! 定容字节容器:栈上(`StackBytes`)与堆上(`HeapBytes`,需 `alloc`)实现,`Drop` 与显式擦除均经易失写清零。
2//!
3//! 需要启用 `"types-bytes"` 特性。
4#![allow(unused_qualifications)]
5#![allow(clippy::similar_names)]
6#![allow(unused)]
7
8#[cfg(feature = "alloc")]
9extern crate alloc;
10
11use core::fmt;
12use core::hint::black_box;
13use core::sync::atomic::{Ordering, compiler_fence};
14
15/// 字节容器的错误类型。未来可能新增变体/字段,请勿依赖穷尽匹配。
16///
17/// # Feature Requirement
18///
19/// 需要启用 `"types-bytes"` 特性。
20///
21/// # Examples
22///
23/// ```rust
24/// use lib_unknown::types::bytes::{Bytes, StackBytes};
25///
26/// let mut b = StackBytes::<4>::new();
27/// let err = b.extend_from_slice(b"toolong").unwrap_err();
28/// assert!(matches!(err, lib_unknown::types::bytes::BytesError::CapacityExceeded { .. }));
29/// ```
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31#[non_exhaustive]
32pub enum BytesError {
33 /// 请求长度超出容器容量。
34 CapacityExceeded {
35 /// 请求的总长度(字节)。
36 requested: usize,
37 /// 容器支持的最大长度(字节)。
38 max: usize,
39 },
40}
41
42impl fmt::Display for BytesError {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 match self {
45 Self::CapacityExceeded { requested, max } => write!(
46 f,
47 "capacity exceeded: requested {requested} bytes, max supported {max} bytes"
48 ),
49 }
50 }
51}
52
53impl core::error::Error for BytesError {}
54
55/// 字节容器操作的统一返回类型。
56///
57/// # Feature Requirement
58///
59/// 需要启用 `"types-bytes"` 特性。
60///
61/// # Errors
62///
63/// - 当请求长度超出容器容量时返回 [`BytesError::CapacityExceeded`]。
64pub type BytesResult<T = ()> = Result<T, BytesError>;
65
66#[inline(always)]
67pub(crate) fn volatile_zero(buf: &mut [u8]) {
68 for byte in black_box(buf.iter_mut()) {
69 // SAFETY: `byte` 为 `buf` 的独占借用派生的有效可写引用,`write_volatile` 写入对齐的 `u8`。
70 unsafe {
71 let _: () = core::ptr::write_volatile(black_box(byte), 0);
72 black_box(());
73 }
74 }
75 compiler_fence(Ordering::SeqCst);
76}
77
78/// 定容字节容器的统一接口:写入、擦除与向更大容器搬运。
79///
80/// 所有实现([`StackBytes`] / `HeapBytes`)在 `Drop` 与显式擦除时经易失写清零。
81///
82/// # Feature Requirement
83///
84/// 需要启用 `"types-bytes"` 特性。
85///
86/// # Examples
87///
88/// ```rust
89/// use lib_unknown::types::bytes::{Bytes, StackBytes};
90///
91/// let mut b = StackBytes::<8>::new();
92/// b.extend_from_slice(b"hi").unwrap();
93/// assert_eq!(b.as_slice(), b"hi");
94/// b.wipe_data();
95/// assert!(b.is_empty());
96/// ```
97pub trait Bytes:
98 core::ops::Deref<Target = [u8]> + core::ops::DerefMut + AsRef<[u8]> + AsMut<[u8]> + Default + Sized
99{
100 /// 返回容器容量(字节),与已写入长度无关。
101 ///
102 /// # Feature Requirement
103 ///
104 /// 需要启用 `"types-bytes"` 特性。
105 fn capacity(&self) -> usize;
106 /// 返回已写入数据的长度(字节)。
107 ///
108 /// # Feature Requirement
109 ///
110 /// 需要启用 `"types-bytes"` 特性。
111 fn len(&self) -> usize;
112
113 /// 已写入数据是否为空。
114 ///
115 /// # Feature Requirement
116 ///
117 /// 需要启用 `"types-bytes"` 特性。
118 fn is_empty(&self) -> bool {
119 self.len() == 0
120 }
121
122 /// 追加 `other` 的全部字节。
123 ///
124 /// # Feature Requirement
125 ///
126 /// 需要启用 `"types-bytes"` 特性。
127 ///
128 /// # Examples
129 ///
130 /// ```rust
131 /// use lib_unknown::types::bytes::{Bytes, StackBytes};
132 ///
133 /// let mut b = StackBytes::<8>::new();
134 /// b.extend_from_slice(b"hi").unwrap();
135 /// assert_eq!(b.len(), 2);
136 /// ```
137 ///
138 /// # Errors
139 ///
140 /// - 当追加后总长度超出容量时返回 [`BytesError::CapacityExceeded`],容器内容不变。
141 fn extend_from_slice(&mut self, other: &[u8]) -> BytesResult;
142
143 /// 清零全部底层存储并将长度置 0。
144 ///
145 /// # Feature Requirement
146 ///
147 /// 需要启用 `"types-bytes"` 特性。
148 fn wipe_data(&mut self);
149
150 /// 以不可变切片查看已写入数据。
151 ///
152 /// # Feature Requirement
153 ///
154 /// 需要启用 `"types-bytes"` 特性。
155 fn as_slice(&self) -> &[u8] {
156 self.as_ref()
157 }
158
159 /// 以可变切片访问已写入数据(不改变长度)。
160 ///
161 /// # Feature Requirement
162 ///
163 /// 需要启用 `"types-bytes"` 特性。
164 fn as_mut_slice(&mut self) -> &mut [u8] {
165 self.as_mut()
166 }
167
168 /// 将自身内容与 `other` 先后写入新容器,并擦除自身。
169 ///
170 /// # Feature Requirement
171 ///
172 /// 需要启用 `"types-bytes"` 特性。
173 ///
174 /// # Examples
175 ///
176 /// ```rust
177 /// use lib_unknown::types::bytes::{Bytes, StackBytes};
178 ///
179 /// let mut b = StackBytes::<8>::new();
180 /// b.extend_from_slice(b"hi").unwrap();
181 /// let c: StackBytes<8> = b.extend_into(b"!").unwrap();
182 /// assert_eq!(c.as_slice(), b"hi!");
183 /// ```
184 ///
185 /// # Errors
186 ///
187 /// - 当任一写入超出目标容器容量时返回 [`BytesError::CapacityExceeded`]。
188 fn extend_into<T>(mut self, other: &[u8]) -> BytesResult<T>
189 where
190 Self: Sized,
191 T: Bytes + Default,
192 {
193 let mut new_buf = T::default();
194 new_buf.extend_from_slice(self.as_slice())?;
195 new_buf.extend_from_slice(other)?;
196 self.wipe_data();
197
198 Ok(new_buf)
199 }
200
201 /// 将 `source` 内容追加到自身,成功后清零 `source`;失败时 `source` 保持不变。
202 ///
203 /// # Feature Requirement
204 ///
205 /// 需要启用 `"types-bytes"` 特性。
206 ///
207 /// # Examples
208 ///
209 /// ```rust
210 /// use lib_unknown::types::bytes::{Bytes, StackBytes};
211 ///
212 /// let mut b = StackBytes::<8>::new();
213 /// let mut secret = *b"hi";
214 /// b.extend_and_wipe(&mut secret).unwrap();
215 /// assert_eq!(secret, [0u8; 2]);
216 /// ```
217 ///
218 /// # Errors
219 ///
220 /// - 当追加后总长度超出容量时返回 [`BytesError::CapacityExceeded`]。
221 fn extend_and_wipe<T>(&mut self, mut source: T) -> BytesResult
222 where
223 Self: Sized,
224 T: AsRef<[u8]> + AsMut<[u8]>,
225 {
226 let res = self.extend_from_slice(source.as_ref());
227 if res.is_ok() {
228 volatile_zero(source.as_mut());
229 }
230 res
231 }
232}
233
234macro_rules! impl_secure_buffer {
235 ($name:ident) => {
236 impl<const N: usize> $name<N> {
237 /// 将内容搬运到容量为 `M` 的同类容器中。
238 ///
239 /// # Feature Requirement
240 ///
241 /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
242 ///
243 /// # Examples
244 ///
245 /// ```rust
246 /// use lib_unknown::types::bytes::StackBytes;
247 ///
248 /// let mut b = StackBytes::<4>::new();
249 /// b.extend_from_slice(b"hi").unwrap();
250 /// let c = b.try_grow::<8>().unwrap();
251 /// assert_eq!(c.capacity(), 8);
252 /// ```
253 ///
254 /// # Errors
255 ///
256 /// - 当已有长度超出 `M` 时返回 [`BytesError::CapacityExceeded`]。
257 pub fn try_grow<const M: usize>(self) -> BytesResult<$name<M>> {
258 if self.len > M {
259 return Err(BytesError::CapacityExceeded {
260 requested: self.len,
261 max: M,
262 });
263 }
264 let mut out = $name::<M>::new();
265 out.data[..self.len].copy_from_slice(&self.data[..self.len]);
266 out.len = self.len;
267 Ok(out)
268 }
269
270 /// 返回容器容量(字节),恒为 `N`。
271 ///
272 /// # Feature Requirement
273 ///
274 /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
275 #[inline(always)]
276 pub fn capacity(&self) -> usize {
277 N
278 }
279
280 /// 返回已写入数据的长度(字节)。
281 ///
282 /// # Feature Requirement
283 ///
284 /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
285 #[inline(always)]
286 pub fn len(&self) -> usize {
287 self.len
288 }
289
290 /// 已写入数据是否为空。
291 ///
292 /// # Feature Requirement
293 ///
294 /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
295 #[inline(always)]
296 pub fn is_empty(&self) -> bool {
297 self.len == 0
298 }
299
300 /// 以不可变切片查看已写入数据。
301 ///
302 /// # Feature Requirement
303 ///
304 /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
305 #[inline(always)]
306 pub fn as_slice(&self) -> &[u8] {
307 self.as_ref()
308 }
309
310 /// 以可变切片访问已写入数据(不改变长度)。
311 ///
312 /// # Feature Requirement
313 ///
314 /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
315 #[inline(always)]
316 pub fn as_mut_slice(&mut self) -> &mut [u8] {
317 self.as_mut()
318 }
319
320 /// 追加 `other` 的全部字节。
321 ///
322 /// # Feature Requirement
323 ///
324 /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
325 ///
326 /// # Examples
327 ///
328 /// ```rust
329 /// use lib_unknown::types::bytes::StackBytes;
330 ///
331 /// let mut b = StackBytes::<4>::new();
332 /// b.extend_from_slice(b"hi").unwrap();
333 /// assert!(b.extend_from_slice(b"toolong").is_err());
334 /// ```
335 ///
336 /// # Errors
337 ///
338 /// - 当追加后总长度超出容量时返回 [`BytesError::CapacityExceeded`],容器内容不变。
339 pub fn extend_from_slice(&mut self, other: &[u8]) -> BytesResult {
340 let new_len =
341 self.len
342 .checked_add(other.len())
343 .ok_or(BytesError::CapacityExceeded {
344 requested: usize::MAX,
345 max: N,
346 })?;
347 if new_len > N {
348 return Err(BytesError::CapacityExceeded {
349 requested: new_len,
350 max: N,
351 });
352 }
353 self.data[self.len..new_len].copy_from_slice(other);
354 self.len = new_len;
355 Ok(())
356 }
357
358 /// 清零全部底层存储并将长度置 0。
359 ///
360 /// # Feature Requirement
361 ///
362 /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
363 pub fn wipe_data(&mut self) {
364 volatile_zero(&mut self.data[..]);
365 self.len = 0;
366 }
367
368 /// 将自身内容与 `other` 先后写入新容器,并擦除自身。
369 ///
370 /// # Feature Requirement
371 ///
372 /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
373 ///
374 /// # Examples
375 ///
376 /// ```rust
377 /// use lib_unknown::types::bytes::StackBytes;
378 ///
379 /// let mut b = StackBytes::<8>::new();
380 /// b.extend_from_slice(b"hi").unwrap();
381 /// let c: StackBytes<8> = b.extend_into(b"!").unwrap();
382 /// assert_eq!(c.as_slice(), b"hi!");
383 /// ```
384 ///
385 /// # Errors
386 ///
387 /// - 当任一写入超出目标容器容量时返回 [`BytesError::CapacityExceeded`]。
388 pub fn extend_into<T>(mut self, other: &[u8]) -> BytesResult<T>
389 where
390 T: Bytes + Default,
391 {
392 let mut new_buf = T::default();
393 new_buf.extend_from_slice(self.as_slice())?;
394 new_buf.extend_from_slice(other)?;
395 self.wipe_data();
396 Ok(new_buf)
397 }
398
399 /// 将 `source` 内容追加到自身,成功后清零 `source`;失败时 `source` 保持不变。
400 ///
401 /// # Feature Requirement
402 ///
403 /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
404 ///
405 /// # Examples
406 ///
407 /// ```rust
408 /// use lib_unknown::types::bytes::StackBytes;
409 ///
410 /// let mut b = StackBytes::<8>::new();
411 /// let mut src = *b"hi";
412 /// b.extend_and_wipe(&mut src).unwrap();
413 /// assert_eq!(src, [0u8; 2]);
414 /// ```
415 ///
416 /// # Errors
417 ///
418 /// - 当追加后总长度超出容量时返回 [`BytesError::CapacityExceeded`]。
419 pub fn extend_and_wipe<T>(&mut self, mut source: T) -> BytesResult
420 where
421 T: AsRef<[u8]> + AsMut<[u8]>,
422 {
423 let res = self.extend_from_slice(source.as_ref());
424 if res.is_ok() {
425 volatile_zero(source.as_mut());
426 }
427 res
428 }
429 }
430
431 impl<const N: usize> Default for $name<N> {
432 fn default() -> Self {
433 Self::new()
434 }
435 }
436
437 impl<const N: usize> Drop for $name<N> {
438 fn drop(&mut self) {
439 volatile_zero(&mut self.data[..]);
440 }
441 }
442
443 impl<const N: usize> AsRef<[u8]> for $name<N> {
444 fn as_ref(&self) -> &[u8] {
445 &self.data[..self.len]
446 }
447 }
448
449 impl<const N: usize> AsMut<[u8]> for $name<N> {
450 fn as_mut(&mut self) -> &mut [u8] {
451 &mut self.data[..self.len]
452 }
453 }
454
455 impl<const N: usize> core::ops::Deref for $name<N> {
456 type Target = [u8];
457 fn deref(&self) -> &Self::Target {
458 &self.data[..self.len]
459 }
460 }
461
462 impl<const N: usize> core::ops::DerefMut for $name<N> {
463 fn deref_mut(&mut self) -> &mut Self::Target {
464 &mut self.data[..self.len]
465 }
466 }
467
468 impl<const N: usize> fmt::Debug for $name<N> {
469 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470 f.debug_struct(stringify!($name))
471 .field("len", &self.len)
472 .field("capacity", &N)
473 .finish()
474 }
475 }
476
477 impl<const N: usize> Bytes for $name<N> {
478 #[inline(always)]
479 fn capacity(&self) -> usize {
480 self.capacity()
481 }
482 #[inline(always)]
483 fn len(&self) -> usize {
484 self.len()
485 }
486 #[inline(always)]
487 fn is_empty(&self) -> bool {
488 self.is_empty()
489 }
490 #[inline(always)]
491 fn as_slice(&self) -> &[u8] {
492 self.as_slice()
493 }
494 #[inline(always)]
495 fn as_mut_slice(&mut self) -> &mut [u8] {
496 self.as_mut_slice()
497 }
498 #[inline(always)]
499 fn extend_from_slice(&mut self, other: &[u8]) -> BytesResult {
500 self.extend_from_slice(other)
501 }
502 #[inline(always)]
503 fn wipe_data(&mut self) {
504 self.wipe_data()
505 }
506 #[inline(always)]
507 fn extend_into<T>(self, other: &[u8]) -> BytesResult<T>
508 where
509 Self: Sized,
510 T: Bytes + Default,
511 {
512 self.extend_into(other)
513 }
514 #[inline(always)]
515 fn extend_and_wipe<T>(&mut self, source: T) -> BytesResult
516 where
517 Self: Sized,
518 T: AsRef<[u8]> + AsMut<[u8]>,
519 {
520 self.extend_and_wipe(source)
521 }
522 }
523 };
524}
525
526/// 栈上定容字节容器,`Drop` 时自动清零,适用于短密钥、非对称 nonce 等小敏感数据。
527///
528/// # Feature Requirement
529///
530/// 需要启用 `"types-bytes"` 特性。
531///
532/// # Examples
533///
534/// ```rust
535/// use lib_unknown::types::bytes::{Bytes, StackBytes};
536///
537/// let mut b = StackBytes::<16>::new();
538/// b.extend_from_slice(b"secret").unwrap();
539/// assert_eq!(b.len(), 6);
540/// ```
541pub struct StackBytes<const N: usize> {
542 len: usize,
543 data: [u8; N],
544}
545impl<const N: usize> StackBytes<N> {
546 /// 创建长度为 0、内容全零的容器。
547 ///
548 /// # Feature Requirement
549 ///
550 /// 需要启用 `"types-bytes"` 特性。
551 pub const fn new() -> Self {
552 Self {
553 len: 0,
554 data: [0u8; N],
555 }
556 }
557}
558impl_secure_buffer!(StackBytes);
559
560/// 堆上定容字节容器,语义与 [`StackBytes`] 一致,适用于超过栈承载的较大敏感数据。
561///
562/// # Feature Requirement
563///
564/// 需要启用 `"types-bytes"` 与 `"alloc"` 特性。
565///
566/// # Examples
567///
568/// ```rust
569/// use lib_unknown::types::bytes::{Bytes, HeapBytes};
570///
571/// let mut b = HeapBytes::<64>::new();
572/// b.extend_from_slice(b"secret").unwrap();
573/// assert_eq!(b.len(), 6);
574/// ```
575#[cfg(feature = "alloc")]
576pub struct HeapBytes<const N: usize> {
577 len: usize,
578 data: alloc::boxed::Box<[u8; N]>,
579}
580
581#[cfg(feature = "alloc")]
582fn zeroed_box<const N: usize>() -> alloc::boxed::Box<[u8; N]> {
583 // SAFETY: `[u8; N]` 全零为合法值,`assume_init` 安全。
584 unsafe { alloc::boxed::Box::<[u8; N]>::new_zeroed().assume_init() }
585}
586
587#[cfg(feature = "alloc")]
588impl<const N: usize> HeapBytes<N> {
589 /// 创建长度为 0、内容全零的容器。
590 ///
591 /// # Feature Requirement
592 ///
593 /// 需要启用 `"types-bytes"` 与 `"alloc"` 特性。
594 pub fn new() -> Self {
595 Self {
596 len: 0,
597 data: zeroed_box::<N>(),
598 }
599 }
600}
601#[cfg(feature = "alloc")]
602impl_secure_buffer!(HeapBytes);
603
604#[cfg(test)]
605#[allow(clippy::unwrap_used, clippy::expect_used)]
606mod tests {
607 use super::*;
608
609 #[test]
610 fn test_stack_buffer() {
611 let mut d = StackBytes::<32>::new();
612
613 let mut secret_data = *b"super_secret_password";
614 d.extend_and_wipe(&mut secret_data).unwrap();
615
616 assert_eq!(&secret_data, &[0u8; 21]);
617 assert_eq!(d.as_slice(), b"super_secret_password");
618 }
619
620 #[cfg(feature = "alloc")]
621 #[test]
622 fn test_heap_buffer() {
623 let mut d = StackBytes::<32>::new();
624
625 let mut secret_data = *b"super_secret_password";
626 d.extend_and_wipe(&mut secret_data).unwrap();
627
628 let extra_data = b"_suffix";
629 let mut x = d.extend_into::<HeapBytes<512>>(extra_data).unwrap();
630
631 fn aaa(d: &impl Bytes) {
632 assert!(d.capacity() >= 512);
633 }
634 aaa(&x);
635
636 assert_eq!(x.as_slice(), b"super_secret_password_suffix");
637 assert!(x.starts_with(b"super_secret"));
638
639 x[0] = b'S';
640 assert_eq!(x.as_slice(), b"Super_secret_password_suffix");
641
642 fn requires_slice(s: &[u8]) {
643 assert_eq!(s.len(), 28);
644 }
645 requires_slice(&x);
646
647 fn bbb(d: impl Bytes) {
648 assert!(d.capacity() >= 512);
649 }
650 bbb(x);
651 }
652}