1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
//! Contains the [`RawBatchValues`] and [`RawBatchValuesIterator`] trait and their
//! implementations.
use super::batch::{BatchValues, BatchValuesIterator};
use super::row::{RowSerializationContext, SerializedValues};
use super::{RowWriter, SerializationError};
/// Represents a list of sets of values for a batch statement.
///
/// Unlike [`BatchValues`]), it doesn't require type
/// information from the statements of the batch in order to be serialized.
///
/// This is a lower level trait than [`BatchValues`])
/// and is only used for interaction between the code in `scylla` and
/// `scylla-cql` crates. If you are a regular user of the driver, you shouldn't
/// care about this trait at all.
pub trait RawBatchValues {
/// An `Iterator`-like object over the values from the parent `BatchValues` object.
// For some unknown reason, this type, when not resolved to a concrete type for a given async function,
// cannot live across await boundaries while maintaining the corresponding future `Send`, unless `'r: 'static`
//
// See <https://github.com/scylladb/scylla-rust-driver/issues/599> for more details
type RawBatchValuesIter<'r>: RawBatchValuesIterator<'r>
where
Self: 'r;
/// Returns an iterator over the data contained in this object.
fn batch_values_iter(&self) -> Self::RawBatchValuesIter<'_>;
}
/// An `Iterator`-like object over the values from the parent [`RawBatchValues`] object.
///
/// It's not a true [`Iterator`] because it does not provide direct access to the
/// items being iterated over, instead it allows calling methods of the underlying
/// [`SerializeRow`](super::row::SerializeRow) trait while advancing the iterator.
///
/// Unlike [`BatchValuesIterator`], it doesn't
/// need type information for serialization.
pub trait RawBatchValuesIterator<'a> {
/// Serializes the next set of values in the sequence and advances the iterator.
fn serialize_next(&mut self, writer: &mut RowWriter) -> Option<Result<(), SerializationError>>;
/// Returns whether the next set of values is empty or not and advances the iterator.
fn is_empty_next(&mut self) -> Option<bool>;
/// Skips the next set of values.
fn skip_next(&mut self) -> Option<()>;
/// Return the number of sets of values, consuming the iterator in the process.
#[inline]
fn count(mut self) -> usize
where
Self: Sized,
{
std::iter::from_fn(|| self.skip_next()).count()
}
}
// An implementation used by `scylla-proxy`
impl RawBatchValues for Vec<SerializedValues> {
type RawBatchValuesIter<'r>
= std::slice::Iter<'r, SerializedValues>
where
Self: 'r;
fn batch_values_iter(&self) -> Self::RawBatchValuesIter<'_> {
self.iter()
}
}
impl<'r> RawBatchValuesIterator<'r> for std::slice::Iter<'r, SerializedValues> {
#[inline]
fn serialize_next(&mut self, writer: &mut RowWriter) -> Option<Result<(), SerializationError>> {
self.next().map(|sv| {
writer.append_serialize_row(sv);
Ok(())
})
}
fn is_empty_next(&mut self) -> Option<bool> {
self.next().map(|sv| sv.is_empty())
}
#[inline]
fn skip_next(&mut self) -> Option<()> {
self.next().map(|_| ())
}
#[inline]
fn count(self) -> usize {
<_ as Iterator>::count(self)
}
}
/// Takes `BatchValues` and an iterator over contexts, and turns them into a `RawBatchValues`.
pub struct RawBatchValuesAdapter<BV, CTX> {
batch_values: BV,
contexts: CTX,
}
impl<BV, CTX> RawBatchValuesAdapter<BV, CTX> {
/// Creates a new `RawBatchValuesAdapter` object.
#[inline]
pub fn new(batch_values: BV, contexts: CTX) -> Self {
Self {
batch_values,
contexts,
}
}
}
impl<'ctx, BV, CTX> RawBatchValues for RawBatchValuesAdapter<BV, CTX>
where
BV: BatchValues,
CTX: Iterator<Item = RowSerializationContext<'ctx>> + Clone,
{
type RawBatchValuesIter<'r>
= RawBatchValuesIteratorAdapter<BV::BatchValuesIter<'r>, CTX>
where
Self: 'r;
#[inline]
fn batch_values_iter(&self) -> Self::RawBatchValuesIter<'_> {
RawBatchValuesIteratorAdapter {
batch_values_iterator: self.batch_values.batch_values_iter(),
contexts: self.contexts.clone(),
}
}
}
/// Takes `BatchValuesIterator` and an iterator over contexts, and turns them into a `RawBatchValuesIterator`.
pub struct RawBatchValuesIteratorAdapter<BVI, CTX> {
batch_values_iterator: BVI,
contexts: CTX,
}
impl<'bvi, 'ctx, BVI, CTX> RawBatchValuesIterator<'bvi> for RawBatchValuesIteratorAdapter<BVI, CTX>
where
BVI: BatchValuesIterator<'bvi>,
CTX: Iterator<Item = RowSerializationContext<'ctx>>,
{
#[inline]
fn serialize_next(&mut self, writer: &mut RowWriter) -> Option<Result<(), SerializationError>> {
// We do `unwrap_or` because we want the iterator length to be the same
// as the amount of values. Limiting to length of the amount of
// statements (contexts) causes the caller to not be able to correctly
// detect that amount of statements and values is different.
let ctx = self
.contexts
.next()
.unwrap_or(RowSerializationContext::empty());
self.batch_values_iterator.serialize_next(&ctx, writer)
}
fn is_empty_next(&mut self) -> Option<bool> {
let _ = self.contexts.next();
let ret = self.batch_values_iterator.is_empty_next()?;
Some(ret)
}
#[inline]
fn skip_next(&mut self) -> Option<()> {
let _ = self.contexts.next();
self.batch_values_iterator.skip_next()?;
Some(())
}
}