use std::ffi::CStr;
use std::os::raw::c_char;
use crate::{Handle, ObjectType, SysFuncType, Value, ValueType};
pub type RawSystfData = vpi_sys::s_vpi_systf_data;
pub type SystfCallback = unsafe extern "C" fn(*mut c_char) -> i32;
#[derive(Debug, Clone)]
pub struct SystfInfo {
pub kind: i32,
pub sys_func_type: i32,
pub name: Option<String>,
pub calltf: Option<SystfCallback>,
pub compiletf: Option<SystfCallback>,
pub sizetf: Option<SystfCallback>,
pub user_data: *mut c_char,
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum SystfKind {
Task = vpi_sys::vpiSysTask,
Func = vpi_sys::vpiSysFunc,
}
#[must_use]
pub fn register_systf_raw(data: &mut RawSystfData) -> Handle {
let handle = unsafe { vpi_sys::vpi_register_systf(data) };
Handle::from_raw(handle)
}
#[must_use]
pub fn register_systf(
kind: SystfKind,
name: &'static CStr,
calltf: Option<SystfCallback>,
compiletf: Option<SystfCallback>,
sizetf: Option<SystfCallback>,
user_data: *mut c_char,
sys_func_type: Option<SysFuncType>,
) -> Handle {
let sysfunctype = match kind {
SystfKind::Task => vpi_sys::vpiSysTask as i32,
SystfKind::Func => sys_func_type.map_or(vpi_sys::vpiIntFunc as i32, |t| t as i32),
};
let mut data = RawSystfData {
type_: kind as i32,
sysfunctype,
tfname: name.as_ptr().cast_mut(),
calltf,
compiletf,
sizetf,
user_data,
};
register_systf_raw(&mut data)
}
#[must_use]
pub fn current_systf_call() -> Handle {
Handle::null().get(ObjectType::SysTfCall)
}
#[must_use]
pub fn get_systf_info_raw(object: &Handle) -> Option<RawSystfData> {
if object.is_null() {
return None;
}
let mut data = RawSystfData {
type_: 0,
sysfunctype: 0,
tfname: std::ptr::null_mut(),
calltf: None,
compiletf: None,
sizetf: None,
user_data: std::ptr::null_mut(),
};
unsafe {
vpi_sys::vpi_get_systf_info(object.as_raw(), &raw mut data);
}
Some(data)
}
#[must_use]
pub fn get_systf_info(object: &Handle) -> Option<SystfInfo> {
let data = get_systf_info_raw(object)?;
let name = if data.tfname.is_null() {
None
} else {
Some(
unsafe { CStr::from_ptr(data.tfname) }
.to_string_lossy()
.into_owned(),
)
};
Some(SystfInfo {
kind: data.type_,
sys_func_type: data.sysfunctype,
name,
calltf: data.calltf,
compiletf: data.compiletf,
sizetf: data.sizetf,
user_data: data.user_data,
})
}
#[must_use]
pub fn current_systf_info() -> Option<SystfInfo> {
let call = current_systf_call();
get_systf_info(&call)
}
#[must_use]
pub fn get_systf_arg(index: u32, format: ValueType) -> Option<Value> {
let call = current_systf_call();
if call.is_null() {
return None;
}
call.iterator(ObjectType::Argument)
.nth(index as usize)
.and_then(|arg| arg.get_value(format))
}
#[must_use]
pub fn get_systf_args(formats: impl AsRef<[ValueType]>) -> Vec<Option<Value>> {
let call = current_systf_call();
if call.is_null() {
return std::iter::repeat_with(|| None)
.take(formats.as_ref().len())
.collect();
}
let mut args = call.iterator(ObjectType::Argument);
formats
.as_ref()
.iter()
.map(|format| args.next().and_then(|arg| arg.get_value(*format)))
.collect()
}
#[cfg(test)]
mod tests {
use super::{get_systf_info, get_systf_info_raw};
use crate::Handle;
#[test]
fn get_systf_info_on_null_handle_returns_none() {
let h = Handle::null();
assert!(get_systf_info_raw(&h).is_none());
assert!(get_systf_info(&h).is_none());
}
}