use crate::{PgBox, pg_sys};
use core::{ops::DerefMut, slice, str};
#[inline(always)]
pub unsafe fn set_varsize_4b(ptr: *mut pg_sys::varlena, len: i32) {
let header = &mut (*ptr.cast::<pg_sys::varattrib_4b>()).va_4byte.deref_mut().va_header;
core::ptr::write(header, encode_vlen_4b(len))
}
pub(crate) fn encode_vlen_4b(len: i32) -> u32 {
#[cfg(target_endian = "big")]
let value = (len as u32) & 0x3FFFFFFFu32;
#[cfg(target_endian = "little")]
let value = (len as u32) << 2u32;
value
}
pub(crate) fn encode_vlen_1b(len: i32) -> u8 {
#[cfg(target_endian = "big")]
let value = (len as u8) | 0x80;
#[cfg(target_endian = "little")]
let value = ((len as u8) << 1) | 0x01;
value
}
#[inline(always)]
#[deprecated(since = "0.12.0", note = "you probably meant set_varsize_4b")]
pub unsafe fn set_varsize(ptr: *mut pg_sys::varlena, len: i32) {
set_varsize_4b(ptr, len)
}
#[inline(always)]
pub unsafe fn set_varsize_1b(ptr: *mut pg_sys::varlena, len: i32) {
(*ptr.cast::<pg_sys::varattrib_1b>()).va_header = encode_vlen_1b(len);
}
#[inline(always)]
pub unsafe fn set_varsize_short(ptr: *mut pg_sys::varlena, len: i32) {
set_varsize_1b(ptr, len)
}
#[inline]
pub unsafe fn varsize_external(ptr: *const pg_sys::varlena) -> usize {
pg_sys::VARHDRSZ_EXTERNAL + vartag_size(vartag_external(ptr) as pg_sys::vartag_external::Type)
}
#[inline]
pub unsafe fn vartag_external(ptr: *const pg_sys::varlena) -> u8 {
vartag_1b_e(ptr)
}
#[inline]
pub unsafe fn vartag_is_expanded(tag: pg_sys::vartag_external::Type) -> bool {
(tag & !1) == pg_sys::vartag_external::VARTAG_EXPANDED_RO
}
#[inline]
pub unsafe fn vartag_size(tag: pg_sys::vartag_external::Type) -> usize {
if tag == pg_sys::vartag_external::VARTAG_INDIRECT {
std::mem::size_of::<pg_sys::varatt_indirect>()
} else if vartag_is_expanded(tag) {
std::mem::size_of::<pg_sys::varatt_expanded>()
} else if tag == pg_sys::vartag_external::VARTAG_ONDISK {
std::mem::size_of::<pg_sys::varatt_external>()
} else {
panic!("unrecognized TOAST vartag")
}
}
#[allow(clippy::cast_ptr_alignment)]
#[inline]
pub unsafe fn varsize_4b(ptr: *const pg_sys::varlena) -> usize {
let va4b = ptr as *const pg_sys::varattrib_4b__bindgen_ty_1; #[cfg(target_endian = "big")]
{
((*va4b).va_header & 0x3FFF_FFFF) as usize
}
#[cfg(target_endian = "little")]
{
(((*va4b).va_header >> 2) & 0x3FFF_FFFF) as usize
}
}
#[inline]
pub unsafe fn varsize_1b(ptr: *const pg_sys::varlena) -> usize {
let va1b = ptr as *const pg_sys::varattrib_1b;
#[cfg(target_endian = "big")]
{
((*va1b).va_header & 0x7F) as usize
}
#[cfg(target_endian = "little")]
{
(((*va1b).va_header >> 1) & 0x7F) as usize
}
}
#[inline]
pub unsafe fn vartag_1b_e(ptr: *const pg_sys::varlena) -> u8 {
let va1be = ptr as *const pg_sys::varattrib_1b_e;
(*va1be).va_tag
}
#[inline]
pub unsafe fn varsize(ptr: *const pg_sys::varlena) -> usize {
varsize_4b(ptr)
}
#[inline]
pub unsafe fn varatt_is_4b(ptr: *const pg_sys::varlena) -> bool {
let va1b = ptr as *const pg_sys::varattrib_1b;
#[cfg(target_endian = "big")]
{
(*va1b).va_header & 0x80 == 0x00
}
#[cfg(target_endian = "little")]
{
(*va1b).va_header & 0x01 == 0x00
}
}
#[allow(clippy::verbose_bit_mask)]
#[inline]
pub unsafe fn varatt_is_4b_u(ptr: *const pg_sys::varlena) -> bool {
let va1b = ptr as *const pg_sys::varattrib_1b;
#[cfg(target_endian = "big")]
{
(*va1b).va_header & 0xC0 == 0x00
}
#[cfg(target_endian = "little")]
{
(*va1b).va_header & 0x03 == 0x00
}
}
#[inline]
pub unsafe fn varatt_is_4b_c(ptr: *const pg_sys::varlena) -> bool {
let va1b = ptr as *const pg_sys::varattrib_1b;
#[cfg(target_endian = "big")]
{
(*va1b).va_header & 0xC0 == 0x40
}
#[cfg(target_endian = "little")]
{
(*va1b).va_header & 0x03 == 0x02
}
}
#[inline]
pub unsafe fn varatt_is_1b(ptr: *const pg_sys::varlena) -> bool {
let va1b = ptr as *const pg_sys::varattrib_1b;
#[cfg(target_endian = "big")]
{
(*va1b).va_header & 0x80 == 0x80
}
#[cfg(target_endian = "little")]
{
(*va1b).va_header & 0x01 == 0x01
}
}
#[inline]
pub unsafe fn varatt_is_1b_e(ptr: *const pg_sys::varlena) -> bool {
let va1b = ptr as *const pg_sys::varattrib_1b;
#[cfg(target_endian = "big")]
{
(*va1b).va_header == 0x80
}
#[cfg(target_endian = "little")]
{
(*va1b).va_header == 0x01
}
}
#[inline]
pub unsafe fn varatt_not_pad_byte(ptr: *const pg_sys::varlena) -> bool {
!ptr.is_null()
}
#[inline]
pub unsafe fn varsize_any(ptr: *const pg_sys::varlena) -> usize {
if varatt_is_1b_e(ptr) {
varsize_external(ptr)
} else if varatt_is_1b(ptr) {
varsize_1b(ptr)
} else {
varsize_4b(ptr)
}
}
#[inline]
pub unsafe fn varsize_any_exhdr(ptr: *const pg_sys::varlena) -> usize {
if varatt_is_1b_e(ptr) {
varsize_external(ptr) - pg_sys::VARHDRSZ_EXTERNAL
} else if varatt_is_1b(ptr) {
varsize_1b(ptr) - pg_sys::VARHDRSZ_SHORT
} else {
varsize_4b(ptr) - pg_sys::VARHDRSZ
}
}
#[inline]
pub unsafe fn vardata_1b(ptr: *const pg_sys::varlena) -> *const std::os::raw::c_char {
let va1b = ptr as *const pg_sys::varattrib_1b;
(*va1b).va_data.as_slice(varsize_1b(ptr as *const pg_sys::varlena) as usize).as_ptr()
as *const std::os::raw::c_char
}
#[allow(clippy::cast_ptr_alignment)]
#[inline]
pub unsafe fn vardata_4b(ptr: *const pg_sys::varlena) -> *const std::os::raw::c_char {
let va1b = ptr as *const pg_sys::varattrib_4b__bindgen_ty_1; (*va1b).va_data.as_slice(varsize_1b(ptr as *const pg_sys::varlena) as usize).as_ptr()
as *const std::os::raw::c_char
}
#[allow(clippy::cast_ptr_alignment)]
#[inline]
pub unsafe fn vardata_4b_c(ptr: *const pg_sys::varlena) -> *const std::os::raw::c_char {
let va1b = ptr as *const pg_sys::varattrib_4b__bindgen_ty_2; (*va1b).va_data.as_slice(varsize_1b(ptr as *const pg_sys::varlena) as usize).as_ptr()
as *const std::os::raw::c_char
}
#[allow(clippy::cast_ptr_alignment)]
#[inline]
pub unsafe fn vardata_1b_e(ptr: *const pg_sys::varlena) -> *const std::os::raw::c_char {
let va1b = ptr as *const pg_sys::varattrib_1b_e;
(*va1b).va_data.as_slice(varsize_1b(ptr as *const pg_sys::varlena) as usize).as_ptr()
as *const std::os::raw::c_char
}
#[inline]
pub unsafe fn vardata_any(ptr: *const pg_sys::varlena) -> *const std::os::raw::c_char {
if varatt_is_1b(ptr) { vardata_1b(ptr) } else { vardata_4b(ptr) }
}
#[inline]
pub unsafe fn text_to_rust_str<'a>(
varlena: *const pg_sys::varlena,
) -> Result<&'a str, str::Utf8Error> {
let len = varsize_any_exhdr(varlena);
let data = vardata_any(varlena);
str::from_utf8(slice::from_raw_parts(data as *mut u8, len))
}
#[inline]
pub unsafe fn text_to_rust_str_unchecked<'a>(varlena: *const pg_sys::varlena) -> &'a str {
let len = varsize_any_exhdr(varlena);
let data = vardata_any(varlena);
str::from_utf8_unchecked(slice::from_raw_parts(data as *mut u8, len))
}
#[inline]
pub unsafe fn varlena_to_byte_slice<'a>(varlena: *const pg_sys::varlena) -> &'a [u8] {
let len = varsize_any_exhdr(varlena);
let data = vardata_any(varlena);
std::slice::from_raw_parts(data as *const u8, len)
}
#[inline]
pub fn rust_str_to_text_p(s: &str) -> PgBox<pg_sys::varlena> {
let bytea = rust_byte_slice_to_bytea(s.as_bytes());
unsafe { PgBox::from_pg(bytea.as_ptr() as *mut pg_sys::varlena) }
}
#[inline]
pub fn rust_byte_slice_to_bytea(slice: &[u8]) -> PgBox<pg_sys::bytea> {
unsafe {
PgBox::from_pg(pg_sys::cstring_to_text_with_len(
slice.as_ptr() as *const std::os::raw::c_char,
slice.len() as i32,
))
}
}