use crate::{
string::StringPtr,
time::{HmsNano, OrdinalDate, OrdinalDateHmsNano, OrdinalDateHmsNanoOffset},
vec::VecPtr
};
use paste::paste;
use sea_orm::Value;
use std::mem::ManuallyDrop;
#[cfg(feature = "with-uuid")]
use uuid::Uuid;
#[cfg(not(feature = "with-uuid"))]
type Uuid = [u8; 16];
#[repr(C)]
pub(crate) struct FfiValue {
inner: FfiValueInner,
ty: FfiValueTy,
option: FfiValueOption
}
#[derive(Clone, Copy, Debug)]
#[repr(u8)]
enum FfiValueOption {
None,
Some
}
macro_rules! impl_ffi_value {
($(
$(#[un $unbox:tt box])?
$(#[drop $manually_drop:tt manually])?
$(#[cfg($($cfg:tt)*)])?
$variant:ident($ty:ty)
),*) => {
#[derive(Clone, Copy, Debug)]
#[repr(u8)]
enum FfiValueTy {
$(
$(#[cfg_attr(not($($cfg)*), allow(dead_code))])?
$variant
),*
}
paste! {
#[repr(C)]
union FfiValueInner {
none: (),
$(
$(#[cfg_attr(not($($cfg)*), allow(dead_code))])?
[< $variant:snake >]: $ty
),*
}
}
impl Drop for FfiValue {
fn drop(&mut self) {
if matches!(self.option, FfiValueOption::None) {
return;
}
match self.ty { $(
$(#[cfg($($cfg)*)])?
FfiValueTy::$variant => {
$(unsafe {
_ = stringify!($manually_drop);
ManuallyDrop::drop(paste! {
&mut self.inner.[< $variant:snake >]
});
})?
},
$(#[cfg(not($($cfg)*))]
FfiValueTy::$variant => {
panic!(
"Value::{} is only supported with cfg({})",
stringify!($variant),
stringify!($($cfg)*)
);
})?
)* }
}
}
impl From<Value> for FfiValue {
fn from(value: Value) -> Self {
paste! {
match value {
$($(#[cfg($($cfg)*)])? Value::$variant(None) => Self {
inner: FfiValueInner { none: () },
ty: FfiValueTy::$variant,
option: FfiValueOption::None
},)*
$($(#[cfg($($cfg)*)])? Value::$variant(Some(value)) => {
$(
_ = stringify!($unbox);
let value = *value;
)?
let value = value.into();
$(
_ = stringify!($manually_drop);
let value = ManuallyDrop::new(value);
)?
Self {
inner: FfiValueInner { [< $variant:snake >]: value },
ty: FfiValueTy::$variant,
option: FfiValueOption::Some
}
},)*
#[allow(unreachable_patterns)]
_ => panic!(concat!(
"sea-orm's Value enum gains variants with enabled features. ",
"Some of those are supported if sea-orm-ffi is compiled ",
"with the corresponding feature flag. ",
"Otherwise, you found one that isn't implemented by sea-orm-ffi."
))
}
}
}
}
impl From<FfiValue> for Value {
fn from(value: FfiValue) -> Self {
let mut value = ManuallyDrop::new(value);
paste! {
match (value.ty, value.option) {
$($(#[cfg($($cfg)*)])? (FfiValueTy::$variant, FfiValueOption::None) => {
Self::$variant(None)
},)*
$($(#[cfg($($cfg)*)])? (FfiValueTy::$variant, FfiValueOption::Some) => {
let value = unsafe { &mut value.inner.[< $variant:snake >] };
$(
_ = stringify!($manually_drop);
let manually_drop = value;
let value = &();
#[allow(unused_variables)]
)?
let value = *value;
$(
_ = stringify!($manually_drop);
let value = unsafe { ManuallyDrop::take(manually_drop) };
)?
let value = value.into();
$(
_ = stringify!($unbox);
let value = Box::new(value);
)?
Self::$variant(Some(value))
},)*
$($(#[cfg(not($($cfg)*))] (FfiValueTy::$variant, _) => panic!(
"Value::{} is only supported with cfg({})",
stringify!($variant),
stringify!($($cfg)*)
),)?)*
}
}
}
}
};
}
impl_ffi_value! {
Bool(bool),
TinyInt(i8),
SmallInt(i16),
Int(i32),
BigInt(i64),
TinyUnsigned(u8),
SmallUnsigned(u16),
Unsigned(u32),
BigUnsigned(u64),
Float(f32),
Double(f64),
#[un-box]
#[drop-manually]
String(ManuallyDrop<StringPtr>),
Char(char),
#[un-box]
#[drop-manually]
Bytes(ManuallyDrop<VecPtr<u8>>),
#[un-box]
#[cfg(feature = "with-time")]
TimeDate(OrdinalDate),
#[un-box]
#[cfg(feature = "with-time")]
TimeTime(HmsNano),
#[un-box]
#[cfg(feature = "with-time")]
TimeDateTime(OrdinalDateHmsNano),
#[un-box]
#[cfg(feature = "with-time")]
TimeDateTimeWithTimeZone(OrdinalDateHmsNanoOffset),
#[un-box]
#[cfg(feature = "with-uuid")]
Uuid(Uuid)
}