use libduckdb_sys::{
duckdb_validity_set_row_invalid, duckdb_validity_set_row_valid, duckdb_vector,
duckdb_vector_assign_string_element_len, duckdb_vector_ensure_validity_writable,
duckdb_vector_get_data, duckdb_vector_get_validity, idx_t,
};
pub struct VectorWriter {
vector: duckdb_vector,
data: *mut u8,
}
impl VectorWriter {
pub unsafe fn new(vector: duckdb_vector) -> Self {
let data = unsafe { duckdb_vector_get_data(vector) }.cast::<u8>();
Self { vector, data }
}
pub unsafe fn from_vector(vector: duckdb_vector) -> Self {
let data = unsafe { duckdb_vector_get_data(vector) }.cast::<u8>();
Self { vector, data }
}
#[inline]
pub const unsafe fn write_i8(&mut self, idx: usize, value: i8) {
unsafe { core::ptr::write_unaligned(self.data.add(idx).cast::<i8>(), value) };
}
#[inline]
pub const unsafe fn write_i16(&mut self, idx: usize, value: i16) {
unsafe { core::ptr::write_unaligned(self.data.add(idx * 2).cast::<i16>(), value) };
}
#[inline]
pub const unsafe fn write_i32(&mut self, idx: usize, value: i32) {
unsafe { core::ptr::write_unaligned(self.data.add(idx * 4).cast::<i32>(), value) };
}
#[inline]
pub const unsafe fn write_i64(&mut self, idx: usize, value: i64) {
unsafe { core::ptr::write_unaligned(self.data.add(idx * 8).cast::<i64>(), value) };
}
#[inline]
pub const unsafe fn write_u8(&mut self, idx: usize, value: u8) {
unsafe { *self.data.add(idx) = value };
}
#[inline]
pub const unsafe fn write_u32(&mut self, idx: usize, value: u32) {
unsafe { core::ptr::write_unaligned(self.data.add(idx * 4).cast::<u32>(), value) };
}
#[inline]
pub const unsafe fn write_u64(&mut self, idx: usize, value: u64) {
unsafe { core::ptr::write_unaligned(self.data.add(idx * 8).cast::<u64>(), value) };
}
#[inline]
pub const unsafe fn write_f32(&mut self, idx: usize, value: f32) {
unsafe { core::ptr::write_unaligned(self.data.add(idx * 4).cast::<f32>(), value) };
}
#[inline]
pub const unsafe fn write_f64(&mut self, idx: usize, value: f64) {
unsafe { core::ptr::write_unaligned(self.data.add(idx * 8).cast::<f64>(), value) };
}
#[inline]
pub unsafe fn write_bool(&mut self, idx: usize, value: bool) {
unsafe { *self.data.add(idx) = u8::from(value) };
}
#[inline]
pub const unsafe fn write_i128(&mut self, idx: usize, value: i128) {
let base = unsafe { self.data.add(idx * 16) };
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let lower = value as u64;
#[allow(clippy::cast_possible_truncation)]
let upper = (value >> 64) as i64;
unsafe {
core::ptr::write_unaligned(base.cast::<u64>(), lower);
core::ptr::write_unaligned(base.add(8).cast::<i64>(), upper);
}
}
#[inline]
pub const unsafe fn write_u16(&mut self, idx: usize, value: u16) {
unsafe { core::ptr::write_unaligned(self.data.add(idx * 2).cast::<u16>(), value) };
}
pub unsafe fn write_varchar(&mut self, idx: usize, value: &str) {
unsafe {
duckdb_vector_assign_string_element_len(
self.vector,
idx as idx_t,
value.as_ptr().cast::<std::os::raw::c_char>(),
idx_t::try_from(value.len()).unwrap_or(idx_t::MAX),
);
}
}
#[inline]
pub const unsafe fn write_date(&mut self, idx: usize, days_since_epoch: i32) {
unsafe { self.write_i32(idx, days_since_epoch) };
}
#[inline]
pub const unsafe fn write_timestamp(&mut self, idx: usize, micros_since_epoch: i64) {
unsafe { self.write_i64(idx, micros_since_epoch) };
}
#[inline]
pub const unsafe fn write_time(&mut self, idx: usize, micros_since_midnight: i64) {
unsafe { self.write_i64(idx, micros_since_midnight) };
}
#[inline]
pub const unsafe fn write_interval(
&mut self,
idx: usize,
value: crate::interval::DuckInterval,
) {
let base = unsafe { self.data.add(idx * 16) };
unsafe {
core::ptr::write_unaligned(base.cast::<i32>(), value.months);
core::ptr::write_unaligned(base.add(4).cast::<i32>(), value.days);
core::ptr::write_unaligned(base.add(8).cast::<i64>(), value.micros);
}
}
pub unsafe fn write_blob(&mut self, idx: usize, value: &[u8]) {
unsafe {
duckdb_vector_assign_string_element_len(
self.vector,
idx as idx_t,
value.as_ptr().cast::<std::os::raw::c_char>(),
idx_t::try_from(value.len()).unwrap_or(idx_t::MAX),
);
}
}
#[inline]
pub const unsafe fn write_uuid(&mut self, idx: usize, value: i128) {
unsafe { self.write_i128(idx, value) };
}
#[inline]
pub unsafe fn write_str(&mut self, idx: usize, value: &str) {
unsafe { self.write_varchar(idx, value) };
}
pub unsafe fn set_null(&mut self, idx: usize) {
unsafe {
duckdb_vector_ensure_validity_writable(self.vector);
}
let validity = unsafe { duckdb_vector_get_validity(self.vector) };
unsafe {
duckdb_validity_set_row_invalid(validity, idx as idx_t);
}
}
pub unsafe fn set_valid(&mut self, idx: usize) {
unsafe {
duckdb_vector_ensure_validity_writable(self.vector);
}
let validity = unsafe { duckdb_vector_get_validity(self.vector) };
unsafe {
duckdb_validity_set_row_valid(validity, idx as idx_t);
}
}
#[must_use]
#[inline]
pub const fn as_raw(&self) -> duckdb_vector {
self.vector
}
}
#[cfg(test)]
mod tests {
#[test]
fn size_of_vector_writer() {
use super::VectorWriter;
use std::mem::size_of;
assert_eq!(size_of::<VectorWriter>(), 2 * size_of::<usize>());
}
}