use rudb_common::{Error, Result};
use rudb_vector::Vector;
#[derive(Debug, Default)]
pub(crate) struct SignedBlock {
held: Vec<i64>,
nulled: bool,
}
impl SignedBlock {
pub(crate) fn read(&mut self, rows: usize, column: &Vector) -> Result<()> {
self.nulled = !column.none_null();
if column.signed_block(&mut self.held) {
return Ok(());
}
self.held.clear();
self.held.reserve(rows);
for row in 0..rows {
self.held.push(match column.signed_at(row) {
Some(value) => i64::try_from(value)
.map_err(|_| Error::internal("a signed column is out of range"))?,
None if column.is_null_at(row) => 0,
None => {
return Err(Error::internal("a signed column has no signed representation"));
}
});
}
Ok(())
}
pub(crate) fn nulled(&self) -> bool {
self.nulled
}
pub(crate) fn cut(&self, rows: usize) -> Result<&[i64]> {
self.held
.get(..rows)
.ok_or_else(|| Error::internal("a signed column was read short of the chunk"))
}
}
#[cfg(test)]
mod tests {
use rudb_common::{LogicalType, Value};
use rudb_vector::Vector;
use super::SignedBlock;
#[test]
fn a_block_reads_the_same_values_from_a_run_and_from_a_dictionary() {
let held = [Value::Integer(7), Value::Integer(-3), Value::Integer(7)];
let flat = Vector::from_values(LogicalType::Integer, &held).expect("a flat run");
let mut block = SignedBlock::default();
block.read(3, &flat).expect("a flat run is read as a block");
assert_eq!(block.cut(3).expect("three rows"), [7, -3, 7]);
assert!(!block.nulled(), "no nulls in it");
let values = Vector::from_values(LogicalType::Integer, &held[..2]).expect("two values");
let coded = Vector::dictionary(vec![0, 1, 0], values).expect("a dictionary");
let mut other = SignedBlock::default();
other.read(3, &coded).expect("a dictionary is read a row at a time");
assert_eq!(other.cut(3).expect("three rows"), [7, -3, 7]);
assert!(!other.nulled(), "no nulls in it either");
}
#[test]
fn a_null_leaves_a_zero_behind_and_raises_the_flag() {
let held = [Value::BigInt(5), Value::Null, Value::BigInt(9)];
let column = Vector::from_values(LogicalType::BigInt, &held).expect("one null in it");
let mut block = SignedBlock::default();
block.read(3, &column).expect("a column with a null is read");
assert_eq!(block.cut(3).expect("three rows"), [5, 0, 9]);
assert!(block.nulled(), "the flag says the loop has to ask the column");
assert!(block.cut(4).is_err(), "more rows than the chunk held");
}
#[test]
fn a_block_agrees_with_the_vector_on_an_offset_packed_column() {
let values: Vec<Value> =
(0..256).map(|row| Value::Integer((row * 37 % 127) - 30)).collect();
let flat = Vector::from_values(LogicalType::Integer, &values).expect("an integer vector");
let packed = flat.bit_packed().expect("the vector packs");
assert!(packed.packed_parts().is_some());
let cut = packed.slice(3, 200).expect("an offset packed vector");
let mut block = SignedBlock::default();
block.read(cut.len(), &cut).expect("a packed column is read as a block");
let held = block.cut(cut.len()).expect("every row of it");
for (row, &value) in held.iter().enumerate() {
assert_eq!(i128::from(value), cut.signed_at(row).expect("a signed value"));
}
}
}