duckdb/core/vector/flat.rs
1use std::{ffi::CString, marker::PhantomData, slice};
2
3use crate::{
4 Result,
5 core::LogicalTypeHandle,
6 ffi::{
7 duckdb_validity_set_row_invalid, duckdb_vector, duckdb_vector_assign_string_element,
8 duckdb_vector_assign_string_element_len, duckdb_vector_ensure_validity_writable, duckdb_vector_get_column_type,
9 duckdb_vector_get_data, duckdb_vector_get_validity, duckdb_vector_size,
10 },
11};
12
13use super::{try_vector_row_is_null, vector_row_is_null};
14
15/// A flat (contiguous, scalar-row) vector borrowed from a
16/// [`DataChunkHandle`][crate::core::DataChunkHandle].
17pub struct FlatVector<'a> {
18 pub(super) ptr: duckdb_vector,
19 capacity: usize,
20 _phantom: PhantomData<&'a ()>,
21}
22
23impl<'a> FlatVector<'a> {
24 /// Wrap a raw `duckdb_vector` pointer.
25 ///
26 /// # Safety
27 /// `ptr` must be a valid `duckdb_vector` that remains valid for all of `'a`.
28 pub(crate) unsafe fn from_raw(ptr: duckdb_vector) -> Self {
29 Self {
30 ptr,
31 capacity: unsafe { duckdb_vector_size() as usize },
32 _phantom: PhantomData,
33 }
34 }
35
36 /// Wrap a raw vector pointer with a caller-supplied element capacity.
37 ///
38 /// # Safety
39 /// `ptr` must be a valid `duckdb_vector` that remains valid for all of `'a`.
40 /// The caller must ensure `capacity` does not exceed the backing allocation
41 /// for the logical view being exposed. Later typed slice and copy methods
42 /// trust this value for bounds checks.
43 pub(crate) unsafe fn with_capacity(ptr: duckdb_vector, capacity: usize) -> Self {
44 Self {
45 ptr,
46 capacity,
47 _phantom: PhantomData,
48 }
49 }
50
51 /// Returns the capacity of the vector
52 pub fn capacity(&self) -> usize {
53 self.capacity
54 }
55
56 #[cfg(feature = "vtab-arrow")]
57 pub(crate) fn ptr(&self) -> duckdb_vector {
58 self.ptr
59 }
60
61 /// Returns true if the row at the given index is null
62 ///
63 /// # Panics
64 /// Panics if `row` is outside the vector capacity.
65 pub fn row_is_null(&self, row: u64) -> bool {
66 vector_row_is_null(self.ptr, row, self.capacity)
67 }
68
69 /// Returns whether the row is null, or an error if it is out of range.
70 pub fn try_row_is_null(&self, row: u64) -> Result<bool> {
71 try_vector_row_is_null(self.ptr, row, self.capacity)
72 }
73
74 /// Returns a mutable pointer to the vector's backing data cast to `T`.
75 ///
76 /// # Safety
77 /// The caller must ensure `T` matches the DuckDB vector's physical storage.
78 /// Before dereferencing the pointer, the caller must also ensure the target
79 /// element is initialized, in bounds, and not accessed through another
80 /// incompatible or aliased reference.
81 pub unsafe fn as_mut_ptr<T>(&self) -> *mut T {
82 unsafe { duckdb_vector_get_data(self.ptr).cast() }
83 }
84
85 /// Returns a typed slice of the vector.
86 ///
87 /// # Safety
88 /// The caller must ensure `T` matches the DuckDB vector's physical storage,
89 /// the backing allocation is sized for `self.capacity()` elements of `T`,
90 /// each returned element is initialized before it is read, and no `&mut`
91 /// references to the same storage exist for the returned lifetime.
92 pub unsafe fn as_slice<T>(&self) -> &[T] {
93 unsafe { slice::from_raw_parts(self.as_mut_ptr(), self.capacity()) }
94 }
95
96 /// Returns a typed slice of the vector up to a certain length.
97 ///
98 /// # Safety
99 /// The caller must ensure `T` matches the DuckDB vector's physical storage,
100 /// the backing allocation is sized for at least `len` elements of `T`, each
101 /// returned element is initialized before it is read, and no `&mut`
102 /// references to the same storage exist for the returned lifetime.
103 pub unsafe fn as_slice_with_len<T>(&self, len: usize) -> &[T] {
104 unsafe { slice::from_raw_parts(self.as_mut_ptr(), len) }
105 }
106
107 /// Returns a typed mutable slice of the vector.
108 ///
109 /// # Safety
110 /// The caller must ensure `T` matches the DuckDB vector's physical storage,
111 /// the backing allocation is sized for `self.capacity()` elements of `T`,
112 /// and no other references to the same storage exist for the returned
113 /// lifetime.
114 pub unsafe fn as_mut_slice<T>(&mut self) -> &mut [T] {
115 unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.capacity()) }
116 }
117
118 /// Returns a typed mutable slice of the vector up to a certain length.
119 ///
120 /// # Safety
121 /// The caller must ensure `T` matches the DuckDB vector's physical storage,
122 /// the backing allocation is sized for at least `len` elements of `T`, and
123 /// no other references to the same storage exist for the returned lifetime.
124 pub unsafe fn as_mut_slice_with_len<T>(&mut self, len: usize) -> &mut [T] {
125 unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), len) }
126 }
127
128 /// Returns the logical type of the vector
129 pub fn logical_type(&self) -> LogicalTypeHandle {
130 unsafe { LogicalTypeHandle::new(duckdb_vector_get_column_type(self.ptr)) }
131 }
132
133 /// Set row as null
134 pub fn set_null(&mut self, row: usize) {
135 unsafe {
136 duckdb_vector_ensure_validity_writable(self.ptr);
137 let idx = duckdb_vector_get_validity(self.ptr);
138 duckdb_validity_set_row_invalid(idx, row as u64);
139 }
140 }
141
142 /// Copy typed data to the vector.
143 ///
144 /// # Safety
145 /// The caller must ensure `T` matches the DuckDB vector's physical storage
146 /// and no other references to the same storage exist during the copy.
147 ///
148 /// # Panics
149 /// Panics if `data.len()` exceeds the vector capacity.
150 pub unsafe fn copy<T: Copy>(&mut self, data: &[T]) {
151 assert!(data.len() <= self.capacity());
152 (unsafe { self.as_mut_slice::<T>() })[0..data.len()].copy_from_slice(data);
153 }
154}
155
156/// A trait for inserting data into a vector.
157pub trait Inserter<T> {
158 /// Insert a value into the vector.
159 fn insert(&self, index: usize, value: T);
160}
161
162impl Inserter<CString> for FlatVector<'_> {
163 fn insert(&self, index: usize, value: CString) {
164 unsafe {
165 duckdb_vector_assign_string_element(self.ptr, index as u64, value.as_ptr());
166 }
167 }
168}
169
170impl Inserter<&str> for FlatVector<'_> {
171 fn insert(&self, index: usize, value: &str) {
172 self.insert(index, value.as_bytes());
173 }
174}
175
176impl Inserter<&String> for FlatVector<'_> {
177 fn insert(&self, index: usize, value: &String) {
178 self.insert(index, value.as_str());
179 }
180}
181
182impl Inserter<&[u8]> for FlatVector<'_> {
183 fn insert(&self, index: usize, value: &[u8]) {
184 let value_size = value.len();
185 unsafe {
186 // This function also works for binary data. https://duckdb.org/docs/api/c/api#duckdb_vector_assign_string_element_len
187 duckdb_vector_assign_string_element_len(
188 self.ptr,
189 index as u64,
190 value.as_ptr() as *const ::std::os::raw::c_char,
191 value_size as u64,
192 );
193 }
194 }
195}
196
197impl Inserter<&Vec<u8>> for FlatVector<'_> {
198 fn insert(&self, index: usize, value: &Vec<u8>) {
199 self.insert(index, value.as_slice());
200 }
201}