posthog_symbol_data/
symbol_data.rs1use crate::{error::Error, utils::assert_at_least_as_long_as};
2
3const MAGIC: &[u8] = b"posthog_error_tracking";
4const VERSION: u32 = 1;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum SymbolDataType {
8 SourceAndMap = 2,
9 HermesMap = 3,
10 ProguardMapping = 4,
11}
12
13pub trait SymbolData: Sized {
14 fn from_bytes(data: Vec<u8>) -> Result<Self, Error>;
15 fn into_bytes(self) -> Vec<u8>;
16 fn data_type() -> SymbolDataType;
17}
18
19pub fn write<T>(data: T) -> Result<Vec<u8>, Error>
20where
21 T: SymbolData,
22{
23 let d_type = T::data_type();
24 let bytes = data.into_bytes();
25 let mut buffer = Vec::with_capacity(header_len() + bytes.len());
26 buffer.extend_from_slice(MAGIC);
27 buffer.extend_from_slice(&VERSION.to_le_bytes());
28 buffer.extend_from_slice(&(d_type as u32).to_le_bytes());
29 buffer.extend_from_slice(&bytes);
30 Ok(buffer)
31}
32
33pub fn read_as<T>(data: Vec<u8>) -> Result<T, Error>
34where
35 T: SymbolData,
36{
37 assert_at_least_as_long_as(header_len(), data.len())?;
38 assert_has_magic(&data)?;
39 assert_version(&data)?;
40 assert_data_type(&data, T::data_type())?;
41 T::from_bytes(data[header_len()..].to_vec())
42}
43
44pub fn assert_version(buffer: &[u8]) -> Result<(), Error> {
45 let version = u32::from_le_bytes(buffer[MAGIC.len()..MAGIC.len() + 4].try_into().unwrap());
46 if version > VERSION {
47 return Err(Error::WrongVersion(version, VERSION));
48 }
49 Ok(())
50}
51
52fn assert_has_magic(buffer: &[u8]) -> Result<(), Error> {
53 if &buffer[..MAGIC.len()] != MAGIC {
54 return Err(Error::InvalidMagic);
55 }
56 Ok(())
57}
58
59pub fn assert_data_type(buffer: &[u8], expected_type: SymbolDataType) -> Result<(), Error> {
60 let data_type = u32::from_le_bytes(buffer[header_len() - 4..header_len()].try_into().unwrap());
61 if data_type != expected_type as u32 {
62 Err(Error::InvalidDataType(
63 data_type,
64 format!("{expected_type:?}"),
65 ))
66 } else {
67 Ok(())
68 }
69}
70
71const fn header_len() -> usize {
72 MAGIC.len() + VERSION.to_le_bytes().len() + std::mem::size_of::<u32>()
74}