use crate::NullableDatum;
use std::ptr::NonNull;
#[repr(C)]
struct DatumBlob {
_data: [u8; 0],
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Datum(*mut DatumBlob);
impl Datum {
#[inline]
pub fn value(self) -> usize {
self.0.addr()
}
#[inline]
pub const fn null() -> Datum {
Datum(core::ptr::null_mut())
}
#[inline]
pub fn is_null(self) -> bool {
self.0.is_null()
}
#[inline]
pub fn cast_mut_ptr<T>(self) -> *mut T {
self.0.cast()
}
}
impl From<usize> for Datum {
#[inline]
fn from(val: usize) -> Datum {
Datum(NonNull::<DatumBlob>::dangling().as_ptr().with_addr(val))
}
}
impl From<Datum> for usize {
#[inline]
fn from(val: Datum) -> usize {
val.0.addr()
}
}
impl From<isize> for Datum {
#[inline]
fn from(val: isize) -> Datum {
Datum::from(val as usize)
}
}
impl From<u8> for Datum {
#[inline]
fn from(val: u8) -> Datum {
Datum::from(usize::from(val))
}
}
impl From<u16> for Datum {
#[inline]
fn from(val: u16) -> Datum {
Datum::from(usize::from(val))
}
}
impl From<u32> for Datum {
#[inline]
fn from(val: u32) -> Datum {
Datum::from(val as usize)
}
}
impl From<u64> for Datum {
#[inline]
fn from(val: u64) -> Datum {
if cfg!(target_pointer_width = "64") {
Datum::from(val as usize)
} else {
unsafe {
let ptr = crate::palloc(size_of::<u64>()) as *mut u64;
*ptr = val;
Datum::from(ptr)
}
}
}
}
impl From<i8> for Datum {
#[inline]
fn from(val: i8) -> Datum {
Datum::from(isize::from(val))
}
}
impl From<i16> for Datum {
#[inline]
fn from(val: i16) -> Datum {
Datum::from(isize::from(val))
}
}
impl From<i32> for Datum {
#[inline]
fn from(val: i32) -> Datum {
Datum::from(val as usize)
}
}
impl From<i64> for Datum {
#[inline]
fn from(val: i64) -> Datum {
if cfg!(target_pointer_width = "64") {
Datum::from(val as usize)
} else {
unsafe {
let ptr = crate::palloc(size_of::<i64>()) as *mut i64;
*ptr = val;
Datum::from(ptr)
}
}
}
}
impl From<bool> for Datum {
#[inline]
fn from(val: bool) -> Datum {
Datum::from(val as usize)
}
}
impl<T> From<*mut T> for Datum {
#[inline]
fn from(val: *mut T) -> Datum {
Datum(val.cast())
}
}
impl<T> From<*const T> for Datum {
#[inline]
fn from(val: *const T) -> Datum {
Datum(val as *mut _)
}
}
impl<T> PartialEq<*mut T> for Datum {
#[inline]
fn eq(&self, other: &*mut T) -> bool {
&self.0.cast() == other
}
}
impl<T> PartialEq<Datum> for *mut T {
#[inline]
fn eq(&self, other: &Datum) -> bool {
self == &other.0.cast()
}
}
impl TryFrom<NullableDatum> for Datum {
type Error = ();
#[inline]
fn try_from(nd: NullableDatum) -> Result<Datum, ()> {
let NullableDatum { value, isnull } = nd;
if isnull { Err(()) } else { Ok(value) }
}
}
impl From<NullableDatum> for Option<Datum> {
#[inline]
fn from(nd: NullableDatum) -> Option<Datum> {
Datum::try_from(nd).ok()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn roundtrip_integers() {
let val = i64::MAX;
let datum = Datum::from(val);
assert_eq!(datum.value() as i64, val);
let val = isize::MAX;
let datum = Datum::from(val);
assert_eq!(datum.value() as isize, val);
let val = i64::MIN;
let datum = Datum::from(val);
assert_eq!(datum.value() as i64, val);
let val = isize::MIN;
let datum = Datum::from(val);
assert_eq!(datum.value() as isize, val);
let val = u64::MAX;
let datum = Datum::from(val);
assert_eq!(datum.value() as u64, val);
let val = usize::MAX;
let datum = Datum::from(val);
assert_eq!(datum.value(), val);
}
}