#![allow(clippy::not_unsafe_ptr_arg_deref)]
use crate::{
simics_exception,
sys::{
cycles_t, event_class_t, SIM_event_cancel_step, SIM_event_cancel_time,
SIM_event_find_next_cycle, SIM_event_find_next_step, SIM_event_find_next_time,
SIM_event_post_cycle, SIM_event_post_step, SIM_event_post_time, SIM_register_event,
},
ConfClass, ConfObject, Error, PcStep, Result,
};
use raw_cstr::raw_cstr;
use std::{ffi::c_void, ptr::null_mut};
use typed_builder::TypedBuilder;
pub use crate::api::sys::event_class_flag_t as EventClassFlag;
pub type EventClass = event_class_t;
pub type Cycles = cycles_t;
pub type EventCallbackClosure = Box<dyn FnMut(*mut ConfObject)>;
pub type EventFilterClosure = Box<dyn Fn(*mut c_void) -> i32>;
extern "C" fn event_callback_handler(obj: *mut ConfObject, cb: *mut c_void) {
let closure = Box::leak(unsafe { Box::from_raw(cb as *mut EventCallbackClosure) });
closure(obj)
}
extern "C" fn event_destroy_handler(_: *mut ConfObject, cb: *mut c_void) {
let _ = unsafe { Box::from_raw(cb as *mut EventCallbackClosure) };
}
extern "C" fn event_filter_handler(data: *mut c_void, callback: *mut c_void) -> i32 {
let closure = Box::leak(unsafe { Box::from_raw(callback as *mut EventFilterClosure) });
closure(data)
}
#[derive(TypedBuilder, Debug, Clone)]
pub struct Event {
#[builder(setter(into))]
#[allow(unused)]
name: String,
#[allow(unused)]
cls: *mut ConfClass,
#[builder(default = EventClassFlag(0), setter(into))]
#[allow(unused)]
flags: EventClassFlag,
#[builder(default = register_event(&name, cls, flags).expect("Failed to register event"))]
event_class: *mut EventClass,
}
impl Event {
pub fn cls(&self) -> *mut ConfClass {
self.cls
}
pub fn event_class(&self) -> *mut EventClass {
self.event_class
}
pub fn register<S>(name: S, cls: *mut ConfClass, flags: EventClassFlag) -> Result<Self>
where
S: AsRef<str>,
{
Ok(Self {
name: name.as_ref().to_string(),
cls,
flags,
event_class: register_event(name, cls, flags)?,
})
}
pub fn post_time<F>(
&self,
obj: *mut ConfObject,
clock: *mut ConfObject,
seconds: f64,
callback: F,
) -> Result<()>
where
F: FnMut(*mut ConfObject) + 'static,
{
event_post_time(clock, self.event_class, obj, seconds, callback)
}
pub fn cancel_time(&self, obj: *mut ConfObject, clock: *mut ConfObject) -> Result<()> {
event_cancel_time::<Box<dyn Fn(*mut c_void) -> i32>>(clock, self.event_class, obj, None)
}
#[deprecated = "Filter function will not be freed. This will lead to memory leaks."]
pub fn cancel_time_filter<F>(
&self,
obj: *mut ConfObject,
clock: *mut ConfObject,
filter: Option<F>,
) -> Result<()>
where
F: Fn(*mut c_void) -> i32 + 'static,
{
event_cancel_time(clock, self.event_class, obj, filter)
}
pub fn post_step<F>(
&self,
obj: *mut ConfObject,
clock: *mut ConfObject,
steps: PcStep,
callback: F,
) -> Result<()>
where
F: FnMut(*mut ConfObject) + 'static,
{
event_post_step(clock, self.event_class, obj, steps, callback)
}
pub fn cancel_step(&self, obj: *mut ConfObject, clock: *mut ConfObject) -> Result<()> {
event_cancel_step::<Box<dyn Fn(*mut c_void) -> i32>>(clock, self.event_class, obj, None)
}
#[deprecated = "Filter function will not be freed. This will lead to memory leaks."]
pub fn cancel_step_filter<F>(
&self,
obj: *mut ConfObject,
clock: *mut ConfObject,
filter: Option<F>,
) -> Result<()>
where
F: Fn(*mut c_void) -> i32 + 'static,
{
event_cancel_step(clock, self.event_class, obj, filter)
}
pub fn post_cycle<F>(
&self,
obj: *mut ConfObject,
clock: *mut ConfObject,
cycles: Cycles,
callback: F,
) -> Result<()>
where
F: FnMut(*mut ConfObject) + 'static,
{
event_post_cycle(clock, self.event_class, obj, cycles, callback)
}
pub fn find_next_time(&self, obj: *mut ConfObject, clock: *mut ConfObject) -> Result<f64> {
event_find_next_time::<Box<dyn Fn(*mut c_void) -> i32>>(clock, self.event_class, obj, None)
}
pub fn find_next_time_filter<F>(
&self,
obj: *mut ConfObject,
clock: *mut ConfObject,
filter: F,
) -> Result<f64>
where
F: Fn(*mut c_void) -> i32 + 'static,
{
event_find_next_time(clock, self.event_class, obj, Some(filter))
}
pub fn find_next_cycle(&self, obj: *mut ConfObject, clock: *mut ConfObject) -> Result<Cycles> {
event_find_next_cycle::<Box<dyn Fn(*mut c_void) -> i32>>(clock, self.event_class, obj, None)
}
pub fn find_next_cycle_filter<F>(
&self,
obj: *mut ConfObject,
clock: *mut ConfObject,
filter: F,
) -> Result<Cycles>
where
F: Fn(*mut c_void) -> i32 + 'static,
{
event_find_next_cycle(clock, self.event_class, obj, Some(filter))
}
pub fn find_next_step(&self, obj: *mut ConfObject, clock: *mut ConfObject) -> Result<PcStep> {
event_find_next_step::<Box<dyn Fn(*mut c_void) -> i32>>(clock, self.event_class, obj, None)
}
pub fn find_next_step_filter<F>(
&self,
obj: *mut ConfObject,
clock: *mut ConfObject,
filter: F,
) -> Result<PcStep>
where
F: Fn(*mut c_void) -> i32 + 'static,
{
event_find_next_step(clock, self.event_class, obj, Some(filter))
}
}
#[simics_exception]
fn register_event<S>(name: S, cls: *mut ConfClass, flags: EventClassFlag) -> Result<*mut EventClass>
where
S: AsRef<str>,
{
let event = unsafe {
SIM_register_event(
raw_cstr(name.as_ref())?,
cls,
flags,
Some(event_callback_handler),
Some(event_destroy_handler),
None,
None,
None,
)
};
Ok(event)
}
#[simics_exception]
pub fn event_post_time<F>(
clock: *mut ConfObject,
event: *mut EventClass,
obj: *mut ConfObject,
seconds: f64,
callback: F,
) where
F: FnMut(*mut ConfObject) + 'static,
{
let callbacks: EventCallbackClosure = Box::new(callback);
let callbacks_box = Box::new(callbacks);
let callbacks_raw = Box::into_raw(callbacks_box);
unsafe { SIM_event_post_time(clock, event, obj, seconds, callbacks_raw as *mut c_void) };
}
#[simics_exception]
pub fn event_post_cycle<F>(
clock: *mut ConfObject,
event: *mut EventClass,
obj: *mut ConfObject,
cycles: Cycles,
callback: F,
) where
F: FnMut(*mut ConfObject) + 'static,
{
let callbacks: EventCallbackClosure = Box::new(callback);
let callbacks_box = Box::new(callbacks);
let callbacks_raw = Box::into_raw(callbacks_box);
unsafe { SIM_event_post_cycle(clock, event, obj, cycles, callbacks_raw as *mut c_void) };
}
#[simics_exception]
pub fn event_post_step<F>(
clock: *mut ConfObject,
event: *mut EventClass,
obj: *mut ConfObject,
steps: PcStep,
callback: F,
) where
F: FnMut(*mut ConfObject) + 'static,
{
let callbacks: EventCallbackClosure = Box::new(callback);
let callbacks_box = Box::new(callbacks);
let callbacks_raw = Box::into_raw(callbacks_box);
unsafe { SIM_event_post_step(clock, event, obj, steps, callbacks_raw as *mut c_void) };
}
#[simics_exception]
pub fn event_cancel_time<F>(
clock: *mut ConfObject,
event: *mut EventClass,
obj: *mut ConfObject,
filter: Option<F>,
) where
F: Fn(*mut c_void) -> i32 + 'static,
{
let (callback, callback_data) = if let Some(filter) = filter {
let filter: EventFilterClosure = Box::new(filter);
let filter_box = Box::new(filter);
(Some(event_filter_handler as _), Box::into_raw(filter_box))
} else {
(None, null_mut())
};
unsafe { SIM_event_cancel_time(clock, event, obj, callback, callback_data as *mut c_void) }
}
#[simics_exception]
pub fn event_cancel_step<F>(
clock: *mut ConfObject,
event: *mut EventClass,
obj: *mut ConfObject,
filter: Option<F>,
) where
F: Fn(*mut c_void) -> i32 + 'static,
{
let (callback, callback_data) = if let Some(filter) = filter {
let filter: EventFilterClosure = Box::new(filter);
let filter_box = Box::new(filter);
(Some(event_filter_handler as _), Box::into_raw(filter_box))
} else {
(None, null_mut())
};
unsafe { SIM_event_cancel_step(clock, event, obj, callback, callback_data as *mut c_void) }
}
#[simics_exception]
pub fn event_find_next_cycle<F>(
clock: *mut ConfObject,
event: *mut EventClass,
obj: *mut ConfObject,
filter: Option<F>,
) -> Result<Cycles>
where
F: Fn(*mut c_void) -> i32 + 'static,
{
let (callback, callback_data) = if let Some(filter) = filter {
let filter: EventFilterClosure = Box::new(filter);
let filter_box = Box::new(filter);
(Some(event_filter_handler as _), Box::into_raw(filter_box))
} else {
(None, null_mut())
};
let time =
unsafe { SIM_event_find_next_cycle(clock, event, obj, callback, callback_data as _) };
if time == -1 {
Err(Error::NoEventFound)
} else {
Ok(time)
}
}
#[simics_exception]
pub fn event_find_next_time<F>(
clock: *mut ConfObject,
event: *mut EventClass,
obj: *mut ConfObject,
filter: Option<F>,
) -> Result<f64>
where
F: Fn(*mut c_void) -> i32 + 'static,
{
let (callback, callback_data) = if let Some(filter) = filter {
let filter: EventFilterClosure = Box::new(filter);
let filter_box = Box::new(filter);
(Some(event_filter_handler as _), Box::into_raw(filter_box))
} else {
(None, null_mut())
};
let time = unsafe { SIM_event_find_next_time(clock, event, obj, callback, callback_data as _) };
if time == -1.0 {
Err(Error::NoEventFound)
} else {
Ok(time)
}
}
#[simics_exception]
pub fn event_find_next_step<F>(
clock: *mut ConfObject,
event: *mut EventClass,
obj: *mut ConfObject,
filter: Option<F>,
) -> Result<PcStep>
where
F: Fn(*mut c_void) -> i32 + 'static,
{
let (callback, callback_data) = if let Some(filter) = filter {
let filter: EventFilterClosure = Box::new(filter);
let filter_box = Box::new(filter);
(Some(event_filter_handler as _), Box::into_raw(filter_box))
} else {
(None, null_mut())
};
let time = unsafe { SIM_event_find_next_step(clock, event, obj, callback, callback_data as _) };
if time == -1 {
Err(Error::NoEventFound)
} else {
Ok(time)
}
}