1use crate::LogEntryParams;
2use crate::UUID_LENGTH;
3use crate::helpers::*;
4
5pub fn encode_log_entry(params: &LogEntryParams<'_>) -> Vec<u8> {
16 let has_session_id = params.session_id.is_some();
17 let has_source = params.source.is_some();
18 let has_service = params.service.is_some();
19 let has_payload = params.payload.is_some();
20
21 let vtable_size: u16 = 4 + 7 * 2;
23
24 let table_size: u16 = 4 + 28;
34
35 let session_id_size = if has_session_id { 4 + UUID_LENGTH } else { 0 };
36 let source_size = params.source.map(|s| 4 + s.len() + 1).unwrap_or(0);
37 let service_size = params.service.map(|s| 4 + s.len() + 1).unwrap_or(0);
38 let payload_size = params.payload.map(|p| 4 + p.len()).unwrap_or(0);
39
40 let estimated = 4
41 + vtable_size as usize
42 + table_size as usize
43 + session_id_size
44 + source_size
45 + service_size
46 + payload_size
47 + 16;
48 let mut buf = Vec::with_capacity(estimated);
49
50 buf.extend_from_slice(&[0u8; 4]);
52
53 let vtable_start = buf.len();
55 write_u16(&mut buf, vtable_size);
56 write_u16(&mut buf, table_size);
57
58 write_u16(&mut buf, 28); write_u16(&mut buf, if has_session_id { 4 } else { 0 }); write_u16(&mut buf, 29); write_u16(&mut buf, 20); write_u16(&mut buf, if has_source { 8 } else { 0 }); write_u16(&mut buf, if has_service { 12 } else { 0 }); write_u16(&mut buf, if has_payload { 16 } else { 0 }); buf.extend_from_slice(&[0u8; 2]);
69
70 let table_start = buf.len();
72 let soffset = (table_start - vtable_start) as i32;
73 write_i32(&mut buf, soffset);
74
75 let session_id_off_pos = buf.len();
77 write_u32(&mut buf, 0);
78
79 let source_off_pos = buf.len();
80 write_u32(&mut buf, 0);
81
82 let service_off_pos = buf.len();
83 write_u32(&mut buf, 0);
84
85 let payload_off_pos = buf.len();
86 write_u32(&mut buf, 0);
87
88 write_u64(&mut buf, params.timestamp);
90
91 buf.push(params.event_type.as_u8());
93
94 buf.push(params.level.as_u8());
96
97 buf.extend_from_slice(&[0u8; 2]);
99
100 align4(&mut buf);
102
103 let session_id_start = params.session_id.map(|id| write_byte_vector(&mut buf, id));
105 align4(&mut buf);
106
107 let source_start = params.source.map(|s| write_string(&mut buf, s));
109 align4(&mut buf);
110
111 let service_start = params.service.map(|s| write_string(&mut buf, s));
113 align4(&mut buf);
114
115 let payload_start = params.payload.map(|data| write_byte_vector(&mut buf, data));
117
118 buf[0..4].copy_from_slice(&(table_start as u32).to_le_bytes());
120
121 if let Some(start) = session_id_start {
122 patch_offset(&mut buf, session_id_off_pos, start);
123 }
124 if let Some(start) = source_start {
125 patch_offset(&mut buf, source_off_pos, start);
126 }
127 if let Some(start) = service_start {
128 patch_offset(&mut buf, service_off_pos, start);
129 }
130 if let Some(start) = payload_start {
131 patch_offset(&mut buf, payload_off_pos, start);
132 }
133
134 buf
135}
136
137pub fn encode_log_data(encoded_logs: &[Vec<u8>]) -> Vec<u8> {
142 let vtable_size: u16 = 4 + 2;
144 let table_size: u16 = 8; let logs_total: usize = encoded_logs.iter().map(|l| l.len() + 4).sum();
147 let estimated = 4 + vtable_size as usize + table_size as usize + 4 + logs_total + 64;
148 let mut buf = Vec::with_capacity(estimated);
149
150 buf.extend_from_slice(&[0u8; 4]);
152
153 let vtable_start = buf.len();
155 write_u16(&mut buf, vtable_size);
156 write_u16(&mut buf, table_size);
157 write_u16(&mut buf, 4); buf.extend_from_slice(&[0u8; 2]);
161
162 let table_start = buf.len();
164 let soffset = (table_start - vtable_start) as i32;
165 write_i32(&mut buf, soffset);
166
167 let logs_off_pos = buf.len();
168 write_u32(&mut buf, 0);
169
170 align4(&mut buf);
171
172 let logs_vec_start = buf.len();
174 let count = encoded_logs.len();
175
176 write_u32(&mut buf, count as u32);
177
178 let offsets_start = buf.len();
179 for _ in 0..count {
180 write_u32(&mut buf, 0);
181 }
182
183 align4(&mut buf);
184
185 let mut table_positions = Vec::with_capacity(count);
186 for log_bytes in encoded_logs {
187 align4(&mut buf);
188
189 let log_start = buf.len();
190 let root_offset = if log_bytes.len() >= 4 {
191 u32::from_le_bytes([log_bytes[0], log_bytes[1], log_bytes[2], log_bytes[3]]) as usize
192 } else {
193 0
194 };
195
196 table_positions.push(log_start + root_offset);
197 buf.extend_from_slice(log_bytes);
198 }
199
200 for (i, &table_pos) in table_positions.iter().enumerate() {
201 let offset_pos = offsets_start + i * 4;
202 patch_offset(&mut buf, offset_pos, table_pos);
203 }
204
205 patch_offset(&mut buf, logs_off_pos, logs_vec_start);
206 buf[0..4].copy_from_slice(&(table_start as u32).to_le_bytes());
207
208 buf
209}
210
211pub fn encode_log_data_into(
217 buf: &mut Vec<u8>,
218 logs: &[LogEntryParams<'_>],
219) -> std::ops::Range<usize> {
220 let data_start = buf.len();
221 let count = logs.len();
222
223 let root_pos = buf.len();
225 buf.extend_from_slice(&[0u8; 4]);
226
227 let vtable_start = buf.len();
228 write_u16(buf, 6); write_u16(buf, 8); write_u16(buf, 4); buf.extend_from_slice(&[0u8; 2]); let table_start = buf.len();
234 write_i32(buf, (table_start - vtable_start) as i32);
235
236 let logs_off_pos = buf.len();
237 write_u32(buf, 0);
238
239 align4(buf);
240
241 let logs_vec_start = buf.len();
242 write_u32(buf, count as u32);
243
244 let offsets_start = buf.len();
245 for _ in 0..count {
246 write_u32(buf, 0);
247 }
248
249 align4(buf);
250
251 let mut table_positions = Vec::with_capacity(count);
253 for params in logs {
254 align4(buf);
255 let entry_start = buf.len();
256 encode_log_entry_into(buf, params);
257 let root_offset = u32::from_le_bytes([
258 buf[entry_start],
259 buf[entry_start + 1],
260 buf[entry_start + 2],
261 buf[entry_start + 3],
262 ]) as usize;
263 table_positions.push(entry_start + root_offset);
264 }
265
266 for (i, &table_pos) in table_positions.iter().enumerate() {
268 patch_offset(buf, offsets_start + i * 4, table_pos);
269 }
270
271 patch_offset(buf, logs_off_pos, logs_vec_start);
272 buf[root_pos..root_pos + 4].copy_from_slice(&((table_start - data_start) as u32).to_le_bytes());
273
274 data_start..buf.len()
275}
276
277fn encode_log_entry_into(buf: &mut Vec<u8>, params: &LogEntryParams<'_>) {
279 let has_session_id = params.session_id.is_some();
280 let has_source = params.source.is_some();
281 let has_service = params.service.is_some();
282 let has_payload = params.payload.is_some();
283
284 let vtable_size: u16 = 4 + 7 * 2;
285 let table_size: u16 = 4 + 28;
286
287 let root_pos = buf.len();
288 buf.extend_from_slice(&[0u8; 4]);
289
290 let vtable_start = buf.len();
291 write_u16(buf, vtable_size);
292 write_u16(buf, table_size);
293
294 write_u16(buf, 28);
295 write_u16(buf, if has_session_id { 4 } else { 0 });
296 write_u16(buf, 29);
297 write_u16(buf, 20);
298 write_u16(buf, if has_source { 8 } else { 0 });
299 write_u16(buf, if has_service { 12 } else { 0 });
300 write_u16(buf, if has_payload { 16 } else { 0 });
301
302 buf.extend_from_slice(&[0u8; 2]); let table_start = buf.len();
305 let soffset = (table_start - vtable_start) as i32;
306 write_i32(buf, soffset);
307
308 let session_id_off_pos = buf.len();
309 write_u32(buf, 0);
310 let source_off_pos = buf.len();
311 write_u32(buf, 0);
312 let service_off_pos = buf.len();
313 write_u32(buf, 0);
314 let payload_off_pos = buf.len();
315 write_u32(buf, 0);
316
317 write_u64(buf, params.timestamp);
318 buf.push(params.event_type.as_u8());
319 buf.push(params.level.as_u8());
320 buf.extend_from_slice(&[0u8; 2]);
321
322 align4(buf);
323
324 let session_id_start = params.session_id.map(|id| write_byte_vector(buf, id));
325 align4(buf);
326 let source_start = params.source.map(|s| write_string(buf, s));
327 align4(buf);
328 let service_start = params.service.map(|s| write_string(buf, s));
329 align4(buf);
330 let payload_start = params.payload.map(|data| write_byte_vector(buf, data));
331
332 buf[root_pos..root_pos + 4].copy_from_slice(&((table_start - root_pos) as u32).to_le_bytes());
334
335 if let Some(start) = session_id_start {
336 patch_offset(buf, session_id_off_pos, start);
337 }
338 if let Some(start) = source_start {
339 patch_offset(buf, source_off_pos, start);
340 }
341 if let Some(start) = service_start {
342 patch_offset(buf, service_off_pos, start);
343 }
344 if let Some(start) = payload_start {
345 patch_offset(buf, payload_off_pos, start);
346 }
347}