use crate::Color;
use std::mem::{MaybeUninit, transmute_copy};
use std::os::raw::{c_char, c_void};
pub(crate) type GDExtensionInterfaceFunctionPtr = Option<unsafe extern "C" fn()>;
pub(crate) type GDExtensionInterfaceGetProcAddress =
Option<unsafe extern "C" fn(*const c_char) -> GDExtensionInterfaceFunctionPtr>;
pub(crate) type GDExtensionClassLibraryPtr = *mut c_void;
pub(crate) type GDExtensionMethodBindPtr = *const c_void;
pub(crate) type GDExtensionConstStringNamePtr = *const c_void;
pub(crate) type GDExtensionUninitializedStringNamePtr = *mut c_void;
pub(crate) type GDExtensionConstTypePtr = *const c_void;
pub(crate) type GDExtensionTypePtr = *mut c_void;
pub(crate) type GDExtensionObjectPtr = *mut c_void;
pub(crate) type GDExtensionPtrDestructor = unsafe extern "C" fn(GDExtensionTypePtr);
pub(crate) type GDExtensionInterfaceStringNewWithUtf8Chars =
unsafe extern "C" fn(GDExtensionTypePtr, *const c_char);
pub(crate) type GDExtensionInterfaceStringToUtf8Chars =
unsafe extern "C" fn(GDExtensionConstTypePtr, *mut c_char, i64) -> i64;
pub(crate) type GDExtensionInterfaceStringNameNewWithUtf8Chars =
unsafe extern "C" fn(GDExtensionUninitializedStringNamePtr, *const c_char);
pub(crate) type GDExtensionInterfaceClassdbGetMethodBind =
unsafe extern "C" fn(
GDExtensionConstStringNamePtr,
GDExtensionConstStringNamePtr,
i64,
) -> GDExtensionMethodBindPtr;
pub(crate) type GDExtensionInterfaceObjectMethodBindPtrcall = unsafe extern "C" fn(
GDExtensionMethodBindPtr,
GDExtensionObjectPtr,
*const GDExtensionConstTypePtr,
GDExtensionTypePtr,
);
pub(crate) type GDExtensionInterfaceClassdbConstructObject =
unsafe extern "C" fn(GDExtensionConstStringNamePtr) -> GDExtensionObjectPtr;
pub(crate) type GDExtensionInterfaceGlobalGetSingleton =
unsafe extern "C" fn(GDExtensionConstStringNamePtr) -> GDExtensionObjectPtr;
pub(crate) type GDExtensionInterfaceVariantGetPtrDestructor =
unsafe extern "C" fn(i32) -> Option<GDExtensionPtrDestructor>;
pub(crate) type GDExtensionInterfaceVariantNewNil = unsafe extern "C" fn(GDExtensionTypePtr);
pub(crate) type GDExtensionInterfaceVariantDestroy = unsafe extern "C" fn(GDExtensionTypePtr);
pub(crate) type GDExtensionVariantFromTypeConstructorFunc =
unsafe extern "C" fn(GDExtensionTypePtr, GDExtensionTypePtr);
pub(crate) type GDExtensionInterfaceGetVariantFromTypeConstructor =
unsafe extern "C" fn(i32) -> Option<GDExtensionVariantFromTypeConstructorFunc>;
pub(crate) type GDExtensionInterfaceObjectMethodBindCall = unsafe extern "C" fn(
GDExtensionMethodBindPtr,
GDExtensionObjectPtr,
*const GDExtensionConstTypePtr,
i64,
GDExtensionTypePtr,
*mut GDExtensionCallError,
);
pub(crate) struct GDExtensionCallError {
pub(crate) error: i32,
pub(crate) _argument: i32,
pub(crate) _expected: i32,
}
#[derive(Clone, Copy)]
pub(crate) struct GodotObject(pub(crate) GDExtensionObjectPtr);
pub(crate) struct StringNameStorage {
storage: MaybeUninit<[usize; 1]>,
destructor: GDExtensionPtrDestructor,
}
impl StringNameStorage {
pub(crate) fn new(destructor: GDExtensionPtrDestructor) -> Self {
Self {
storage: MaybeUninit::uninit(),
destructor,
}
}
pub(crate) fn as_ptr(&self) -> GDExtensionConstStringNamePtr {
self.storage.as_ptr() as GDExtensionConstStringNamePtr
}
pub(crate) fn as_mut_ptr(&mut self) -> GDExtensionUninitializedStringNamePtr {
self.storage.as_mut_ptr() as GDExtensionUninitializedStringNamePtr
}
}
impl Drop for StringNameStorage {
fn drop(&mut self) {
unsafe {
(self.destructor)(self.storage.as_mut_ptr() as GDExtensionTypePtr);
}
}
}
#[repr(C)]
pub(crate) struct GodotString {
storage: MaybeUninit<[usize; 1]>,
destructor: GDExtensionPtrDestructor,
}
impl GodotString {
pub(crate) fn new(destructor: GDExtensionPtrDestructor) -> Self {
Self {
storage: MaybeUninit::uninit(),
destructor,
}
}
pub(crate) fn as_ptr(&self) -> GDExtensionConstTypePtr {
self.storage.as_ptr() as GDExtensionConstTypePtr
}
pub(crate) fn as_mut_ptr(&mut self) -> GDExtensionTypePtr {
self.storage.as_mut_ptr() as GDExtensionTypePtr
}
}
impl Drop for GodotString {
fn drop(&mut self) {
unsafe {
(self.destructor)(self.storage.as_mut_ptr() as GDExtensionTypePtr);
}
}
}
#[repr(C)]
pub(crate) struct GodotVariant {
storage: MaybeUninit<[usize; 3]>,
destructor: GDExtensionInterfaceVariantDestroy,
}
impl GodotVariant {
pub(crate) fn nil(
newNil: GDExtensionInterfaceVariantNewNil,
destructor: GDExtensionInterfaceVariantDestroy,
) -> Self {
let mut value = Self {
storage: MaybeUninit::uninit(),
destructor,
};
unsafe {
newNil(value.as_mut_ptr());
}
value
}
pub(crate) fn fromType(
newNil: GDExtensionInterfaceVariantNewNil,
destructor: GDExtensionInterfaceVariantDestroy,
constructor: GDExtensionVariantFromTypeConstructorFunc,
value: GDExtensionTypePtr,
) -> Self {
let mut variant = Self::nil(newNil, destructor);
unsafe {
constructor(variant.as_mut_ptr(), value);
}
variant
}
pub(crate) fn as_ptr(&self) -> GDExtensionConstTypePtr {
self.storage.as_ptr() as GDExtensionConstTypePtr
}
pub(crate) fn as_mut_ptr(&mut self) -> GDExtensionTypePtr {
self.storage.as_mut_ptr() as GDExtensionTypePtr
}
}
impl Drop for GodotVariant {
fn drop(&mut self) {
unsafe {
(self.destructor)(self.as_mut_ptr());
}
}
}
#[repr(C)]
pub(crate) struct GodotVector2 {
pub(crate) x: f32,
pub(crate) y: f32,
}
#[repr(C)]
pub(crate) struct GodotColor {
pub(crate) red: f32,
pub(crate) green: f32,
pub(crate) blue: f32,
pub(crate) alpha: f32,
}
impl From<&Color> for GodotColor {
fn from(color: &Color) -> Self {
Self {
red: color.red,
green: color.green,
blue: color.blue,
alpha: color.alpha,
}
}
}
pub(crate) unsafe fn loadProc<T: Copy>(
getProcAddress: GDExtensionInterfaceGetProcAddress,
name: &[u8],
) -> Option<T> {
let getProcAddress = getProcAddress?;
let function = unsafe { getProcAddress(name.as_ptr() as *const c_char) }?;
Some(unsafe { transmute_copy(&function) })
}
pub(crate) fn boolArg(value: bool) -> u8 {
if value { 1 } else { 0 }
}