1use crate::helpers::*;
2use crate::UUID_LENGTH;
3use crate::LogEntryParams;
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 + vtable_size as usize + table_size as usize
41 + session_id_size + source_size + service_size + payload_size + 16;
42 let mut buf = Vec::with_capacity(estimated);
43
44 buf.extend_from_slice(&[0u8; 4]);
46
47 let vtable_start = buf.len();
49 write_u16(&mut buf, vtable_size);
50 write_u16(&mut buf, table_size);
51
52 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]);
63
64 let table_start = buf.len();
66 let soffset = (table_start - vtable_start) as i32;
67 write_i32(&mut buf, soffset);
68
69 let session_id_off_pos = buf.len();
71 write_u32(&mut buf, 0);
72
73 let source_off_pos = buf.len();
74 write_u32(&mut buf, 0);
75
76 let service_off_pos = buf.len();
77 write_u32(&mut buf, 0);
78
79 let payload_off_pos = buf.len();
80 write_u32(&mut buf, 0);
81
82 write_u64(&mut buf, params.timestamp);
84
85 buf.push(params.event_type.as_u8());
87
88 buf.push(params.level.as_u8());
90
91 buf.extend_from_slice(&[0u8; 2]);
93
94 align4(&mut buf);
96
97 let session_id_start = params.session_id.map(|id| write_byte_vector(&mut buf, id));
99 align4(&mut buf);
100
101 let source_start = params.source.map(|s| write_string(&mut buf, s));
103 align4(&mut buf);
104
105 let service_start = params.service.map(|s| write_string(&mut buf, s));
107 align4(&mut buf);
108
109 let payload_start = params.payload.map(|data| write_byte_vector(&mut buf, data));
111
112 buf[0..4].copy_from_slice(&(table_start as u32).to_le_bytes());
114
115 if let Some(start) = session_id_start {
116 patch_offset(&mut buf, session_id_off_pos, start);
117 }
118 if let Some(start) = source_start {
119 patch_offset(&mut buf, source_off_pos, start);
120 }
121 if let Some(start) = service_start {
122 patch_offset(&mut buf, service_off_pos, start);
123 }
124 if let Some(start) = payload_start {
125 patch_offset(&mut buf, payload_off_pos, start);
126 }
127
128 buf
129}
130
131pub fn encode_log_data(encoded_logs: &[Vec<u8>]) -> Vec<u8> {
136 let vtable_size: u16 = 4 + 2;
138 let table_size: u16 = 8; let logs_total: usize = encoded_logs.iter().map(|l| l.len() + 4).sum();
141 let estimated = 4 + vtable_size as usize + table_size as usize + 4 + logs_total + 64;
142 let mut buf = Vec::with_capacity(estimated);
143
144 buf.extend_from_slice(&[0u8; 4]);
146
147 let vtable_start = buf.len();
149 write_u16(&mut buf, vtable_size);
150 write_u16(&mut buf, table_size);
151 write_u16(&mut buf, 4); buf.extend_from_slice(&[0u8; 2]);
155
156 let table_start = buf.len();
158 let soffset = (table_start - vtable_start) as i32;
159 write_i32(&mut buf, soffset);
160
161 let logs_off_pos = buf.len();
162 write_u32(&mut buf, 0);
163
164 align4(&mut buf);
165
166 let logs_vec_start = buf.len();
168 let count = encoded_logs.len();
169
170 write_u32(&mut buf, count as u32);
171
172 let offsets_start = buf.len();
173 for _ in 0..count {
174 write_u32(&mut buf, 0);
175 }
176
177 align4(&mut buf);
178
179 let mut table_positions = Vec::with_capacity(count);
180 for log_bytes in encoded_logs {
181 align4(&mut buf);
182
183 let log_start = buf.len();
184 let root_offset = if log_bytes.len() >= 4 {
185 u32::from_le_bytes([log_bytes[0], log_bytes[1], log_bytes[2], log_bytes[3]]) as usize
186 } else {
187 0
188 };
189
190 table_positions.push(log_start + root_offset);
191 buf.extend_from_slice(log_bytes);
192 }
193
194 for (i, &table_pos) in table_positions.iter().enumerate() {
195 let offset_pos = offsets_start + i * 4;
196 patch_offset(&mut buf, offset_pos, table_pos);
197 }
198
199 patch_offset(&mut buf, logs_off_pos, logs_vec_start);
200 buf[0..4].copy_from_slice(&(table_start as u32).to_le_bytes());
201
202 buf
203}
204
205pub fn encode_log_data_into(buf: &mut Vec<u8>, logs: &[LogEntryParams<'_>]) -> std::ops::Range<usize> {
211 let data_start = buf.len();
212 let count = logs.len();
213
214 let root_pos = buf.len();
216 buf.extend_from_slice(&[0u8; 4]);
217
218 let vtable_start = buf.len();
219 write_u16(buf, 6); write_u16(buf, 8); write_u16(buf, 4); buf.extend_from_slice(&[0u8; 2]); let table_start = buf.len();
225 write_i32(buf, (table_start - vtable_start) as i32);
226
227 let logs_off_pos = buf.len();
228 write_u32(buf, 0);
229
230 align4(buf);
231
232 let logs_vec_start = buf.len();
233 write_u32(buf, count as u32);
234
235 let offsets_start = buf.len();
236 for _ in 0..count {
237 write_u32(buf, 0);
238 }
239
240 align4(buf);
241
242 let mut table_positions = Vec::with_capacity(count);
244 for params in logs {
245 align4(buf);
246 let entry_start = buf.len();
247 encode_log_entry_into(buf, params);
248 let root_offset = u32::from_le_bytes([
249 buf[entry_start],
250 buf[entry_start + 1],
251 buf[entry_start + 2],
252 buf[entry_start + 3],
253 ]) as usize;
254 table_positions.push(entry_start + root_offset);
255 }
256
257 for (i, &table_pos) in table_positions.iter().enumerate() {
259 patch_offset(buf, offsets_start + i * 4, table_pos);
260 }
261
262 patch_offset(buf, logs_off_pos, logs_vec_start);
263 buf[root_pos..root_pos + 4].copy_from_slice(&((table_start - data_start) as u32).to_le_bytes());
264
265 data_start..buf.len()
266}
267
268fn encode_log_entry_into(buf: &mut Vec<u8>, params: &LogEntryParams<'_>) {
270 let has_session_id = params.session_id.is_some();
271 let has_source = params.source.is_some();
272 let has_service = params.service.is_some();
273 let has_payload = params.payload.is_some();
274
275 let vtable_size: u16 = 4 + 7 * 2;
276 let table_size: u16 = 4 + 28;
277
278 let root_pos = buf.len();
279 buf.extend_from_slice(&[0u8; 4]);
280
281 let vtable_start = buf.len();
282 write_u16(buf, vtable_size);
283 write_u16(buf, table_size);
284
285 write_u16(buf, 28);
286 write_u16(buf, if has_session_id { 4 } else { 0 });
287 write_u16(buf, 29);
288 write_u16(buf, 20);
289 write_u16(buf, if has_source { 8 } else { 0 });
290 write_u16(buf, if has_service { 12 } else { 0 });
291 write_u16(buf, if has_payload { 16 } else { 0 });
292
293 buf.extend_from_slice(&[0u8; 2]); let table_start = buf.len();
296 let soffset = (table_start - vtable_start) as i32;
297 write_i32(buf, soffset);
298
299 let session_id_off_pos = buf.len();
300 write_u32(buf, 0);
301 let source_off_pos = buf.len();
302 write_u32(buf, 0);
303 let service_off_pos = buf.len();
304 write_u32(buf, 0);
305 let payload_off_pos = buf.len();
306 write_u32(buf, 0);
307
308 write_u64(buf, params.timestamp);
309 buf.push(params.event_type.as_u8());
310 buf.push(params.level.as_u8());
311 buf.extend_from_slice(&[0u8; 2]);
312
313 align4(buf);
314
315 let session_id_start = params.session_id.map(|id| write_byte_vector(buf, id));
316 align4(buf);
317 let source_start = params.source.map(|s| write_string(buf, s));
318 align4(buf);
319 let service_start = params.service.map(|s| write_string(buf, s));
320 align4(buf);
321 let payload_start = params.payload.map(|data| write_byte_vector(buf, data));
322
323 buf[root_pos..root_pos + 4].copy_from_slice(&((table_start - root_pos) as u32).to_le_bytes());
325
326 if let Some(start) = session_id_start {
327 patch_offset(buf, session_id_off_pos, start);
328 }
329 if let Some(start) = source_start {
330 patch_offset(buf, source_off_pos, start);
331 }
332 if let Some(start) = service_start {
333 patch_offset(buf, service_off_pos, start);
334 }
335 if let Some(start) = payload_start {
336 patch_offset(buf, payload_off_pos, start);
337 }
338}