use dmsdk_ffi::dmConfigFile;
use std::ffi::{c_char, CStr, CString};
pub type ConfigFile = dmConfigFile::HConfig;
pub struct Config {}
pub unsafe fn get_string(config: ConfigFile, key: &str, default_value: &str) -> String {
let key = CString::new(key).unwrap();
let default_value = CString::new(default_value).unwrap();
let ptr = dmConfigFile::GetString(config, key.as_ptr(), default_value.as_ptr());
let cstr = CStr::from_ptr(ptr);
String::from_utf8_lossy(cstr.to_bytes()).into_owned()
}
pub unsafe fn get_int(config: ConfigFile, key: &str, default_value: i32) -> i32 {
let key = CString::new(key).unwrap();
dmConfigFile::GetInt(config, key.as_ptr(), default_value)
}
pub unsafe fn get_float(config: ConfigFile, key: &str, default_value: f32) -> f32 {
let key = CString::new(key).unwrap();
dmConfigFile::GetFloat(config, key.as_ptr(), default_value)
}
pub type PluginLifecycle = fn(ConfigFile);
pub type PluginGetter<T> = fn(ConfigFile, &str, T) -> Option<T>;
#[doc(hidden)]
pub type StringGetter = fn(ConfigFile, &str, &str) -> Option<String>;
#[doc(hidden)]
pub type RawPluginLifecycle = unsafe extern "C" fn(ConfigFile);
#[doc(hidden)]
pub type RawPluginGetter<T> = unsafe extern "C" fn(ConfigFile, *const c_char, T, *mut T) -> bool;
#[doc(hidden)]
pub type Desc = [u8; DESC_BUFFER_SIZE as usize];
#[doc(hidden)]
pub const DESC_BUFFER_SIZE: u32 = 64;
#[doc(hidden)]
#[macro_export]
macro_rules! declare_plugin_lifecycle {
($symbol:ident, $option:expr) => {
#[no_mangle]
unsafe extern "C" fn $symbol(config: dmconfigfile::ConfigFile) {
let func: Option<dmconfigfile::PluginLifecycle> = $option;
if let Some(func) = func {
func(config);
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! declare_plugin_getter {
($symbol:ident, $option:expr, $type:ident) => {
#[no_mangle]
unsafe extern "C" fn $symbol(
config: dmconfigfile::ConfigFile,
key: *const core::ffi::c_char,
default_value: $type,
out: *mut $type,
) -> bool {
let func: Option<dmconfigfile::PluginGetter<$type>> = $option;
if let Some(func) = func {
let key = core::ffi::CStr::from_ptr(key)
.to_str()
.expect("Invalid UTF-8 sequence in key!");
if let Some(value) = func(config, key, default_value) {
out.write(value);
true
} else {
false
}
} else {
false
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! declare_plugin_string_getter {
($symbol:ident, $option:expr) => {
#[no_mangle]
unsafe extern "C" fn $symbol(
config: dmconfigfile::ConfigFile,
key: *const core::ffi::c_char,
default_value: *const core::ffi::c_char,
out: *mut *const core::ffi::c_char,
) -> bool {
let func: Option<dmconfigfile::StringGetter> = $option;
if let Some(func) = func {
let key = core::ffi::CStr::from_ptr(key).to_str();
if key.is_err() {
dmlog::error!("Invalid UTF-8 sequence in key!");
return false;
}
let default_value = if default_value.is_null() {
""
} else {
match core::ffi::CStr::from_ptr(default_value).to_str() {
Ok(str) => str,
Err(_) => {
dmlog::error!("Invalid UTF-8 sequence in default value!");
return false;
}
}
};
if let Some(value) = func(config, key.unwrap(), default_value) {
let cstr =
std::ffi::CString::new(value).expect("Unexpected null in return value!");
let boxed_str = Box::new(cstr);
out.write(Box::leak(boxed_str).as_ptr());
true
} else {
false
}
} else {
false
}
}
};
}
#[macro_export]
macro_rules! declare_configfile_extension {
($symbol:ident, $create:expr, $destroy:expr, $get_string:expr, $get_int:expr, $get_float:expr) => {
paste! {
static mut [<$symbol _PLUGIN_DESC>]: dmconfigfile::Desc = [0u8; dmconfigfile::DESC_BUFFER_SIZE as usize];
declare_plugin_lifecycle!([<$symbol _plugin_create>], $create);
declare_plugin_lifecycle!([<$symbol _plugin_destroy>], $destroy);
declare_plugin_string_getter!([<$symbol _plugin_get_string>], $get_string);
declare_plugin_getter!([<$symbol _plugin_get_int>], $get_int, i32);
declare_plugin_getter!([<$symbol _plugin_get_float>], $get_float, f32);
#[no_mangle]
#[dmextension::ctor]
unsafe fn $symbol() {
dmconfigfile::register(
&mut [<$symbol _PLUGIN_DESC>],
stringify!($symbol),
[<$symbol _plugin_create>],
[<$symbol _plugin_destroy>],
[<$symbol _plugin_get_string>],
[<$symbol _plugin_get_int>],
[<$symbol _plugin_get_float>],
);
}
}
};
}
#[doc(hidden)]
pub fn register(
desc: &mut Desc,
name: &str,
create: RawPluginLifecycle,
destroy: RawPluginLifecycle,
get_string: RawPluginGetter<*const c_char>,
get_int: RawPluginGetter<i32>,
get_float: RawPluginGetter<f32>,
) {
let name = CString::new(name).unwrap();
unsafe {
dmConfigFile::Register(
desc.as_mut_ptr() as *mut dmConfigFile::PluginDesc,
DESC_BUFFER_SIZE,
name.as_ptr(),
Some(create),
Some(destroy),
Some(get_string),
Some(get_int),
Some(get_float),
);
}
}
#[doc(inline)]
pub use crate::declare_configfile_extension;