1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use std::{fmt::Debug, slice};
#[derive(Clone, Default)]
pub struct Storage {
vec: Vec<u128>,
size: usize,
}
impl Storage {
/// Creates a new `Storage` instance from a byte slice.
///
/// This function creates a new `Storage` instance and initializes it with the contents of the input byte slice.
/// The `Storage` instance will have a capacity of at least the length of the input slice, and the data will be
/// copied into the internal buffer.
///
/// # Arguments
/// - `input`: A byte slice containing the data to be stored in the `Storage` instance.
///
/// # Returns
/// A new `Storage` instance containing the data from the input byte slice.
///
/// # Example
/// ```
/// use flat_message::*;
///
/// let data = [1, 2, 3, 4, 5];
/// let storage = Storage::from_buffer(&data);
/// assert_eq!(storage.as_slice(), &data);
/// ```
pub fn from_buffer(input: &[u8]) -> Storage {
let mut r = Storage::default();
r.resize_zero(input.len());
r.as_mut_slice().copy_from_slice(input);
r
}
/// Creates a new `Storage` instance with a given capacity filled with zeros.
/// Since a Storage object can be reused, this is a good way to create an initial object and then use it to serrialize / deserialize multiple objects.
pub fn with_capacity(capacity: usize) -> Storage {
let mut r = Storage::default();
r.resize_zero(capacity);
r
}
/// Returns the length of the data stored in the `Storage` instance.
#[inline(always)]
pub fn len(&self) -> usize {
self.size
}
/// Returns whether the length of the data stored in the `Storage` instance is zero.
pub fn is_empty(&self) -> bool {
self.size == 0
}
/// Clears the contents of the buffer.
#[inline]
pub fn clear(&mut self) {
self.vec.clear();
self.size = 0;
}
/// Resizes the buffer to the specified length, initializing additional bytes to 0.
#[inline]
pub fn resize_zero(&mut self, new_len: usize) {
self.vec
.resize(new_len / std::mem::size_of::<u128>() + 1, 0);
self.size = new_len;
}
/// Returns a slice of the buffer.
#[inline]
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.vec.as_ptr() as *const u8, self.size) }
}
/// Returns a mutable slice of the buffer.
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.as_mut_ptr() as *mut u8, self.size) }
}
pub fn as_ref(&self) -> &StorageRef {
StorageRef::from_storage(self)
}
}
impl Debug for Storage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self.as_slice(), f)
}
}
impl PartialEq<Storage> for Storage {
fn eq(&self, other: &Storage) -> bool {
self.as_slice() == other.as_slice()
}
}
impl std::ops::Deref for Storage {
type Target = StorageRef;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
#[cfg(feature = "stable_deref")]
unsafe impl stable_deref_trait::StableDeref for Storage {}
/// Wraps a raw byte slice that is known to be aligned to a 128-bit boundary.
/// This pattern is simiarily used (but with a different invariant) in CString / CStr.
/// (CStr itself is a #[repr(transparent)] struct over a raw byte slice, with the invariant that it ends with a nul byte.)
#[repr(transparent)]
pub struct StorageRef([u8]);
impl StorageRef {
pub fn from_storage(storage: &Storage) -> &Self {
// # Safety:
// The storage only returns us a slice that is guaranteed to be aligned to a 128-bit boundary.
// We can safely transmute the slice to a &StorageRef due to the repr(transparent).
// This is the same pattern used to convert from a &CString to a &Cstr,
// although with a pointer cast instead of a transmute.
unsafe { std::mem::transmute(storage.as_slice()) }
}
pub fn as_slice(&self) -> &[u8] {
&self.0
}
}