use std::{ffi::CStr, ptr::NonNull};
use crate::{Result, cstring, status_to_result, sys};
macro_rules! call_ffi {
($call:expr) => {{
unsafe { $call }
}};
}
pub struct Event {
raw: Option<NonNull<sys::switch_event_t>>,
}
impl Event {
pub fn custom(subclass: impl AsRef<str>) -> Result<Self> {
let subclass = cstring(subclass)?;
let mut raw = std::ptr::null_mut();
let status = unsafe { create_custom_event(&mut raw, subclass.as_c_str()) };
status_to_result(status)?;
Ok(Self {
raw: NonNull::new(raw),
})
}
pub fn as_ptr(&self) -> *mut sys::switch_event_t {
self.raw.map_or(std::ptr::null_mut(), NonNull::as_ptr)
}
pub fn add_header(&mut self, name: impl AsRef<str>, value: &str) -> Result<()> {
let Some(raw) = self.raw else {
return Ok(());
};
let name = cstring(name)?;
let value = cstring(value)?;
let status = unsafe {
sys::switch_event_add_header_string(
raw.as_ptr(),
sys::switch_stack_t::SWITCH_STACK_BOTTOM,
name.as_ptr(),
value.as_ptr(),
)
};
status_to_result(status)
}
pub fn add_header_name(&mut self, name: impl AsRef<str>, value: &str) -> Result<()> {
self.add_header(name, value)
}
pub fn fire(mut self) -> Result<()> {
let Some(raw) = self.raw.take() else {
return Ok(());
};
let mut raw = raw.as_ptr();
let status = unsafe { fire_event(&mut raw) };
if status == crate::SUCCESS {
Ok(())
} else {
self.raw = NonNull::new(raw);
Err(crate::SwitchError(status))
}
}
}
unsafe fn create_custom_event(
raw: &mut *mut sys::switch_event_t,
subclass: &CStr,
) -> sys::switch_status_t {
let create = sys::switch_event_create_subclass_detailed;
let event = sys::switch_event_types_t::SWITCH_EVENT_CUSTOM;
call_ffi!(create(
c"fswtch-rs".as_ptr(),
c"Event::custom".as_ptr(),
line!() as _,
raw,
event,
subclass.as_ptr(),
))
}
unsafe fn fire_event(raw: &mut *mut sys::switch_event_t) -> sys::switch_status_t {
let fire = sys::switch_event_fire_detailed;
call_ffi!(fire(
c"fswtch-rs".as_ptr(),
c"Event::fire".as_ptr(),
line!() as _,
raw,
std::ptr::null_mut(),
))
}
impl Drop for Event {
fn drop(&mut self) {
if let Some(raw) = self.raw.take() {
let mut raw = raw.as_ptr();
unsafe {
sys::switch_event_destroy(&mut raw);
}
}
}
}
#[derive(Copy, Clone)]
pub struct EventRef {
raw: Option<NonNull<sys::switch_event_t>>,
}
impl EventRef {
pub unsafe fn from_raw(raw: *mut sys::switch_event_t) -> Self {
Self {
raw: NonNull::new(raw),
}
}
pub fn as_ptr(self) -> *mut sys::switch_event_t {
self.raw.map_or(std::ptr::null_mut(), NonNull::as_ptr)
}
pub fn header(self, name: impl AsRef<str>) -> Option<String> {
let raw = self.raw?;
let name = cstring(name).ok()?;
let value = unsafe { sys::switch_event_get_header_idx(raw.as_ptr(), name.as_ptr(), -1) };
if value.is_null() {
return None;
}
unsafe { CStr::from_ptr(value) }
.to_str()
.ok()
.map(ToOwned::to_owned)
}
}