use byteorder::{BigEndian, ByteOrder, LittleEndian};
use crate::{Endianness, RawData, SampleFormat};
use super::RecordParseInfo;
#[derive(Clone, Debug, Default)]
pub struct CommonData {
pub pid: Option<i32>,
pub tid: Option<i32>,
pub timestamp: Option<u64>,
pub id: Option<u64>,
pub stream_id: Option<u64>,
pub cpu: Option<u32>,
}
impl CommonData {
pub fn parse_sample(
data: RawData,
parse_info: &RecordParseInfo,
) -> Result<Self, std::io::Error> {
match parse_info.endian {
Endianness::LittleEndian => Self::parse_sample_impl::<LittleEndian>(data, parse_info),
Endianness::BigEndian => Self::parse_sample_impl::<BigEndian>(data, parse_info),
}
}
pub fn parse_sample_impl<T: ByteOrder>(
data: RawData,
parse_info: &RecordParseInfo,
) -> Result<Self, std::io::Error> {
let sample_format = parse_info.sample_format;
let mut cur = data;
let identifier = if sample_format.contains(SampleFormat::IDENTIFIER) {
Some(cur.read_u64::<T>()?)
} else {
None
};
if sample_format.contains(SampleFormat::IP) {
let _ip = cur.read_u64::<T>()?;
}
let (pid, tid) = if sample_format.contains(SampleFormat::TID) {
let pid = cur.read_i32::<T>()?;
let tid = cur.read_i32::<T>()?;
(Some(pid), Some(tid))
} else {
(None, None)
};
let timestamp = if sample_format.contains(SampleFormat::TIME) {
Some(cur.read_u64::<T>()?)
} else {
None
};
if sample_format.contains(SampleFormat::ADDR) {
let _addr = cur.read_u64::<T>()?;
}
let id = if sample_format.contains(SampleFormat::ID) {
Some(cur.read_u64::<T>()?)
} else {
None
};
let id = identifier.or(id);
let stream_id = if sample_format.contains(SampleFormat::STREAM_ID) {
Some(cur.read_u64::<T>()?)
} else {
None
};
let cpu = if sample_format.contains(SampleFormat::CPU) {
let cpu = cur.read_u32::<T>()?;
let _ = cur.read_u32::<T>()?; Some(cpu)
} else {
None
};
Ok(CommonData {
pid,
tid,
timestamp,
id,
stream_id,
cpu,
})
}
pub fn parse_nonsample(
data: RawData,
parse_info: &RecordParseInfo,
) -> Result<Self, std::io::Error> {
match parse_info.endian {
Endianness::LittleEndian => {
Self::parse_nonsample_impl::<LittleEndian>(data, parse_info)
}
Endianness::BigEndian => Self::parse_nonsample_impl::<BigEndian>(data, parse_info),
}
}
pub fn parse_nonsample_impl<T: ByteOrder>(
data: RawData,
parse_info: &RecordParseInfo,
) -> Result<Self, std::io::Error> {
if let Some(common_data_offset_from_end) = parse_info.common_data_offset_from_end {
let common_data_offset_from_end = common_data_offset_from_end as usize;
let sample_format = parse_info.sample_format;
let mut cur = data;
let common_data_offset_from_start = cur
.len()
.checked_sub(common_data_offset_from_end)
.ok_or(std::io::ErrorKind::UnexpectedEof)?;
cur.skip(common_data_offset_from_start)?;
let (pid, tid) = if sample_format.contains(SampleFormat::TID) {
let pid = cur.read_i32::<T>()?;
let tid = cur.read_i32::<T>()?;
(Some(pid), Some(tid))
} else {
(None, None)
};
let timestamp = if sample_format.contains(SampleFormat::TIME) {
Some(cur.read_u64::<T>()?)
} else {
None
};
let id = if sample_format.contains(SampleFormat::ID) {
Some(cur.read_u64::<T>()?)
} else {
None
};
let stream_id = if sample_format.contains(SampleFormat::STREAM_ID) {
Some(cur.read_u64::<T>()?)
} else {
None
};
let cpu = if sample_format.contains(SampleFormat::CPU) {
let cpu = cur.read_u32::<T>()?;
let _ = cur.read_u32::<T>()?; Some(cpu)
} else {
None
};
let identifier = if sample_format.contains(SampleFormat::IDENTIFIER) {
Some(cur.read_u64::<T>()?)
} else {
None
};
let id = identifier.or(id);
Ok(CommonData {
pid,
tid,
timestamp,
id,
stream_id,
cpu,
})
} else {
Ok(Default::default())
}
}
}