#![deny(unsafe_op_in_unsafe_fn)]
use super::*;
use crate::array::Element;
use crate::callconv::DatumPass;
use crate::layout::PassBy;
use core::{ffi, mem, ptr};
pub unsafe trait BorrowDatum {
const PASS: PassBy;
unsafe fn point_from(ptr: ptr::NonNull<u8>) -> ptr::NonNull<Self>;
unsafe fn point_from_align4(ptr: ptr::NonNull<u32>) -> ptr::NonNull<Self> {
debug_assert!(ptr.is_aligned());
unsafe { BorrowDatum::point_from(ptr.cast()) }
}
unsafe fn borrow_unchecked<'dat>(ptr: ptr::NonNull<u8>) -> &'dat Self {
unsafe { BorrowDatum::point_from(ptr).as_ref() }
}
}
pub(crate) unsafe fn datum_ptr_to_bytes<T>(ptr: ptr::NonNull<Datum<'_>>) -> Option<ptr::NonNull<u8>>
where
T: BorrowDatum,
{
match T::PASS {
PassBy::Value => Some(ptr.cast()),
PassBy::Ref => unsafe {
let datum = ptr.read();
ptr::NonNull::new(datum.sans_lifetime().cast_mut_ptr())
},
}
}
macro_rules! impl_borrow_fixed_len {
($($value_ty:ty),*) => {
$(
unsafe impl DatumPass for $value_ty {
const PASS: PassBy = if mem::size_of::<Self>() <= mem::size_of::<Datum>() {
PassBy::Value
} else {
PassBy::Ref
};
}
unsafe impl Element for $value_ty {
unsafe fn point_from(ptr: ptr::NonNull<u8>) -> ptr::NonNull<Self> {
#[cfg(target_endian = "big")]
unsafe {
if mem::size_of::<Self>() <= mem::size_of::<Datum>() {
ptr.add(mem::size_of::<Datum>() - mem::size_of::<Self>()).cast()
} else {
ptr.cast()
}
}
#[cfg(target_endian = "little")]
{
ptr.cast()
}
}
}
)*
}
}
impl_borrow_fixed_len! {
i8, i16, i32, i64, bool, f32, f64,
pg_sys::Oid, pg_sys::Point,
Date, Time, TimeWithTimeZone, Timestamp, TimestampWithTimeZone
}
unsafe impl DatumPass for ffi::CStr {
const PASS: PassBy = PassBy::Ref;
}
unsafe impl Element for ffi::CStr {
unsafe fn point_from(ptr: ptr::NonNull<u8>) -> ptr::NonNull<Self> {
let char_ptr: *mut ffi::c_char = ptr.as_ptr().cast();
unsafe {
let len = ffi::CStr::from_ptr(char_ptr).to_bytes_with_nul().len();
ptr::NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(char_ptr, len) as *mut Self)
}
}
unsafe fn borrow_unchecked<'dat>(ptr: ptr::NonNull<u8>) -> &'dat Self {
let char_ptr: *const ffi::c_char = ptr.as_ptr().cast();
unsafe { ffi::CStr::from_ptr(char_ptr) }
}
}