use std::ffi::c_char;
use std::ffi::c_void;
use crate::{
bindings::{WXRSceneError, clear_error, set_error, str_from_ptr},
scene::{
assets,
component::{self, FieldType},
},
};
pub type WXRGetter = unsafe extern "C" fn(*mut c_void) -> *mut c_void;
pub type WXRSerializer = unsafe extern "C" fn(*const c_void) -> component::SerializedBytes;
pub type WXRDeserializer = unsafe extern "C" fn(*mut c_void, component::SerializedBytes);
pub struct WXRComponentSchema {
_private: [u8; 0],
}
pub struct WXRAssetSchema {
_private: [u8; 0],
}
fn component_schema_mut<'a>(
schema: *mut WXRComponentSchema,
) -> Result<&'a mut component::Schema, WXRSceneError> {
if schema.is_null() {
return Err(WXRSceneError::NullPointer);
}
Ok(unsafe { &mut *(schema as *mut component::Schema) })
}
fn asset_schema_mut<'a>(
schema: *mut WXRAssetSchema,
) -> Result<&'a mut assets::Schema, WXRSceneError> {
if schema.is_null() {
return Err(WXRSceneError::NullPointer);
}
Ok(unsafe { &mut *(schema as *mut assets::Schema) })
}
#[unsafe(no_mangle)]
pub extern "C" fn wxr_component_schema_new() -> *mut WXRComponentSchema {
clear_error();
Box::into_raw(Box::new(component::Schema::default())).cast()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wxr_component_schema_free(schema: *mut WXRComponentSchema) {
if !schema.is_null() {
unsafe {
drop(Box::from_raw(schema as *mut component::Schema));
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wxr_component_schema_add_field(
schema: *mut WXRComponentSchema,
id: *const c_char,
type_hint: FieldType,
getter: WXRGetter,
mutable: i32,
) -> i32 {
match (component_schema_mut(schema), unsafe { str_from_ptr(id) }) {
(Ok(schema), Ok(id)) => {
schema.add_field(
id.to_owned(),
type_hint,
Some(getter),
mutable != 0,
None,
None,
);
clear_error();
0
}
(Err(error), _) | (_, Err(error)) => {
set_error(error);
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wxr_component_schema_add_serialized_field(
schema: *mut WXRComponentSchema,
id: *const c_char,
type_hint: FieldType,
getter: WXRGetter,
mutable: i32,
serializer: WXRSerializer,
deserializer: WXRDeserializer,
) -> i32 {
match (component_schema_mut(schema), unsafe { str_from_ptr(id) }) {
(Ok(schema), Ok(id)) => {
schema.add_field(
id.to_owned(),
type_hint,
Some(getter),
mutable != 0,
Some(serializer),
Some(deserializer),
);
clear_error();
0
}
(Err(error), _) | (_, Err(error)) => {
set_error(error);
-1
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn wxr_asset_schema_new() -> *mut WXRAssetSchema {
clear_error();
Box::into_raw(Box::new(assets::Schema::default())).cast()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wxr_asset_schema_free(schema: *mut WXRAssetSchema) {
if !schema.is_null() {
unsafe {
drop(Box::from_raw(schema as *mut assets::Schema));
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wxr_asset_schema_add_field(
schema: *mut WXRAssetSchema,
id: *const c_char,
type_hint: FieldType,
getter: WXRGetter,
) -> i32 {
match (asset_schema_mut(schema), unsafe { str_from_ptr(id) }) {
(Ok(schema), Ok(id)) => {
schema.add_field(id.to_owned(), type_hint, Some(getter));
clear_error();
0
}
(Err(error), _) | (_, Err(error)) => {
set_error(error);
-1
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{
ffi::{CString, c_void},
ptr,
};
unsafe extern "C" fn getter(_data: *mut c_void) -> *mut c_void {
ptr::null_mut()
}
#[test]
fn component_schema_add_field_accepts_c_values() {
let schema = wxr_component_schema_new();
let field = CString::new("value").unwrap();
assert_eq!(
unsafe {
wxr_component_schema_add_field(
schema,
field.as_ptr(),
component::FieldType::I64,
getter,
1,
)
},
0
);
unsafe {
wxr_component_schema_free(schema);
}
}
#[test]
fn asset_schema_add_field_accepts_c_values() {
let schema = wxr_asset_schema_new();
let field = CString::new("value").unwrap();
assert_eq!(
unsafe {
wxr_asset_schema_add_field(
schema,
field.as_ptr(),
component::FieldType::I64,
getter,
)
},
0
);
unsafe {
wxr_asset_schema_free(schema);
}
}
}