#![allow(clippy::not_unsafe_ptr_arg_deref)]
use std::ffi::{c_void, CString};
use super::{ffi_result::FFIResultStatus, FFIBorrowedArray, FFIResult};
use crate::{ObjectDescriptor, TagDescriptor};
#[derive(Clone)]
pub struct FFITagDescriptor {
pub(super) descriptor: TagDescriptor,
json_cstring: Option<CString>,
}
impl From<&TagDescriptor> for FFITagDescriptor {
fn from(tag_descriptor: &TagDescriptor) -> Self {
FFITagDescriptor { descriptor: tag_descriptor.clone(), json_cstring: None }
}
}
#[no_mangle]
pub extern "C" fn hakuban_tag_descriptor_new(json: *const i8) -> FFIResult<*mut FFITagDescriptor> {
let json = match c_string_to_json_value(json) {
Ok(json) => json,
Err(error) => return FFIResult::error(error),
};
FFIResult::ok(Box::into_raw(Box::new(FFITagDescriptor { descriptor: TagDescriptor::new(json), json_cstring: None })))
}
#[no_mangle]
pub extern "C" fn hakuban_tag_descriptor_drop(descriptor_pointer: *mut FFITagDescriptor) {
drop(unsafe { Box::from_raw(descriptor_pointer) });
}
#[no_mangle]
pub extern "C" fn hakuban_tag_descriptor_clone(descriptor_pointer: *mut FFITagDescriptor) -> *mut FFITagDescriptor {
let descriptor: &mut FFITagDescriptor = unsafe { descriptor_pointer.as_mut().unwrap() };
Box::into_raw(Box::new(descriptor.clone()))
}
#[no_mangle]
pub extern "C" fn hakuban_tag_descriptor_json(descriptor_pointer: *mut FFITagDescriptor) -> *const i8 {
let descriptor: &mut FFITagDescriptor = unsafe { descriptor_pointer.as_mut().unwrap() };
let json_cstring = descriptor.json_cstring.get_or_insert_with(|| CString::new(descriptor.descriptor.json.to_string()).unwrap());
json_cstring.as_ptr()
}
pub struct FFIObjectDescriptor {
pub(super) descriptor: ObjectDescriptor,
tags: Option<(Vec<FFITagDescriptor>, Vec<*mut FFITagDescriptor>)>,
json_cstring: Option<CString>,
}
impl Clone for FFIObjectDescriptor {
fn clone(&self) -> Self {
Self { descriptor: self.descriptor.clone(), tags: None, json_cstring: self.json_cstring.clone() }
}
}
impl From<&ObjectDescriptor> for FFIObjectDescriptor {
fn from(object_descriptor: &ObjectDescriptor) -> Self {
FFIObjectDescriptor { descriptor: object_descriptor.clone(), tags: None, json_cstring: None }
}
}
#[no_mangle]
pub extern "C" fn hakuban_object_descriptor_new(
json: *const i8, tag_descriptors_length: usize, tag_descriptors: *const *mut FFITagDescriptor,
) -> FFIResult<*mut FFIObjectDescriptor> {
let json = match c_string_to_json_value(json) {
Ok(json) => json,
Err(error) => return FFIResult::error(error),
};
let tags_c_slice: &[*mut FFITagDescriptor] = unsafe { std::slice::from_raw_parts(tag_descriptors, tag_descriptors_length) };
let tags: Vec<TagDescriptor> =
tags_c_slice.iter().map(|ffi_tag_descriptor_pointer| unsafe { ffi_tag_descriptor_pointer.as_mut().unwrap() }.descriptor.clone()).collect();
FFIResult::ok(Box::into_raw(Box::new(FFIObjectDescriptor { descriptor: ObjectDescriptor::new(tags, json), tags: None, json_cstring: None })))
}
#[no_mangle]
pub extern "C" fn hakuban_object_descriptor_drop(descriptor_pointer: *mut FFIObjectDescriptor) {
drop(unsafe { Box::from_raw(descriptor_pointer) });
}
#[no_mangle]
pub extern "C" fn hakuban_object_descriptor_clone(descriptor_pointer: *mut FFIObjectDescriptor) -> *mut FFIObjectDescriptor {
let descriptor: &mut FFIObjectDescriptor = unsafe { descriptor_pointer.as_mut().unwrap() };
Box::into_raw(Box::new(descriptor.clone()))
}
#[no_mangle]
pub extern "C" fn hakuban_object_descriptor_json(descriptor_pointer: *mut FFIObjectDescriptor) -> *const i8 {
let descriptor: &mut FFIObjectDescriptor = unsafe { descriptor_pointer.as_mut().unwrap() };
let json_cstring = descriptor.json_cstring.get_or_insert_with(|| CString::new(descriptor.descriptor.json.to_string()).unwrap());
json_cstring.as_ptr()
}
#[no_mangle]
pub extern "C" fn hakuban_object_descriptor_tags(descriptor_pointer: *mut FFIObjectDescriptor) -> FFIBorrowedArray {
let descriptor: &mut FFIObjectDescriptor = unsafe { descriptor_pointer.as_mut().unwrap() };
let tags_pointers = &descriptor
.tags
.get_or_insert_with(|| {
let mut tags: Vec<FFITagDescriptor> = descriptor.descriptor.tags.iter().map(|tag| tag.into()).collect();
let pointers: Vec<*mut FFITagDescriptor> = tags.iter_mut().map(|tag: &mut FFITagDescriptor| tag as *mut FFITagDescriptor).collect();
(tags, pointers)
})
.1;
FFIBorrowedArray { length: tags_pointers.len(), pointer: tags_pointers.as_ptr() as *mut c_void }
}
fn c_string_to_json_value(json_c: *const i8) -> Result<serde_json::Value, FFIResultStatus> {
let json_str: &str = unsafe { std::ffi::CStr::from_ptr(json_c).to_str() }.map_err(|_error| FFIResultStatus::InvalidString)?;
let json: serde_json::Value = serde_json::from_str(json_str).map_err(|_error| FFIResultStatus::InvalidJSON)?;
Ok(json)
}