use koicore::{
Value,
command::{Command, CompositeValue, Parameter},
};
use std::{
ffi::{CStr, c_char},
ptr, slice,
};
use crate::command::param::KoiParamType;
use super::command::KoiCommand;
#[repr(C)]
pub struct KoiCompositeDict {
_data: (),
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_New(name: *const c_char) -> *mut KoiCompositeDict {
if name.is_null() {
return ptr::null_mut();
}
let name_str = match unsafe { CStr::from_ptr(name) }.to_str() {
Ok(s) => s.to_string(),
Err(_) => return ptr::null_mut(),
};
let param = Parameter::Composite(name_str, CompositeValue::Dict(Vec::new()));
Box::into_raw(Box::new(param)) as *mut KoiCompositeDict
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCommand_AddCompositeDict(
command: *mut KoiCommand,
dict: *mut KoiCompositeDict,
) -> i32 {
if command.is_null() || dict.is_null() {
return -1;
}
let command = unsafe { &mut *(command as *mut Command) };
let dict_param = unsafe { Box::from_raw(dict as *mut Parameter) };
command.params.push(*dict_param);
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCommand_GetCompositeDict(
command: *mut KoiCommand,
index: usize,
) -> *mut KoiCompositeDict {
if command.is_null() {
return ptr::null_mut();
}
let command = unsafe { &*(command as *mut Command) };
let params = command.params();
if index >= params.len() {
return ptr::null_mut();
}
match ¶ms[index] {
p @ &Parameter::Composite(_, CompositeValue::Dict(_)) => {
p as *const Parameter as *mut KoiCompositeDict
}
_ => ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_GetLength(dict: *mut KoiCompositeDict) -> usize {
if dict.is_null() {
return 0;
}
let param = unsafe { &*(dict as *const Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => entries.len(),
_ => 0,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_Remove(
dict: *mut KoiCompositeDict,
key: *const c_char,
) -> i32 {
if dict.is_null() || key.is_null() {
return -1;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return -2,
};
let param = unsafe { &mut *(dict as *mut Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
let original_len = entries.len();
entries.retain(|(k, _)| k != key_str);
if entries.len() == original_len {
return -3;
}
0
}
_ => -4,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_Clear(dict: *mut KoiCompositeDict) -> i32 {
if dict.is_null() {
return -1;
}
let param = unsafe { &mut *(dict as *mut Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
entries.clear();
0
}
_ => -3,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_Del(dict: *mut KoiCompositeDict) {
if dict.is_null() {
return;
}
unsafe { drop(Box::from_raw(dict as *mut Parameter)) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_SetIntValue(
dict: *mut KoiCompositeDict,
key: *const c_char,
value: i64,
) -> i32 {
if dict.is_null() || key.is_null() {
return -1;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return -2,
};
let param = unsafe { &mut *(dict as *mut Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if let Some((_, v)) = entries.iter_mut().find(|(k, _)| k == key_str) {
*v = Value::Int(value);
0
} else {
entries.push((key_str.to_string(), Value::Int(value)));
0
}
}
_ => -3,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_SetFloatValue(
dict: *mut KoiCompositeDict,
key: *const c_char,
value: f64,
) -> i32 {
if dict.is_null() || key.is_null() {
return -1;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return -2,
};
let param = unsafe { &mut *(dict as *mut Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if let Some((_, v)) = entries.iter_mut().find(|(k, _)| k == key_str) {
*v = Value::Float(value);
0
} else {
entries.push((key_str.to_string(), Value::Float(value)));
0
}
}
_ => -3,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_SetStringValue(
dict: *mut KoiCompositeDict,
key: *const c_char,
value: *const c_char,
) -> i32 {
if dict.is_null() || key.is_null() || value.is_null() {
return -1;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return -2,
};
let value_str = unsafe { CStr::from_ptr(value) };
let value_str = match value_str.to_str() {
Ok(s) => s,
Err(_) => return -3,
};
let param = unsafe { &mut *(dict as *mut Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if let Some((_, v)) = entries.iter_mut().find(|(k, _)| k == key_str) {
*v = Value::String(value_str.to_string());
0
} else {
entries.push((key_str.to_string(), Value::String(value_str.to_string())));
0
}
}
_ => -4,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_GetKeybyIndex(
dict: *mut KoiCompositeDict,
index: usize,
buffer: *mut c_char,
buffer_size: usize,
) -> usize {
if dict.is_null() {
return 0;
}
let param = unsafe { &*(dict as *const Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if index >= entries.len() {
return 0;
}
let key = &entries[index].0;
let key_bytes = key.as_bytes();
let key_len = key_bytes.len();
let required_size = key_len + 1;
if buffer.is_null() || buffer_size < required_size {
return required_size;
}
let buffer_slice = unsafe { slice::from_raw_parts_mut(buffer as *mut u8, buffer_size) };
buffer_slice[..key_len].copy_from_slice(key_bytes);
buffer_slice[key_len] = 0;
required_size
}
_ => 0,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_GetKeyLenByIndex(
dict: *mut KoiCompositeDict,
index: usize,
) -> usize {
if dict.is_null() {
return 0;
}
let param = unsafe { &*(dict as *const Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if index >= entries.len() {
return 0;
}
let key = &entries[index].0;
key.len() + 1
}
_ => 0,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_GetValueTypeByIndex(
dict: *mut KoiCompositeDict,
index: usize,
) -> i32 {
if dict.is_null() {
return KoiParamType::Invalid as i32;
}
let param = unsafe { &*(dict as *const Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if index >= entries.len() {
KoiParamType::Invalid as i32
} else {
match &entries[index].1 {
Value::Int(_) => KoiParamType::BasicInt as i32,
Value::Float(_) => KoiParamType::BasicFloat as i32,
Value::String(_) => KoiParamType::BasicString as i32,
Value::Bool(_) => KoiParamType::BasicBool as i32,
}
}
}
_ => KoiParamType::Invalid as i32,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_GetValueType(
dict: *mut KoiCompositeDict,
key: *const c_char,
) -> i32 {
if dict.is_null() || key.is_null() {
return KoiParamType::Invalid as i32;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return KoiParamType::Invalid as i32,
};
let param = unsafe { &*(dict as *const Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if let Some((_, value)) = entries.iter().find(|(k, _)| k == key_str) {
match value {
Value::Int(_) => KoiParamType::BasicInt as i32,
Value::Float(_) => KoiParamType::BasicFloat as i32,
Value::String(_) => KoiParamType::BasicString as i32,
Value::Bool(_) => KoiParamType::BasicBool as i32,
}
} else {
KoiParamType::Invalid as i32
}
}
_ => KoiParamType::Invalid as i32,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_GetIntValue(
dict: *mut KoiCompositeDict,
key: *const c_char,
out_value: *mut i64,
) -> i32 {
if dict.is_null() || key.is_null() || out_value.is_null() {
return -1;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return -2,
};
let param = unsafe { &*(dict as *const Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if let Some((_, value)) = entries.iter().find(|(k, _)| k == key_str) {
match value {
Value::Int(v) => {
unsafe { *out_value = *v };
0
}
_ => -3,
}
} else {
-2 }
}
_ => -4,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_GetFloatValue(
dict: *mut KoiCompositeDict,
key: *const c_char,
out_value: *mut f64,
) -> i32 {
if dict.is_null() || key.is_null() || out_value.is_null() {
return -1;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return -2,
};
let param = unsafe { &*(dict as *const Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if let Some((_, value)) = entries.iter().find(|(k, _)| k == key_str) {
match value {
Value::Float(v) => {
unsafe { *out_value = *v };
0
}
_ => -3,
}
} else {
-2 }
}
_ => -4,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_GetStringValue(
dict: *mut KoiCompositeDict,
key: *const c_char,
buffer: *mut c_char,
buffer_size: usize,
) -> usize {
if dict.is_null() || key.is_null() {
return 0;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return 0,
};
let param = unsafe { &*(dict as *const Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if let Some((_, Value::String(v))) = entries.iter().find(|(k, _)| k == key_str) {
let v_bytes = v.as_bytes();
let v_len = v_bytes.len();
let required_size = v_len + 1;
if buffer.is_null() || buffer_size < required_size {
return required_size;
}
let buffer_slice =
unsafe { slice::from_raw_parts_mut(buffer as *mut u8, buffer_size) };
buffer_slice[..v_len].copy_from_slice(v_bytes);
buffer_slice[v_len] = 0;
required_size
} else {
0 }
}
_ => 0,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_GetStringValueLen(
dict: *mut KoiCompositeDict,
key: *const c_char,
) -> usize {
if dict.is_null() || key.is_null() {
return 0;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return 0,
};
let param = unsafe { &*(dict as *const Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if let Some((_, Value::String(v))) = entries.iter().find(|(k, _)| k == key_str) {
v.len() + 1
} else {
0 }
}
_ => 0,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_GetBoolValue(
dict: *mut KoiCompositeDict,
key: *const c_char,
out_value: *mut i32,
) -> i32 {
if dict.is_null() || key.is_null() || out_value.is_null() {
return -1;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return -2,
};
let param = unsafe { &*(dict as *const Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if let Some((_, value)) = entries.iter().find(|(k, _)| k == key_str) {
match value {
Value::Bool(v) => {
unsafe { *out_value = if *v { 1 } else { 0 } };
0
}
_ => -3,
}
} else {
-2 }
}
_ => -4,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn KoiCompositeDict_SetBoolValue(
dict: *mut KoiCompositeDict,
key: *const c_char,
value: i32,
) -> i32 {
if dict.is_null() || key.is_null() {
return -1;
}
let key_str = unsafe { CStr::from_ptr(key) };
let key_str = match key_str.to_str() {
Ok(s) => s,
Err(_) => return -2,
};
let param = unsafe { &mut *(dict as *mut Parameter) };
match param {
Parameter::Composite(_, CompositeValue::Dict(entries)) => {
if let Some((_, v)) = entries.iter_mut().find(|(k, _)| k == key_str) {
*v = Value::Bool(value != 0);
0
} else {
entries.push((key_str.to_string(), Value::Bool(value != 0)));
0
}
}
_ => -3,
}
}