use crate::helpers::*;
use crate::{EventParams, UUID_LENGTH};
pub fn encode_event(params: &EventParams<'_>) -> Vec<u8> {
let has_device_id = params.device_id.is_some();
let has_session_id = params.session_id.is_some();
let has_service = params.service.is_some();
let has_event_name = params.event_name.is_some();
let has_payload = params.payload.is_some();
let vtable_size: u16 = 4 + 7 * 2;
let table_size: u16 = 4 + 32;
let device_id_size = if has_device_id { 4 + UUID_LENGTH } else { 0 };
let session_id_size = if has_session_id { 4 + UUID_LENGTH } else { 0 };
let service_size = params.service.map(|s| 4 + s.len() + 1).unwrap_or(0);
let event_name_size = params.event_name.map(|s| 4 + s.len() + 1).unwrap_or(0);
let payload_size = params.payload.map(|p| 4 + p.len()).unwrap_or(0);
let estimated = 4
+ vtable_size as usize
+ table_size as usize
+ device_id_size
+ session_id_size
+ service_size
+ event_name_size
+ payload_size
+ 16;
let mut buf = Vec::with_capacity(estimated);
buf.extend_from_slice(&[0u8; 4]);
let vtable_start = buf.len();
write_u16(&mut buf, vtable_size);
write_u16(&mut buf, table_size);
write_u16(&mut buf, 28); write_u16(&mut buf, 20); write_u16(&mut buf, if has_service { 32 } else { 0 }); write_u16(&mut buf, if has_device_id { 4 } else { 0 }); write_u16(&mut buf, if has_session_id { 8 } else { 0 }); write_u16(&mut buf, if has_event_name { 12 } else { 0 }); write_u16(&mut buf, if has_payload { 16 } else { 0 }); buf.extend_from_slice(&[0u8; 2]);
let table_start = buf.len();
let soffset = (table_start - vtable_start) as i32;
write_i32(&mut buf, soffset);
let device_id_off_pos = buf.len();
write_u32(&mut buf, 0);
let session_id_off_pos = buf.len();
write_u32(&mut buf, 0);
let event_name_off_pos = buf.len();
write_u32(&mut buf, 0);
let payload_off_pos = buf.len();
write_u32(&mut buf, 0);
write_u64(&mut buf, params.timestamp);
buf.push(params.event_type.as_u8());
buf.extend_from_slice(&[0u8; 3]);
let service_off_pos = buf.len();
write_u32(&mut buf, 0);
align4(&mut buf);
let device_id_start = params.device_id.map(|id| write_byte_vector(&mut buf, id));
align4(&mut buf);
let session_id_start = params.session_id.map(|id| write_byte_vector(&mut buf, id));
align4(&mut buf);
let service_start = params.service.map(|s| write_string(&mut buf, s));
align4(&mut buf);
let event_name_start = params.event_name.map(|name| write_string(&mut buf, name));
align4(&mut buf);
let payload_start = params.payload.map(|data| write_byte_vector(&mut buf, data));
buf[0..4].copy_from_slice(&(table_start as u32).to_le_bytes());
if let Some(start) = device_id_start {
patch_offset(&mut buf, device_id_off_pos, start);
}
if let Some(start) = session_id_start {
patch_offset(&mut buf, session_id_off_pos, start);
}
if let Some(start) = service_start {
patch_offset(&mut buf, service_off_pos, start);
}
if let Some(start) = event_name_start {
patch_offset(&mut buf, event_name_off_pos, start);
}
if let Some(start) = payload_start {
patch_offset(&mut buf, payload_off_pos, start);
}
buf
}
pub fn encode_event_data(encoded_events: &[Vec<u8>]) -> Vec<u8> {
let vtable_size: u16 = 4 + 2;
let table_size: u16 = 8;
let events_total: usize = encoded_events.iter().map(|e| e.len() + 4).sum();
let estimated = 4 + vtable_size as usize + table_size as usize + 4 + events_total + 64;
let mut buf = Vec::with_capacity(estimated);
buf.extend_from_slice(&[0u8; 4]);
let vtable_start = buf.len();
write_u16(&mut buf, vtable_size);
write_u16(&mut buf, table_size);
write_u16(&mut buf, 4);
buf.extend_from_slice(&[0u8; 2]);
let table_start = buf.len();
let soffset = (table_start - vtable_start) as i32;
write_i32(&mut buf, soffset);
let events_off_pos = buf.len();
write_u32(&mut buf, 0);
align4(&mut buf);
let events_vec_start = buf.len();
let count = encoded_events.len();
write_u32(&mut buf, count as u32);
let offsets_start = buf.len();
for _ in 0..count {
write_u32(&mut buf, 0);
}
align4(&mut buf);
let mut table_positions = Vec::with_capacity(count);
for event_bytes in encoded_events {
align4(&mut buf);
let event_start = buf.len();
let root_offset = if event_bytes.len() >= 4 {
u32::from_le_bytes([
event_bytes[0],
event_bytes[1],
event_bytes[2],
event_bytes[3],
]) as usize
} else {
0
};
table_positions.push(event_start + root_offset);
buf.extend_from_slice(event_bytes);
}
for (i, &table_pos) in table_positions.iter().enumerate() {
let offset_pos = offsets_start + i * 4;
patch_offset(&mut buf, offset_pos, table_pos);
}
patch_offset(&mut buf, events_off_pos, events_vec_start);
buf[0..4].copy_from_slice(&(table_start as u32).to_le_bytes());
buf
}
pub fn encode_event_data_into(
buf: &mut Vec<u8>,
events: &[EventParams<'_>],
) -> std::ops::Range<usize> {
let data_start = buf.len();
let count = events.len();
let root_pos = buf.len();
buf.extend_from_slice(&[0u8; 4]);
let vtable_start = buf.len();
write_u16(buf, 6); write_u16(buf, 8); write_u16(buf, 4); buf.extend_from_slice(&[0u8; 2]);
let table_start = buf.len();
write_i32(buf, (table_start - vtable_start) as i32);
let events_off_pos = buf.len();
write_u32(buf, 0);
align4(buf);
let events_vec_start = buf.len();
write_u32(buf, count as u32);
let offsets_start = buf.len();
for _ in 0..count {
write_u32(buf, 0);
}
align4(buf);
let mut table_positions = Vec::with_capacity(count);
for params in events {
align4(buf);
let event_start = buf.len();
encode_event_into(buf, params);
let root_offset = u32::from_le_bytes([
buf[event_start],
buf[event_start + 1],
buf[event_start + 2],
buf[event_start + 3],
]) as usize;
table_positions.push(event_start + root_offset);
}
for (i, &table_pos) in table_positions.iter().enumerate() {
patch_offset(buf, offsets_start + i * 4, table_pos);
}
patch_offset(buf, events_off_pos, events_vec_start);
buf[root_pos..root_pos + 4].copy_from_slice(&((table_start - data_start) as u32).to_le_bytes());
data_start..buf.len()
}
fn encode_event_into(buf: &mut Vec<u8>, params: &EventParams<'_>) {
let has_device_id = params.device_id.is_some();
let has_session_id = params.session_id.is_some();
let has_service = params.service.is_some();
let has_event_name = params.event_name.is_some();
let has_payload = params.payload.is_some();
let vtable_size: u16 = 4 + 7 * 2;
let table_size: u16 = 4 + 32;
let root_pos = buf.len();
buf.extend_from_slice(&[0u8; 4]);
let vtable_start = buf.len();
write_u16(buf, vtable_size);
write_u16(buf, table_size);
write_u16(buf, 28); write_u16(buf, 20); write_u16(buf, if has_service { 32 } else { 0 }); write_u16(buf, if has_device_id { 4 } else { 0 }); write_u16(buf, if has_session_id { 8 } else { 0 }); write_u16(buf, if has_event_name { 12 } else { 0 }); write_u16(buf, if has_payload { 16 } else { 0 }); buf.extend_from_slice(&[0u8; 2]);
let table_start = buf.len();
let soffset = (table_start - vtable_start) as i32;
write_i32(buf, soffset);
let device_id_off_pos = buf.len();
write_u32(buf, 0);
let session_id_off_pos = buf.len();
write_u32(buf, 0);
let event_name_off_pos = buf.len();
write_u32(buf, 0);
let payload_off_pos = buf.len();
write_u32(buf, 0);
write_u64(buf, params.timestamp);
buf.push(params.event_type.as_u8());
buf.extend_from_slice(&[0u8; 3]);
let service_off_pos = buf.len();
write_u32(buf, 0);
align4(buf);
let device_id_start = params.device_id.map(|id| write_byte_vector(buf, id));
align4(buf);
let session_id_start = params.session_id.map(|id| write_byte_vector(buf, id));
align4(buf);
let service_start = params.service.map(|s| write_string(buf, s));
align4(buf);
let event_name_start = params.event_name.map(|name| write_string(buf, name));
align4(buf);
let payload_start = params.payload.map(|data| write_byte_vector(buf, data));
buf[root_pos..root_pos + 4].copy_from_slice(&((table_start - root_pos) as u32).to_le_bytes());
if let Some(start) = device_id_start {
patch_offset(buf, device_id_off_pos, start);
}
if let Some(start) = session_id_start {
patch_offset(buf, session_id_off_pos, start);
}
if let Some(start) = service_start {
patch_offset(buf, service_off_pos, start);
}
if let Some(start) = event_name_start {
patch_offset(buf, event_name_off_pos, start);
}
if let Some(start) = payload_start {
patch_offset(buf, payload_off_pos, start);
}
}