use crate::datum::{Array, FromDatum};
use crate::pg_sys;
use bitvec::prelude::*;
use bitvec::ptr::{bitslice_from_raw_parts_mut, BitPtr, BitPtrError, Mut};
use core::ptr::{slice_from_raw_parts_mut, NonNull};
use core::slice;
#[allow(non_snake_case)]
#[inline(always)]
const fn TYPEALIGN(alignval: usize, len: usize) -> usize {
(len + (alignval - 1)) & !(alignval - 1)
}
#[allow(non_snake_case)]
#[inline(always)]
const fn MAXALIGN(len: usize) -> usize {
TYPEALIGN(pg_sys::MAXIMUM_ALIGNOF as _, len)
}
#[allow(non_snake_case)]
#[inline(always)]
unsafe fn ARR_NDIM(a: *mut pg_sys::ArrayType) -> usize {
unsafe {
(*a).ndim as usize
}
}
#[allow(non_snake_case)]
#[inline(always)]
unsafe fn ARR_HASNULL(a: *mut pg_sys::ArrayType) -> bool {
unsafe {
(*a).dataoffset != 0
}
}
#[allow(non_snake_case)]
#[inline(always)]
const unsafe fn ARR_DIMS(a: *mut pg_sys::ArrayType) -> *mut i32 {
unsafe {
a.cast::<u8>().add(std::mem::size_of::<pg_sys::ArrayType>()).cast::<i32>()
}
}
#[allow(non_snake_case)]
#[inline(always)]
unsafe fn ARR_NELEMS(a: *mut pg_sys::ArrayType) -> usize {
unsafe {
pg_sys::ArrayGetNItems((*a).ndim, ARR_DIMS(a)) as usize
}
}
#[allow(non_snake_case)]
#[inline(always)]
unsafe fn ARR_NULLBITMAP(a: *mut pg_sys::ArrayType) -> *mut pg_sys::bits8 {
unsafe {
if ARR_HASNULL(a) {
a.cast::<u8>().add(
std::mem::size_of::<pg_sys::ArrayType>()
+ 2 * std::mem::size_of::<i32>() * ARR_NDIM(a),
)
} else {
std::ptr::null_mut()
}
}
}
#[allow(non_snake_case)]
#[inline(always)]
const fn ARR_OVERHEAD_NONULLS(ndims: usize) -> usize {
MAXALIGN(std::mem::size_of::<pg_sys::ArrayType>() + 2 * std::mem::size_of::<i32>() * ndims)
}
#[allow(non_snake_case)]
#[inline(always)]
unsafe fn ARR_DATA_OFFSET(a: *mut pg_sys::ArrayType) -> usize {
unsafe {
if ARR_HASNULL(a) {
(*a).dataoffset as _
} else {
ARR_OVERHEAD_NONULLS(ARR_NDIM(a))
}
}
}
#[allow(non_snake_case)]
#[inline(always)]
unsafe fn ARR_DATA_PTR(a: *mut pg_sys::ArrayType) -> *mut u8 {
unsafe { a.cast::<u8>().add(ARR_DATA_OFFSET(a)) }
}
#[derive(Debug)]
pub struct RawArray {
ptr: NonNull<pg_sys::ArrayType>,
len: usize,
}
#[deny(unsafe_op_in_unsafe_fn)]
impl RawArray {
pub unsafe fn from_ptr(ptr: NonNull<pg_sys::ArrayType>) -> RawArray {
let len = unsafe { ARR_NELEMS(ptr.as_ptr()) } as usize;
RawArray { ptr, len }
}
pub unsafe fn from_array<T: FromDatum>(arr: Array<T>) -> Option<RawArray> {
let array_type = arr.into_array_type() as *mut _;
let len = unsafe { ARR_NELEMS(array_type) } as usize;
Some(RawArray { ptr: NonNull::new(array_type)?, len })
}
#[inline]
pub fn into_ptr(self) -> NonNull<pg_sys::ArrayType> {
self.ptr
}
#[inline]
fn ndim(&self) -> libc::c_int {
unsafe {
(*self.ptr.as_ptr()).ndim
as _
}
}
pub fn dims(&self) -> &[libc::c_int] {
unsafe {
let ndim = self.ndim() as usize;
slice::from_raw_parts(ARR_DIMS(self.ptr.as_ptr()), ndim)
}
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
pub fn oid(&self) -> pg_sys::Oid {
unsafe { (*self.ptr.as_ptr()).elemtype }
}
#[inline]
fn data_offset(&self) -> i32 {
unsafe { (*self.ptr.as_ptr()).dataoffset }
}
#[allow(unused)]
fn nullable(&self) -> bool {
self.data_offset() != 0
}
#[inline]
fn nulls_mut_ptr(&mut self) -> *mut u8 {
unsafe { ARR_NULLBITMAP(self.ptr.as_ptr()) }
}
#[inline]
fn nulls_bitptr(&mut self) -> Option<BitPtr<Mut, u8>> {
match BitPtr::try_from(self.nulls_mut_ptr()) {
Ok(ptr) => Some(ptr),
Err(BitPtrError::Null(_)) => None,
Err(BitPtrError::Misaligned(_)) => unreachable!("impossible to misalign *mut u8"),
}
}
pub fn nulls(&mut self) -> Option<NonNull<[u8]>> {
let len = self.len + 7 >> 3;
NonNull::new(slice_from_raw_parts_mut(self.nulls_mut_ptr(), len))
}
pub fn nulls_bitslice(&mut self) -> Option<NonNull<BitSlice<u8>>> {
NonNull::new(bitslice_from_raw_parts_mut(self.nulls_bitptr()?, self.len))
}
pub unsafe fn any_nulls(&self) -> bool {
unsafe { pg_sys::array_contains_nulls(self.ptr.as_ptr()) }
}
pub fn data<T>(&mut self) -> NonNull<[T]> {
unsafe {
NonNull::new_unchecked(slice_from_raw_parts_mut(
ARR_DATA_PTR(self.ptr.as_ptr()).cast(),
self.len,
))
}
}
pub(crate) unsafe fn assume_init_data_slice<T>(&self) -> &[T] {
unsafe {
&*NonNull::new_unchecked(slice_from_raw_parts_mut(
ARR_DATA_PTR(self.ptr.as_ptr()).cast(),
self.len,
))
.as_ptr()
}
}
}