use bitflags::bitflags;
use perfetto_sdk_sys::*;
use std::{ffi::CString, ptr, time::Duration};
use thiserror::Error;
#[derive(Error, Debug, PartialEq)]
pub enum ProducerError {
#[error("Invalid string: {0}.")]
InvalidString(std::ffi::NulError),
#[error("Invalid TTL: {0}.")]
InvalidTTL(std::num::TryFromIntError),
}
bitflags! {
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Backends: u32 {
const IN_PROCESS = 0b00000001;
const SYSTEM = 0b00000010;
}
}
#[derive(Default)]
pub struct ProducerInitArgs {
backends: Backends,
shmem_size_hint_kb: u32,
}
#[derive(Default)]
#[must_use = "This is a builder; remember to call `.build()` (or keep chaining)."]
pub struct ProducerInitArgsBuilder {
args: ProducerInitArgs,
}
impl ProducerInitArgsBuilder {
pub fn new() -> Self {
Self::default()
}
#[must_use = "Builder methods return an updated builder; use the returned value or keep chaining."]
pub fn backends(mut self, backends: Backends) -> Self {
self.args.backends = backends;
self
}
#[must_use = "Builder methods return an updated builder; use the returned value or keep chaining."]
pub fn shmem_size_hint_kb(mut self, shmem_size_hint_kb: u32) -> Self {
self.args.shmem_size_hint_kb = shmem_size_hint_kb;
self
}
pub fn build(&self) -> &ProducerInitArgs {
&self.args
}
}
pub struct Producer {}
impl Producer {
pub fn init(args: &ProducerInitArgs) {
let backend_args = unsafe { PerfettoProducerBackendInitArgsCreate() };
unsafe {
PerfettoProducerBackendInitArgsSetShmemSizeHintKb(
backend_args,
args.shmem_size_hint_kb,
);
if args.backends.contains(Backends::IN_PROCESS) {
PerfettoProducerInProcessInit(backend_args);
}
if args.backends.contains(Backends::SYSTEM) {
PerfettoProducerSystemInit(backend_args);
}
}
unsafe { PerfettoProducerBackendInitArgsDestroy(backend_args) };
}
pub fn activate_trigger(trigger_name: &str, ttl: Duration) -> Result<(), ProducerError> {
let ctrigger_name = CString::new(trigger_name).map_err(ProducerError::InvalidString)?;
let mut trigger_names = [ctrigger_name.as_ptr(), ptr::null_mut()];
let ttl_ms = ttl
.as_millis()
.try_into()
.map_err(ProducerError::InvalidTTL)?;
unsafe { PerfettoProducerActivateTriggers(trigger_names.as_mut_ptr(), ttl_ms) };
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::acquire_test_environment;
use std::error::Error;
#[test]
fn activate_trigger() -> Result<(), Box<dyn Error>> {
let _lock = acquire_test_environment();
Producer::activate_trigger("trigger_name", Duration::from_millis(10))?;
Ok(())
}
}