use crate::{
codec::Decode,
database::client::postgres::{Postgres, PostgresDecodeWrapper, PostgresError, Ty},
misc::Usize,
};
use core::marker::PhantomData;
#[derive(Debug)]
pub struct StructDecoder<'de, E> {
bytes: &'de [u8],
phantom: PhantomData<fn() -> E>,
}
impl<'de, E> StructDecoder<'de, E>
where
E: From<crate::Error>,
{
#[inline]
pub fn new(dw: &mut PostgresDecodeWrapper<'de, '_>) -> Self {
let bytes = if let [_, _, _, _, rest @ ..] = dw.bytes() { rest } else { dw.bytes() };
Self { bytes, phantom: PhantomData }
}
#[inline]
pub fn decode<T>(&mut self) -> Result<T, E>
where
T: Decode<'de, Postgres<E>>,
{
Ok(self.decode_opt()?.ok_or_else(|| PostgresError::DecodingError.into())?)
}
#[inline]
pub fn decode_opt<T>(&mut self) -> Result<Option<T>, E>
where
T: Decode<'de, Postgres<E>>,
{
let [b0, b1, b2, b3, b4, b5, b6, b7, rest @ ..] = self.bytes else {
return Ok(None);
};
let ty = Ty::from_arbitrary_u32(u32::from_be_bytes([*b0, *b1, *b2, *b3]));
let Ok(length) = u32::try_from(i32::from_be_bytes([*b4, *b5, *b6, *b7])) else {
self.bytes = rest;
return Ok(None);
};
let Some((before, after)) = rest.split_at_checked(*Usize::from(length)) else {
self.bytes = rest;
return Ok(None);
};
self.bytes = after;
Ok(Some(T::decode(&mut PostgresDecodeWrapper::new(before, "", ty))?))
}
}