diff --git a/tiledb/api/src/array/enumeration.rs b/tiledb/api/src/array/enumeration.rs new file mode 100644 index 00000000..138bb849 --- /dev/null +++ b/tiledb/api/src/array/enumeration.rs @@ -0,0 +1,387 @@ +use std::fmt::{self, Debug, Formatter, Result as FmtResult}; +use std::ops::Deref; + +use serde_json::json; + +use crate::column::Column; +use crate::context::Context; +use crate::string::{RawTDBString, TDBString}; +use crate::Datatype; +use crate::Result as TileDBResult; + +pub(crate) enum RawEnumeration { + Owned(*mut ffi::tiledb_enumeration_t), +} + +impl Deref for RawEnumeration { + type Target = *mut ffi::tiledb_enumeration_t; + fn deref(&self) -> &Self::Target { + let RawEnumeration::Owned(ref ffi) = *self; + ffi + } +} + +impl Drop for RawEnumeration { + fn drop(&mut self) { + let RawEnumeration::Owned(ref mut ffi) = *self; + unsafe { + ffi::tiledb_enumeration_free(ffi); + } + } +} + +pub struct Enumeration<'ctx> { + pub(crate) context: &'ctx Context, + pub(crate) raw: RawEnumeration, +} + +impl<'ctx> Enumeration<'ctx> { + pub(crate) fn capi(&self) -> *mut ffi::tiledb_enumeration_t { + *self.raw + } + + pub fn name(&self) -> TileDBResult { + let mut c_str: *mut ffi::tiledb_string_t = out_ptr!(); + let res = unsafe { + ffi::tiledb_enumeration_get_name( + self.context.capi(), + self.capi(), + &mut c_str, + ) + }; + if res == ffi::TILEDB_OK { + let tdb_str = TDBString { + raw: RawTDBString::Owned(c_str), + }; + tdb_str.to_string() + } else { + Err(self.context.expect_last_error()) + } + } + + pub fn datatype(&self) -> TileDBResult { + let mut dtype: ffi::tiledb_datatype_t = 0; + let res = unsafe { + ffi::tiledb_enumeration_get_type( + self.context.capi(), + self.capi(), + &mut dtype, + ) + }; + if res == ffi::TILEDB_OK { + Ok(Datatype::from_capi_enum(dtype)) + } else { + Err(self.context.expect_last_error()) + } + } + + pub fn cell_val_num(&self) -> TileDBResult { + let mut c_cvn: u32 = 0; + let res = unsafe { + ffi::tiledb_enumeration_get_cell_val_num( + self.context.capi(), + self.capi(), + &mut c_cvn, + ) + }; + if res == ffi::TILEDB_OK { + Ok(c_cvn) + } else { + Err(self.context.expect_last_error()) + } + } + + pub fn is_var_sized(&self) -> TileDBResult { + Ok(self.cell_val_num()? == u32::MAX) + } + + pub fn ordered(&self) -> TileDBResult { + let mut c_ordered: i32 = 0; + let res = unsafe { + ffi::tiledb_enumeration_get_ordered( + self.context.capi(), + self.capi(), + &mut c_ordered, + ) + }; + if res == ffi::TILEDB_OK { + Ok(c_ordered != 0) + } else { + Err(self.context.expect_last_error()) + } + } + + pub fn extend(&self, column: Column) -> TileDBResult> { + let mut c_new_enmr: *mut ffi::tiledb_enumeration_t = out_ptr!(); + + // Rust semantics require that slice pointers aren't nullptr so that + // nullptr can be used to distinguish between Some and None. The stdlib + // empty slices all appear to return 0x1 which is mentioned in the docs + // as a valid strategy. For our situation, we just use a zero length to + // indicate when we should pass nullptr. + let offsets_ptr = if column.offsets().is_empty() { + std::ptr::null_mut() + } else { + column.offsets().as_ptr() + }; + + // An important note here is that the Enumeration allocator copies the + // contents of data of offsets rather than assumes ownership. That + // means this is safe as those bytes are guaranteed to be alive until + // we drop self at the end of this method after returning from + // tiledb_enumeration_alloc. + let res = unsafe { + ffi::tiledb_enumeration_extend( + self.context.capi(), + self.capi(), + column.data().as_ptr() as *const std::ffi::c_void, + column.data().len() as u64, + offsets_ptr as *const std::ffi::c_void, + column.offsets().len() as u64, + &mut c_new_enmr, + ) + }; + + if res == ffi::TILEDB_OK { + Ok(Enumeration { + context: self.context, + raw: RawEnumeration::Owned(c_new_enmr), + }) + } else { + Err(self.context.expect_last_error()) + } + } +} + +impl<'ctx> Debug for Enumeration<'ctx> { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + let name = self.name().map_err(|_| fmt::Error)?; + let dtype = self + .datatype() + .map_err(|_| fmt::Error)? + .to_string() + .unwrap_or("".to_owned()); + let cell_val_num = self.cell_val_num().map_err(|_| fmt::Error)?; + let ordered = self.ordered().map_err(|_| fmt::Error)?; + + // TODO: Add enumeration values display. + + let json = json!({ + "name": name, + "datatype": dtype, + "cell_val_num": cell_val_num, + "ordered": ordered + }); + write!(f, "{}", json) + } +} + +impl<'c1, 'c2> PartialEq> for Enumeration<'c1> { + fn eq(&self, other: &Enumeration<'c2>) -> bool { + let names_match = match (self.name(), other.name()) { + (Ok(mine), Ok(theirs)) => mine == theirs, + _ => false, + }; + if !names_match { + return false; + } + + let types_match = match (self.datatype(), other.datatype()) { + (Ok(mine), Ok(theirs)) => mine == theirs, + _ => false, + }; + if !types_match { + return false; + } + + let cell_val_num_match = + match (self.cell_val_num(), other.cell_val_num()) { + (Ok(mine), Ok(theirs)) => mine == theirs, + _ => false, + }; + if !cell_val_num_match { + return false; + } + + let ordered_match = match (self.ordered(), other.ordered()) { + (Ok(mine), Ok(theirs)) => mine == theirs, + _ => false, + }; + if !ordered_match { + return false; + } + + // TODO: Match data and offsets + + true + } +} + +pub struct Builder<'ctx> { + context: &'ctx Context, + name: String, + dtype: Datatype, + cell_val_num: u32, + ordered: bool, +} + +impl<'ctx> Builder<'ctx> { + pub fn new(context: &'ctx Context, name: &str, dtype: Datatype) -> Self { + Builder { + context, + name: name.to_owned(), + dtype, + cell_val_num: 1, + ordered: false, + } + } + + pub fn cell_val_num(self, cell_val_num: u32) -> Self { + Self { + cell_val_num, + ..self + } + } + + pub fn var_sized(self) -> Self { + Self { + cell_val_num: u32::MAX, + ..self + } + } + + pub fn ordered(self, ordered: bool) -> Self { + Self { ordered, ..self } + } + + pub fn build(self, column: Column) -> TileDBResult> { + let mut c_enmr: *mut ffi::tiledb_enumeration_t = out_ptr!(); + let name_bytes = self.name.as_bytes(); + let c_name = cstring!(name_bytes); + let c_dtype = self.dtype.capi_enum(); + + // Rust semantics require that slice pointers aren't nullptr so that + // nullptr can be used to distinguish between Some and None. The stdlib + // empty slices all appear to return 0x1 which is mentioned in the docs + // as a valid strategy. For our situation, we just use a zero length to + // indicate when we should pass nullptr. + let offsets_ptr = if column.offsets().is_empty() { + std::ptr::null_mut() + } else { + column.offsets().as_ptr() + }; + + // An important note here is that the Enumeration allocator copies the + // contents of data of offsets rather than assumes ownership. That + // means this is safe as those bytes are guaranteed to be alive until + // we drop self at the end of this method after returning from + // tiledb_enumeration_alloc. + let res = unsafe { + ffi::tiledb_enumeration_alloc( + self.context.capi(), + c_name.as_c_str().as_ptr(), + c_dtype, + self.cell_val_num, + if self.ordered { 1 } else { 0 }, + column.data().as_ptr() as *const std::ffi::c_void, + column.data().len() as u64, + offsets_ptr as *const std::ffi::c_void, + column.offsets().len() as u64, + &mut c_enmr, + ) + }; + + if res == ffi::TILEDB_OK { + Ok(Enumeration { + context: self.context, + raw: RawEnumeration::Owned(c_enmr), + }) + } else { + Err(self.context.expect_last_error()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::column::AsColumn; + + #[test] + fn basic_build() -> TileDBResult<()> { + let ctx = Context::new().expect("Error creating context instance."); + let enmr = Builder::new(&ctx, "foo", Datatype::Int32) + .build(vec![0, 1, 2, 3, 4].as_column()) + .expect("Error building enumeration."); + + assert_eq!(enmr.name()?, "foo"); + assert_eq!(enmr.datatype()?, Datatype::Int32); + assert_eq!(enmr.cell_val_num()?, 1); + assert!(!enmr.ordered()?); + + Ok(()) + } + + #[test] + fn var_sized_error_build() -> TileDBResult<()> { + let ctx = Context::new().expect("Error creating context instance."); + let enmr_res = Builder::new(&ctx, "foo", Datatype::Int32) + .var_sized() + .build(vec![0u8, 1, 2, 3, 4].as_column()); + + assert!(enmr_res.is_err()); + + Ok(()) + } + + #[test] + fn ordered_build() -> TileDBResult<()> { + let ctx = Context::new().expect("Error creating context instance."); + let enmr = Builder::new(&ctx, "foo", Datatype::Int32) + .ordered(true) + .build(vec![0, 1, 2, 3, 4].as_column()) + .expect("Error building enumeration."); + + assert_eq!(enmr.name()?, "foo"); + assert_eq!(enmr.datatype()?, Datatype::Int32); + assert_eq!(enmr.cell_val_num()?, 1); + assert!(enmr.ordered()?); + + Ok(()) + } + + #[test] + fn string_build() -> TileDBResult<()> { + let ctx = Context::new().expect("Error creating context instance."); + let enmr = Builder::new(&ctx, "foo", Datatype::StringAscii) + .var_sized() + .build(vec!["foo", "bar", "baz", "bam", "mam"].as_column()) + .expect("Error building enumeration."); + + assert_eq!(enmr.name()?, "foo"); + assert_eq!(enmr.datatype()?, Datatype::StringAscii); + assert_eq!(enmr.cell_val_num()?, u32::MAX); + assert!(!enmr.ordered()?); + + Ok(()) + } + + #[test] + fn extend_enumeration() -> TileDBResult<()> { + let ctx = Context::new().expect("Error creating context instance."); + let enmr1 = Builder::new(&ctx, "foo", Datatype::Int32) + .build(vec![1, 2, 3, 4, 5].as_column()) + .expect("Error building enumeration."); + + let enmr2 = enmr1 + .extend(vec![6, 7, 8, 9, 10].as_column()) + .expect("Error extending enumeration."); + + assert_eq!(enmr1.name()?, enmr2.name()?); + assert_eq!(enmr1.datatype()?, enmr2.datatype()?); + assert_eq!(enmr1.cell_val_num()?, enmr2.cell_val_num()?); + assert_eq!(enmr1.ordered()?, enmr2.ordered()?); + + Ok(()) + } +} diff --git a/tiledb/api/src/array/mod.rs b/tiledb/api/src/array/mod.rs index f8911b7e..969e36bb 100644 --- a/tiledb/api/src/array/mod.rs +++ b/tiledb/api/src/array/mod.rs @@ -7,11 +7,13 @@ use crate::Result as TileDBResult; mod attribute; mod dimension; mod domain; +mod enumeration; mod schema; pub use attribute::{Attribute, Builder as AttributeBuilder}; pub use dimension::{Builder as DimensionBuilder, Dimension}; pub use domain::{Builder as DomainBuilder, Domain}; +pub use enumeration::{Builder as EnumerationBuilder, Enumeration}; pub use schema::{ArrayType, Builder as SchemaBuilder, Schema}; pub enum Mode { diff --git a/tiledb/api/src/column.rs b/tiledb/api/src/column.rs new file mode 100644 index 00000000..ec4bc486 --- /dev/null +++ b/tiledb/api/src/column.rs @@ -0,0 +1,245 @@ +/// The ReferenceColumn is used when we can safely use the existing Vec's or +/// slices being used to create a column. This avoids the allocation, copy, and +/// eventual deallocation when providing column data to TileDB. +pub struct ReferenceColumn<'data> { + num_values: u64, + value_size: u64, + data: &'data [u8], + offsets: &'data [u8], +} + +/// If a column requires allocating a linearized buffer (i.e., when passing a +/// Vec or slice of AsRef values), this structure is used to hold the +/// allocated buffers. +pub struct AllocatedColumn { + num_values: u64, + value_size: u64, + data: Box<[u8]>, + offsets: Box<[u64]>, +} + +/// The Column struct is used to represent a column of data in TileDB. A column +/// contains a required data slice and an optional offsets slice when the +/// underlying column definition has a variable number of values per cell. +/// +/// An AsColumn trait is provided for a number of common use cases such that +/// users should be able to pass common instances directly as arguments that +/// have the Column type. +pub enum Column<'data> { + Referenced(ReferenceColumn<'data>), + Allocated(AllocatedColumn), +} + +impl<'data> Column<'data> { + pub fn num_values(&self) -> u64 { + match self { + Column::Referenced(col) => col.num_values, + Column::Allocated(col) => col.num_values, + } + } + + pub fn value_size(&self) -> u64 { + match self { + Column::Referenced(col) => col.value_size, + Column::Allocated(col) => col.value_size, + } + } + + pub fn data(&self) -> &[u8] { + match self { + Column::Referenced(col) => col.data, + Column::Allocated(col) => &col.data[..], + } + } + + pub fn offsets(&self) -> &[u8] { + match self { + Column::Referenced(col) => col.offsets, + Column::Allocated(col) => { + let num_bytes = + self.num_values() as usize * std::mem::size_of::(); + unsafe { + std::slice::from_raw_parts( + col.offsets.as_ptr() as *const u8, + num_bytes, + ) + } + } + } + } + + pub fn is_allocated(&self) -> bool { + match self { + Column::Referenced(_) => false, + Column::Allocated(_) => true, + } + } +} + +/// The AsColumn trait provides an auto-conversion from common datatypes into +/// the columnar format used by TileDB. +/// +/// There are three type "patterns" that fit into the auto conversion scheme. +/// +/// 1. The simplest is a Vec or slice of primitive values. This mode can be +/// used for any non-variable sized cell type, even multi-value cells. The +/// length of the Vec or slice must be a multiple of the cell value num. +/// +/// 2. The second most common is for string based data. This allows users to +/// pass a Vec or slice of `AsRef` instances which are then transformed +/// into the correct data and offsets buffers. This method allocates memory +/// to hold the linearized data buffer and offsets buffer. +/// +/// 3. The third is a pair of Vec's or slices where the first is the contents +/// of the data buffer and the second is a `Vec` or `&[u64]` that +/// contains the offsets for each var sized cell. Generally speaking this +/// is an uncommon use case when users need a variable sized cell that is +/// not a string. +pub trait AsColumn<'data> { + fn as_column(&'data self) -> Column<'data>; +} + +// Conversion for Vec or slices of primitive values for non-variadic columns. +macro_rules! derive_primitive_as_column { + ($typename:ty) => { + impl<'data> AsColumn<'data> for &'data [$typename] { + fn as_column(&self) -> Column<'data> { + let num_bytes = self.len() * std::mem::size_of::<$typename>(); + let data = unsafe { + std::slice::from_raw_parts( + self.as_ptr() as *const u8, + num_bytes, + ) + }; + + Column::Referenced(ReferenceColumn { + num_values: self.len() as u64, + value_size: std::mem::size_of::<$typename>() as u64, + data, + offsets: &[0u8; 0], + }) + } + } + + impl<'data> AsColumn<'data> for Vec<$typename> { + fn as_column(&self) -> Column<'data> { + let num_bytes = self.len() * std::mem::size_of::<$typename>(); + let data = unsafe { + std::slice::from_raw_parts( + self.as_ptr() as *const u8, + num_bytes, + ) + }; + + Column::Referenced(ReferenceColumn { + num_values: self.len() as u64, + value_size: std::mem::size_of::<$typename>() as u64, + data, + offsets: &[0u8; 0], + }) + } + } + }; +} + +derive_primitive_as_column!(u8); +derive_primitive_as_column!(u16); +derive_primitive_as_column!(u32); +derive_primitive_as_column!(u64); +derive_primitive_as_column!(i8); +derive_primitive_as_column!(i16); +derive_primitive_as_column!(i32); +derive_primitive_as_column!(i64); +derive_primitive_as_column!(f32); +derive_primitive_as_column!(f64); + +// I couldn't figure out how to derive directly from the AsRef so I've +// made this for now. Ideally we could just implement two for Vec> +// and &[AsRef]. Rather than beat my head against it I'm moving on. +macro_rules! derive_strings_as_column { + ($typename:ty) => { + impl AsColumn<'_> for &[$typename] { + fn as_column(&self) -> Column { + let (data, offsets) = strings_to_buffers(self); + Column::Allocated(AllocatedColumn { + num_values: self.len() as u64, + value_size: 1, + data, + offsets, + }) + } + } + + impl AsColumn<'_> for Vec<$typename> { + fn as_column(&self) -> Column { + let (data, offsets) = strings_to_buffers(self); + Column::Allocated(AllocatedColumn { + num_values: self.len() as u64, + value_size: 1, + data, + offsets, + }) + } + } + }; +} + +derive_strings_as_column!(&str); +derive_strings_as_column!(&String); +derive_strings_as_column!(String); + +// Internal helper to convert a slice of strings to a single linear data buffer +// and an offsets buffer. +fn strings_to_buffers(vals: &[impl AsRef]) -> (Box<[u8]>, Box<[u64]>) { + let mut num_bytes: usize = 0; + for val in vals { + num_bytes += val.as_ref().len(); + } + + let mut data: Box<[u8]> = vec![0; num_bytes].into_boxed_slice(); + let mut offsets: Box<[u64]> = vec![0; vals.len()].into_boxed_slice(); + + let mut offset: usize = 0; + for (idx, val) in vals.iter().enumerate() { + let len = val.as_ref().len(); + data[offset..(offset + len)].copy_from_slice(val.as_ref().as_bytes()); + offsets[idx] = offset as u64; + offset += len; + } + + (data, offsets) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn u32_test() { + let data = vec![1u32, 2, 3, 4, 5]; + let col = data.as_column(); + assert_eq!(col.num_values(), 5); + assert_eq!(col.value_size(), std::mem::size_of::() as u64); + assert_eq!(col.data().len(), 5 * std::mem::size_of::()); + assert_eq!(col.data()[0], 1u8); + assert_eq!(col.data()[16], 5u8); + assert_eq!(col.offsets().len(), 0); + assert!(!col.is_allocated()); + } + + #[test] + fn str_test() { + let data = vec!["foo", "bar", "baz", "bing"]; + let col = data.as_column(); + assert_eq!(col.num_values(), 4); + assert_eq!(col.value_size(), 1); + assert_eq!(col.data().len(), 13); + assert_eq!(col.data()[0], b'f'); + assert_eq!(col.data()[6], b'b'); + assert_eq!(col.data()[7], b'a'); + assert_eq!(col.data()[8], b'z'); + assert_eq!(col.offsets().len(), 4 * std::mem::size_of::()); + assert_eq!(col.offsets()[8], 3u8); + assert!(col.is_allocated()); + } +} diff --git a/tiledb/api/src/lib.rs b/tiledb/api/src/lib.rs index 7f1c5f74..a5eaf74d 100644 --- a/tiledb/api/src/lib.rs +++ b/tiledb/api/src/lib.rs @@ -23,6 +23,7 @@ macro_rules! out_ptr { } pub mod array; +pub mod column; pub mod config; pub mod context; pub mod convert; diff --git a/tiledb/api/src/string.rs b/tiledb/api/src/string.rs index b7227113..87594332 100644 --- a/tiledb/api/src/string.rs +++ b/tiledb/api/src/string.rs @@ -1,24 +1,58 @@ -extern crate tiledb_sys as ffi; +use std::ops::Deref; -pub struct String { - _wrapped: *mut ffi::tiledb_string_t, +use crate::error::Error; +use crate::Result as TileDBResult; + +pub(crate) enum RawTDBString { + Owned(*mut ffi::tiledb_string_t), } -impl Default for String { - fn default() -> String { - Self { - _wrapped: std::ptr::null_mut::(), - } +impl Deref for RawTDBString { + type Target = *mut ffi::tiledb_string_t; + fn deref(&self) -> &Self::Target { + let RawTDBString::Owned(ref ffi) = *self; + ffi } } -impl Drop for String { +impl Drop for RawTDBString { fn drop(&mut self) { - if self._wrapped.is_null() { - return; - } + let RawTDBString::Owned(ref mut ffi) = *self; unsafe { - ffi::tiledb_string_free(&mut self._wrapped); + ffi::tiledb_string_free(ffi); + } + } +} + +pub struct TDBString { + pub(crate) raw: RawTDBString, +} + +impl TDBString { + pub fn to_string(&self) -> TileDBResult { + let mut c_str = std::ptr::null::(); + let mut c_len: usize = 0; + + let res = unsafe { + ffi::tiledb_string_view( + *self.raw, + &mut c_str as *mut *const u8, + &mut c_len, + ) + }; + + if res == ffi::TILEDB_OK { + let raw_slice: &[u8] = + unsafe { std::slice::from_raw_parts(c_str, c_len) }; + let c_str = std::str::from_utf8(raw_slice).map_err(|e| { + Error::from(format!( + "Core returned a string that is not UTF-8: {}", + e + )) + })?; + Ok(c_str.to_owned()) + } else { + Err(Error::from("Error getting string view from core.")) } } } diff --git a/tiledb/sys/src/enumeration.rs b/tiledb/sys/src/enumeration.rs new file mode 100644 index 00000000..c4e7a0dc --- /dev/null +++ b/tiledb/sys/src/enumeration.rs @@ -0,0 +1,69 @@ +use crate::datatype::tiledb_datatype_t; +use crate::types::{ + capi_return_t, tiledb_ctx_t, tiledb_enumeration_t, tiledb_string_t, +}; + +extern "C" { + pub fn tiledb_enumeration_alloc( + ctx: *mut tiledb_ctx_t, + name: *const ::std::os::raw::c_char, + type_: tiledb_datatype_t, + cell_val_num: u32, + ordered: ::std::os::raw::c_int, + data: *const ::std::os::raw::c_void, + data_size: u64, + offsets: *const ::std::os::raw::c_void, + offsets_size: u64, + enumeration: *mut *mut tiledb_enumeration_t, + ) -> capi_return_t; + + pub fn tiledb_enumeration_free(enumeration: *mut *mut tiledb_enumeration_t); + + pub fn tiledb_enumeration_extend( + ctx: *mut tiledb_ctx_t, + old_enumeration: *mut tiledb_enumeration_t, + data: *const ::std::os::raw::c_void, + data_size: u64, + offsets: *const ::std::os::raw::c_void, + offsets_size: u64, + new_enumeration: *mut *mut tiledb_enumeration_t, + ) -> capi_return_t; + + pub fn tiledb_enumeration_get_name( + ctx: *mut tiledb_ctx_t, + enumeration: *mut tiledb_enumeration_t, + name: *mut *mut tiledb_string_t, + ) -> capi_return_t; + + pub fn tiledb_enumeration_get_type( + ctx: *mut tiledb_ctx_t, + enumeration: *mut tiledb_enumeration_t, + type_: *mut tiledb_datatype_t, + ) -> capi_return_t; + + pub fn tiledb_enumeration_get_cell_val_num( + ctx: *mut tiledb_ctx_t, + enumeration: *mut tiledb_enumeration_t, + cell_val_num: *mut u32, + ) -> capi_return_t; + + pub fn tiledb_enumeration_get_ordered( + ctx: *mut tiledb_ctx_t, + enumeration: *mut tiledb_enumeration_t, + ordered: *mut ::std::os::raw::c_int, + ) -> capi_return_t; + + pub fn tiledb_enumeration_get_data( + ctx: *mut tiledb_ctx_t, + enumeration: *mut tiledb_enumeration_t, + data: *mut *const ::std::os::raw::c_void, + data_size: *mut u64, + ) -> capi_return_t; + + pub fn tiledb_enumeration_get_offsets( + ctx: *mut tiledb_ctx_t, + enumeration: *mut tiledb_enumeration_t, + offsets: *mut *const ::std::os::raw::c_void, + offsets_size: *mut u64, + ) -> capi_return_t; +} diff --git a/tiledb/sys/src/lib.rs b/tiledb/sys/src/lib.rs index deb81a5d..d417d6b5 100644 --- a/tiledb/sys/src/lib.rs +++ b/tiledb/sys/src/lib.rs @@ -11,6 +11,7 @@ mod context; mod datatype; mod dimension; mod domain; +mod enumeration; mod error; mod filesystem; mod filter; @@ -35,6 +36,7 @@ pub use context::*; pub use datatype::*; pub use dimension::*; pub use domain::*; +pub use enumeration::*; pub use error::*; pub use filesystem::*; pub use filter::*; diff --git a/tiledb/sys/src/string.rs b/tiledb/sys/src/string.rs index d060c189..87f0d51a 100644 --- a/tiledb/sys/src/string.rs +++ b/tiledb/sys/src/string.rs @@ -4,7 +4,7 @@ use crate::types::tiledb_string_t; extern "C" { pub fn tiledb_string_view( s: *mut tiledb_string_t, - data: *mut *const ::std::os::raw::c_char, + data: *mut *const ::std::os::raw::c_uchar, length: *mut usize, ) -> capi_return_t; diff --git a/tiledb/sys/src/types.rs b/tiledb/sys/src/types.rs index 2e32fcf6..84b6bbc1 100644 --- a/tiledb/sys/src/types.rs +++ b/tiledb/sys/src/types.rs @@ -51,6 +51,12 @@ pub struct tiledb_domain_t { _unused: [u8; 0], } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct tiledb_enumeration_t { + _unused: [u8; 0], +} + #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct tiledb_error_t { diff --git a/tiledb/sys/wrapper.h b/tiledb/sys/wrapper.h index 319eb6ef..aba4bd3e 100644 --- a/tiledb/sys/wrapper.h +++ b/tiledb/sys/wrapper.h @@ -1,2 +1,3 @@ #include #include +#include