use bytes::Bytes;
use crate::frame::response::result::{
DeserializedMetadataAndRawRows, ResultMetadata, ResultMetadataHolder,
};
use super::row::{BuiltinDeserializationErrorKind, ColumnIterator, mk_deser_err};
use super::{DeserializationError, FrameSlice};
pub use scylla_cql_core::deserialize::result::{RawRowIterator, TypedRowIterator};
#[derive(Debug)]
pub struct RawRowLendingIterator {
metadata: ResultMetadataHolder,
remaining: usize,
at: usize,
raw_rows: Bytes,
}
impl RawRowLendingIterator {
#[inline]
pub fn new(raw_rows: DeserializedMetadataAndRawRows) -> Self {
let (metadata, rows_count, raw_rows) = raw_rows.into_inner();
Self {
metadata,
remaining: rows_count,
at: 0,
raw_rows,
}
}
#[inline]
#[expect(clippy::should_implement_trait)] pub fn next(&mut self) -> Option<Result<ColumnIterator<'_, '_>, DeserializationError>> {
self.remaining = self.remaining.checked_sub(1)?;
let mut remaining_frame = FrameSlice::new(&self.raw_rows);
*remaining_frame.as_slice_mut() = &remaining_frame.as_slice()[self.at..];
let iter = ColumnIterator::new(self.metadata.inner().col_specs(), remaining_frame);
for (column_index, spec) in self.metadata.inner().col_specs().iter().enumerate() {
let remaining_frame_len_before_column_read = remaining_frame.as_slice().len();
if let Err(err) = remaining_frame.read_cql_bytes() {
return Some(Err(mk_deser_err::<Self>(
BuiltinDeserializationErrorKind::RawColumnDeserializationFailed {
column_index,
column_name: spec.name().to_owned(),
err: DeserializationError::new(err),
},
)));
} else {
let remaining_frame_len_after_column_read = remaining_frame.as_slice().len();
self.at +=
remaining_frame_len_before_column_read - remaining_frame_len_after_column_read;
}
}
Some(Ok(iter))
}
#[inline]
pub fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
#[inline]
pub fn metadata(&self) -> &ResultMetadata<'_> {
self.metadata.inner()
}
#[inline]
pub fn rows_remaining(&self) -> usize {
self.remaining
}
}
#[cfg(test)]
mod tests {
use crate::frame::response::result::{
ColumnType, DeserializedMetadataAndRawRows, NativeType, ResultMetadata,
};
use super::super::tests::{CELL1, CELL2, serialize_cells, spec};
use super::RawRowLendingIterator;
#[test]
fn test_raw_row_lending_iterator_basic_parse() {
let raw_data = serialize_cells([Some(CELL1), Some(CELL2), Some(CELL2), Some(CELL1)]);
let specs = [
spec("b1", ColumnType::Native(NativeType::Blob)),
spec("b2", ColumnType::Native(NativeType::Blob)),
];
let mut iter = RawRowLendingIterator::new(DeserializedMetadataAndRawRows::new_for_test(
ResultMetadata::new_for_test(specs.len(), specs.to_vec()),
2,
raw_data,
));
let mut row1 = iter.next().unwrap().unwrap();
let c11 = row1.next().unwrap().unwrap();
assert_eq!(c11.slice.unwrap().as_slice(), CELL1);
let c12 = row1.next().unwrap().unwrap();
assert_eq!(c12.slice.unwrap().as_slice(), CELL2);
assert!(row1.next().is_none());
let mut row2 = iter.next().unwrap().unwrap();
let c21 = row2.next().unwrap().unwrap();
assert_eq!(c21.slice.unwrap().as_slice(), CELL2);
let c22 = row2.next().unwrap().unwrap();
assert_eq!(c22.slice.unwrap().as_slice(), CELL1);
assert!(row2.next().is_none());
assert!(iter.next().is_none());
}
#[test]
fn test_raw_row_lending_iterator_too_few_rows() {
let raw_data = serialize_cells([Some(CELL1), Some(CELL2)]);
let specs = [
spec("b1", ColumnType::Native(NativeType::Blob)),
spec("b2", ColumnType::Native(NativeType::Blob)),
];
let mut iter = RawRowLendingIterator::new(DeserializedMetadataAndRawRows::new_for_test(
ResultMetadata::new_for_test(specs.len(), specs.to_vec()),
2,
raw_data,
));
iter.next().unwrap().unwrap();
iter.next().unwrap().unwrap_err();
}
}