Skip to content

Commit

Permalink
Initial wrappers for Enumerations
Browse files Browse the repository at this point in the history
  • Loading branch information
davisp committed Mar 22, 2024
1 parent d1b95d1 commit 700213c
Show file tree
Hide file tree
Showing 9 changed files with 549 additions and 14 deletions.
262 changes: 262 additions & 0 deletions tiledb/api/src/array/enumeration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
use std::ops::Deref;

use crate::context::Context;
use crate::convert::{ToByteBuffer, ToOffsetsBuffer};
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<String> {
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<Datatype> {
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<u32> {
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<bool> {
Ok(self.cell_val_num()? == u32::MAX)
}

pub fn ordered(&self) -> TileDBResult<bool> {
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 struct Builder<'ctx> {
context: &'ctx Context,
name: String,
dtype: Datatype,
cell_val_num: u32,
ordered: bool,
data: Box<[u8]>,
offsets: Box<[u8]>,
}

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,
data: Default::default(),
offsets: Default::default(),
}
}

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 values<T: ToByteBuffer + ToOffsetsBuffer>(self, vals: T) -> Self {
let offsets = if self.cell_val_num == u32::MAX {
vals.to_offsets_buffer()
} else {
Default::default()
};
Self {
data: vals.to_byte_buffer(),
offsets,
..self
}
}

pub fn build(mut self) -> TileDBResult<Enumeration<'ctx>> {
let c_context = self.context.capi();
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();

let (offsets_ptr, offsets_size) = if self.cell_val_num == u32::MAX {
(self.offsets.as_mut_ptr(), self.offsets.len() as u64)
} else {
(std::ptr::null_mut(), 0u64)
};

// 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(
c_context,
c_name.as_c_str().as_ptr(),
c_dtype,
self.cell_val_num,
if self.ordered { 1 } else { 0 },
self.data.as_mut_ptr() as *const std::ffi::c_void,
self.data.len() as u64,
offsets_ptr as *const std::ffi::c_void,
offsets_size,
&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::*;

#[test]
fn basic_build() -> TileDBResult<()> {
let ctx = Context::new().expect("Error creating context instance.");
let enmr = Builder::new(&ctx, "foo", Datatype::Int32)
.values(&(vec![0, 1, 2, 3, 4])[..])
.build()
.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_build() -> TileDBResult<()> {
let ctx = Context::new().expect("Error creating context instance.");
let enmr = Builder::new(&ctx, "foo", Datatype::Int32)
.var_sized()
.values(&(vec![0, 1, 2, 3, 4])[..])
.build()
.expect("Error building enumeration.");

assert_eq!(enmr.name()?, "foo");
assert_eq!(enmr.datatype()?, Datatype::Int32);
assert_eq!(enmr.cell_val_num()?, u32::MAX);
assert!(!enmr.ordered()?);

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)
.values(&(vec![0, 1, 2, 3, 4])[..])
.build()
.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(())
}
}
2 changes: 2 additions & 0 deletions tiledb/api/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit 700213c

Please sign in to comment.