use crate::event_id::EventId;
use crate::stringtable::StringId;
#[cfg(target_endian = "big")]
use std::convert::TryInto;
#[derive(Eq, PartialEq, Debug)]
#[repr(C)]
pub struct RawEvent {
pub event_kind: StringId,
pub event_id: EventId,
pub thread_id: u32,
pub payload1_lower: u32,
pub payload2_lower: u32,
pub payloads_upper: u32,
}
const INSTANT_MARKER: u64 = 0xFFFF_FFFF_FFFF;
const INTEGER_MARKER: u64 = INSTANT_MARKER - 1;
pub const MAX_SINGLE_VALUE: u64 = 0xFFFF_FFFF_FFFF;
pub const MAX_INTERVAL_VALUE: u64 = INTEGER_MARKER - 1;
impl RawEvent {
#[inline]
pub fn new_interval(
event_kind: StringId,
event_id: EventId,
thread_id: u32,
start: u64,
end: u64,
) -> Self {
assert!(start <= end);
assert!(end <= MAX_INTERVAL_VALUE);
Self::pack_values(event_kind, event_id, thread_id, start, end)
}
#[inline]
pub fn new_instant(
event_kind: StringId,
event_id: EventId,
thread_id: u32,
instant: u64,
) -> Self {
assert!(instant <= MAX_SINGLE_VALUE);
Self::pack_values(event_kind, event_id, thread_id, instant, INSTANT_MARKER)
}
#[inline]
pub fn new_integer(
event_kind: StringId,
event_id: EventId,
thread_id: u32,
value: u64,
) -> Self {
assert!(value <= MAX_SINGLE_VALUE);
Self::pack_values(event_kind, event_id, thread_id, value, INTEGER_MARKER)
}
#[inline]
fn pack_values(
event_kind: StringId,
event_id: EventId,
thread_id: u32,
value1: u64,
value2: u64,
) -> Self {
let payload1_lower = value1 as u32;
let payload2_lower = value2 as u32;
let value1_upper = (value1 >> 16) as u32 & 0xFFFF_0000;
let value2_upper = (value2 >> 32) as u32;
let payloads_upper = value1_upper | value2_upper;
Self {
event_kind,
event_id,
thread_id,
payload1_lower,
payload2_lower,
payloads_upper,
}
}
#[inline]
pub fn start_value(&self) -> u64 {
self.payload1_lower as u64 | (((self.payloads_upper & 0xFFFF_0000) as u64) << 16)
}
#[inline]
pub fn end_value(&self) -> u64 {
self.payload2_lower as u64 | (((self.payloads_upper & 0x0000_FFFF) as u64) << 32)
}
#[inline]
pub fn value(&self) -> u64 {
self.payload1_lower as u64 | (((self.payloads_upper & 0xFFFF_0000) as u64) << 16)
}
#[inline]
pub fn is_instant(&self) -> bool {
self.end_value() == INSTANT_MARKER
}
#[inline]
pub fn is_integer(&self) -> bool {
self.end_value() == INTEGER_MARKER
}
#[inline]
pub fn serialize(&self, bytes: &mut [u8]) {
assert!(bytes.len() == std::mem::size_of::<RawEvent>());
#[cfg(target_endian = "little")]
{
let raw_event_bytes: &[u8] = unsafe {
std::slice::from_raw_parts(
self as *const _ as *const u8,
std::mem::size_of::<RawEvent>(),
)
};
bytes.copy_from_slice(raw_event_bytes);
}
#[cfg(target_endian = "big")]
{
bytes[0..8].copy_from_slice(&self.event_kind.as_u64().to_le_bytes());
bytes[8..16].copy_from_slice(&self.event_id.as_u64().to_le_bytes());
bytes[16..20].copy_from_slice(&self.thread_id.to_le_bytes());
bytes[20..24].copy_from_slice(&self.payload1_lower.to_le_bytes());
bytes[24..28].copy_from_slice(&self.payload2_lower.to_le_bytes());
bytes[28..32].copy_from_slice(&self.payloads_upper.to_le_bytes());
}
}
#[inline]
pub fn deserialize(bytes: &[u8]) -> RawEvent {
assert!(bytes.len() == std::mem::size_of::<RawEvent>());
#[cfg(target_endian = "little")]
{
let mut raw_event = RawEvent::default();
unsafe {
let raw_event = std::slice::from_raw_parts_mut(
&mut raw_event as *mut RawEvent as *mut u8,
std::mem::size_of::<RawEvent>(),
);
raw_event.copy_from_slice(bytes);
};
raw_event
}
#[cfg(target_endian = "big")]
{
RawEvent {
event_kind: StringId::new(u64::from_le_bytes(bytes[0..8].try_into().unwrap())),
event_id: EventId::from_u64(u64::from_le_bytes(bytes[8..16].try_into().unwrap())),
thread_id: u32::from_le_bytes(bytes[16..20].try_into().unwrap()),
payload1_lower: u32::from_le_bytes(bytes[20..24].try_into().unwrap()),
payload2_lower: u32::from_le_bytes(bytes[24..28].try_into().unwrap()),
payloads_upper: u32::from_le_bytes(bytes[28..32].try_into().unwrap()),
}
}
}
}
impl Default for RawEvent {
fn default() -> Self {
RawEvent {
event_kind: StringId::INVALID,
event_id: EventId::INVALID,
thread_id: 0,
payload1_lower: 0,
payload2_lower: 0,
payloads_upper: 0,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn raw_event_has_expected_size() {
assert_eq!(std::mem::size_of::<RawEvent>(), 32);
}
#[test]
fn is_instant() {
assert!(RawEvent::new_instant(StringId::INVALID, EventId::INVALID, 987, 0,).is_instant());
assert!(
RawEvent::new_instant(StringId::INVALID, EventId::INVALID, 987, MAX_SINGLE_VALUE,)
.is_instant()
);
assert!(!RawEvent::new_interval(
StringId::INVALID,
EventId::INVALID,
987,
0,
MAX_INTERVAL_VALUE,
)
.is_instant());
}
#[test]
fn is_integer() {
let integer = RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, 0);
assert!(integer.is_integer());
assert_eq!(integer.value(), 0);
let integer = RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, 8769);
assert!(integer.is_integer());
assert_eq!(integer.value(), 8769);
assert!(
RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, MAX_SINGLE_VALUE,)
.is_integer()
);
assert!(!RawEvent::new_interval(
StringId::INVALID,
EventId::INVALID,
987,
0,
MAX_INTERVAL_VALUE,
)
.is_integer());
}
#[test]
#[should_panic]
fn invalid_instant_count() {
let _ = RawEvent::new_instant(
StringId::INVALID,
EventId::INVALID,
123,
MAX_SINGLE_VALUE + 1,
);
}
#[test]
#[should_panic]
fn invalid_start_count() {
let _ = RawEvent::new_interval(
StringId::INVALID,
EventId::INVALID,
123,
MAX_INTERVAL_VALUE + 1,
MAX_INTERVAL_VALUE + 1,
);
}
#[test]
#[should_panic]
fn invalid_end_count() {
let _ = RawEvent::new_interval(
StringId::INVALID,
EventId::INVALID,
123,
0,
MAX_INTERVAL_VALUE + 3,
);
}
#[test]
#[should_panic]
fn invalid_end_count2() {
let _ = RawEvent::new_interval(StringId::INVALID, EventId::INVALID, 123, 0, INTEGER_MARKER);
}
#[test]
#[should_panic]
fn start_greater_than_end_count() {
let _ = RawEvent::new_interval(
StringId::INVALID,
EventId::INVALID,
123,
1,
0,
);
}
#[test]
fn start_equal_to_end_count() {
let _ = RawEvent::new_interval(StringId::INVALID, EventId::INVALID, 123, 1, 1);
}
#[test]
fn interval_count_decoding() {
let e = RawEvent::new_interval(
StringId::INVALID,
EventId::INVALID,
1234,
MAX_INTERVAL_VALUE,
MAX_INTERVAL_VALUE,
);
assert_eq!(e.start_value(), MAX_INTERVAL_VALUE);
assert_eq!(e.end_value(), MAX_INTERVAL_VALUE);
let e = RawEvent::new_interval(StringId::INVALID, EventId::INVALID, 1234, 0, 0);
assert_eq!(e.start_value(), 0);
assert_eq!(e.end_value(), 0);
let e = RawEvent::new_interval(
StringId::INVALID,
EventId::INVALID,
1234,
0,
MAX_INTERVAL_VALUE,
);
assert_eq!(e.start_value(), 0);
assert_eq!(e.end_value(), MAX_INTERVAL_VALUE);
let e = RawEvent::new_interval(
StringId::INVALID,
EventId::INVALID,
1234,
0x1234567890,
0x1234567890A,
);
assert_eq!(e.start_value(), 0x1234567890);
assert_eq!(e.end_value(), 0x1234567890A);
}
#[test]
fn instant_count_decoding() {
assert_eq!(
RawEvent::new_instant(StringId::INVALID, EventId::INVALID, 987, 0,).start_value(),
0
);
assert_eq!(
RawEvent::new_instant(StringId::INVALID, EventId::INVALID, 987, 42,).start_value(),
42
);
assert_eq!(
RawEvent::new_instant(StringId::INVALID, EventId::INVALID, 987, MAX_SINGLE_VALUE,)
.start_value(),
MAX_SINGLE_VALUE
);
}
#[test]
fn integer_decoding() {
assert_eq!(
RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, 0,).start_value(),
0
);
assert_eq!(
RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, 42,).start_value(),
42
);
assert_eq!(
RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, MAX_SINGLE_VALUE,)
.start_value(),
MAX_SINGLE_VALUE
);
}
}