use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum MemoryEventType {
Allocate,
Deallocate,
Reallocate,
Move,
Borrow,
Return,
Metadata,
}
impl fmt::Display for MemoryEventType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MemoryEventType::Allocate => write!(f, "Allocate"),
MemoryEventType::Deallocate => write!(f, "Deallocate"),
MemoryEventType::Reallocate => write!(f, "Reallocate"),
MemoryEventType::Move => write!(f, "Move"),
MemoryEventType::Borrow => write!(f, "Borrow"),
MemoryEventType::Return => write!(f, "Return"),
MemoryEventType::Metadata => write!(f, "Metadata"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryEvent {
pub timestamp: u64,
pub event_type: MemoryEventType,
pub ptr: usize,
pub size: usize,
pub old_size: Option<usize>,
pub thread_id: u64,
pub var_name: Option<String>,
pub type_name: Option<String>,
pub call_stack_hash: Option<u64>,
pub thread_name: Option<String>,
pub source_file: Option<String>,
pub source_line: Option<u32>,
}
impl MemoryEvent {
pub fn allocate(ptr: usize, size: usize, thread_id: u64) -> Self {
Self {
timestamp: Self::now(),
event_type: MemoryEventType::Allocate,
ptr,
size,
old_size: None,
thread_id,
var_name: None,
type_name: None,
call_stack_hash: None,
thread_name: None,
source_file: None,
source_line: None,
}
}
pub fn deallocate(ptr: usize, size: usize, thread_id: u64) -> Self {
Self {
timestamp: Self::now(),
event_type: MemoryEventType::Deallocate,
ptr,
size,
old_size: None,
thread_id,
var_name: None,
type_name: None,
call_stack_hash: None,
thread_name: None,
source_file: None,
source_line: None,
}
}
pub fn reallocate(ptr: usize, old_size: usize, new_size: usize, thread_id: u64) -> Self {
Self {
timestamp: Self::now(),
event_type: MemoryEventType::Reallocate,
ptr,
size: new_size,
old_size: Some(old_size),
thread_id,
var_name: None,
type_name: None,
call_stack_hash: None,
thread_name: None,
source_file: None,
source_line: None,
}
}
pub fn metadata(var_name: String, type_name: String, thread_id: u64, size: usize) -> Self {
Self {
timestamp: Self::now(),
event_type: MemoryEventType::Metadata,
ptr: 0, size,
old_size: None,
thread_id,
var_name: Some(var_name),
type_name: Some(type_name),
call_stack_hash: None,
thread_name: None,
source_file: None,
source_line: None,
}
}
pub fn now() -> u64 {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or_default()
}
pub fn with_var_name(mut self, name: String) -> Self {
self.var_name = Some(name);
self
}
pub fn with_type_name(mut self, name: String) -> Self {
self.type_name = Some(name);
self
}
pub fn with_source_file(mut self, file: String) -> Self {
self.source_file = Some(file);
self
}
pub fn with_source_line(mut self, line: u32) -> Self {
self.source_line = Some(line);
self
}
pub fn with_call_stack_hash(mut self, hash: u64) -> Self {
self.call_stack_hash = Some(hash);
self
}
pub fn with_thread_name(mut self, name: String) -> Self {
self.thread_name = Some(name);
self
}
pub fn is_allocation(&self) -> bool {
matches!(
self.event_type,
MemoryEventType::Allocate | MemoryEventType::Reallocate | MemoryEventType::Metadata
)
}
pub fn is_deallocation(&self) -> bool {
matches!(self.event_type, MemoryEventType::Deallocate)
}
pub fn is_move(&self) -> bool {
matches!(self.event_type, MemoryEventType::Move)
}
pub fn is_borrow(&self) -> bool {
matches!(self.event_type, MemoryEventType::Borrow)
}
pub fn is_return(&self) -> bool {
matches!(self.event_type, MemoryEventType::Return)
}
}