use std::hash::{Hash, Hasher};
use std::io;
use std::ops::{Deref, Range};
use std::path::Path;
use std::sync::Arc;
use memmap2::Mmap;
#[derive(Clone)]
pub struct ModulePath(ModulePathStorage);
#[derive(Clone)]
enum ModulePathStorage {
Owned(Arc<str>),
Mmap {
mmap: Arc<Mmap>,
range: Range<usize>,
},
}
impl ModulePath {
#[must_use]
pub fn as_str(&self) -> &str {
match &self.0 {
ModulePathStorage::Owned(path) => path,
ModulePathStorage::Mmap { mmap, range } => std::str::from_utf8(&mmap[range.clone()])
.expect("mmap-backed module path was validated while reading the spool"),
}
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
self.as_str().as_bytes()
}
#[must_use]
pub fn as_path(&self) -> &Path {
Path::new(self.as_str())
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.as_str().is_empty()
}
pub(crate) fn is_bracketed_mapping(&self) -> bool {
self.as_str().starts_with('[')
}
pub(super) fn from_mmap(mmap: Arc<Mmap>, range: Range<usize>) -> io::Result<Self> {
std::str::from_utf8(&mmap[range.clone()])
.map_err(|err| super::invalid_data(err.to_string()))?;
Ok(Self(ModulePathStorage::Mmap { mmap, range }))
}
}
impl Deref for ModulePath {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl AsRef<str> for ModulePath {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl AsRef<std::ffi::OsStr> for ModulePath {
fn as_ref(&self) -> &std::ffi::OsStr {
std::ffi::OsStr::new(self.as_str())
}
}
impl AsRef<Path> for ModulePath {
fn as_ref(&self) -> &Path {
Path::new(self.as_str())
}
}
impl std::borrow::Borrow<str> for ModulePath {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl From<String> for ModulePath {
fn from(path: String) -> Self {
Self(ModulePathStorage::Owned(Arc::from(path.into_boxed_str())))
}
}
impl From<&str> for ModulePath {
fn from(path: &str) -> Self {
Self(ModulePathStorage::Owned(Arc::from(path)))
}
}
impl From<ModulePath> for std::rc::Rc<str> {
fn from(path: ModulePath) -> Self {
path.as_str().into()
}
}
impl std::fmt::Debug for ModulePath {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_str().fmt(fmt)
}
}
impl std::fmt::Display for ModulePath {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.write_str(self.as_str())
}
}
impl PartialEq for ModulePath {
fn eq(&self, other: &Self) -> bool {
self.as_str() == other.as_str()
}
}
impl Eq for ModulePath {}
impl Hash for ModulePath {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_str().hash(state);
}
}
#[derive(Clone, Debug)]
pub struct ModuleRecord {
pub id: u32,
pub process_id: i32,
pub start: u64,
pub end: u64,
pub file_offset: u64,
pub inode: u64,
pub path: ModulePath,
pub is_kernel: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum FrameMode {
User,
Kernel,
TruncatedStackMarker,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FrameRecord {
pub module_id: Option<u32>,
pub rel_ip: u64,
pub abs_ip: u64,
pub mode: FrameMode,
}
impl FrameRecord {
#[must_use]
pub fn truncated_stack_marker() -> Self {
Self {
module_id: None,
rel_ip: 0,
abs_ip: 0,
mode: FrameMode::TruncatedStackMarker,
}
}
#[must_use]
pub fn is_truncated_stack_marker(&self) -> bool {
*self == Self::truncated_stack_marker()
}
}
#[derive(Clone, Debug)]
pub struct OwnedSampleRecord {
pub timestamp_ns: u64,
pub process_id: i32,
pub thread_id: u64,
pub stack_id: u32,
}
#[derive(Clone, Debug)]
pub struct ProcessExecRecord {
pub timestamp_ns: u64,
pub process_id: i32,
pub is_python_runtime: bool,
}