hakuban 0.7.2

Data-object sharing library
Documentation
#![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)
}