use libduckdb_sys::{duckdb_data_chunk, duckdb_data_chunk_set_size, idx_t};
use crate::vector::{StructWriter, VectorWriter};
const STANDARD_VECTOR_SIZE: usize = 2048;
pub struct ChunkWriter {
raw: duckdb_data_chunk,
row_count: usize,
capacity: usize,
}
impl ChunkWriter {
#[inline]
#[must_use]
pub const unsafe fn new(chunk: duckdb_data_chunk) -> Self {
Self {
raw: chunk,
row_count: 0,
capacity: STANDARD_VECTOR_SIZE,
}
}
#[inline]
#[must_use]
pub const unsafe fn with_capacity(chunk: duckdb_data_chunk, capacity: usize) -> Self {
Self {
raw: chunk,
row_count: 0,
capacity,
}
}
#[inline]
#[must_use]
pub const fn is_full(&self) -> bool {
self.row_count >= self.capacity
}
#[inline]
pub const fn next_row(&mut self) -> Option<usize> {
if self.is_full() {
return None;
}
let row = self.row_count;
self.row_count += 1;
Some(row)
}
#[inline]
#[must_use]
pub const fn row_count(&self) -> usize {
self.row_count
}
#[inline]
#[must_use]
pub const fn capacity(&self) -> usize {
self.capacity
}
#[inline]
#[must_use]
pub fn column_count(&self) -> usize {
usize::try_from(unsafe { libduckdb_sys::duckdb_data_chunk_get_column_count(self.raw) })
.unwrap_or(0)
}
#[must_use]
pub unsafe fn vector(&self, col_idx: usize) -> libduckdb_sys::duckdb_vector {
unsafe { libduckdb_sys::duckdb_data_chunk_get_vector(self.raw, col_idx as idx_t) }
}
pub unsafe fn writer(&self, col_idx: usize) -> VectorWriter {
let vec =
unsafe { libduckdb_sys::duckdb_data_chunk_get_vector(self.raw, col_idx as idx_t) };
unsafe { VectorWriter::from_vector(vec) }
}
pub unsafe fn struct_writer(&self, col_idx: usize, field_count: usize) -> StructWriter {
let vec =
unsafe { libduckdb_sys::duckdb_data_chunk_get_vector(self.raw, col_idx as idx_t) };
unsafe { StructWriter::new(vec, field_count) }
}
#[inline]
#[must_use]
pub const fn as_raw(&self) -> duckdb_data_chunk {
self.raw
}
pub unsafe fn finish_with_size(self, size: usize) {
unsafe { duckdb_data_chunk_set_size(self.raw, size as idx_t) };
std::mem::forget(self);
}
}
impl Drop for ChunkWriter {
fn drop(&mut self) {
unsafe { duckdb_data_chunk_set_size(self.raw, self.row_count as idx_t) };
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn size_of_chunk_writer() {
assert_eq!(
std::mem::size_of::<ChunkWriter>(),
std::mem::size_of::<usize>() * 3 );
}
#[test]
fn next_row_increments() {
let mut cw = ChunkWriter {
raw: std::ptr::null_mut(),
row_count: 0,
capacity: 3,
};
assert_eq!(cw.next_row(), Some(0));
assert_eq!(cw.next_row(), Some(1));
assert_eq!(cw.next_row(), Some(2));
assert_eq!(cw.next_row(), None);
assert!(cw.is_full());
assert_eq!(cw.row_count(), 3);
std::mem::forget(cw);
}
#[test]
fn is_full_at_zero_capacity() {
let cw = ChunkWriter {
raw: std::ptr::null_mut(),
row_count: 0,
capacity: 0,
};
assert!(cw.is_full());
std::mem::forget(cw);
}
}