-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
549 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.