use std::marker::PhantomData;
use libduckdb_sys::DuckDbString;
use crate::{
Result,
core::LogicalTypeHandle,
ffi::{
duckdb_struct_type_child_count, duckdb_struct_type_child_name, duckdb_struct_vector_get_child,
duckdb_validity_set_row_invalid, duckdb_vector, duckdb_vector_ensure_validity_writable,
duckdb_vector_get_column_type, duckdb_vector_get_validity, duckdb_vector_size,
},
};
use super::{ArrayVector, FlatVector, ListVector, try_vector_row_is_null, vector_row_is_null};
pub struct StructVector<'a> {
ptr: duckdb_vector,
capacity: usize,
_phantom: PhantomData<&'a ()>,
}
impl<'a> StructVector<'a> {
pub(crate) unsafe fn from_raw(ptr: duckdb_vector) -> Self {
unsafe { Self::from_raw_with_capacity(ptr, duckdb_vector_size() as usize) }
}
pub(crate) unsafe fn from_raw_with_capacity(ptr: duckdb_vector, capacity: usize) -> Self {
Self {
ptr,
capacity,
_phantom: PhantomData,
}
}
pub fn child(&self, idx: usize, capacity: usize) -> FlatVector<'a> {
assert!(
capacity <= self.capacity,
"struct child capacity {capacity} exceeds parent capacity {}",
self.capacity
);
unsafe { FlatVector::with_capacity(self.child_ptr(idx), capacity) }
}
pub fn struct_vector_child(&self, idx: usize) -> StructVector<'a> {
unsafe { StructVector::from_raw_with_capacity(self.child_ptr(idx), self.capacity) }
}
pub fn list_vector_child(&self, idx: usize) -> ListVector<'a> {
unsafe { ListVector::from_raw_with_capacity(self.child_ptr(idx), self.capacity) }
}
pub fn array_vector_child(&self, idx: usize) -> ArrayVector<'a> {
unsafe { ArrayVector::from_raw_with_capacity(self.child_ptr(idx), self.capacity) }
}
pub(crate) fn child_ptr(&self, idx: usize) -> duckdb_vector {
unsafe { duckdb_struct_vector_get_child(self.ptr, idx as u64) }
}
pub fn logical_type(&self) -> LogicalTypeHandle {
unsafe { LogicalTypeHandle::new(duckdb_vector_get_column_type(self.ptr)) }
}
pub fn row_is_null(&self, row: u64) -> bool {
vector_row_is_null(self.ptr, row, self.capacity)
}
pub fn try_row_is_null(&self, row: u64) -> Result<bool> {
try_vector_row_is_null(self.ptr, row, self.capacity)
}
pub fn child_name(&self, idx: usize) -> DuckDbString {
let logical_type = self.logical_type();
unsafe {
let child_name_ptr = duckdb_struct_type_child_name(logical_type.ptr, idx as u64);
if child_name_ptr.is_null() {
panic!("child index {idx} out of range");
}
DuckDbString::from_ptr(child_name_ptr)
}
}
pub fn num_children(&self) -> usize {
let logical_type = self.logical_type();
unsafe { duckdb_struct_type_child_count(logical_type.ptr) as usize }
}
pub fn set_null(&mut self, row: usize) {
unsafe {
duckdb_vector_ensure_validity_writable(self.ptr);
let idx = duckdb_vector_get_validity(self.ptr);
duckdb_validity_set_row_invalid(idx, row as u64);
}
}
}