From 41e8d5f388b53661c68d1b99ee669c2425d41c9c Mon Sep 17 00:00:00 2001 From: Ryan Roelke Date: Fri, 2 Aug 2024 18:19:28 -0400 Subject: [PATCH 1/2] Query API borrows array instead of consuming it --- tiledb/api/examples/fragment_info.rs | 4 +- tiledb/api/examples/multi_range_subarray.rs | 6 +- tiledb/api/examples/query_condition_dense.rs | 6 +- tiledb/api/examples/query_condition_sparse.rs | 6 +- tiledb/api/examples/quickstart_dense.rs | 6 +- .../api/examples/quickstart_sparse_string.rs | 6 +- tiledb/api/examples/reading_incomplete.rs | 29 +++++---- tiledb/api/examples/using_tiledb_stats.rs | 6 +- tiledb/api/src/array/fragment_info.rs | 11 ++-- tiledb/api/src/array/mod.rs | 4 +- tiledb/api/src/query/mod.rs | 50 +++++++-------- tiledb/api/src/query/read/callback.rs | 50 ++++++++------- tiledb/api/src/query/read/mod.rs | 32 +++++----- tiledb/api/src/query/read/raw.rs | 55 ++++++++-------- tiledb/api/src/query/read/typed.rs | 23 +++---- tiledb/api/src/query/strategy.rs | 10 +-- tiledb/api/src/query/subarray.rs | 25 ++++---- tiledb/api/src/query/write/mod.rs | 30 ++++----- tiledb/api/src/query/write/strategy.rs | 64 +++++++++---------- 19 files changed, 216 insertions(+), 207 deletions(-) diff --git a/tiledb/api/examples/fragment_info.rs b/tiledb/api/examples/fragment_info.rs index 7c2a7737..2478aea0 100644 --- a/tiledb/api/examples/fragment_info.rs +++ b/tiledb/api/examples/fragment_info.rs @@ -148,7 +148,7 @@ fn create_array() -> TileDBResult<()> { fn write_array() -> TileDBResult<()> { let tdb = tiledb::context::Context::new()?; - let array = tiledb::Array::open( + let mut array = tiledb::Array::open( &tdb, FRAGMENT_INFO_ARRAY_URI, tiledb::array::Mode::Write, @@ -156,7 +156,7 @@ fn write_array() -> TileDBResult<()> { let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - let query = tiledb::query::WriteBuilder::new(array)? + let query = tiledb::query::WriteBuilder::new(&mut array)? .layout(tiledb::query::QueryLayout::RowMajor)? .data_typed(FRAGMENT_INFO_ATTRIBUTE_NAME, &data)? .build(); diff --git a/tiledb/api/examples/multi_range_subarray.rs b/tiledb/api/examples/multi_range_subarray.rs index 370cfa42..84d691f6 100644 --- a/tiledb/api/examples/multi_range_subarray.rs +++ b/tiledb/api/examples/multi_range_subarray.rs @@ -55,7 +55,7 @@ fn main() -> TileDBResult<()> { } let array = Array::open(&ctx, ARRAY_URI, tiledb::array::Mode::Read)?; - let mut query = ReadBuilder::new(array)? + let mut query = ReadBuilder::new(&array)? .layout(tiledb::query::QueryLayout::RowMajor)? .register_constructor::<_, Vec>("rows", Default::default())? .register_constructor::<_, Vec>("cols", Default::default())? @@ -117,10 +117,10 @@ fn create_array(ctx: &Context) -> TileDBResult<()> { fn write_array(ctx: &Context) -> TileDBResult<()> { let data = vec![1i32, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - let array = + let mut array = tiledb::Array::open(ctx, ARRAY_URI, tiledb::array::Mode::Write)?; - let query = WriteBuilder::new(array)? + let query = WriteBuilder::new(&mut array)? .layout(CellOrder::RowMajor)? .data_typed("a", &data)? .build(); diff --git a/tiledb/api/examples/query_condition_dense.rs b/tiledb/api/examples/query_condition_dense.rs index d37c3c24..7559a99e 100644 --- a/tiledb/api/examples/query_condition_dense.rs +++ b/tiledb/api/examples/query_condition_dense.rs @@ -66,7 +66,7 @@ fn main() -> TileDBResult<()> { /// to stdout. fn read_array(ctx: &Context, qc: Option) -> TileDBResult<()> { let array = tiledb::Array::open(ctx, ARRAY_URI, tiledb::array::Mode::Read)?; - let mut query = ReadBuilder::new(array)? + let mut query = ReadBuilder::new(&array)? .layout(tiledb::query::QueryLayout::RowMajor)? .register_constructor::<_, Vec>("index", Default::default())? .register_constructor::<_, (Vec, Vec)>( @@ -182,10 +182,10 @@ fn write_array(ctx: &Context) -> TileDBResult<()> { let c_input = vec![0i32, 0, 0, 0, 0, 0, 1, 2, 3, 4]; let d_input = vec![4.1f32, 3.4, 5.6, 3.7, 2.3, 1.7, 3.8, 4.9, 3.2, 3.1]; - let array = + let mut array = tiledb::Array::open(ctx, ARRAY_URI, tiledb::array::Mode::Write)?; - let query = WriteBuilder::new(array)? + let query = WriteBuilder::new(&mut array)? .data_typed("a", &a_input)? .data_typed("b", &b_input)? .data_typed("c", &c_input)? diff --git a/tiledb/api/examples/query_condition_sparse.rs b/tiledb/api/examples/query_condition_sparse.rs index d656bcf5..457bb6f9 100644 --- a/tiledb/api/examples/query_condition_sparse.rs +++ b/tiledb/api/examples/query_condition_sparse.rs @@ -66,7 +66,7 @@ fn main() -> TileDBResult<()> { /// to stdout. fn read_array(ctx: &Context, qc: Option) -> TileDBResult<()> { let array = tiledb::Array::open(ctx, ARRAY_URI, tiledb::array::Mode::Read)?; - let mut query = ReadBuilder::new(array)? + let mut query = ReadBuilder::new(&array)? .layout(tiledb::query::QueryLayout::RowMajor)? .register_constructor::<_, Vec>("index", Default::default())? .register_constructor::<_, (Vec, Vec)>( @@ -184,10 +184,10 @@ fn write_array(ctx: &Context) -> TileDBResult<()> { let c_input = vec![0i32, 0, 0, 0, 0, 0, 1, 2, 3, 4]; let d_input = vec![4.1f32, 3.4, 5.6, 3.7, 2.3, 1.7, 3.8, 4.9, 3.2, 3.1]; - let array = + let mut array = tiledb::Array::open(ctx, ARRAY_URI, tiledb::array::Mode::Write)?; - let query = WriteBuilder::new(array)? + let query = WriteBuilder::new(&mut array)? .layout(CellOrder::Unordered)? .data_typed("index", &index_input)? .data_typed("a", &a_input)? diff --git a/tiledb/api/examples/quickstart_dense.rs b/tiledb/api/examples/quickstart_dense.rs index 49e19aa1..e92eff3b 100644 --- a/tiledb/api/examples/quickstart_dense.rs +++ b/tiledb/api/examples/quickstart_dense.rs @@ -80,7 +80,7 @@ fn create_array() -> TileDBResult<()> { fn write_array() -> TileDBResult<()> { let tdb = tiledb::context::Context::new()?; - let array = tiledb::Array::open( + let mut array = tiledb::Array::open( &tdb, QUICKSTART_DENSE_ARRAY_URI, tiledb::array::Mode::Write, @@ -88,7 +88,7 @@ fn write_array() -> TileDBResult<()> { let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - let query = tiledb::query::WriteBuilder::new(array)? + let query = tiledb::query::WriteBuilder::new(&mut array)? .layout(tiledb::query::QueryLayout::RowMajor)? .data_typed(QUICKSTART_ATTRIBUTE_NAME, &data)? .build(); @@ -113,7 +113,7 @@ fn read_array() -> TileDBResult<()> { tiledb::array::Mode::Read, )?; - let mut query = tiledb::query::ReadBuilder::new(array)? + let mut query = tiledb::query::ReadBuilder::new(&array)? .layout(tiledb::query::QueryLayout::RowMajor)? .register_constructor::<_, Vec>( QUICKSTART_ATTRIBUTE_NAME, diff --git a/tiledb/api/examples/quickstart_sparse_string.rs b/tiledb/api/examples/quickstart_sparse_string.rs index efe91598..e6ee4dee 100644 --- a/tiledb/api/examples/quickstart_sparse_string.rs +++ b/tiledb/api/examples/quickstart_sparse_string.rs @@ -32,7 +32,7 @@ fn main() -> TileDBResult<()> { } let array = Array::open(&ctx, ARRAY_URI, tiledb::array::Mode::Read)?; - let mut query = ReadBuilder::new(array)? + let mut query = ReadBuilder::new(&array)? .layout(tiledb::query::QueryLayout::RowMajor)? .register_constructor::<_, Vec>("rows", Default::default())? .register_constructor::<_, Vec>("cols", Default::default())? @@ -95,10 +95,10 @@ fn write_array(ctx: &Context) -> TileDBResult<()> { let col_data = vec![1, 4, 3]; let a_data = vec![1, 2, 3]; - let array = + let mut array = tiledb::Array::open(ctx, ARRAY_URI, tiledb::array::Mode::Write)?; - let query = WriteBuilder::new(array)? + let query = WriteBuilder::new(&mut array)? .layout(CellOrder::Unordered)? .data_typed("rows", &row_data)? .data_typed("cols", &col_data)? diff --git a/tiledb/api/examples/reading_incomplete.rs b/tiledb/api/examples/reading_incomplete.rs index e5f007f0..d1ea13f4 100644 --- a/tiledb/api/examples/reading_incomplete.rs +++ b/tiledb/api/examples/reading_incomplete.rs @@ -4,7 +4,7 @@ use std::cell::{Ref, RefCell}; use std::path::PathBuf; use itertools::izip; -use tiledb::array::{CellOrder, TileOrder}; +use tiledb::array::{Array, CellOrder, TileOrder}; use tiledb::query::buffer::{ BufferMut, CellStructureMut, QueryBuffers, QueryBuffersMut, }; @@ -103,7 +103,7 @@ fn create_array() -> TileDBResult<()> { fn write_array() -> TileDBResult<()> { let tdb = tiledb::Context::new()?; - let array = + let mut array = tiledb::Array::open(&tdb, ARRAY_NAME, tiledb::array::Mode::Write)?; let coords_rows = vec![1, 2, 2]; @@ -112,7 +112,7 @@ fn write_array() -> TileDBResult<()> { let int32_data = vec![1, 2, 3]; let char_data = vec!["a", "bb", "ccc"]; - let query = tiledb::query::WriteBuilder::new(array)? + let query = tiledb::query::WriteBuilder::new(&mut array)? .layout(tiledb::query::QueryLayout::Global)? .data_typed("rows", &coords_rows)? .data_typed("columns", &coords_cols)? @@ -128,11 +128,8 @@ fn write_array() -> TileDBResult<()> { /// from a query. The example wants to print out the query result set. /// Below are several different ways to implement this functionality. -fn query_builder_start(tdb: &tiledb::Context) -> TileDBResult { - let array = - tiledb::Array::open(tdb, ARRAY_NAME, tiledb::array::Mode::Read)?; - - tiledb::query::ReadBuilder::new(array)? +fn query_builder_start(array: &Array) -> TileDBResult { + tiledb::query::ReadBuilder::new(&array)? .layout(tiledb::query::QueryLayout::RowMajor)? .start_subarray()? .add_range(0, &[1i32, 4])? @@ -187,7 +184,10 @@ fn read_array_step() -> TileDBResult<()> { validity: None, }); - let mut qq = query_builder_start(&tdb)? + let array = + tiledb::Array::open(&tdb, ARRAY_NAME, tiledb::array::Mode::Read)?; + + let mut qq = query_builder_start(&array)? .register_raw("rows", &rows_output)? .register_raw("columns", &cols_output)? .register_raw(INT32_ATTRIBUTE_NAME, &int32_output)? @@ -249,7 +249,10 @@ fn read_array_collect() -> TileDBResult<()> { let tdb = tiledb::context::Context::new()?; - let mut qq = query_builder_start(&tdb)? + let array = + tiledb::Array::open(&tdb, ARRAY_NAME, tiledb::array::Mode::Read)?; + + let mut qq = query_builder_start(&array)? .register_constructor::<_, Vec>( "rows", ScratchStrategy::CustomAllocator(Box::new(NonVarSized { @@ -326,7 +329,11 @@ fn read_array_callback() -> TileDBResult<()> { )), validity: None, }); - let mut qq = query_builder_start(&tdb)? + + let array = + tiledb::Array::open(&tdb, ARRAY_NAME, tiledb::array::Mode::Read)?; + + let mut qq = query_builder_start(&array)? .register_callback4::>( ("rows", ScratchStrategy::RawBuffers(&rows_output)), ("columns", ScratchStrategy::RawBuffers(&cols_output)), diff --git a/tiledb/api/examples/using_tiledb_stats.rs b/tiledb/api/examples/using_tiledb_stats.rs index e20b4b84..8d84ca6f 100644 --- a/tiledb/api/examples/using_tiledb_stats.rs +++ b/tiledb/api/examples/using_tiledb_stats.rs @@ -99,11 +99,11 @@ pub fn create_array( /// [143988000, 143988001 ... 143999999]] pub fn write_array() -> TileDBResult<()> { let tdb = tiledb::context::Context::new()?; - let array: Array = + let mut array: Array = tiledb::Array::open(&tdb, ARRAY_NAME, tiledb::array::Mode::Write)?; let data: Vec = Vec::from_iter(0..12000 * 12000); - let query = tiledb::query::WriteBuilder::new(array)? + let query = tiledb::query::WriteBuilder::new(&mut array)? .layout(tiledb::query::QueryLayout::RowMajor)? .data_typed(ATTRIBUTE_NAME, &data)? .build(); @@ -131,7 +131,7 @@ pub fn read_array(json: bool) -> TileDBResult<()> { let array = tiledb::Array::open(&tdb, ARRAY_NAME, tiledb::array::Mode::Read)?; - let mut query = tiledb::query::ReadBuilder::new(array)? + let mut query = tiledb::query::ReadBuilder::new(&array)? .layout(tiledb::query::QueryLayout::RowMajor)? .register_constructor::<_, Vec>( ATTRIBUTE_NAME, diff --git a/tiledb/api/src/array/fragment_info.rs b/tiledb/api/src/array/fragment_info.rs index db043a29..aee49957 100644 --- a/tiledb/api/src/array/fragment_info.rs +++ b/tiledb/api/src/array/fragment_info.rs @@ -975,9 +975,10 @@ pub mod tests { /// Write another fragment to the test array. fn write_dense_array(ctx: &Context, array_uri: &str) -> TileDBResult<()> { let data = vec![1u64, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let array = Array::open(ctx, array_uri, Mode::Write)?; - let query = - WriteBuilder::new(array)?.data_typed("attr", &data)?.build(); + let mut array = Array::open(ctx, array_uri, Mode::Write)?; + let query = WriteBuilder::new(&mut array)? + .data_typed("attr", &data)? + .build(); query.submit()?; Ok(()) } @@ -1021,8 +1022,8 @@ pub mod tests { fn write_sparse_array(ctx: &Context, array_uri: &str) -> TileDBResult<()> { let id_data = vec![1u32, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let attr_data = vec![1u64, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let array = Array::open(ctx, array_uri, Mode::Write)?; - let query = WriteBuilder::new(array)? + let mut array = Array::open(ctx, array_uri, Mode::Write)?; + let query = WriteBuilder::new(&mut array)? .data_typed("id", &id_data)? .data_typed("attr", &attr_data)? .build(); diff --git a/tiledb/api/src/array/mod.rs b/tiledb/api/src/array/mod.rs index 95ede3b3..992f48aa 100644 --- a/tiledb/api/src/array/mod.rs +++ b/tiledb/api/src/array/mod.rs @@ -1168,9 +1168,9 @@ pub mod tests { let opener = ArrayOpener::new(ctx, array_uri, Mode::Write)? .end_timestamp(timestamp + i as u64 + 1)?; - let array = opener.open()?; + let mut array = opener.open()?; - let q1 = WriteBuilder::new(array)? + let q1 = WriteBuilder::new(&mut array)? .layout(QueryLayout::RowMajor)? .start_subarray()? .add_range(0, &[low_bound + 1, boundaries[i + 1]])? diff --git a/tiledb/api/src/query/mod.rs b/tiledb/api/src/query/mod.rs index f8cb3e39..398e648c 100644 --- a/tiledb/api/src/query/mod.rs +++ b/tiledb/api/src/query/mod.rs @@ -44,10 +44,10 @@ impl Drop for RawQuery { } } -pub trait Query { - fn base(&self) -> &QueryBase; +pub trait Query<'a> { + fn base(&self) -> &QueryBase<'a>; - fn finalize(self) -> TileDBResult + fn finalize(self) -> TileDBResult<()> where Self: Sized; @@ -79,18 +79,18 @@ pub trait Query { } } -pub struct QueryBase { - array: Array, +pub struct QueryBase<'a> { + array: &'a Array, raw: RawQuery, } -impl ContextBound for QueryBase { +impl<'a> ContextBound for QueryBase<'a> { fn context(&self) -> Context { self.array.context() } } -impl QueryBase { +impl<'a> QueryBase<'a> { fn cquery(&self) -> &RawQuery { &self.raw } @@ -119,22 +119,20 @@ impl QueryBase { } } -impl Query for QueryBase { - fn base(&self) -> &QueryBase { +impl<'a> Query<'a> for QueryBase<'a> { + fn base(&self) -> &QueryBase<'a> { self } - fn finalize(self) -> TileDBResult { + fn finalize(self) -> TileDBResult<()> { let c_query = **self.base().cquery(); self.capi_call(|ctx| unsafe { ffi::tiledb_query_finalize(ctx, c_query) - })?; - - Ok(self.array) + }) } } -impl ReadQuery for QueryBase { +impl<'a> ReadQuery<'a> for QueryBase<'a> { type Intermediate = (); type Final = (); @@ -177,10 +175,10 @@ impl ReadQuery for QueryBase { } } -pub trait QueryBuilder: Sized { - type Query: Query; +pub trait QueryBuilder<'a>: Sized { + type Query: Query<'a>; - fn base(&self) -> &BuilderBase; + fn base(&self) -> &BuilderBase<'a>; fn layout(self, layout: QueryLayout) -> TileDBResult where @@ -231,17 +229,17 @@ pub trait QueryBuilder: Sized { fn build(self) -> Self::Query; } -pub struct BuilderBase { - query: QueryBase, +pub struct BuilderBase<'a> { + query: QueryBase<'a>, } -impl ContextBound for BuilderBase { +impl<'a> ContextBound for BuilderBase<'a> { fn context(&self) -> Context { self.query.context() } } -impl BuilderBase { +impl<'a> BuilderBase<'a> { fn carray(&self) -> &RawArray { self.query.array.capi() } @@ -254,10 +252,10 @@ impl BuilderBase { } } -impl QueryBuilder for BuilderBase { - type Query = QueryBase; +impl<'a> QueryBuilder<'a> for BuilderBase<'a> { + type Query = QueryBase<'a>; - fn base(&self) -> &BuilderBase { + fn base(&self) -> &BuilderBase<'a> { self } @@ -266,8 +264,8 @@ impl QueryBuilder for BuilderBase { } } -impl BuilderBase { - fn new(array: Array, query_type: QueryType) -> TileDBResult { +impl<'a> BuilderBase<'a> { + fn new(array: &'a Array, query_type: QueryType) -> TileDBResult { let c_array = **array.capi(); let c_query_type = query_type.capi_enum(); let mut c_query: *mut ffi::tiledb_query_t = out_ptr!(); diff --git a/tiledb/api/src/query/read/callback.rs b/tiledb/api/src/query/read/callback.rs index 2a9c3683..1a1bb557 100644 --- a/tiledb/api/src/query/read/callback.rs +++ b/tiledb/api/src/query/read/callback.rs @@ -643,7 +643,7 @@ macro_rules! query_read_callback { } } - impl<'data, T, Q> ContextBound for $query<'data, T, Q> + impl<'array, 'data, T, Q> ContextBound for $query<'data, T, Q> where T: $callback, Q: ContextBound, @@ -653,22 +653,22 @@ macro_rules! query_read_callback { } } - impl<'data, T, Q> Query for $query<'data, T, Q> + impl<'array, 'data, T, Q> Query<'array> for $query<'data, T, Q> where T: $callback, - Q: Query, + Q: Query<'array>, { - fn base(&self) -> &QueryBase { + fn base(&self) -> &QueryBase<'array> { self.base.base() } - fn finalize(self) -> TileDBResult { + fn finalize(self) -> TileDBResult<()> { self.base.finalize() } } } - impl<'data, T, Q> $query<'data, T, Q> where T: $callback { + impl<'array, 'data, T, Q> $query<'data, T, Q> where T: $callback { fn realloc_managed_buffers(&mut self) { paste! { $( @@ -678,9 +678,9 @@ macro_rules! query_read_callback { } } - impl<'data, T, Q> ReadQuery for $query <'data, T, Q> + impl<'array, 'data, T, Q> ReadQuery<'array> for $query<'data, T, Q> where T: $callback, - Q: ReadQuery + Q: ReadQuery<'array> { type Intermediate = (T::Intermediate, Q::Intermediate); type Final = (T::Final, Q::Final); @@ -836,13 +836,13 @@ macro_rules! query_read_callback { } } - impl<'data, T, B> QueryBuilder for $Builder <'data, T, B> + impl<'array, 'data, T, B> QueryBuilder<'array> for $Builder<'data, T, B> where T: $callback, - B: QueryBuilder, + B: QueryBuilder<'array>, { type Query = $query<'data, T, B::Query>; - fn base(&self) -> &BuilderBase { + fn base(&self) -> &BuilderBase<'array> { self.base.base() } @@ -857,10 +857,10 @@ macro_rules! query_read_callback { } } - impl<'data, T, B> ReadQueryBuilder<'data> for $Builder<'data, T, B> + impl<'array, 'data, T, B> ReadQueryBuilder<'array, 'data> for $Builder<'data, T, B> where T: $callback, - B: ReadQueryBuilder<'data>, + B: ReadQueryBuilder<'array, 'data>, { } } @@ -968,23 +968,24 @@ where } } -impl<'data, T, Q> Query for CallbackVarArgReadQuery<'data, T, Q> +impl<'array, 'data, T, Q> Query<'array> for CallbackVarArgReadQuery<'data, T, Q> where - VarRawReadQuery<'data, Q>: Query, + VarRawReadQuery<'data, Q>: Query<'array>, { - fn base(&self) -> &QueryBase { + fn base(&self) -> &QueryBase<'array> { self.base.base() } - fn finalize(self) -> TileDBResult { + fn finalize(self) -> TileDBResult<()> { self.base.finalize() } } -impl<'data, T, Q> ReadQuery for CallbackVarArgReadQuery<'data, T, Q> +impl<'array, 'data, T, Q> ReadQuery<'array> + for CallbackVarArgReadQuery<'data, T, Q> where T: ReadCallbackVarArg, - Q: ReadQuery, + Q: ReadQuery<'array>, { type Intermediate = (T::Intermediate, Q::Intermediate); type Final = (T::Final, Q::Final); @@ -1140,13 +1141,14 @@ where } } -impl<'data, T, B> QueryBuilder for CallbackVarArgReadBuilder<'data, T, B> +impl<'array, 'data, T, B> QueryBuilder<'array> + for CallbackVarArgReadBuilder<'data, T, B> where - B: QueryBuilder, + B: QueryBuilder<'array>, { type Query = CallbackVarArgReadQuery<'data, T, B::Query>; - fn base(&self) -> &BuilderBase { + fn base(&self) -> &BuilderBase<'array> { self.base.base() } @@ -1158,10 +1160,10 @@ where } } -impl<'data, T, B> ReadQueryBuilder<'data> +impl<'array, 'data, T, B> ReadQueryBuilder<'array, 'data> for CallbackVarArgReadBuilder<'data, T, B> where - B: QueryBuilder, + B: QueryBuilder<'array>, { } diff --git a/tiledb/api/src/query/read/mod.rs b/tiledb/api/src/query/read/mod.rs index 5e7e296e..64684803 100644 --- a/tiledb/api/src/query/read/mod.rs +++ b/tiledb/api/src/query/read/mod.rs @@ -182,7 +182,7 @@ impl<'data, C> From<&'data RefCell>> } /// Trait for runnable read queries. -pub trait ReadQuery: Query { +pub trait ReadQuery<'a>: Query<'a> { type Intermediate; type Final; @@ -204,7 +204,7 @@ pub trait ReadQuery: Query { /// Convert this query into an iterator which yields an item /// for each step of the query. - fn into_iter(self) -> ReadQueryIterator + fn into_iter(self) -> ReadQueryIterator<'a, Self::Intermediate, Self::Final> where Self: Sized + 'static, { @@ -272,7 +272,7 @@ macro_rules! fn_register_callback { /// Trait for constructing a read query. /// Provides methods for flexibly adapting requested attributes into raw results, /// callbacks, or strongly-typed objects. -pub trait ReadQueryBuilder<'data>: QueryBuilder { +pub trait ReadQueryBuilder<'array, 'data>: QueryBuilder<'array> { /// Register a raw memory location to read query results into. fn register_raw( self, @@ -385,18 +385,18 @@ pub trait ReadQueryBuilder<'data>: QueryBuilder { } } -pub struct ReadBuilder { - base: BuilderBase, +pub struct ReadBuilder<'a> { + base: BuilderBase<'a>, } -impl ContextBound for ReadBuilder { +impl<'a> ContextBound for ReadBuilder<'a> { fn context(&self) -> Context { self.base.context() } } -impl ReadBuilder { - pub fn new(array: Array) -> TileDBResult { +impl<'a> ReadBuilder<'a> { + pub fn new(array: &'a Array) -> TileDBResult { let base = BuilderBase::new(array, QueryType::Read)?; /* configure the query to always use arrow-like output */ @@ -421,10 +421,10 @@ impl ReadBuilder { } } -impl QueryBuilder for ReadBuilder { - type Query = QueryBase; +impl<'a> QueryBuilder<'a> for ReadBuilder<'a> { + type Query = QueryBase<'a>; - fn base(&self) -> &BuilderBase { + fn base(&self) -> &BuilderBase<'a> { &self.base } @@ -433,13 +433,13 @@ impl QueryBuilder for ReadBuilder { } } -impl<'data> ReadQueryBuilder<'data> for ReadBuilder {} +impl<'array, 'data> ReadQueryBuilder<'array, 'data> for ReadBuilder<'array> {} -pub struct ReadQueryIterator { - query: Option>>, +pub struct ReadQueryIterator<'array, I, F> { + query: Option>>, } -impl Iterator for ReadQueryIterator { +impl<'a, I, F> Iterator for ReadQueryIterator<'a, I, F> { type Item = TileDBResult>; fn next(&mut self) -> Option { @@ -453,4 +453,4 @@ impl Iterator for ReadQueryIterator { } } -impl std::iter::FusedIterator for ReadQueryIterator {} +impl<'a, I, F> std::iter::FusedIterator for ReadQueryIterator<'a, I, F> {} diff --git a/tiledb/api/src/query/read/raw.rs b/tiledb/api/src/query/read/raw.rs index a8077eae..536ec59e 100644 --- a/tiledb/api/src/query/read/raw.rs +++ b/tiledb/api/src/query/read/raw.rs @@ -451,22 +451,22 @@ where } } -impl<'data, Q> Query for RawReadQuery<'data, Q> +impl<'array, 'data, Q> Query<'array> for RawReadQuery<'data, Q> where - Q: Query, + Q: Query<'array>, { - fn base(&self) -> &QueryBase { + fn base(&self) -> &QueryBase<'array> { self.base.base() } - fn finalize(self) -> TileDBResult { + fn finalize(self) -> TileDBResult<()> { self.base.finalize() } } -impl<'data, Q> ReadQuery for RawReadQuery<'data, Q> +impl<'array, 'data, Q> ReadQuery<'array> for RawReadQuery<'data, Q> where - Q: ReadQuery + ContextBound, + Q: ReadQuery<'array> + ContextBound, { type Intermediate = (usize, Q::Intermediate); type Final = (usize, Q::Final); @@ -521,23 +521,23 @@ pub struct RawReadBuilder<'data, B> { pub(crate) base: B, } -impl<'data, B> ContextBound for RawReadBuilder<'data, B> +impl<'array, 'data, B> ContextBound for RawReadBuilder<'data, B> where - B: QueryBuilder, + B: QueryBuilder<'array>, { fn context(&self) -> Context { self.base.base().context() } } -impl<'data, B> QueryBuilder for RawReadBuilder<'data, B> +impl<'array, 'data, B> QueryBuilder<'array> for RawReadBuilder<'data, B> where - B: QueryBuilder, - ::Query: ContextBound, + B: QueryBuilder<'array>, + >::Query: ContextBound, { type Query = RawReadQuery<'data, B::Query>; - fn base(&self) -> &BuilderBase { + fn base(&self) -> &BuilderBase<'array> { self.base.base() } @@ -549,10 +549,11 @@ where } } -impl<'data, B> ReadQueryBuilder<'data> for RawReadBuilder<'data, B> +impl<'array, 'data, B> ReadQueryBuilder<'array, 'data> + for RawReadBuilder<'data, B> where - B: ReadQueryBuilder<'data>, - ::Query: ContextBound, + B: ReadQueryBuilder<'array, 'data>, + >::Query: ContextBound, { } @@ -574,22 +575,22 @@ where } } -impl<'data, Q> Query for VarRawReadQuery<'data, Q> +impl<'array, 'data, Q> Query<'array> for VarRawReadQuery<'data, Q> where - Q: Query, + Q: Query<'array>, { - fn base(&self) -> &QueryBase { + fn base(&self) -> &QueryBase<'array> { self.base.base() } - fn finalize(self) -> TileDBResult { + fn finalize(self) -> TileDBResult<()> { self.base.finalize() } } -impl<'data, Q> ReadQuery for VarRawReadQuery<'data, Q> +impl<'array, 'data, Q> ReadQuery<'array> for VarRawReadQuery<'data, Q> where - Q: ReadQuery, + Q: ReadQuery<'array>, { type Intermediate = (Vec, Q::Intermediate); type Final = (Vec, Q::Final); @@ -669,13 +670,13 @@ where } } -impl<'data, B> QueryBuilder for VarRawReadBuilder<'data, B> +impl<'array, 'data, B> QueryBuilder<'array> for VarRawReadBuilder<'data, B> where - B: QueryBuilder, + B: QueryBuilder<'array>, { type Query = VarRawReadQuery<'data, B::Query>; - fn base(&self) -> &BuilderBase { + fn base(&self) -> &BuilderBase<'array> { self.base.base() } @@ -687,7 +688,9 @@ where } } -impl<'data, B> ReadQueryBuilder<'data> for VarRawReadBuilder<'data, B> where - B: ReadQueryBuilder<'data> +impl<'array, 'data, B> ReadQueryBuilder<'array, 'data> + for VarRawReadBuilder<'data, B> +where + B: ReadQueryBuilder<'array, 'data>, { } diff --git a/tiledb/api/src/query/read/typed.rs b/tiledb/api/src/query/read/typed.rs index 47669754..521bda7c 100644 --- a/tiledb/api/src/query/read/typed.rs +++ b/tiledb/api/src/query/read/typed.rs @@ -26,24 +26,24 @@ where } } -impl<'data, T, Q> Query for TypedReadQuery<'data, T, Q> +impl<'array, 'data, T, Q> Query<'array> for TypedReadQuery<'data, T, Q> where T: ReadResult, - CallbackReadQuery<'data, ::Constructor, Q>: Query, + CallbackReadQuery<'data, ::Constructor, Q>: Query<'array>, { - fn base(&self) -> &QueryBase { + fn base(&self) -> &QueryBase<'array> { self.base.base() } - fn finalize(self) -> TileDBResult { + fn finalize(self) -> TileDBResult<()> { self.base.finalize() } } -impl<'data, T, Q> ReadQuery for TypedReadQuery<'data, T, Q> +impl<'array, 'data, T, Q> ReadQuery<'array> for TypedReadQuery<'data, T, Q> where T: ReadResult, - Q: ReadQuery, + Q: ReadQuery<'array>, { type Intermediate = Q::Intermediate; type Final = (T, Q::Final); @@ -82,14 +82,14 @@ where } } -impl<'data, T, B> QueryBuilder for TypedReadBuilder<'data, T, B> +impl<'array, 'data, T, B> QueryBuilder<'array> for TypedReadBuilder<'data, T, B> where T: ReadResult, - B: QueryBuilder, + B: QueryBuilder<'array>, { type Query = TypedReadQuery<'data, T, B::Query>; - fn base(&self) -> &BuilderBase { + fn base(&self) -> &BuilderBase<'array> { self.base.base() } @@ -101,10 +101,11 @@ where } } -impl<'data, T, B> ReadQueryBuilder<'data> for TypedReadBuilder<'data, T, B> +impl<'array, 'data, T, B> ReadQueryBuilder<'array, 'data> + for TypedReadBuilder<'data, T, B> where T: ReadResult, - B: ReadQueryBuilder<'data>, + B: ReadQueryBuilder<'array, 'data>, { } diff --git a/tiledb/api/src/query/strategy.rs b/tiledb/api/src/query/strategy.rs index ef1ef9d9..727e7ab7 100644 --- a/tiledb/api/src/query/strategy.rs +++ b/tiledb/api/src/query/strategy.rs @@ -764,10 +764,10 @@ impl Cells { &self.fields } - pub fn attach_write<'data>( + pub fn attach_write<'array, 'data>( &'data self, - b: WriteBuilder<'data>, - ) -> TileDBResult> { + b: WriteBuilder<'array, 'data>, + ) -> TileDBResult> { let mut b = b; for f in self.fields.iter() { b = typed_field_data_go!(f.1, data, b.data_typed(f.0, data))?; @@ -775,12 +775,12 @@ impl Cells { Ok(b) } - pub fn attach_read<'data, B>( + pub fn attach_read<'array, 'data, B>( &self, b: B, ) -> TileDBResult> where - B: ReadQueryBuilder<'data>, + B: ReadQueryBuilder<'array, 'data>, { let field_order = self.fields.keys().cloned().collect::>(); let handles = { diff --git a/tiledb/api/src/query/subarray.rs b/tiledb/api/src/query/subarray.rs index d3bfb618..d33433cc 100644 --- a/tiledb/api/src/query/subarray.rs +++ b/tiledb/api/src/query/subarray.rs @@ -169,26 +169,23 @@ impl<'query> Subarray<'query> { } } -pub struct Builder -where - Q: QueryBuilder + Sized, -{ +pub struct Builder { query: Q, raw: RawSubarray, } -impl ContextBound for Builder +impl<'array, Q> ContextBound for Builder where - Q: QueryBuilder, + Q: QueryBuilder<'array>, { fn context(&self) -> Context { self.query.base().context() } } -impl Builder +impl<'array, Q> Builder where - Q: QueryBuilder + Sized, + Q: QueryBuilder<'array> + Sized, { pub(crate) fn for_query(query: Q) -> TileDBResult { let context = query.base().context(); @@ -594,7 +591,7 @@ mod tests { crate::array::tests::create_quickstart_dense(&test_uri, &ctx)?; let a = Array::open(&ctx, test_uri, Mode::Read)?; - let b = ReadBuilder::new(a)?; + let b = ReadBuilder::new(&a)?; // inspect builder in-progress subarray { @@ -643,7 +640,7 @@ mod tests { )?; let a = Array::open(&ctx, test_uri, Mode::Read)?; - let b = ReadBuilder::new(a)?; + let b = ReadBuilder::new(&a)?; // inspect builder in-progress subarray { @@ -705,7 +702,7 @@ mod tests { ) -> TileDBResult<()> { let array_uri = create_array(ctx, atype, test_uri)?; let array = Array::open(ctx, array_uri, Mode::Read)?; - let query = ReadBuilder::new(array)? + let query = ReadBuilder::new(&array)? .start_subarray()? .add_range("id", &[1, 2])? .add_range("id", &[4, 6])? @@ -973,8 +970,8 @@ mod tests { }) .collect::<(Vec, (Vec, Vec))>(); - let w = Array::open(&ctx, &test_uri, Mode::Write).unwrap(); - let q = WriteBuilder::new(w) + let mut w = Array::open(&ctx, &test_uri, Mode::Write).unwrap(); + let q = WriteBuilder::new(&mut w) .unwrap() .data("rows", &rows) .unwrap() @@ -995,7 +992,7 @@ mod tests { let do_dimension_ranges = |subarray: SubarrayData| -> TileDBResult<()> { let array = Array::open(&ctx, &test_uri, Mode::Read).unwrap(); - let mut q = ReadBuilder::new(array)? + let mut q = ReadBuilder::new(&array)? .start_subarray()? .dimension_ranges(subarray.dimension_ranges.clone())? .finish_subarray()? diff --git a/tiledb/api/src/query/write/mod.rs b/tiledb/api/src/query/write/mod.rs index cdda9b7a..ead568a6 100644 --- a/tiledb/api/src/query/write/mod.rs +++ b/tiledb/api/src/query/write/mod.rs @@ -22,50 +22,50 @@ struct RawWriteInput<'data> { type InputMap<'data> = HashMap>; -pub struct WriteQuery<'data> { - base: QueryBase, +pub struct WriteQuery<'array, 'data> { + base: QueryBase<'array>, /// Hold on to query inputs to ensure they live long enough _inputs: InputMap<'data>, } -impl<'data> ContextBound for WriteQuery<'data> { +impl<'array, 'data> ContextBound for WriteQuery<'array, 'data> { fn context(&self) -> Context { self.base.context() } } -impl<'data> Query for WriteQuery<'data> { - fn base(&self) -> &QueryBase { +impl<'array, 'data> Query<'array> for WriteQuery<'array, 'data> { + fn base(&self) -> &QueryBase<'array> { self.base.base() } - fn finalize(self) -> TileDBResult { + fn finalize(self) -> TileDBResult<()> { self.base.finalize() } } -impl<'data> WriteQuery<'data> { +impl<'array, 'data> WriteQuery<'array, 'data> { pub fn submit(&self) -> TileDBResult<()> { self.base.do_submit() } } -pub struct WriteBuilder<'data> { - base: BuilderBase, +pub struct WriteBuilder<'array, 'data> { + base: BuilderBase<'array>, inputs: InputMap<'data>, } -impl<'data> ContextBound for WriteBuilder<'data> { +impl<'array, 'data> ContextBound for WriteBuilder<'array, 'data> { fn context(&self) -> Context { self.base.context() } } -impl<'data> QueryBuilder for WriteBuilder<'data> { - type Query = WriteQuery<'data>; +impl<'array, 'data> QueryBuilder<'array> for WriteBuilder<'array, 'data> { + type Query = WriteQuery<'array, 'data>; - fn base(&self) -> &BuilderBase { + fn base(&self) -> &BuilderBase<'array> { &self.base } @@ -77,8 +77,8 @@ impl<'data> QueryBuilder for WriteBuilder<'data> { } } -impl<'data> WriteBuilder<'data> { - pub fn new(array: Array) -> TileDBResult { +impl<'array, 'data> WriteBuilder<'array, 'data> { + pub fn new(array: &'array mut Array) -> TileDBResult { let base = BuilderBase::new(array, QueryType::Write)?; { diff --git a/tiledb/api/src/query/write/strategy.rs b/tiledb/api/src/query/write/strategy.rs index 9636ec3f..1800d7d2 100644 --- a/tiledb/api/src/query/write/strategy.rs +++ b/tiledb/api/src/query/write/strategy.rs @@ -79,10 +79,10 @@ pub struct DenseWriteInput { impl DenseWriteInput { /// Prepares a write query to insert data from this write. - pub fn attach_write<'data>( + pub fn attach_write<'array, 'data>( &'data self, - b: WriteBuilder<'data>, - ) -> TileDBResult> { + b: WriteBuilder<'array, 'data>, + ) -> TileDBResult> { let mut subarray = self.data.attach_write(b)?.start_subarray()?; for i in 0..self.subarray.len() { @@ -94,7 +94,7 @@ impl DenseWriteInput { /// Prepares a read query to read the fields written by this operation /// restricted to the subarray represented by this write. - pub fn attach_read<'data, B>( + pub fn attach_read<'array, 'data, B>( &'data self, b: B, ) -> TileDBResult< @@ -105,7 +105,7 @@ impl DenseWriteInput { >, > where - B: ReadQueryBuilder<'data>, + B: ReadQueryBuilder<'array, 'data>, { let mut subarray = b.start_subarray()?; @@ -517,15 +517,15 @@ impl SparseWriteInput { } /// Prepares a write query to insert data from this write operation. - pub fn attach_write<'data>( + pub fn attach_write<'array, 'data>( &'data self, - b: WriteBuilder<'data>, - ) -> TileDBResult> { + b: WriteBuilder<'array, 'data>, + ) -> TileDBResult> { self.data.attach_write(b) } /// Prepares a read query to read the fields written by this operation. - pub fn attach_read<'data, B>( + pub fn attach_read<'array, 'data, B>( &'data self, b: B, ) -> TileDBResult< @@ -536,7 +536,7 @@ impl SparseWriteInput { >, > where - B: ReadQueryBuilder<'data>, + B: ReadQueryBuilder<'array, 'data>, { Ok(self.data.attach_read(b)?.map(CellsConstructor::new())) } @@ -813,10 +813,10 @@ impl WriteInput { } /// Prepares a write queryto insert data from this write operation. - pub fn attach_write<'data>( + pub fn attach_write<'array, 'data>( &'data self, - b: WriteBuilder<'data>, - ) -> TileDBResult> { + b: WriteBuilder<'array, 'data>, + ) -> TileDBResult> { match self { Self::Dense(ref d) => d.attach_write(b), Self::Sparse(ref s) => s.attach_write(b), @@ -824,7 +824,7 @@ impl WriteInput { } /// Prepares a read query to read the fields written by this operation. - pub fn attach_read<'data, B>( + pub fn attach_read<'array, 'data, B>( &'data self, b: B, ) -> TileDBResult< @@ -835,7 +835,7 @@ impl WriteInput { >, > where - B: ReadQueryBuilder<'data>, + B: ReadQueryBuilder<'array, 'data>, { match self { Self::Dense(ref d) => d.attach_read(b), @@ -885,10 +885,10 @@ impl<'a> WriteInputRef<'a> { } /// Prepares a write queryto insert data from this write operation. - pub fn attach_write<'data>( + pub fn attach_write<'array, 'data>( &'data self, - b: WriteBuilder<'data>, - ) -> TileDBResult> { + b: WriteBuilder<'array, 'data>, + ) -> TileDBResult> { match self { Self::Dense(d) => d.attach_write(b), Self::Sparse(s) => s.attach_write(b), @@ -896,7 +896,7 @@ impl<'a> WriteInputRef<'a> { } /// Prepares a read query to read the fields written by this operation. - pub fn attach_read<'data, B>( + pub fn attach_read<'array, 'data, B>( &'data self, b: B, ) -> TileDBResult< @@ -907,7 +907,7 @@ impl<'a> WriteInputRef<'a> { >, > where - B: ReadQueryBuilder<'data>, + B: ReadQueryBuilder<'array, 'data>, { match self { Self::Dense(d) => d.attach_read(b), @@ -1185,7 +1185,7 @@ mod tests { self.write = Some(write) } - pub fn attach_read<'data, B>( + pub fn attach_read<'array, 'data, B>( &'data self, b: B, ) -> TileDBResult< @@ -1196,7 +1196,7 @@ mod tests { >, > where - B: ReadQueryBuilder<'data>, + B: ReadQueryBuilder<'array, 'data>, { // TODO: this is not correct as we accumulate multiple writes self.write.as_ref().unwrap().attach_read(b) @@ -1249,7 +1249,7 @@ mod tests { } } - pub fn attach_read<'data, B>( + pub fn attach_read<'array, 'data, B>( &'data self, b: B, ) -> TileDBResult< @@ -1260,7 +1260,7 @@ mod tests { >, > where - B: ReadQueryBuilder<'data>, + B: ReadQueryBuilder<'array, 'data>, { Ok(self.cells().attach_read(b)?.map(CellsConstructor::new())) } @@ -1307,7 +1307,7 @@ mod tests { } } - pub fn attach_read<'data, B>( + pub fn attach_read<'array, 'data, B>( &'data self, b: B, ) -> TileDBResult< @@ -1318,7 +1318,7 @@ mod tests { >, > where - B: ReadQueryBuilder<'data>, + B: ReadQueryBuilder<'array, 'data>, { match self { Self::Dense(ref d) => d.attach_read(b), @@ -1365,12 +1365,12 @@ mod tests { for write in write_sequence { /* write data and preserve ranges for sanity check */ let write_ranges = { - let array = Array::open(ctx, &uri, Mode::Write) + let mut array = Array::open(ctx, &uri, Mode::Write) .expect("Error opening array"); let write_query = write .attach_write( - WriteBuilder::new(array) + WriteBuilder::new(&mut array) .expect("Error building write query"), ) .expect("Error building write query") @@ -1392,7 +1392,7 @@ mod tests { None }; - let _ = write_query + write_query .finalize() .expect("Error finalizing write query"); @@ -1452,7 +1452,7 @@ mod tests { .unwrap(); let mut read = write - .attach_read(ReadBuilder::new(array).unwrap()) + .attach_read(ReadBuilder::new(&array).unwrap()) .unwrap() .build(); @@ -1471,7 +1471,7 @@ mod tests { assert_eq!(write_sorted, cells); } - array = read.finalize().unwrap(); + read.finalize().expect("Error finalizing query"); } /* finally, check that everything written up until now is correct */ @@ -1502,7 +1502,7 @@ mod tests { let cells = { let mut read = accumulated_write - .attach_read(ReadBuilder::new(array).unwrap()) + .attach_read(ReadBuilder::new(&array).unwrap()) .unwrap() .build(); From a61a3ded30b47267b94a66a87b82f25dcf09d37f Mon Sep 17 00:00:00 2001 From: Ryan Roelke Date: Wed, 14 Aug 2024 09:25:37 -0400 Subject: [PATCH 2/2] Test that Array is not Sync --- Cargo.lock | 76 ++++++++++++++++++++++++++++++ Cargo.toml | 3 +- tiledb/api/Cargo.toml | 1 + tiledb/api/src/array/mod.rs | 13 +++++ tiledb/api/tests/array/sync.rs | 32 +++++++++++++ tiledb/api/tests/array/sync.stderr | 51 ++++++++++++++++++++ tiledb/api/tests/compile_fail.rs | 7 +++ 7 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 tiledb/api/tests/array/sync.rs create mode 100644 tiledb/api/tests/array/sync.stderr create mode 100644 tiledb/api/tests/compile_fail.rs diff --git a/Cargo.lock b/Cargo.lock index 237a3d20..d6d9c9a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1206,6 +1206,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1277,6 +1286,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.58" @@ -1316,6 +1334,7 @@ dependencies = [ "tiledb-sys", "tiledb-test-utils", "tiledb-utils", + "trybuild", ] [[package]] @@ -1364,6 +1383,54 @@ dependencies = [ "crunchy", ] +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "trybuild" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" +dependencies = [ + "glob", + "serde", + "serde_derive", + "serde_json", + "termcolor", + "toml", +] + [[package]] name = "unarray" version = "0.1.4" @@ -1591,6 +1658,15 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + [[package]] name = "zerocopy" version = "0.7.32" diff --git a/Cargo.toml b/Cargo.toml index 23cf0032..4e7765b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ version = "0.1.0" [workspace.dependencies] anyhow = "1.0" +pkg-config = "0.3.30" proptest = { version = "1.0.0" } proptest-derive = { version = "0.4.0" } serde_json = { version = "1.0.114", features = ["float_roundtrip"] } @@ -30,4 +31,4 @@ tiledb-proc-macro = { path = "tiledb/proc-macro", version = "0.1.0" } tiledb-sys = { path = "tiledb/sys", version = "0.1.0" } tiledb-test-utils = { path = "tiledb/test-utils", version = "0.1.0" } tiledb-utils = { path = "tiledb/utils", version = "0.1.0" } -pkg-config = "0.3.30" +trybuild = "1" diff --git a/tiledb/api/Cargo.toml b/tiledb/api/Cargo.toml index 840629f3..126b3cc4 100644 --- a/tiledb/api/Cargo.toml +++ b/tiledb/api/Cargo.toml @@ -28,6 +28,7 @@ num-traits = { version = "0.2" } proptest = { workspace = true } proptest-derive = { workspace = true } tiledb-test-utils = { workspace = true } +trybuild = { workspace = true } [build-dependencies] pkg-config = { workspace = true } diff --git a/tiledb/api/src/array/mod.rs b/tiledb/api/src/array/mod.rs index 992f48aa..e74bca22 100644 --- a/tiledb/api/src/array/mod.rs +++ b/tiledb/api/src/array/mod.rs @@ -187,6 +187,19 @@ impl Drop for RawArray { } } +/// A handle to a tiledb array object. +/// +/// An array object represents array data at some URI. +/// This structure provides methods for querying and managing +/// the array location, schema, fragments, non-empty domain, and so on. +/// See the `query` module for constructing queries to the array contents. +// +// NB: `query::ReadBuilder::new` takes `&Array` as its argument, +// and that means that we must not add async query support AND we must +// require that `Array` is not `Sync`. See test `compile_fail/array.rs`. +// If either of the above requriements changes then we can make +// `query::ReadBuilder::new` take `&mut Array` instead, but that feels +// sort of wrong. pub struct Array { context: Context, uri: String, diff --git a/tiledb/api/tests/array/sync.rs b/tiledb/api/tests/array/sync.rs new file mode 100644 index 00000000..61282a7d --- /dev/null +++ b/tiledb/api/tests/array/sync.rs @@ -0,0 +1,32 @@ +extern crate tiledb; + +use tiledb::array::Array; + +/// Fails to compile unless `T` is `Sync`. +fn require_sync() +where + T: Sync, +{ +} + +/// Check whether `Array` is `Sync`. +/// +/// This is expected to fail because `Array` must not be `Sync` +/// for the query API to be thread-safe. +/// +/// In core it is not safe to submit multiple queries concurrently +/// against the same open array. The Rust API therefore must +/// prevent multiple concurrent calls to `tiledb_query_submit` +/// occurring concurrently for the same `Array` instance. +/// +/// This can be preventing using `&mut Array` in the query API, +/// and while that feels right for write queries, it does not +/// feel right for read queries. To enable `&Array` for read +/// queries, instead we must require: +/// 1) we do not support async query submit +/// 2) we cannot share an `Array` between multiple threads +/// +/// This test will intentionally fail to compile as long as (2) is true, +fn main() { + require_sync::(); +} diff --git a/tiledb/api/tests/array/sync.stderr b/tiledb/api/tests/array/sync.stderr new file mode 100644 index 00000000..6d6a5ee4 --- /dev/null +++ b/tiledb/api/tests/array/sync.stderr @@ -0,0 +1,51 @@ +error[E0277]: `Rc` cannot be shared between threads safely + --> tests/array/sync.rs:31:20 + | +31 | require_sync::(); + | ^^^^^ `Rc` cannot be shared between threads safely + | + = help: within `tiledb::Array`, the trait `Sync` is not implemented for `Rc`, which is required by `tiledb::Array: Sync` +note: required because it appears within the type `tiledb::Context` + --> src/context.rs + | + | pub struct Context { + | ^^^^^^^ +note: required because it appears within the type `tiledb::Array` + --> src/array/mod.rs + | + | pub struct Array { + | ^^^^^ +note: required by a bound in `require_sync` + --> tests/array/sync.rs:8:8 + | +6 | fn require_sync() + | ------------ required by a bound in this function +7 | where +8 | T: Sync, + | ^^^^ required by this bound in `require_sync` + +error[E0277]: `*mut tiledb_sys::types::tiledb_array_t` cannot be shared between threads safely + --> tests/array/sync.rs:31:20 + | +31 | require_sync::(); + | ^^^^^ `*mut tiledb_sys::types::tiledb_array_t` cannot be shared between threads safely + | + = help: within `tiledb::Array`, the trait `Sync` is not implemented for `*mut tiledb_sys::types::tiledb_array_t`, which is required by `tiledb::Array: Sync` +note: required because it appears within the type `RawArray` + --> src/array/mod.rs + | + | pub enum RawArray { + | ^^^^^^^^ +note: required because it appears within the type `tiledb::Array` + --> src/array/mod.rs + | + | pub struct Array { + | ^^^^^ +note: required by a bound in `require_sync` + --> tests/array/sync.rs:8:8 + | +6 | fn require_sync() + | ------------ required by a bound in this function +7 | where +8 | T: Sync, + | ^^^^ required by this bound in `require_sync` diff --git a/tiledb/api/tests/compile_fail.rs b/tiledb/api/tests/compile_fail.rs new file mode 100644 index 00000000..2c9b0728 --- /dev/null +++ b/tiledb/api/tests/compile_fail.rs @@ -0,0 +1,7 @@ +extern crate trybuild; + +#[test] +fn compile_fail() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/array/*.rs"); +}