use crate::pb_utils::PbWireType;
use perfetto_sdk_sys::*;
use thiserror::Error;
#[derive(Error, Debug, PartialEq)]
pub enum PbDecoderError {
#[error("Invalid wire type: {0}.")]
InvalidWireType(u32),
}
#[derive(Debug, PartialEq)]
pub enum PbDecoderField<'a> {
Varint(u64),
Fixed64(u64),
Delimited(&'a [u8]),
Fixed32(u32),
}
pub struct PbDecoder<'a> {
decoder: PerfettoPbDecoder,
_data: &'a [u8],
}
impl<'a> PbDecoder<'a> {
pub fn new(data: &'a [u8]) -> Self {
let read_ptr = data.as_ptr();
PbDecoder {
decoder: PerfettoPbDecoder {
read_ptr,
end_ptr: unsafe { read_ptr.add(data.len()) },
},
_data: data,
}
}
}
impl<'a> Iterator for PbDecoder<'a> {
type Item = Result<(u32, PbDecoderField<'a>), PbDecoderError>;
fn next(&mut self) -> Option<Self::Item> {
let next: PerfettoPbDecoderField =
unsafe { PerfettoPbDecoderParseField(&raw mut self.decoder) };
if next.status != PerfettoPbDecoderStatus_PERFETTO_PB_DECODER_OK {
return None;
}
let field = unsafe {
match PbWireType::try_from(next.wire_type) {
Ok(PbWireType::Varint) => PbDecoderField::Varint(next.value.integer64),
Ok(PbWireType::Fixed64) => PbDecoderField::Fixed64(next.value.integer64),
Ok(PbWireType::Delimited) => {
let data = std::slice::from_raw_parts(
next.value.delimited.start,
next.value.delimited.len,
);
PbDecoderField::Delimited(data)
}
Ok(PbWireType::Fixed32) => PbDecoderField::Fixed32(next.value.integer32),
Err(_) => {
return Some(Err(PbDecoderError::InvalidWireType(next.wire_type)));
}
}
};
Some(Ok((next.id, field)))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty() {
let decoder = PbDecoder::new(&[]);
let items: Vec<_> = decoder.collect();
assert_eq!(items.len(), 0);
}
static MSG: &[u8] = b"\x18\x05\x2a\x12\x0a\x05\x68\x65\x6c\x6c\x6f\
\x28\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01";
#[test]
fn test_event() {
use PbDecoderField::*;
let decoder = PbDecoder::new(MSG);
let items: Vec<_> = decoder.collect();
assert_eq!(items[0], Ok((3, Varint(5))));
match &items[1] {
Ok((5, Delimited(data))) => {
let payload_decoder = PbDecoder::new(data);
let payload_items: Vec<_> = payload_decoder.collect();
assert_eq!(payload_items[0], Ok((1, Delimited(b"hello"))));
assert_eq!(payload_items[1], Ok((5, Varint(-1i64 as u64))));
}
other => panic!("unexpected item: {:?}", other),
}
}
}