#![allow(clippy::module_inception)]
use crate::error::{PyroscopeError, Result};
use std::{
fmt::Debug,
sync::{Arc, Mutex},
};
use super::{ReportBatch, ThreadTag};
#[derive(Debug, Copy, Clone, Default)]
pub struct BackendConfig {
pub report_thread_id: bool,
pub report_thread_name: bool,
pub report_pid: bool,
}
pub trait Backend: Send {
fn initialize(&mut self) -> Result<()>;
fn shutdown(self: Box<Self>) -> Result<()>;
fn report(&mut self) -> Result<ReportBatch>;
fn add_tag(&self, tag: ThreadTag) -> Result<()>;
fn remove_tag(&self, tag: ThreadTag) -> Result<()>;
}
#[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 {}
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>) -> BackendImpl<BackendUninitialized> {
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 add_tag(&self, tag: ThreadTag) -> Result<()> {
self.backend
.lock()?
.as_ref()
.ok_or(PyroscopeError::BackendImpl)?
.add_tag(tag)
}
pub fn remove_tag(&self, rule: ThreadTag) -> Result<()> {
self.backend
.lock()?
.as_ref()
.ok_or(PyroscopeError::BackendImpl)?
.remove_tag(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<ReportBatch> {
self.backend
.lock()?
.as_mut()
.ok_or(PyroscopeError::BackendImpl)?
.report()
}
}