use std::alloc::Layout;
use std::fmt;
use std::mem::size_of;
use std::ops::{Deref, DerefMut};
use bytes::Bytes;
use zerocopy::byteorder::little_endian::{U32 as lu32, U64 as lu64};
use zerocopy::FromBytes;
use crate::error::Error;
use crate::LIBSQL_PAGE_SIZE;
pub type FrameNo = u64;
#[repr(C)]
#[derive(Debug, Clone, Copy, zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
pub struct FrameHeader {
pub frame_no: lu64,
pub checksum: lu64,
pub page_no: lu32,
pub size_after: lu32,
}
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct Frame {
inner: Bytes,
}
impl TryFrom<&[u8]> for Frame {
type Error = Error;
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
Ok(FrameMut::try_from(data)?.into())
}
}
impl fmt::Debug for Frame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Frame")
.field("header", &self.header())
.field("data", &"[..]")
.finish()
}
}
pub struct FrameMut {
inner: Box<FrameBorrowed>,
}
impl TryFrom<&[u8]> for FrameMut {
type Error = Error;
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() != size_of::<FrameBorrowed>() {
return Err(Error::InvalidFrameLen);
}
let inner = unsafe {
let layout = Layout::new::<FrameBorrowed>();
let ptr = std::alloc::alloc(layout);
ptr.copy_from(data.as_ptr(), data.len());
Box::from_raw(ptr as *mut FrameBorrowed)
};
Ok(Self { inner })
}
}
impl From<FrameMut> for Frame {
fn from(value: FrameMut) -> Self {
let data = unsafe {
Vec::from_raw_parts(
Box::into_raw(value.inner) as *mut u8,
size_of::<FrameBorrowed>(),
size_of::<FrameBorrowed>(),
)
};
Self {
inner: Bytes::from(data),
}
}
}
impl From<FrameBorrowed> for FrameMut {
fn from(inner: FrameBorrowed) -> Self {
Self {
inner: Box::new(inner),
}
}
}
impl From<Box<FrameBorrowed>> for FrameMut {
fn from(inner: Box<FrameBorrowed>) -> Self {
Self { inner }
}
}
impl Frame {
pub fn from_parts(header: &FrameHeader, data: &[u8]) -> Self {
FrameBorrowed::from_parts(header, data).into()
}
pub fn bytes(&self) -> Bytes {
self.inner.clone()
}
}
impl From<FrameBorrowed> for Frame {
fn from(value: FrameBorrowed) -> Self {
FrameMut::from(value).into()
}
}
#[repr(C)]
#[derive(Copy, Clone, zerocopy::AsBytes, zerocopy::FromZeroes, zerocopy::FromBytes)]
pub struct FrameBorrowed {
header: FrameHeader,
page: [u8; LIBSQL_PAGE_SIZE],
}
impl FrameBorrowed {
pub fn page(&self) -> &[u8] {
&self.page
}
pub fn page_mut(&mut self) -> &mut [u8] {
&mut self.page
}
pub fn header(&self) -> &FrameHeader {
&self.header
}
pub fn header_mut(&mut self) -> &mut FrameHeader {
&mut self.header
}
pub fn from_parts(header: &FrameHeader, page: &[u8]) -> Self {
assert_eq!(page.len(), LIBSQL_PAGE_SIZE);
FrameBorrowed {
header: *header,
page: page.try_into().unwrap(),
}
}
pub fn is_commit(&self) -> bool {
self.header().size_after.get() != 0
}
}
impl Deref for Frame {
type Target = FrameBorrowed;
fn deref(&self) -> &Self::Target {
FrameBorrowed::ref_from(&self.inner).unwrap()
}
}
impl Deref for FrameMut {
type Target = FrameBorrowed;
fn deref(&self) -> &Self::Target {
self.inner.as_ref()
}
}
impl DerefMut for FrameMut {
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner.as_mut()
}
}