Skip to main content

memscope_rs/event_store/
event.rs

1//! Core memory event types for the event store
2//!
3//! This module defines the unified memory event type used across
4//! all engines in the memscope architecture.
5
6use serde::{Deserialize, Serialize};
7use std::fmt;
8
9/// Type of memory event
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub enum MemoryEventType {
12    /// Memory allocation event
13    Allocate,
14    /// Memory deallocation event
15    Deallocate,
16    /// Memory reallocation event
17    Reallocate,
18    /// Memory move event
19    Move,
20    /// Memory borrow event
21    Borrow,
22    /// Memory return event
23    Return,
24    /// Metadata event for Container/Value types (no heap allocation)
25    Metadata,
26}
27
28impl fmt::Display for MemoryEventType {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        match self {
31            MemoryEventType::Allocate => write!(f, "Allocate"),
32            MemoryEventType::Deallocate => write!(f, "Deallocate"),
33            MemoryEventType::Reallocate => write!(f, "Reallocate"),
34            MemoryEventType::Move => write!(f, "Move"),
35            MemoryEventType::Borrow => write!(f, "Borrow"),
36            MemoryEventType::Return => write!(f, "Return"),
37            MemoryEventType::Metadata => write!(f, "Metadata"),
38        }
39    }
40}
41
42/// Unified memory event type
43///
44/// This structure captures all essential information about memory operations
45/// across all tracking backends (core, lockfree, async, unified).
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct MemoryEvent {
48    /// Event timestamp (nanoseconds since epoch)
49    pub timestamp: u64,
50    /// Event type
51    pub event_type: MemoryEventType,
52    /// Memory pointer address
53    pub ptr: usize,
54    /// Allocation size in bytes
55    pub size: usize,
56    /// Previous allocation size (for Reallocate events)
57    pub old_size: Option<usize>,
58    /// Thread identifier
59    pub thread_id: u64,
60    /// Optional variable name
61    pub var_name: Option<String>,
62    /// Optional type name
63    pub type_name: Option<String>,
64    /// Optional call stack hash
65    pub call_stack_hash: Option<u64>,
66    /// Optional thread name
67    pub thread_name: Option<String>,
68    /// Optional source file path
69    pub source_file: Option<String>,
70    /// Optional source line number
71    pub source_line: Option<u32>,
72}
73
74impl MemoryEvent {
75    /// Create a new allocation event
76    pub fn allocate(ptr: usize, size: usize, thread_id: u64) -> Self {
77        Self {
78            timestamp: Self::now(),
79            event_type: MemoryEventType::Allocate,
80            ptr,
81            size,
82            old_size: None,
83            thread_id,
84            var_name: None,
85            type_name: None,
86            call_stack_hash: None,
87            thread_name: None,
88            source_file: None,
89            source_line: None,
90        }
91    }
92
93    /// Create a new deallocation event
94    pub fn deallocate(ptr: usize, size: usize, thread_id: u64) -> Self {
95        Self {
96            timestamp: Self::now(),
97            event_type: MemoryEventType::Deallocate,
98            ptr,
99            size,
100            old_size: None,
101            thread_id,
102            var_name: None,
103            type_name: None,
104            call_stack_hash: None,
105            thread_name: None,
106            source_file: None,
107            source_line: None,
108        }
109    }
110
111    /// Create a new reallocation event
112    pub fn reallocate(ptr: usize, old_size: usize, new_size: usize, thread_id: u64) -> Self {
113        Self {
114            timestamp: Self::now(),
115            event_type: MemoryEventType::Reallocate,
116            ptr,
117            size: new_size,
118            old_size: Some(old_size),
119            thread_id,
120            var_name: None,
121            type_name: None,
122            call_stack_hash: None,
123            thread_name: None,
124            source_file: None,
125            source_line: None,
126        }
127    }
128
129    /// Create a new metadata event for Container/Value types (no heap allocation)
130    pub fn metadata(var_name: String, type_name: String, thread_id: u64, size: usize) -> Self {
131        Self {
132            timestamp: Self::now(),
133            event_type: MemoryEventType::Metadata,
134            ptr: 0, // No heap pointer
135            size,
136            old_size: None,
137            thread_id,
138            var_name: Some(var_name),
139            type_name: Some(type_name),
140            call_stack_hash: None,
141            thread_name: None,
142            source_file: None,
143            source_line: None,
144        }
145    }
146
147    /// Get current timestamp in nanoseconds
148    /// Returns 0 if system time is before Unix epoch (should not happen in practice)
149    pub fn now() -> u64 {
150        use std::time::{SystemTime, UNIX_EPOCH};
151        SystemTime::now()
152            .duration_since(UNIX_EPOCH)
153            .map(|d| d.as_nanos() as u64)
154            .unwrap_or_default()
155    }
156
157    /// Set variable name
158    pub fn with_var_name(mut self, name: String) -> Self {
159        self.var_name = Some(name);
160        self
161    }
162
163    /// Set type name
164    pub fn with_type_name(mut self, name: String) -> Self {
165        self.type_name = Some(name);
166        self
167    }
168
169    /// Set source file path
170    pub fn with_source_file(mut self, file: String) -> Self {
171        self.source_file = Some(file);
172        self
173    }
174
175    /// Set source line number
176    pub fn with_source_line(mut self, line: u32) -> Self {
177        self.source_line = Some(line);
178        self
179    }
180
181    /// Set call stack hash
182    pub fn with_call_stack_hash(mut self, hash: u64) -> Self {
183        self.call_stack_hash = Some(hash);
184        self
185    }
186
187    /// Set thread name
188    pub fn with_thread_name(mut self, name: String) -> Self {
189        self.thread_name = Some(name);
190        self
191    }
192
193    /// Check if this is an allocation event
194    pub fn is_allocation(&self) -> bool {
195        matches!(
196            self.event_type,
197            MemoryEventType::Allocate | MemoryEventType::Reallocate | MemoryEventType::Metadata
198        )
199    }
200
201    /// Check if this is a deallocation event
202    pub fn is_deallocation(&self) -> bool {
203        matches!(self.event_type, MemoryEventType::Deallocate)
204    }
205
206    /// Check if this is a move event
207    pub fn is_move(&self) -> bool {
208        matches!(self.event_type, MemoryEventType::Move)
209    }
210
211    /// Check if this is a borrow event
212    pub fn is_borrow(&self) -> bool {
213        matches!(self.event_type, MemoryEventType::Borrow)
214    }
215
216    /// Check if this is a return event
217    pub fn is_return(&self) -> bool {
218        matches!(self.event_type, MemoryEventType::Return)
219    }
220}