use crate::type_id::HasStaticTypeId;
use std::{
ffi::{c_void, CStr},
os::raw::c_char,
slice, str,
};
use crate::type_id::TypeId;
#[repr(C)]
#[derive(Clone)]
pub struct FunctionDefinition<'a> {
pub prototype: FunctionPrototype<'a>,
pub fn_ptr: *const c_void,
}
#[repr(C)]
#[derive(Clone)]
pub struct FunctionPrototype<'a> {
pub name: *const c_char,
pub signature: FunctionSignature<'a>,
}
#[repr(C)]
#[derive(Clone)]
pub struct FunctionSignature<'a> {
pub arg_types: *const TypeId<'a>,
pub return_type: TypeId<'a>,
pub num_arg_types: u16,
}
unsafe impl<'a> Send for FunctionDefinition<'a> {}
unsafe impl<'a> Sync for FunctionDefinition<'a> {}
impl<'a> FunctionPrototype<'a> {
pub fn name(&self) -> &str {
unsafe { str::from_utf8_unchecked(CStr::from_ptr(self.name).to_bytes()) }
}
}
unsafe impl<'a> Send for FunctionPrototype<'a> {}
unsafe impl<'a> Sync for FunctionPrototype<'a> {}
impl<'a> FunctionSignature<'a> {
pub fn arg_types(&self) -> &[TypeId<'a>] {
if self.num_arg_types == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(self.arg_types, self.num_arg_types as usize) }
}
}
pub fn return_type(&self) -> Option<TypeId<'a>> {
if <()>::type_id() == &self.return_type {
None
} else {
Some(self.return_type.clone())
}
}
}
impl<'a> PartialEq for FunctionSignature<'a> {
fn eq(&self, other: &Self) -> bool {
self.return_type() == other.return_type() && self.arg_types().eq(other.arg_types())
}
}
impl<'a> Eq for FunctionSignature<'a> {}
unsafe impl<'a> Send for FunctionSignature<'a> {}
unsafe impl<'a> Sync for FunctionSignature<'a> {}
#[cfg(feature = "serde")]
impl<'a> serde::Serialize for FunctionDefinition<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStruct;
let mut s = serializer.serialize_struct("FunctionDefinition", 1)?;
s.serialize_field("prototype", &self.prototype)?;
s.skip_field("fn_ptr")?;
s.end()
}
}
#[cfg(feature = "serde")]
impl<'a> serde::Serialize for FunctionPrototype<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStruct;
let mut s = serializer.serialize_struct("FunctionPrototype", 2)?;
s.serialize_field("name", self.name())?;
s.serialize_field("signature", &self.signature)?;
s.end()
}
}
#[cfg(feature = "serde")]
impl<'a> serde::Serialize for FunctionSignature<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStruct;
let mut s = serializer.serialize_struct("FunctionSignature", 2)?;
s.serialize_field("arg_types", self.arg_types())?;
s.serialize_field("return_type", &self.return_type())?;
s.end()
}
}
#[cfg(test)]
mod tests {
use std::ffi::CString;
use crate::test_utils::{fake_fn_prototype, fake_fn_signature, FAKE_FN_NAME};
use crate::type_id::HasStaticTypeId;
#[test]
fn test_fn_prototype_name() {
let fn_name = CString::new(FAKE_FN_NAME).expect("Invalid fake fn name.");
let fn_signature = fake_fn_prototype(&fn_name, &[], None);
assert_eq!(fn_signature.name(), FAKE_FN_NAME);
}
#[test]
fn test_fn_signature_arg_types_none() {
let arg_types = &[];
let fn_signature = fake_fn_signature(arg_types, None);
assert_eq!(fn_signature.arg_types(), arg_types);
}
#[test]
fn test_fn_signature_arg_types_some() {
let type_id = i32::type_id();
let arg_types = &[type_id.clone()];
let fn_signature = fake_fn_signature(arg_types, None);
assert_eq!(fn_signature.arg_types(), arg_types);
}
#[test]
fn test_fn_signature_return_type_none() {
let return_type = None;
let fn_signature = fake_fn_signature(&[], return_type.clone());
assert_eq!(fn_signature.return_type(), return_type);
}
#[test]
fn test_fn_signature_return_type_some() {
let type_id = i32::type_id();
let return_type = Some(type_id.clone());
let fn_signature = fake_fn_signature(&[], return_type.clone());
assert_eq!(fn_signature.return_type(), return_type);
}
}