use bytes::Bytes;
use crate::frame::frame_errors::LowLevelDeserializationError;
use crate::frame::types;
#[derive(Clone, Copy, Debug)]
pub struct FrameSlice<'frame> {
frame_subslice: &'frame [u8],
original_frame: &'frame Bytes,
}
static EMPTY_BYTES: Bytes = Bytes::new();
impl<'frame> FrameSlice<'frame> {
#[inline]
pub fn new(frame: &'frame Bytes) -> Self {
Self {
frame_subslice: frame,
original_frame: frame,
}
}
#[inline]
pub fn new_empty() -> Self {
Self {
frame_subslice: &EMPTY_BYTES,
original_frame: &EMPTY_BYTES,
}
}
#[inline]
pub(crate) fn new_borrowed(frame_subslice: &'frame [u8]) -> Self {
Self {
frame_subslice,
original_frame: &EMPTY_BYTES,
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.frame_subslice.is_empty()
}
#[inline]
pub fn as_slice(&self) -> &'frame [u8] {
self.frame_subslice
}
#[inline]
pub fn as_slice_mut(&mut self) -> &mut &'frame [u8] {
&mut self.frame_subslice
}
#[inline]
pub fn as_original_frame_bytes(&self) -> &'frame Bytes {
self.original_frame
}
#[inline]
#[expect(clippy::wrong_self_convention)]
pub fn to_bytes(&self) -> Bytes {
if self.original_frame.is_empty() {
return Bytes::copy_from_slice(self.as_slice());
}
self.original_frame.slice_ref(self.frame_subslice)
}
#[inline]
pub fn read_cql_bytes(
&mut self,
) -> Result<Option<FrameSlice<'frame>>, LowLevelDeserializationError> {
let mut slice = self.frame_subslice;
let cql_bytes = types::read_bytes_opt(&mut slice)?;
self.frame_subslice = slice;
Ok(cql_bytes.map(|slice| Self {
frame_subslice: slice,
original_frame: self.original_frame,
}))
}
#[inline]
pub fn read_n_bytes(
&mut self,
count: usize,
) -> Result<Option<FrameSlice<'frame>>, LowLevelDeserializationError> {
if self.is_empty() {
return Ok(None);
}
let mut slice = self.frame_subslice;
let cql_bytes = types::read_raw_bytes(count, &mut slice)?;
self.frame_subslice = slice;
Ok(Some(Self {
frame_subslice: cql_bytes,
original_frame: self.original_frame,
}))
}
}
#[cfg(test)]
mod tests {
use bytes::Bytes;
use super::super::tests::{serialize_cells, CELL1, CELL2};
use super::FrameSlice;
#[test]
fn test_cql_bytes_consumption() {
let frame = serialize_cells([Some(CELL1), None, Some(CELL2)]);
let mut slice = FrameSlice::new(&frame);
assert!(!slice.is_empty());
assert_eq!(
slice.read_cql_bytes().unwrap().map(|s| s.as_slice()),
Some(CELL1)
);
assert!(!slice.is_empty());
assert!(slice.read_cql_bytes().unwrap().is_none());
assert!(!slice.is_empty());
assert_eq!(
slice.read_cql_bytes().unwrap().map(|s| s.as_slice()),
Some(CELL2)
);
assert!(slice.is_empty());
slice.read_cql_bytes().unwrap_err();
assert!(slice.is_empty());
}
#[test]
fn test_cql_bytes_owned() {
let frame = serialize_cells([Some(CELL1), Some(CELL2)]);
let mut slice = FrameSlice::new(&frame);
let subslice1 = slice.read_cql_bytes().unwrap().unwrap();
let subslice2 = slice.read_cql_bytes().unwrap().unwrap();
assert_eq!(subslice1.as_slice(), CELL1);
assert_eq!(subslice2.as_slice(), CELL2);
assert_eq!(
subslice1.as_original_frame_bytes() as *const Bytes,
&frame as *const Bytes
);
assert_eq!(
subslice2.as_original_frame_bytes() as *const Bytes,
&frame as *const Bytes
);
let subslice1_bytes = subslice1.to_bytes();
let subslice2_bytes = subslice2.to_bytes();
assert_eq!(subslice1.as_slice(), subslice1_bytes.as_ref());
assert_eq!(subslice2.as_slice(), subslice2_bytes.as_ref());
}
}