use crate::pg_sys::{self, TYPALIGN_CHAR, TYPALIGN_DOUBLE, TYPALIGN_INT, TYPALIGN_SHORT};
use core::mem;
#[derive(Clone, Copy, Debug)]
pub(crate) struct Layout {
pub align: Align, pub size: Size, pub pass: PassBy, }
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum PassBy {
Ref,
Value,
}
impl Layout {
pub(crate) fn lookup_oid(oid: pg_sys::Oid) -> Layout {
let (mut typalign, mut typlen, mut passbyval) = Default::default();
unsafe { pg_sys::get_typlenbyvalalign(oid, &mut typlen, &mut passbyval, &mut typalign) };
Layout {
align: Align::try_from(typalign).unwrap(),
size: Size::try_from(typlen).unwrap(),
pass: if passbyval { PassBy::Value } else { PassBy::Ref },
}
}
pub(crate) fn size_matches<T>(&self) -> Option<usize> {
const DATUM_SIZE: usize = mem::size_of::<pg_sys::Datum>();
match (self.pass, mem::size_of::<T>(), self.size.try_as_usize()) {
(PassBy::Value, rs @ (1 | 2 | 4 | 8), Some(pg @ (1 | 2 | 4 | 8))) if rs == pg => {
Some(rs)
}
(PassBy::Value, _, _) => None,
(PassBy::Ref, DATUM_SIZE, _) => Some(DATUM_SIZE),
(PassBy::Ref, _, _) => None,
}
}
}
#[repr(usize)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum Align {
Byte = mem::align_of::<u8>(),
Short = mem::align_of::<libc::c_short>(),
Int = mem::align_of::<libc::c_int>(),
Double = mem::align_of::<f64>(),
}
impl TryFrom<libc::c_char> for Align {
type Error = ();
fn try_from(cchar: libc::c_char) -> Result<Align, ()> {
match cchar as u8 {
TYPALIGN_CHAR => Ok(Align::Byte),
TYPALIGN_SHORT => Ok(Align::Short),
TYPALIGN_INT => Ok(Align::Int),
TYPALIGN_DOUBLE => Ok(Align::Double),
_ => Err(()),
}
}
}
impl Align {
pub(crate) fn as_typalign(&self) -> libc::c_char {
(match self {
Align::Byte => TYPALIGN_CHAR,
Align::Short => TYPALIGN_SHORT,
Align::Int => TYPALIGN_INT,
Align::Double => TYPALIGN_DOUBLE,
}) as _
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum Size {
CStr,
Varlena,
Fixed(u16),
}
impl TryFrom<i16> for Size {
type Error = ();
fn try_from(int2: i16) -> Result<Size, ()> {
match int2 {
-2 => Ok(Size::CStr),
-1 => Ok(Size::Varlena),
v @ 0.. => Ok(Size::Fixed(v as u16)),
_ => Err(()),
}
}
}
impl Size {
pub(crate) fn as_typlen(&self) -> i16 {
match self {
Self::CStr => -2,
Self::Varlena => -1,
Self::Fixed(v) => *v as _,
}
}
pub(crate) fn try_as_usize(&self) -> Option<usize> {
match self {
Self::CStr => None,
Self::Varlena => None,
Self::Fixed(v) => Some(*v as _),
}
}
}