1const SIZE_INT32: usize = 4;
2const SIZE_UINT32: usize = 4;
3const SIZE_INT64: usize = 8;
4const SIZE_UINT64: usize = 8;
5const SIZE_FLOAT: usize = 4;
6const SIZE_DOUBLE: usize = 8;
7const PAYLOAD_UNIT: usize = 64;
8
9macro_rules! write_pod {
10 ($self:ident, $value:expr, $size:ident) => {{
11 let data_length = align_int($size, SIZE_UINT32);
12 let new_size = $self.write_offset + data_length;
13 $self.ensure_capacity(new_size);
14 let offset = $self.header_size + $self.write_offset;
15 $self.header[offset..offset + $size].copy_from_slice(&$value.to_le_bytes());
16 $self.pad_after(offset, $size, data_length);
17 $self.set_payload_size(new_size);
18 $self.write_offset = new_size;
19 }};
20}
21
22macro_rules! read_pod {
23 ($self:ident, $size:ident, $ty:ty) => {{
24 let bytes = $self.read_slice($size);
25 <$ty>::from_le_bytes(bytes.try_into().unwrap())
26 }};
27}
28
29fn align_int(i: usize, alignment: usize) -> usize {
30 i + ((alignment - (i % alignment)) % alignment)
31}
32
33pub struct Pickle {
36 header: Vec<u8>,
37 header_size: usize,
38 capacity_after_header: usize,
39 write_offset: usize,
40}
41
42impl Default for Pickle {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl Pickle {
49 pub fn new() -> Self {
50 let header = vec![0u8; SIZE_UINT32];
51 let mut pickle = Pickle {
52 header,
53 header_size: SIZE_UINT32,
54 capacity_after_header: 0,
55 write_offset: 0,
56 };
57 pickle.resize(PAYLOAD_UNIT);
58 pickle.set_payload_size(0);
59 pickle
60 }
61
62 pub fn from_buffer(buffer: &[u8]) -> Self {
63 let header = buffer.to_vec();
64 let payload_size = u32::from_le_bytes(header[0..4].try_into().unwrap()) as usize;
65 let header_size = header.len().saturating_sub(payload_size);
66
67 let header_size = if header_size <= header.len()
68 && header_size == align_int(header_size, SIZE_UINT32)
69 {
70 header_size
71 } else {
72 0
73 };
74
75 let header = if header_size == 0 {
76 vec![]
77 } else {
78 header
79 };
80
81 Pickle {
82 header,
83 header_size,
84 capacity_after_header: 9_007_199_254_740_992,
85 write_offset: 0,
86 }
87 }
88
89 pub fn iter(&self) -> PickleIterator<'_> {
90 PickleIterator {
91 payload: &self.header,
92 payload_offset: self.header_size,
93 read_index: 0,
94 end_index: self.get_payload_size(),
95 }
96 }
97
98 pub fn into_buffer(self) -> Vec<u8> {
99 let end = self.header_size + self.get_payload_size();
100 if end <= self.header.len() {
101 self.header[..end].to_vec()
102 } else {
103 self.header.to_vec()
104 }
105 }
106
107 pub fn write_bool(&mut self, value: bool) {
108 self.write_i32(if value { 1 } else { 0 });
109 }
110
111 pub fn write_i32(&mut self, value: i32) { write_pod!(self, value, SIZE_INT32); }
112 pub fn write_u32(&mut self, value: u32) { write_pod!(self, value, SIZE_UINT32); }
113 pub fn write_i64(&mut self, value: i64) { write_pod!(self, value, SIZE_INT64); }
114 pub fn write_u64(&mut self, value: u64) { write_pod!(self, value, SIZE_UINT64); }
115 pub fn write_float(&mut self, value: f32) { write_pod!(self, value, SIZE_FLOAT); }
116 pub fn write_double(&mut self, value: f64) { write_pod!(self, value, SIZE_DOUBLE); }
117
118 pub fn write_bytes(&mut self, data: &[u8]) {
119 let length = data.len();
120 let data_length = align_int(length, SIZE_UINT32);
121 let new_size = self.write_offset + data_length;
122 self.ensure_capacity(new_size);
123 let offset = self.header_size + self.write_offset;
124 self.header[offset..offset + length].copy_from_slice(data);
125 self.pad_after(offset, length, data_length);
126 self.set_payload_size(new_size);
127 self.write_offset = new_size;
128 }
129
130 pub fn write_string(&mut self, value: &str) {
131 let bytes = value.as_bytes();
132 let length = bytes.len();
133 let len_i32 = i32::try_from(length).expect("string too long for pickle");
134 self.write_i32(len_i32);
135 let data_length = align_int(length, SIZE_UINT32);
136 let new_size = self.write_offset + data_length;
137 self.ensure_capacity(new_size);
138 let offset = self.header_size + self.write_offset;
139 self.header[offset..offset + length].copy_from_slice(bytes);
140 self.pad_after(offset, length, data_length);
141 self.set_payload_size(new_size);
142 self.write_offset = new_size;
143 }
144
145 fn set_payload_size(&mut self, size: usize) {
146 self.header[0..4].copy_from_slice(&(size as u32).to_le_bytes());
147 }
148
149 fn get_payload_size(&self) -> usize {
150 if self.header.len() < 4 {
151 return 0;
152 }
153 u32::from_le_bytes(self.header[0..4].try_into().unwrap()) as usize
154 }
155
156 fn ensure_capacity(&mut self, new_size: usize) {
157 if new_size > self.capacity_after_header {
158 self.resize(std::cmp::max(self.capacity_after_header * 2, new_size));
159 }
160 }
161
162 fn pad_after(&mut self, offset: usize, data_len: usize, aligned_len: usize) {
163 let end_offset = offset + data_len;
164 let fill_end = end_offset + aligned_len - data_len;
165 if fill_end > end_offset {
166 self.header[end_offset..fill_end].fill(0);
167 }
168 }
169
170 fn resize(&mut self, new_capacity: usize) {
171 let new_capacity = align_int(new_capacity, PAYLOAD_UNIT);
172 let new_len = self.header_size + new_capacity;
173 let mut new_header = vec![0u8; new_len];
174 let copy_len = self.header_size + self.write_offset;
175 new_header[..copy_len].copy_from_slice(&self.header[..copy_len]);
176 self.header = new_header;
177 self.capacity_after_header = new_capacity;
178 }
179}
180
181pub struct PickleIterator<'a> {
185 payload: &'a [u8],
186 payload_offset: usize,
187 read_index: usize,
188 end_index: usize,
189}
190
191impl<'a> PickleIterator<'a> {
192 pub fn read_bool(&mut self) -> bool {
193 self.read_i32() != 0
194 }
195
196 pub fn read_i32(&mut self) -> i32 { read_pod!(self, SIZE_INT32, i32) }
197 pub fn read_u32(&mut self) -> u32 { read_pod!(self, SIZE_UINT32, u32) }
198 pub fn read_i64(&mut self) -> i64 { read_pod!(self, SIZE_INT64, i64) }
199 pub fn read_u64(&mut self) -> u64 { read_pod!(self, SIZE_UINT64, u64) }
200 pub fn read_float(&mut self) -> f32 { read_pod!(self, SIZE_FLOAT, f32) }
201 pub fn read_double(&mut self) -> f64 { read_pod!(self, SIZE_DOUBLE, f64) }
202
203 pub fn read_bytes(&mut self, length: usize) -> Vec<u8> {
204 self.read_slice(length)
205 }
206
207 pub fn read_string(&mut self) -> String {
208 let length = self.read_i32();
209 let length = usize::try_from(length).expect("invalid string length");
210 let bytes = self.read_slice(length);
211 String::from_utf8_lossy(&bytes).into_owned()
212 }
213
214 fn read_slice(&mut self, length: usize) -> Vec<u8> {
217 let aligned_len = align_int(length, SIZE_UINT32);
218 if self.read_index + aligned_len > self.end_index {
219 self.read_index = self.end_index;
220 panic!("Failed to read data with length of {}", length);
221 }
222 let offset = self.payload_offset + self.read_index;
223 let bytes = self.payload[offset..offset + length].to_vec();
224 self.read_index += aligned_len;
225 bytes
226 }
227}