use thiserror::Error;
use super::row::SerializedValues;
pub struct RowWriter<'buf> {
buf: &'buf mut Vec<u8>,
value_count: usize,
}
impl<'buf> RowWriter<'buf> {
#[inline]
pub fn new(buf: &'buf mut Vec<u8>) -> Self {
Self {
buf,
value_count: 0,
}
}
#[inline]
pub fn value_count(&self) -> usize {
self.value_count
}
#[inline]
pub fn make_cell_writer(&mut self) -> CellWriter<'_> {
self.value_count += 1;
CellWriter::new(self.buf)
}
#[inline]
pub fn append_serialize_row(&mut self, sv: &SerializedValues) {
self.value_count += sv.element_count() as usize;
self.buf.extend_from_slice(sv.get_contents())
}
}
pub struct CellWriter<'buf> {
buf: &'buf mut Vec<u8>,
write_size: bool,
}
impl<'buf> CellWriter<'buf> {
#[inline]
pub fn new(buf: &'buf mut Vec<u8>) -> Self {
Self {
buf,
write_size: true,
}
}
#[inline]
pub fn new_without_size(buf: &'buf mut Vec<u8>) -> Self {
Self {
buf,
write_size: false,
}
}
#[inline]
pub fn set_null(self) -> WrittenCellProof<'buf> {
self.buf.extend_from_slice(&(-1i32).to_be_bytes());
WrittenCellProof::new()
}
#[inline]
pub fn set_unset(self) -> WrittenCellProof<'buf> {
self.buf.extend_from_slice(&(-2i32).to_be_bytes());
WrittenCellProof::new()
}
#[inline]
pub fn set_value(self, contents: &[u8]) -> Result<WrittenCellProof<'buf>, CellOverflowError> {
let value_len: i32 = contents.len().try_into().map_err(|_| CellOverflowError)?;
if self.write_size {
self.buf.extend_from_slice(&value_len.to_be_bytes());
}
self.buf.extend_from_slice(contents);
Ok(WrittenCellProof::new())
}
#[inline]
pub fn into_value_builder(self) -> CellValueBuilder<'buf> {
CellValueBuilder::new(self.buf, self.write_size)
}
}
pub struct CellValueBuilder<'buf> {
buf: &'buf mut Vec<u8>,
starting_pos: usize,
write_size: bool,
}
impl<'buf> CellValueBuilder<'buf> {
#[inline]
fn new(buf: &'buf mut Vec<u8>, write_size: bool) -> Self {
let starting_pos = buf.len();
if write_size {
buf.extend_from_slice(&(-3i32).to_be_bytes());
}
Self {
buf,
starting_pos,
write_size,
}
}
#[inline]
pub fn append_bytes(&mut self, bytes: &[u8]) {
self.buf.extend_from_slice(bytes);
}
#[inline]
pub fn make_sub_writer(&mut self) -> CellWriter<'_> {
CellWriter::new(self.buf)
}
#[inline]
pub fn make_sub_writer_without_size(&mut self) -> CellWriter<'_> {
CellWriter::new_without_size(self.buf)
}
#[inline]
pub fn finish(self) -> Result<WrittenCellProof<'buf>, CellOverflowError> {
if self.write_size {
let value_len: i32 = (self.buf.len() - self.starting_pos - 4)
.try_into()
.map_err(|_| CellOverflowError)?;
self.buf[self.starting_pos..self.starting_pos + 4]
.copy_from_slice(&value_len.to_be_bytes());
}
Ok(WrittenCellProof::new())
}
}
#[derive(Debug)]
pub struct WrittenCellProof<'buf> {
_phantom: std::marker::PhantomData<*mut &'buf ()>,
}
impl WrittenCellProof<'_> {
#[inline]
fn new() -> Self {
WrittenCellProof {
_phantom: std::marker::PhantomData,
}
}
}
#[derive(Debug, Clone, Copy, Error)]
#[error("CQL cell overflowed the maximum allowed size of 2^31 - 1")]
pub struct CellOverflowError;
#[cfg(test)]
mod tests {
use super::{CellWriter, RowWriter};
#[test]
fn test_cell_writer() {
let mut data = Vec::new();
let writer = CellWriter::new(&mut data);
let mut sub_writer = writer.into_value_builder();
sub_writer.make_sub_writer().set_null();
sub_writer
.make_sub_writer()
.set_value(&[1, 2, 3, 4])
.unwrap();
sub_writer.make_sub_writer().set_unset();
sub_writer.finish().unwrap();
assert_eq!(
data,
[
0, 0, 0, 16, 255, 255, 255, 255, 0, 0, 0, 4, 1, 2, 3, 4, 255, 255, 255, 254, ]
);
}
#[test]
fn test_poisoned_appender() {
let mut data = Vec::new();
let writer = CellWriter::new(&mut data);
let _ = writer.into_value_builder();
assert_eq!(
data,
[
255, 255, 255, 253, ]
);
}
#[test]
fn test_row_writer() {
let mut data = Vec::new();
let mut writer = RowWriter::new(&mut data);
writer.make_cell_writer().set_null();
writer.make_cell_writer().set_value(&[1, 2, 3, 4]).unwrap();
writer.make_cell_writer().set_unset();
assert_eq!(
data,
[
255, 255, 255, 255, 0, 0, 0, 4, 1, 2, 3, 4, 255, 255, 255, 254, ]
)
}
}