#![allow(clippy::module_inception)]
use crate::{
backend::Rule,
error::{PyroscopeError, Result},
};
use std::{
fmt::Debug,
sync::{Arc, Mutex},
};
use super::Report;
#[derive(Debug, Copy, Clone)]
pub struct BackendConfig {
pub report_thread_id: bool,
pub report_thread_name: bool,
pub report_pid: bool,
pub report_oncpu: bool,
}
impl Default for BackendConfig {
fn default() -> Self {
Self {
report_thread_id: false,
report_thread_name: false,
report_pid: false,
report_oncpu: false,
}
}
}
pub trait Backend: Send + Debug {
fn spy_name(&self) -> Result<String>;
fn spy_extension(&self) -> Result<Option<String>>;
fn sample_rate(&self) -> Result<u32>;
fn initialize(&mut self) -> Result<()>;
fn shutdown(self: Box<Self>) -> Result<()>;
fn report(&mut self) -> Result<Vec<Report>>;
fn add_rule(&self, ruleset: Rule) -> Result<()>;
fn remove_rule(&self, ruleset: Rule) -> Result<()>;
fn set_config(&self, config: BackendConfig);
fn get_config(&self) -> Result<BackendConfig>;
}
#[derive(Debug)]
pub struct BackendBare;
#[derive(Debug)]
pub struct BackendUninitialized;
#[derive(Debug)]
pub struct BackendReady;
pub trait BackendState {}
impl BackendState for BackendBare {}
impl BackendState for BackendUninitialized {}
impl BackendState for BackendReady {}
pub trait BackendAccessible: BackendState {}
impl BackendAccessible for BackendUninitialized {}
impl BackendAccessible for BackendReady {}
#[derive(Debug)]
pub struct BackendImpl<S: BackendState + ?Sized> {
pub backend: Arc<Mutex<Option<Box<dyn Backend>>>>,
_state: std::marker::PhantomData<S>,
}
impl BackendImpl<BackendBare> {
pub fn new(
backend_box: Box<dyn Backend>, config: Option<BackendConfig>,
) -> BackendImpl<BackendUninitialized> {
if let Some(config) = config {
backend_box.set_config(config);
} else {
backend_box.set_config(BackendConfig::default());
}
BackendImpl {
backend: Arc::new(Mutex::new(Some(backend_box))),
_state: std::marker::PhantomData,
}
}
}
impl BackendImpl<BackendUninitialized> {
pub fn initialize(self) -> Result<BackendImpl<BackendReady>> {
let backend = self.backend.clone();
backend
.lock()?
.as_mut()
.ok_or(PyroscopeError::BackendImpl)?
.initialize()?;
Ok(BackendImpl {
backend,
_state: std::marker::PhantomData,
})
}
}
impl<S: BackendAccessible> BackendImpl<S> {
pub fn spy_name(&self) -> Result<String> {
self.backend
.lock()?
.as_ref()
.ok_or(PyroscopeError::BackendImpl)?
.spy_name()
}
pub fn spy_extension(&self) -> Result<Option<String>> {
self.backend
.lock()?
.as_ref()
.ok_or(PyroscopeError::BackendImpl)?
.spy_extension()
}
pub fn sample_rate(&self) -> Result<u32> {
self.backend
.lock()?
.as_ref()
.ok_or(PyroscopeError::BackendImpl)?
.sample_rate()
}
pub fn get_config(&self) -> Result<BackendConfig> {
self.backend
.lock()?
.as_ref()
.ok_or(PyroscopeError::BackendImpl)?
.get_config()
}
pub fn add_rule(&self, rule: Rule) -> Result<()> {
self.backend
.lock()?
.as_ref()
.ok_or(PyroscopeError::BackendImpl)?
.add_rule(rule)
}
pub fn remove_rule(&self, rule: Rule) -> Result<()> {
self.backend
.lock()?
.as_ref()
.ok_or(PyroscopeError::BackendImpl)?
.remove_rule(rule)
}
}
impl BackendImpl<BackendReady> {
pub fn shutdown(self) -> Result<()> {
self.backend
.lock()?
.take()
.ok_or(PyroscopeError::BackendImpl)?
.shutdown()?;
Ok(())
}
pub fn report(&mut self) -> Result<Vec<Report>> {
self.backend
.lock()?
.as_mut()
.ok_or(PyroscopeError::BackendImpl)?
.report()
}
}