From 50bc10b6a54405dc9b11102e9983810e2b46df1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Tue, 26 Nov 2024 16:04:35 +0100 Subject: [PATCH 01/12] collection: allocate static empty collections Other parts of the code make an assumption, that the pointer representing `CassDataType` was obtained from an Arc allocation. Take for example `cass_data_type_add_sub_type` - it clones an Arc. This is a bug, that was fortunately detected by applying more restrictions on the pointer types (introduced later in this PR). --- scylla-rust-wrapper/src/collection.rs | 61 +++++++++++++++++++++------ 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/scylla-rust-wrapper/src/collection.rs b/scylla-rust-wrapper/src/collection.rs index dd6e0f2b..8f5621ad 100644 --- a/scylla-rust-wrapper/src/collection.rs +++ b/scylla-rust-wrapper/src/collection.rs @@ -6,19 +6,26 @@ use crate::value::CassCqlValue; use crate::{argconv::*, value}; use std::convert::TryFrom; use std::sync::Arc; +use std::sync::LazyLock; // These constants help us to save an allocation in case user calls `cass_collection_new` (untyped collection). -static UNTYPED_LIST_TYPE: CassDataType = CassDataType::new(CassDataTypeInner::List { - typ: None, - frozen: false, +static UNTYPED_LIST_TYPE: LazyLock> = LazyLock::new(|| { + CassDataType::new_arced(CassDataTypeInner::List { + typ: None, + frozen: false, + }) }); -static UNTYPED_SET_TYPE: CassDataType = CassDataType::new(CassDataTypeInner::Set { - typ: None, - frozen: false, +static UNTYPED_SET_TYPE: LazyLock> = LazyLock::new(|| { + CassDataType::new_arced(CassDataTypeInner::Set { + typ: None, + frozen: false, + }) }); -static UNTYPED_MAP_TYPE: CassDataType = CassDataType::new(CassDataTypeInner::Map { - typ: MapDataType::Untyped, - frozen: false, +static UNTYPED_MAP_TYPE: LazyLock> = LazyLock::new(|| { + CassDataType::new_arced(CassDataTypeInner::Map { + typ: MapDataType::Untyped, + frozen: false, + }) }); #[derive(Clone)] @@ -183,9 +190,9 @@ unsafe extern "C" fn cass_collection_data_type( match &collection_ref.data_type { Some(dt) => ArcFFI::as_ptr(dt), None => match collection_ref.collection_type { - CassCollectionType::CASS_COLLECTION_TYPE_LIST => &UNTYPED_LIST_TYPE, - CassCollectionType::CASS_COLLECTION_TYPE_SET => &UNTYPED_SET_TYPE, - CassCollectionType::CASS_COLLECTION_TYPE_MAP => &UNTYPED_MAP_TYPE, + CassCollectionType::CASS_COLLECTION_TYPE_LIST => ArcFFI::as_ptr(&UNTYPED_LIST_TYPE), + CassCollectionType::CASS_COLLECTION_TYPE_SET => ArcFFI::as_ptr(&UNTYPED_SET_TYPE), + CassCollectionType::CASS_COLLECTION_TYPE_MAP => ArcFFI::as_ptr(&UNTYPED_MAP_TYPE), // CassCollectionType is a C enum. Panic, if it's out of range. _ => panic!( "CassCollectionType enum value out of range: {}", @@ -225,7 +232,10 @@ mod tests { use crate::{ argconv::ArcFFI, cass_error::CassError, - cass_types::{CassDataType, CassDataTypeInner, CassValueType, MapDataType}, + cass_types::{ + cass_data_type_add_sub_type, cass_data_type_free, cass_data_type_new, CassDataType, + CassDataTypeInner, CassValueType, MapDataType, + }, collection::{ cass_collection_append_double, cass_collection_append_float, cass_collection_free, }, @@ -234,7 +244,8 @@ mod tests { use super::{ cass_bool_t, cass_collection_append_bool, cass_collection_append_int16, - cass_collection_new, cass_collection_new_from_data_type, CassCollectionType, + cass_collection_data_type, cass_collection_new, cass_collection_new_from_data_type, + CassCollectionType, }; #[test] @@ -498,4 +509,26 @@ mod tests { } } } + + #[test] + fn regression_empty_collection_data_type_test() { + // This is a regression test that checks whether collections return + // an Arc-based pointer for their type, even if they are empty. + // Previously, they would return the pointer to static data, but not Arc allocated. + unsafe { + let empty_list = cass_collection_new(CassCollectionType::CASS_COLLECTION_TYPE_LIST, 2); + + // This would previously return a non Arc-based pointer. + let empty_list_dt = cass_collection_data_type(empty_list); + + let empty_set_dt = cass_data_type_new(CassValueType::CASS_VALUE_TYPE_SET); + // This will try to increment the reference count of `empty_list_dt`. + // Previously, this would fail, because `empty_list_dt` did not originate from an Arc allocation. + cass_data_type_add_sub_type(empty_set_dt, empty_list_dt); + + // Cast to *mut, because `cass_data_type_new` returns a *const. See the comment + // in this function to see why. + cass_data_type_free(empty_set_dt as *mut _) + } + } } From 27d76c83bb08eadab5e740678374f636b37c86e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Tue, 26 Nov 2024 16:08:38 +0100 Subject: [PATCH 02/12] tuple: allocate empty tuple type The same bug as for collection types. --- scylla-rust-wrapper/src/tuple.rs | 37 ++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/scylla-rust-wrapper/src/tuple.rs b/scylla-rust-wrapper/src/tuple.rs index 93602c63..288d5c67 100644 --- a/scylla-rust-wrapper/src/tuple.rs +++ b/scylla-rust-wrapper/src/tuple.rs @@ -6,8 +6,10 @@ use crate::types::*; use crate::value; use crate::value::CassCqlValue; use std::sync::Arc; +use std::sync::LazyLock; -static UNTYPED_TUPLE_TYPE: CassDataType = CassDataType::new(CassDataTypeInner::Tuple(Vec::new())); +static UNTYPED_TUPLE_TYPE: LazyLock> = + LazyLock::new(|| CassDataType::new_arced(CassDataTypeInner::Tuple(Vec::new()))); #[derive(Clone)] pub struct CassTuple { @@ -92,7 +94,7 @@ unsafe extern "C" fn cass_tuple_free(tuple: *mut CassTuple) { unsafe extern "C" fn cass_tuple_data_type(tuple: *const CassTuple) -> *const CassDataType { match &BoxFFI::as_ref(tuple).data_type { Some(t) => ArcFFI::as_ptr(t), - None => &UNTYPED_TUPLE_TYPE, + None => ArcFFI::as_ptr(&UNTYPED_TUPLE_TYPE), } } @@ -116,3 +118,34 @@ make_binders!(decimal, cass_tuple_set_decimal); make_binders!(collection, cass_tuple_set_collection); make_binders!(tuple, cass_tuple_set_tuple); make_binders!(user_type, cass_tuple_set_user_type); + +#[cfg(test)] +mod tests { + use crate::cass_types::{ + cass_data_type_add_sub_type, cass_data_type_free, cass_data_type_new, CassValueType, + }; + + use super::{cass_tuple_data_type, cass_tuple_new}; + + #[test] + fn regression_empty_tuple_data_type_test() { + // This is a regression test that checks whether tuples return + // an Arc-based pointer for their type, even if they are empty. + // Previously, they would return the pointer to static data, but not Arc allocated. + unsafe { + let empty_tuple = cass_tuple_new(2); + + // This would previously return a non Arc-based pointer. + let empty_tuple_dt = cass_tuple_data_type(empty_tuple); + + let empty_set_dt = cass_data_type_new(CassValueType::CASS_VALUE_TYPE_SET); + // This will try to increment the reference count of `empty_tuple_dt`. + // Previously, this would fail, because `empty_tuple_dt` did not originate from an Arc allocation. + cass_data_type_add_sub_type(empty_set_dt, empty_tuple_dt); + + // Cast to *mut, because `cass_data_type_new` returns a *const. See the comment + // in this function to see why. + cass_data_type_free(empty_set_dt as *mut _) + } + } +} From 54df1bc4d1c9c6b3ecbd6c3c2197b31d06883063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Tue, 26 Nov 2024 16:11:13 +0100 Subject: [PATCH 03/12] metadata: store CassDataType behind an Arc Again, if someone called `cass_data_type_add_sub_type` with a data type obtained from `cass_column_meta_data_type`, it would not be a pointer from an Arc allocation. --- scylla-rust-wrapper/src/metadata.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scylla-rust-wrapper/src/metadata.rs b/scylla-rust-wrapper/src/metadata.rs index ca969069..d1a198a0 100644 --- a/scylla-rust-wrapper/src/metadata.rs +++ b/scylla-rust-wrapper/src/metadata.rs @@ -51,7 +51,7 @@ impl RefFFI for CassMaterializedViewMeta {} pub struct CassColumnMeta { pub name: String, - pub column_type: CassDataType, + pub column_type: Arc, pub column_kind: CassColumnType, } @@ -71,11 +71,11 @@ pub unsafe fn create_table_metadata( .for_each(|(column_name, column_metadata)| { let cass_column_meta = CassColumnMeta { name: column_name.clone(), - column_type: get_column_type_from_cql_type( + column_type: Arc::new(get_column_type_from_cql_type( &column_metadata.type_, user_defined_types, keyspace_name, - ), + )), column_kind: match column_metadata.kind { ColumnKind::Regular => CassColumnType::CASS_COLUMN_TYPE_REGULAR, ColumnKind::Static => CassColumnType::CASS_COLUMN_TYPE_STATIC, @@ -305,7 +305,7 @@ pub unsafe extern "C" fn cass_column_meta_data_type( column_meta: *const CassColumnMeta, ) -> *const CassDataType { let column_meta = RefFFI::as_ref(column_meta); - &column_meta.column_type as *const CassDataType + ArcFFI::as_ptr(&column_meta.column_type) } #[no_mangle] From 9d956cb7bad2d063f5fabe1d44d69c3531f65bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Tue, 26 Nov 2024 16:14:32 +0100 Subject: [PATCH 04/12] metadata: try to upgrade Weak before returning a pointer Weak::as_ptr() can return an invalid pointer. It can be even dangling (non-null). It's safer to try to upgrade to an Arc. If upgrade was successful, make use of RefFFI API to return a valid pointer. Otherwise, return non-dangling null pointer. --- scylla-rust-wrapper/src/metadata.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scylla-rust-wrapper/src/metadata.rs b/scylla-rust-wrapper/src/metadata.rs index d1a198a0..2965c74c 100644 --- a/scylla-rust-wrapper/src/metadata.rs +++ b/scylla-rust-wrapper/src/metadata.rs @@ -433,7 +433,11 @@ pub unsafe extern "C" fn cass_materialized_view_meta_base_table( view_meta: *const CassMaterializedViewMeta, ) -> *const CassTableMeta { let view_meta = RefFFI::as_ref(view_meta); - view_meta.base_table.as_ptr() + + match view_meta.base_table.upgrade() { + Some(arc) => RefFFI::as_ptr(&arc), + None => std::ptr::null(), + } } #[no_mangle] From 95299d2e4739a99cb2b61e8de89081c38c94c78a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Tue, 26 Nov 2024 17:51:14 +0100 Subject: [PATCH 05/12] future: pass future pointer to callback directly Before this PR, the pointer was obtained from a valid reference &CassFuture, which is totally fine. However, I want to reduce the ways one can obtain such pointer. For ArcFFI (shared pointers), I want them to be obtainable only in two ways: - `ArcFFI::as_ptr()` which accepts an &Arc - from the user, as a function parameter This way, we are guaranteed that the pointer comes from a valid Arc allocation (unless user provided pointer to some garbage, but there is no much we can do about it). If we assume that user provides a pointer returned from some prior call to API, we are guaranteed that it is valid, and comes from an Arc allocation (or is null). I don't want to allow ArcFFI api to create a pointer from a refernce, to prevent creating a pointer, from example from stack allocated object: ``` let future = CassFuture { ... }; let future_ptr = ArcFFI::as_ptr(&future); ``` This commit may not make much sense now, but all should be clear once I introduce traits restricting the pointer types later in this PR. --- scylla-rust-wrapper/src/future.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/scylla-rust-wrapper/src/future.rs b/scylla-rust-wrapper/src/future.rs index a3c46f52..328f764b 100644 --- a/scylla-rust-wrapper/src/future.rs +++ b/scylla-rust-wrapper/src/future.rs @@ -40,9 +40,9 @@ struct BoundCallback { unsafe impl Send for BoundCallback {} impl BoundCallback { - fn invoke(self, fut: &CassFuture) { + fn invoke(self, fut_ptr: *const CassFuture) { unsafe { - self.cb.unwrap()(fut as *const CassFuture, self.data); + self.cb.unwrap()(fut_ptr, self.data); } } } @@ -96,7 +96,8 @@ impl CassFuture { guard.callback.take() }; if let Some(bound_cb) = maybe_cb { - bound_cb.invoke(cass_fut_clone.as_ref()); + let fut_ptr = ArcFFI::as_ptr(&cass_fut_clone); + bound_cb.invoke(fut_ptr); } cass_fut_clone.wait_for_value.notify_all(); @@ -258,7 +259,12 @@ impl CassFuture { } } - pub fn set_callback(&self, cb: CassFutureCallback, data: *mut c_void) -> CassError { + pub fn set_callback( + &self, + self_ptr: *const CassFuture, + cb: CassFutureCallback, + data: *mut c_void, + ) -> CassError { let mut lock = self.state.lock().unwrap(); if lock.callback.is_some() { // Another callback has been already set @@ -268,7 +274,7 @@ impl CassFuture { if lock.value.is_some() { // The value is already available, we need to call the callback ourselves mem::drop(lock); - bound_cb.invoke(self); + bound_cb.invoke(self_ptr); return CassError::CASS_OK; } // Store the callback @@ -293,7 +299,7 @@ pub unsafe extern "C" fn cass_future_set_callback( callback: CassFutureCallback, data: *mut ::std::os::raw::c_void, ) -> CassError { - ArcFFI::as_ref(future_raw).set_callback(callback, data) + ArcFFI::as_ref(future_raw).set_callback(future_raw, callback, data) } #[no_mangle] From 1d69f60ee6e792627ffeda3b7bf81b2341c27a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Wed, 18 Dec 2024 20:55:38 +0100 Subject: [PATCH 06/12] iter: hold reference to CassResult in CassResultIterator cpp-driver does not increase the reference count. The lifetime of the iterator is bound to the lifetime of result. --- scylla-rust-wrapper/src/query_result.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scylla-rust-wrapper/src/query_result.rs b/scylla-rust-wrapper/src/query_result.rs index 5cce03ef..35eabf70 100644 --- a/scylla-rust-wrapper/src/query_result.rs +++ b/scylla-rust-wrapper/src/query_result.rs @@ -302,7 +302,7 @@ fn get_column_value(column: CqlValue, column_type: &Arc) -> Value } pub struct CassResultIterator { - result: Arc, + result: &'static CassResult, position: Option, } @@ -848,7 +848,7 @@ pub unsafe extern "C" fn cass_iterator_get_materialized_view_meta( #[no_mangle] pub unsafe extern "C" fn cass_iterator_from_result(result: *const CassResult) -> *mut CassIterator { - let result_from_raw = ArcFFI::cloned_from_ptr(result); + let result_from_raw = ArcFFI::as_ref(result); let iterator = CassResultIterator { result: result_from_raw, From bec3871c9097397d17d77df70b1f87a6f06b40a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Wed, 18 Dec 2024 21:01:18 +0100 Subject: [PATCH 07/12] iter: parameterize CassIterator with lifetime It's more readable (and safe) to have an explicit lifetime instead of lifetime-erased references. --- scylla-rust-wrapper/src/query_result.rs | 114 +++++++++++++----------- 1 file changed, 61 insertions(+), 53 deletions(-) diff --git a/scylla-rust-wrapper/src/query_result.rs b/scylla-rust-wrapper/src/query_result.rs index 35eabf70..18d860d5 100644 --- a/scylla-rust-wrapper/src/query_result.rs +++ b/scylla-rust-wrapper/src/query_result.rs @@ -301,73 +301,73 @@ fn get_column_value(column: CqlValue, column_type: &Arc) -> Value } } -pub struct CassResultIterator { - result: &'static CassResult, +pub struct CassResultIterator<'result> { + result: &'result CassResult, position: Option, } -pub struct CassRowIterator { - row: &'static CassRow, +pub struct CassRowIterator<'result> { + row: &'result CassRow, position: Option, } -pub struct CassCollectionIterator { - value: &'static CassValue, +pub struct CassCollectionIterator<'result> { + value: &'result CassValue, count: u64, position: Option, } -pub struct CassMapIterator { - value: &'static CassValue, +pub struct CassMapIterator<'result> { + value: &'result CassValue, count: u64, position: Option, } -pub struct CassUdtIterator { - value: &'static CassValue, +pub struct CassUdtIterator<'result> { + value: &'result CassValue, count: u64, position: Option, } -pub struct CassSchemaMetaIterator { - value: &'static CassSchemaMeta, +pub struct CassSchemaMetaIterator<'schema> { + value: &'schema CassSchemaMeta, count: usize, position: Option, } -pub struct CassKeyspaceMetaIterator { - value: &'static CassKeyspaceMeta, +pub struct CassKeyspaceMetaIterator<'schema> { + value: &'schema CassKeyspaceMeta, count: usize, position: Option, } -pub struct CassTableMetaIterator { - value: &'static CassTableMeta, +pub struct CassTableMetaIterator<'schema> { + value: &'schema CassTableMeta, count: usize, position: Option, } -pub struct CassViewMetaIterator { - value: &'static CassMaterializedViewMeta, +pub struct CassViewMetaIterator<'schema> { + value: &'schema CassMaterializedViewMeta, count: usize, position: Option, } -pub enum CassIterator { - CassResultIterator(CassResultIterator), - CassRowIterator(CassRowIterator), - CassCollectionIterator(CassCollectionIterator), - CassMapIterator(CassMapIterator), - CassUdtIterator(CassUdtIterator), - CassSchemaMetaIterator(CassSchemaMetaIterator), - CassKeyspaceMetaTableIterator(CassKeyspaceMetaIterator), - CassKeyspaceMetaUserTypeIterator(CassKeyspaceMetaIterator), - CassKeyspaceMetaViewIterator(CassKeyspaceMetaIterator), - CassTableMetaIterator(CassTableMetaIterator), - CassViewMetaIterator(CassViewMetaIterator), +pub enum CassIterator<'result_or_schema> { + CassResultIterator(CassResultIterator<'result_or_schema>), + CassRowIterator(CassRowIterator<'result_or_schema>), + CassCollectionIterator(CassCollectionIterator<'result_or_schema>), + CassMapIterator(CassMapIterator<'result_or_schema>), + CassUdtIterator(CassUdtIterator<'result_or_schema>), + CassSchemaMetaIterator(CassSchemaMetaIterator<'result_or_schema>), + CassKeyspaceMetaTableIterator(CassKeyspaceMetaIterator<'result_or_schema>), + CassKeyspaceMetaUserTypeIterator(CassKeyspaceMetaIterator<'result_or_schema>), + CassKeyspaceMetaViewIterator(CassKeyspaceMetaIterator<'result_or_schema>), + CassTableMetaIterator(CassTableMetaIterator<'result_or_schema>), + CassViewMetaIterator(CassViewMetaIterator<'result_or_schema>), } -impl BoxFFI for CassIterator {} +impl BoxFFI for CassIterator<'_> {} #[no_mangle] pub unsafe extern "C" fn cass_iterator_free(iterator: *mut CassIterator) { @@ -847,7 +847,9 @@ pub unsafe extern "C" fn cass_iterator_get_materialized_view_meta( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_from_result(result: *const CassResult) -> *mut CassIterator { +pub unsafe extern "C" fn cass_iterator_from_result<'result>( + result: *const CassResult, +) -> *mut CassIterator<'result> { let result_from_raw = ArcFFI::as_ref(result); let iterator = CassResultIterator { @@ -859,7 +861,9 @@ pub unsafe extern "C" fn cass_iterator_from_result(result: *const CassResult) -> } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_from_row(row: *const CassRow) -> *mut CassIterator { +pub unsafe extern "C" fn cass_iterator_from_row<'result>( + row: *const CassRow, +) -> *mut CassIterator<'result> { let row_from_raw = RefFFI::as_ref(row); let iterator = CassRowIterator { @@ -871,9 +875,9 @@ pub unsafe extern "C" fn cass_iterator_from_row(row: *const CassRow) -> *mut Cas } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_from_collection( +pub unsafe extern "C" fn cass_iterator_from_collection<'result>( value: *const CassValue, -) -> *mut CassIterator { +) -> *mut CassIterator<'result> { let is_collection = cass_value_is_collection(value) != 0; if value.is_null() || !is_collection { @@ -897,7 +901,9 @@ pub unsafe extern "C" fn cass_iterator_from_collection( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_from_tuple(value: *const CassValue) -> *mut CassIterator { +pub unsafe extern "C" fn cass_iterator_from_tuple<'result>( + value: *const CassValue, +) -> *mut CassIterator<'result> { let tuple = RefFFI::as_ref(value); if let Some(Value::CollectionValue(Collection::Tuple(val))) = &tuple.value { @@ -915,7 +921,9 @@ pub unsafe extern "C" fn cass_iterator_from_tuple(value: *const CassValue) -> *m } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_from_map(value: *const CassValue) -> *mut CassIterator { +pub unsafe extern "C" fn cass_iterator_from_map<'result>( + value: *const CassValue, +) -> *mut CassIterator<'result> { let map = RefFFI::as_ref(value); if let Some(Value::CollectionValue(Collection::Map(val))) = &map.value { @@ -933,9 +941,9 @@ pub unsafe extern "C" fn cass_iterator_from_map(value: *const CassValue) -> *mut } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_fields_from_user_type( +pub unsafe extern "C" fn cass_iterator_fields_from_user_type<'result>( value: *const CassValue, -) -> *mut CassIterator { +) -> *mut CassIterator<'result> { let udt = RefFFI::as_ref(value); if let Some(Value::CollectionValue(Collection::UserDefinedType { fields, .. })) = &udt.value { @@ -953,9 +961,9 @@ pub unsafe extern "C" fn cass_iterator_fields_from_user_type( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_keyspaces_from_schema_meta( +pub unsafe extern "C" fn cass_iterator_keyspaces_from_schema_meta<'schema>( schema_meta: *const CassSchemaMeta, -) -> *mut CassIterator { +) -> *mut CassIterator<'schema> { let metadata = BoxFFI::as_ref(schema_meta); let iterator = CassSchemaMetaIterator { @@ -968,9 +976,9 @@ pub unsafe extern "C" fn cass_iterator_keyspaces_from_schema_meta( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_tables_from_keyspace_meta( +pub unsafe extern "C" fn cass_iterator_tables_from_keyspace_meta<'schema>( keyspace_meta: *const CassKeyspaceMeta, -) -> *mut CassIterator { +) -> *mut CassIterator<'schema> { let metadata = RefFFI::as_ref(keyspace_meta); let iterator = CassKeyspaceMetaIterator { @@ -985,9 +993,9 @@ pub unsafe extern "C" fn cass_iterator_tables_from_keyspace_meta( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_materialized_views_from_keyspace_meta( +pub unsafe extern "C" fn cass_iterator_materialized_views_from_keyspace_meta<'schema>( keyspace_meta: *const CassKeyspaceMeta, -) -> *mut CassIterator { +) -> *mut CassIterator<'schema> { let metadata = RefFFI::as_ref(keyspace_meta); let iterator = CassKeyspaceMetaIterator { @@ -1002,9 +1010,9 @@ pub unsafe extern "C" fn cass_iterator_materialized_views_from_keyspace_meta( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_user_types_from_keyspace_meta( +pub unsafe extern "C" fn cass_iterator_user_types_from_keyspace_meta<'schema>( keyspace_meta: *const CassKeyspaceMeta, -) -> *mut CassIterator { +) -> *mut CassIterator<'schema> { let metadata = RefFFI::as_ref(keyspace_meta); let iterator = CassKeyspaceMetaIterator { @@ -1019,9 +1027,9 @@ pub unsafe extern "C" fn cass_iterator_user_types_from_keyspace_meta( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_columns_from_table_meta( +pub unsafe extern "C" fn cass_iterator_columns_from_table_meta<'schema>( table_meta: *const CassTableMeta, -) -> *mut CassIterator { +) -> *mut CassIterator<'schema> { let metadata = RefFFI::as_ref(table_meta); let iterator = CassTableMetaIterator { @@ -1033,9 +1041,9 @@ pub unsafe extern "C" fn cass_iterator_columns_from_table_meta( BoxFFI::into_ptr(Box::new(CassIterator::CassTableMetaIterator(iterator))) } -pub unsafe extern "C" fn cass_iterator_materialized_views_from_table_meta( +pub unsafe extern "C" fn cass_iterator_materialized_views_from_table_meta<'schema>( table_meta: *const CassTableMeta, -) -> *mut CassIterator { +) -> *mut CassIterator<'schema> { let metadata = RefFFI::as_ref(table_meta); let iterator = CassTableMetaIterator { @@ -1047,9 +1055,9 @@ pub unsafe extern "C" fn cass_iterator_materialized_views_from_table_meta( BoxFFI::into_ptr(Box::new(CassIterator::CassTableMetaIterator(iterator))) } -pub unsafe extern "C" fn cass_iterator_columns_from_materialized_view_meta( +pub unsafe extern "C" fn cass_iterator_columns_from_materialized_view_meta<'schema>( view_meta: *const CassMaterializedViewMeta, -) -> *mut CassIterator { +) -> *mut CassIterator<'schema> { let metadata = RefFFI::as_ref(view_meta); let iterator = CassViewMetaIterator { From fe7c7f9b75d53e6038da5aa108dadabc6a2369bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Wed, 18 Dec 2024 21:06:28 +0100 Subject: [PATCH 08/12] session: pass Arc to async block instead of reference cpp-driver assumes that session object can be prematurely dropped. This means, that we should increase the reference count in functions where we pass the session to an async block. This will prevent UAF. There actually is a test case for this (AsyncTests::Close). However, we cannot enable it yet, since it expects that prematurely dropped session awaits all async tasks and before closing. --- scylla-rust-wrapper/src/session.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scylla-rust-wrapper/src/session.rs b/scylla-rust-wrapper/src/session.rs index 70f0fe6c..38abfbfc 100644 --- a/scylla-rust-wrapper/src/session.rs +++ b/scylla-rust-wrapper/src/session.rs @@ -71,7 +71,7 @@ impl CassSessionInner { // that holding it in our returned future is sound. Ideally, we would prefer to have // the returned future's lifetime constrained by real lifetime of the session's RwLock, // but this is impossible to be guaranteed due to C/Rust cross-language barrier. - session_opt: &'static RwLock>, + session_opt: Arc>>, cluster: &CassCluster, keyspace: Option, ) -> *const CassFuture { @@ -91,7 +91,7 @@ impl CassSessionInner { } async fn connect_fut( - session_opt: &RwLock>, + session_opt: Arc>>, session_builder_fut: impl Future, exec_profile_builder_map: HashMap, client_id: uuid::Uuid, @@ -151,7 +151,7 @@ pub unsafe extern "C" fn cass_session_connect( session_raw: *mut CassSession, cluster_raw: *const CassCluster, ) -> *const CassFuture { - let session_opt = ArcFFI::as_ref(session_raw); + let session_opt = ArcFFI::cloned_from_ptr(session_raw); let cluster: &CassCluster = BoxFFI::as_ref(cluster_raw); CassSessionInner::connect(session_opt, cluster, None) @@ -173,7 +173,7 @@ pub unsafe extern "C" fn cass_session_connect_keyspace_n( keyspace: *const c_char, keyspace_length: size_t, ) -> *const CassFuture { - let session_opt = ArcFFI::as_ref(session_raw); + let session_opt = ArcFFI::cloned_from_ptr(session_raw); let cluster: &CassCluster = BoxFFI::as_ref(cluster_raw); let keyspace = ptr_to_cstr_n(keyspace, keyspace_length).map(ToOwned::to_owned); @@ -185,7 +185,7 @@ pub unsafe extern "C" fn cass_session_execute_batch( session_raw: *mut CassSession, batch_raw: *const CassBatch, ) -> *const CassFuture { - let session_opt = ArcFFI::as_ref(session_raw); + let session_opt = ArcFFI::cloned_from_ptr(session_raw); let batch_from_raw = BoxFFI::as_ref(batch_raw); let mut state = batch_from_raw.state.clone(); let request_timeout_ms = batch_from_raw.batch_request_timeout_ms; @@ -251,7 +251,7 @@ pub unsafe extern "C" fn cass_session_execute( session_raw: *mut CassSession, statement_raw: *const CassStatement, ) -> *const CassFuture { - let session_opt = ArcFFI::as_ref(session_raw); + let session_opt = ArcFFI::cloned_from_ptr(session_raw); // DO NOT refer to `statement_opt` inside the async block, as I've done just to face a segfault. let statement_opt = BoxFFI::as_ref(statement_raw); @@ -386,7 +386,7 @@ pub unsafe extern "C" fn cass_session_prepare_from_existing( cass_session: *mut CassSession, statement: *const CassStatement, ) -> *const CassFuture { - let session = ArcFFI::as_ref(cass_session); + let session = ArcFFI::cloned_from_ptr(cass_session); let cass_statement = BoxFFI::as_ref(statement); let statement = cass_statement.statement.clone(); @@ -438,7 +438,7 @@ pub unsafe extern "C" fn cass_session_prepare_n( // There is a test for this: `NullStringApiArgsTest.Integration_Cassandra_PrepareNullQuery`. .unwrap_or_default(); let query = Query::new(query_str.to_string()); - let cass_session = ArcFFI::as_ref(cass_session_raw); + let cass_session = ArcFFI::cloned_from_ptr(cass_session_raw); CassFuture::make_raw(async move { let session_guard = cass_session.read().await; @@ -471,7 +471,7 @@ pub unsafe extern "C" fn cass_session_free(session_raw: *mut CassSession) { #[no_mangle] pub unsafe extern "C" fn cass_session_close(session: *mut CassSession) -> *const CassFuture { - let session_opt = ArcFFI::as_ref(session); + let session_opt = ArcFFI::cloned_from_ptr(session); CassFuture::make_raw(async move { let mut session_guard = session_opt.write().await; From 03db9fab66a353ef57009aa60f22b107176e0020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Thu, 19 Dec 2024 15:23:43 +0100 Subject: [PATCH 09/12] cargo: add "lib" to crate-type list It's required to enable the doctests for the crate. I also marked the code snippets from documentation in binding.rs with `text`. They should not be run as doc tests. --- scylla-rust-wrapper/Cargo.toml | 2 +- scylla-rust-wrapper/src/binding.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scylla-rust-wrapper/Cargo.toml b/scylla-rust-wrapper/Cargo.toml index b2377c46..43dbfe80 100644 --- a/scylla-rust-wrapper/Cargo.toml +++ b/scylla-rust-wrapper/Cargo.toml @@ -39,7 +39,7 @@ ntest = "0.9.3" rusty-fork = "0.3.0" [lib] name = "scylla_cpp_driver" -crate-type = ["cdylib", "staticlib"] +crate-type = ["cdylib", "staticlib", "lib"] [profile.dev] panic = "abort" diff --git a/scylla-rust-wrapper/src/binding.rs b/scylla-rust-wrapper/src/binding.rs index e9768889..3049b936 100644 --- a/scylla-rust-wrapper/src/binding.rs +++ b/scylla-rust-wrapper/src/binding.rs @@ -371,13 +371,13 @@ macro_rules! invoke_binder_maker_macro_with_type { /// There are also 2 helper variants, to accomodate scenarios often encountered in cppdriver (sets of 3 functions, /// binding the same type by index, name and name_n): /// * `make_binders!(type, fn_idx, fn_name, fn_name_n)` - is equivalent to: -/// ``` +/// ```text /// make_binders!(@index type, fn_idx); /// make_binders!(@name type, fn_name); /// make_binders!(@name_n type, fn_name_n); /// ``` /// * `make_binders!(t1, fn_idx, t2, fn_name, t3, fn_name_n)` - is equivalent to: -/// ``` +/// ```text /// make_binders!(@index t1, fn_idx); /// make_binders!(@name t2, fn_name); /// make_binders!(@name_n t3, fn_name_n); From 549f797c4c03d65820b92f3af4495b7272b4301b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Tue, 17 Dec 2024 17:06:43 +0100 Subject: [PATCH 10/12] argconv: introduce CassPtr This commit introduces a `CassPtr` type, generic over pointer `Properties`. It allows specific pointer-to-reference conversions based on the guarantees provided by the pointer type. --- scylla-rust-wrapper/src/argconv.rs | 205 +++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/scylla-rust-wrapper/src/argconv.rs b/scylla-rust-wrapper/src/argconv.rs index 058ea45e..3d716169 100644 --- a/scylla-rust-wrapper/src/argconv.rs +++ b/scylla-rust-wrapper/src/argconv.rs @@ -1,7 +1,9 @@ use crate::types::size_t; use std::cmp::min; use std::ffi::CStr; +use std::marker::PhantomData; use std::os::raw::c_char; +use std::ptr::NonNull; use std::sync::Arc; pub unsafe fn ptr_to_cstr(ptr: *const c_char) -> Option<&'static str> { @@ -71,6 +73,209 @@ macro_rules! make_c_str { #[cfg(test)] pub(crate) use make_c_str; +mod sealed { + pub trait Sealed {} +} + +/// A trait representing mutability of the pointer. +/// +/// Pointer can either be [`Const`] or [`Mut`]. +/// +/// ## Const pointers +/// Const pointers can only be converted to **immutable** Rust referential types. +/// There is no way to obtain a mutable reference from such pointer. +/// +/// In some cases, we need to be able to mutate the data behind a shared pointer. +/// There is an example of such use case - namely [`crate::cass_types::CassDataType`]. +/// argconv API does not provide a way to mutate such pointer - one can only convert the pointer +/// to [`Arc`] or &. It is the API user's responsibility to implement sound interior mutability +/// pattern in such case. This is what we currently do - CassDataType wraps CassDataTypeInner +/// inside an `UnsafeCell` to implement interior mutability for the type. +/// Other example is [`crate::future::CassFuture`] which uses Mutex. +/// +/// ## Mut pointers +/// Mut pointers can be converted to both immutable and mutable Rust referential types. +pub trait Mutability: sealed::Sealed {} + +/// Represents immutable pointer. +pub struct Const; +impl sealed::Sealed for Const {} +impl Mutability for Const {} + +/// Represents mutable pointer. +pub struct Mut; +impl sealed::Sealed for Mut {} +impl Mutability for Mut {} + +/// Represents additional properties of the pointer. +pub trait Properties: sealed::Sealed { + type Mutability: Mutability; +} + +impl sealed::Sealed for (M,) {} +impl Properties for (M,) { + type Mutability = M; +} + +/// Represents a valid non-dangling pointer. +/// +/// ## Safety and validity guarantees +/// Apart from trivial constructors such as [`CassPtr::null()`] and [`CassPtr::null_mut()`], there +/// is only one way to construct a [`CassPtr`] instance - from raw pointer via [`CassPtr::from_raw()`]. +/// This constructor is `unsafe`. It is user's responsibility to ensure that the raw pointer +/// provided to the constructor is **valid**. In other words, the pointer comes from some valid +/// allocation, or from some valid reference. +/// +/// ## Generic lifetime and aliasing guarantees +/// We distinguish two types of pointers: immutable ([`Const`]) and mutable ([`Mut`]). +/// Immutable pointers can be converted to immutable (&) references, while mutable pointers +/// can be converted to either immutable (&) or mutable (&mut) reference. User needs to pick +/// the correct mutability property of the pointer during construction. This is yet another +/// reason why [`CassPtr::from_raw`] is `unsafe`. +/// +/// Pointer is parameterized by the lifetime. Thanks to that, we can represent +/// the `Ownership` of the pointer. Once again, user is responsible for "picking" +/// the correct lifetime when creating the pointer. For example, when raw pointer +/// comes from [`Box::into_raw()`], user could create a [`CassPtr<'static, T, (Mut,)>`]. +/// `'static` lifetime represents that user is the exclusive **owner** of the pointee, and +/// is responsible for freeing the memory (e.g. via [`Box::from_raw()`]). +/// On the other hand, when pointer is created from some immutable reference `&'a T`, +/// the correct choice of CassPtr would be [`CassPtr<'a, T, (Const,)>`]. It means that +/// holder of the created pointer **borrows** the pointee (with some lifetime `'a` +/// inherited from the immutable borrow `&'a T`). +/// +/// Both [`CassPtr::as_ref()`] and [`CassPtr::as_mut_ref()`] consume the pointer. +/// At first glance, it seems impossible to obtain multiple immutable reference from one pointer. +/// This is why pointer reborrowing mechanism is introduced. There are two methods: [`CassPtr::borrow()`] +/// and [`CassPtr::borrow_mut()`]. Both of them cooperate with borrow checker and enforce +/// aliasing XOR mutability principle at compile time. +/// +/// ## Safe conversions to referential types +/// Thanks to the above guarantees, conversions to referential types are **safe**. +/// See methods [`CassPtr::as_ref()`] and [`CassPtr::as_mut_ref()`]. +/// +/// ## Memory layout +/// We use repr(transparent), so the struct has the same layout as underlying [`Option>`]. +/// Thanks to https://doc.rust-lang.org/std/option/#representation optimization, +/// we are guaranteed, that for `T: Sized`, our struct has the same layout +/// and function call ABI as simply [`NonNull`]. +#[repr(transparent)] +pub struct CassPtr<'a, T: Sized, P: Properties> { + ptr: Option>, + _phantom: PhantomData<&'a P>, +} + +/// Owned immutable pointer. +/// Can be used for pointers with shared ownership - e.g. pointers coming from [`Arc`] allocation. +pub type CassOwnedPtr = CassPtr<'static, T, (Const,)>; + +/// Borrowed immutable pointer. +/// Can be used for pointers created from some immutable reference. +pub type CassBorrowedPtr<'a, T> = CassPtr<'a, T, (Const,)>; + +/// Owned mutable pointer. +/// Can be used for pointers with exclusive ownership - e.g. pointers coming from [`Box`] allocation. +pub type CassOwnedMutPtr = CassPtr<'static, T, (Mut,)>; + +/// Borrowed mutable pointer. +/// This can be for example obtained from mutable reborrow of some [`CassOwnedMutPtr`]. +pub type CassBorrowedMutPtr<'a, T> = CassPtr<'a, T, (Mut,)>; + +/// Pointer constructors. +impl CassPtr<'_, T, P> { + fn null() -> Self { + CassPtr { + ptr: None, + _phantom: PhantomData, + } + } + + fn is_null(&self) -> bool { + self.ptr.is_none() + } + + /// Constructs [`CassPtr`] from raw pointer. + /// + /// ## Safety + /// User needs to ensure that the pointer is **valid**. + /// User is also responsible for picking correct mutability property and lifetime + /// of the created pointer. For more information, see the documentation of [`CassPtr`]. + unsafe fn from_raw(raw: *const T) -> Self { + CassPtr { + ptr: NonNull::new(raw as *mut T), + _phantom: PhantomData, + } + } +} + +/// Conversion to raw pointer. +impl CassPtr<'_, T, P> { + fn to_raw(&self) -> Option<*mut T> { + self.ptr.map(|ptr| ptr.as_ptr()) + } +} + +/// Constructors exclusive to mutable pointers. +impl CassPtr<'_, T, (Mut,)> { + fn null_mut() -> Self { + CassPtr { + ptr: None, + _phantom: PhantomData, + } + } +} + +impl<'a, T: Sized, P: Properties> CassPtr<'a, T, P> { + /// Converts a pointer to an optional valid reference. + /// The reference inherits the lifetime of the pointer. + #[allow(clippy::wrong_self_convention)] + fn as_ref(self) -> Option<&'a T> { + // SAFETY: Thanks to the validity and aliasing ^ mutability guarantees, + // we can safely convert the pointer to valid immutable reference with + // correct lifetime. + unsafe { self.ptr.map(|p| p.as_ref()) } + } +} + +impl<'a, T: Sized> CassPtr<'a, T, (Mut,)> { + /// Converts a pointer to an optional valid mutable reference. + /// The reference inherits the lifetime of the pointer. + #[allow(clippy::wrong_self_convention)] + fn as_mut_ref(self) -> Option<&'a mut T> { + // SAFETY: Thanks to the validity and aliasing ^ mutability guarantees, + // we can safely convert the pointer to valid mutable (and exclusive) reference with + // correct lifetime. + unsafe { self.ptr.map(|mut p| p.as_mut()) } + } +} + +impl CassPtr<'_, T, P> { + /// Immutably reborrows the pointer. + /// Resulting pointer inherits the lifetime from the immutable borrow + /// of original pointer. + #[allow(clippy::needless_lifetimes)] + pub fn borrow<'a>(&'a self) -> CassPtr<'a, T, (Const,)> { + CassPtr { + ptr: self.ptr, + _phantom: PhantomData, + } + } +} + +impl CassPtr<'_, T, (Mut,)> { + /// Mutably reborrows the pointer. + /// Resulting pointer inherits the lifetime from the mutable borrow + /// of original pointer. Since the method accepts a mutable reference + /// to the original pointer, we enforce aliasing ^ mutability principle at compile time. + #[allow(clippy::needless_lifetimes)] + pub fn borrow_mut<'a>(&'a mut self) -> CassPtr<'a, T, (Mut,)> { + CassPtr { + ptr: self.ptr, + _phantom: PhantomData, + } + } +} + /// Defines a pointer manipulation API for non-shared heap-allocated data. /// /// Implement this trait for types that are allocated by the driver via [`Box::new`], From 00f89314b8c1622c84fedaadcfa75a5250e605b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Tue, 26 Nov 2024 16:01:42 +0100 Subject: [PATCH 11/12] argconv: adjust FFI apis to new pointer type Existing `Ref/Box/Arc`FFIs are adjusted, so they now allow interaction with new pointer type. You can say, that for a user of `argconv` API, new type is opaque. The only way to operate on it is to use the corresponding ffi API. --- scylla-rust-wrapper/src/argconv.rs | 274 ++++++-- scylla-rust-wrapper/src/batch.rs | 48 +- scylla-rust-wrapper/src/binding.rs | 34 +- scylla-rust-wrapper/src/cass_types.rs | 131 ++-- scylla-rust-wrapper/src/cluster.rs | 280 ++++---- scylla-rust-wrapper/src/collection.rs | 106 ++- scylla-rust-wrapper/src/exec_profile.rs | 147 ++-- scylla-rust-wrapper/src/future.rs | 157 +++-- .../src/integration_testing.rs | 16 +- scylla-rust-wrapper/src/lib.rs | 2 +- scylla-rust-wrapper/src/logging.rs | 19 +- scylla-rust-wrapper/src/metadata.rs | 239 ++++--- scylla-rust-wrapper/src/prepared.rs | 32 +- scylla-rust-wrapper/src/query_error.rs | 54 +- scylla-rust-wrapper/src/query_result.rs | 639 +++++++++--------- scylla-rust-wrapper/src/retry_policy.rs | 11 +- scylla-rust-wrapper/src/session.rs | 535 ++++++++++----- scylla-rust-wrapper/src/ssl.rs | 33 +- scylla-rust-wrapper/src/statement.rs | 60 +- scylla-rust-wrapper/src/testing.rs | 2 +- scylla-rust-wrapper/src/tuple.rs | 26 +- scylla-rust-wrapper/src/user_type.rs | 16 +- scylla-rust-wrapper/src/uuid.rs | 19 +- 23 files changed, 1722 insertions(+), 1158 deletions(-) diff --git a/scylla-rust-wrapper/src/argconv.rs b/scylla-rust-wrapper/src/argconv.rs index 3d716169..311f616b 100644 --- a/scylla-rust-wrapper/src/argconv.rs +++ b/scylla-rust-wrapper/src/argconv.rs @@ -4,7 +4,7 @@ use std::ffi::CStr; use std::marker::PhantomData; use std::os::raw::c_char; use std::ptr::NonNull; -use std::sync::Arc; +use std::sync::{Arc, Weak}; pub unsafe fn ptr_to_cstr(ptr: *const c_char) -> Option<&'static str> { CStr::from_ptr(ptr).to_str().ok() @@ -281,30 +281,65 @@ impl CassPtr<'_, T, (Mut,)> { /// Implement this trait for types that are allocated by the driver via [`Box::new`], /// and then returned to the user as a pointer. The user is responsible for freeing /// the memory associated with the pointer using corresponding driver's API function. -pub trait BoxFFI { - fn into_ptr(self: Box) -> *mut Self { +pub trait BoxFFI: Sized { + /// Consumes the Box and returns a pointer with exclusive ownership. + /// The pointer needs to be freed. See [`BoxFFI::free()`]. + fn into_ptr(self: Box) -> CassPtr<'static, Self, (M,)> { #[allow(clippy::disallowed_methods)] - Box::into_raw(self) + let ptr = Box::into_raw(self); + + // SAFETY: + // 1. validity guarantee - pointer is obviously valid. It comes from box allocation. + // 2. pointer's lifetime - we choose 'static lifetime. It is ok, because holder of the + // pointer becomes the owner of pointee. He is responsible for freeing the memory + // via BoxFFI::free() - which accepts 'static pointer. User is not able to obtain + // another pointer with 'static lifetime pointing to the same memory. + // 3. mutability - user becomes an exclusive owner of the pointee. Thus, it's ok + // for the pointer to be `Mut`. + unsafe { CassPtr::from_raw(ptr) } } - unsafe fn from_ptr(ptr: *mut Self) -> Box { - #[allow(clippy::disallowed_methods)] - Box::from_raw(ptr) + + /// Consumes the pointer with exclusive ownership back to the Box. + fn from_ptr(ptr: CassPtr<'static, Self, (M,)>) -> Option> { + // SAFETY: + // The only way to obtain an owned pointer (with 'static lifetime) is BoxFFI::into_ptr(). + // It creates a pointer based on Box allocation. It is thus safe to convert the pointer + // back to owned `Box`. + unsafe { + ptr.to_raw().map(|p| { + #[allow(clippy::disallowed_methods)] + Box::from_raw(p) + }) + } } - unsafe fn as_maybe_ref<'a>(ptr: *const Self) -> Option<&'a Self> { - #[allow(clippy::disallowed_methods)] + + /// Creates a reference from an exclusive pointer. + /// Reference inherits the lifetime of the pointer's borrow. + #[allow(clippy::needless_lifetimes)] + fn as_ref<'a, M: Mutability>(ptr: CassPtr<'a, Self, (M,)>) -> Option<&'a Self> { ptr.as_ref() } - unsafe fn as_ref<'a>(ptr: *const Self) -> &'a Self { - #[allow(clippy::disallowed_methods)] - ptr.as_ref().unwrap() - } - unsafe fn as_mut_ref<'a>(ptr: *mut Self) -> &'a mut Self { - #[allow(clippy::disallowed_methods)] - ptr.as_mut().unwrap() + + /// Creates a mutable from an exlusive pointer. + /// Reference inherits the lifetime of the pointer's mutable borrow. + #[allow(clippy::needless_lifetimes)] + fn as_mut_ref<'a>(ptr: CassPtr<'a, Self, (Mut,)>) -> Option<&'a mut Self> { + ptr.as_mut_ref() } - unsafe fn free(ptr: *mut Self) { + + /// Frees the pointee. + fn free(ptr: CassPtr<'static, Self, (Mut,)>) { std::mem::drop(BoxFFI::from_ptr(ptr)); } + + #[cfg(test)] + fn null<'a>() -> CassPtr<'a, Self, (Const,)> { + CassPtr::null() + } + + fn null_mut<'a>() -> CassPtr<'a, Self, (Mut,)> { + CassPtr::null_mut() + } } /// Defines a pointer manipulation API for shared heap-allocated data. @@ -313,36 +348,86 @@ pub trait BoxFFI { /// The data should be allocated via [`Arc::new`], and then returned to the user as a pointer. /// The user is responsible for freeing the memory associated /// with the pointer using corresponding driver's API function. -pub trait ArcFFI { - fn as_ptr(self: &Arc) -> *const Self { +pub trait ArcFFI: Sized { + /// Creates a pointer from a valid reference to Arc-allocated data. + /// Holder of the pointer borrows the pointee. + fn as_ptr<'a>(self: &'a Arc) -> CassPtr<'a, Self, (Const,)> { #[allow(clippy::disallowed_methods)] - Arc::as_ptr(self) + let ptr = Arc::as_ptr(self); + + // SAFETY: + // 1. validity guarantee - pointer is valid, since it's obtained from Arc allocation + // 2. pointer's lifetime - pointer inherits the lifetime of provided Arc's borrow. + // What's important is that the returned pointer borrows the data, and is not the + // shared owner. Thus, user cannot call ArcFFI::free() on such pointer. + // 3. mutability - we always create a `Const` pointer. + unsafe { CassPtr::from_raw(ptr) } } - fn into_ptr(self: Arc) -> *const Self { + + /// Creates a pointer from a valid Arc allocation. + fn into_ptr(self: Arc) -> CassPtr<'static, Self, (Const,)> { #[allow(clippy::disallowed_methods)] - Arc::into_raw(self) + let ptr = Arc::into_raw(self); + + // SAFETY: + // 1. validity guarantee - pointer is valid, since it's obtained from Arc allocation + // 2. pointer's lifetime - returned pointer has a 'static lifetime. It is a shared + // owner of the pointee. User has to decrease the RC of the pointer (and potentially free the memory) + // via ArcFFI::free(). + // 3. mutability - we always create a `Const` pointer. + unsafe { CassPtr::from_raw(ptr) } } - unsafe fn from_ptr(ptr: *const Self) -> Arc { - #[allow(clippy::disallowed_methods)] - Arc::from_raw(ptr) + + /// Converts shared owned pointer back to owned Arc. + fn from_ptr(ptr: CassPtr<'static, Self, (Const,)>) -> Option> { + // SAFETY: + // The only way to obtain a pointer with shared ownership ('static lifetime) is + // ArcFFI::into_ptr(). It converts an owned Arc into the pointer. It is thus safe, + // to convert such pointer back to owned Arc. + unsafe { + ptr.to_raw().map(|p| { + #[allow(clippy::disallowed_methods)] + Arc::from_raw(p) + }) + } } - unsafe fn cloned_from_ptr(ptr: *const Self) -> Arc { - #[allow(clippy::disallowed_methods)] - Arc::increment_strong_count(ptr); - #[allow(clippy::disallowed_methods)] - Arc::from_raw(ptr) + + /// Increases the reference count of the pointer, and returns an owned Arc. + fn cloned_from_ptr(ptr: CassPtr<'_, Self, (Const,)>) -> Option> { + // SAFETY: + // All pointers created via ArcFFI API are originated from Arc allocation. + // It is thus safe, to increase the reference count of the pointer, and convert + // it to Arc. Because of the borrow-checker, it is not possible for the user + // to provide the pointer that points to already deallocated memory. + unsafe { + ptr.to_raw().map(|p| { + #[allow(clippy::disallowed_methods)] + Arc::increment_strong_count(p); + #[allow(clippy::disallowed_methods)] + Arc::from_raw(p) + }) + } } - unsafe fn as_maybe_ref<'a>(ptr: *const Self) -> Option<&'a Self> { - #[allow(clippy::disallowed_methods)] + + /// Converts a shared borrowed pointer to reference. + /// The reference inherits the lifetime of pointer's borrow. + #[allow(clippy::needless_lifetimes)] + fn as_ref<'a>(ptr: CassPtr<'a, Self, (Const,)>) -> Option<&'a Self> { ptr.as_ref() } - unsafe fn as_ref<'a>(ptr: *const Self) -> &'a Self { - #[allow(clippy::disallowed_methods)] - ptr.as_ref().unwrap() - } - unsafe fn free(ptr: *const Self) { + + /// Decreases the reference count (and potentially frees) of the owned pointer. + fn free(ptr: CassPtr<'static, Self, (Const,)>) { std::mem::drop(ArcFFI::from_ptr(ptr)); } + + fn null<'a>() -> CassPtr<'a, Self, (Const,)> { + CassPtr::null() + } + + fn is_null(ptr: &CassPtr<'_, Self, (Const,)>) -> bool { + ptr.is_null() + } } /// Defines a pointer manipulation API for data owned by some other object. @@ -353,12 +438,115 @@ pub trait ArcFFI { /// For example: lifetime of CassRow is bound by the lifetime of CassResult. /// There is no API function that frees the CassRow. It should be automatically /// freed when user calls cass_result_free. -pub trait RefFFI { - fn as_ptr(&self) -> *const Self { - self as *const Self +pub trait RefFFI: Sized { + /// Creates a borrowed pointer from a valid reference. + #[allow(clippy::needless_lifetimes)] + fn as_ptr<'a>(&'a self) -> CassPtr<'a, Self, (Const,)> { + // SAFETY: + // 1. validity guarantee - pointer is valid, since it's obtained a valid reference. + // 2. pointer's lifetime - pointer inherits the lifetime of provided reference's borrow. + // 3. mutability - we always create a `Const` pointer. + unsafe { CassPtr::from_raw(self) } } - unsafe fn as_ref<'a>(ptr: *const Self) -> &'a Self { - #[allow(clippy::disallowed_methods)] - ptr.as_ref().unwrap() + + /// Creates a borrowed pointer from a weak reference. + /// + /// ## SAFETY + /// User needs to ensure that the pointee is not freed when pointer is being + /// dereferenced. + #[allow(clippy::needless_lifetimes)] + unsafe fn weak_as_ptr<'a>(w: &'a Weak) -> CassPtr<'a, Self, (Const,)> { + match w.upgrade() { + Some(a) => { + #[allow(clippy::disallowed_methods)] + let ptr = Arc::as_ptr(&a); + unsafe { CassPtr::from_raw(ptr) } + } + None => CassPtr::null(), + } + } + + /// Converts a borrowed pointer to reference. + /// The reference inherits the lifetime of pointer's borrow. + #[allow(clippy::needless_lifetimes)] + fn as_ref<'a>(ptr: CassPtr<'a, Self, (Const,)>) -> Option<&'a Self> { + ptr.as_ref() + } + + fn null<'a>() -> CassPtr<'a, Self, (Const,)> { + CassPtr::null() + } + + fn is_null(ptr: &CassPtr<'_, Self, (Const,)>) -> bool { + ptr.is_null() } } + +/// ```compile_fail,E0499 +/// # use scylla_cpp_driver::argconv::{CassOwnedMutPtr, CassBorrowedMutPtr}; +/// # use scylla_cpp_driver::argconv::BoxFFI; +/// struct Foo; +/// impl BoxFFI for Foo {} +/// +/// let mut ptr: CassOwnedMutPtr = BoxFFI::into_ptr(Box::new(Foo)); +/// let borrowed_mut_ptr1: CassBorrowedMutPtr = ptr.borrow_mut(); +/// let borrowed_mut_ptr2: CassBorrowedMutPtr = ptr.borrow_mut(); +/// let mutref1 = BoxFFI::as_mut_ref(borrowed_mut_ptr2); +/// let mutref2 = BoxFFI::as_mut_ref(borrowed_mut_ptr1); +/// ``` +fn _test_box_ffi_cannot_have_two_mutable_references() {} + +/// ```compile_fail,E0502 +/// # use scylla_cpp_driver::argconv::{CassOwnedMutPtr, CassBorrowedPtr, CassBorrowedMutPtr}; +/// # use scylla_cpp_driver::argconv::BoxFFI; +/// struct Foo; +/// impl BoxFFI for Foo {} +/// +/// let mut ptr: CassOwnedMutPtr = BoxFFI::into_ptr(Box::new(Foo)); +/// let borrowed_mut_ptr: CassBorrowedMutPtr = ptr.borrow_mut(); +/// let borrowed_ptr: CassBorrowedPtr = ptr.borrow(); +/// let immref = BoxFFI::as_ref(borrowed_ptr); +/// let mutref = BoxFFI::as_mut_ref(borrowed_mut_ptr); +/// ``` +fn _test_box_ffi_cannot_have_mutable_and_immutable_references_at_the_same_time() {} + +/// ```compile_fail,E0505 +/// # use scylla_cpp_driver::argconv::{CassOwnedMutPtr, CassBorrowedPtr}; +/// # use scylla_cpp_driver::argconv::BoxFFI; +/// struct Foo; +/// impl BoxFFI for Foo {} +/// +/// let ptr: CassOwnedMutPtr = BoxFFI::into_ptr(Box::new(Foo)); +/// let borrowed_ptr: CassBorrowedPtr = ptr.borrow(); +/// BoxFFI::free(ptr); +/// let immref = BoxFFI::as_ref(borrowed_ptr); +/// ``` +fn _test_box_ffi_cannot_free_while_having_borrowed_pointer() {} + +/// ```compile_fail,E0505 +/// # use scylla_cpp_driver::argconv::{CassOwnedPtr, CassBorrowedPtr}; +/// # use scylla_cpp_driver::argconv::ArcFFI; +/// # use std::sync::Arc; +/// struct Foo; +/// impl ArcFFI for Foo {} +/// +/// let ptr: CassOwnedPtr = ArcFFI::into_ptr(Arc::new(Foo)); +/// let borrowed_ptr: CassBorrowedPtr = ptr.borrow(); +/// ArcFFI::free(ptr); +/// let immref = ArcFFI::cloned_from_ptr(borrowed_ptr); +/// ``` +fn _test_arc_ffi_cannot_clone_after_free() {} + +/// ```compile_fail,E0505 +/// # use scylla_cpp_driver::argconv::{CassBorrowedPtr}; +/// # use scylla_cpp_driver::argconv::ArcFFI; +/// # use std::sync::Arc; +/// struct Foo; +/// impl ArcFFI for Foo {} +/// +/// let arc = Arc::new(Foo); +/// let borrowed_ptr: CassBorrowedPtr = ArcFFI::as_ptr(&arc); +/// std::mem::drop(arc); +/// let immref = ArcFFI::cloned_from_ptr(borrowed_ptr); +/// ``` +fn _test_arc_ffi_cannot_dereference_borrowed_after_drop() {} diff --git a/scylla-rust-wrapper/src/batch.rs b/scylla-rust-wrapper/src/batch.rs index ea8dd453..076be38b 100644 --- a/scylla-rust-wrapper/src/batch.rs +++ b/scylla-rust-wrapper/src/batch.rs @@ -1,4 +1,4 @@ -use crate::argconv::{ArcFFI, BoxFFI}; +use crate::argconv::{ArcFFI, BoxFFI, CassBorrowedMutPtr, CassBorrowedPtr, CassOwnedMutPtr}; use crate::cass_error::CassError; use crate::cass_types::CassConsistency; use crate::cass_types::{make_batch_type, CassBatchType}; @@ -28,7 +28,7 @@ pub struct CassBatchState { } #[no_mangle] -pub unsafe extern "C" fn cass_batch_new(type_: CassBatchType) -> *mut CassBatch { +pub unsafe extern "C" fn cass_batch_new(type_: CassBatchType) -> CassOwnedMutPtr { if let Some(batch_type) = make_batch_type(type_) { BoxFFI::into_ptr(Box::new(CassBatch { state: Arc::new(CassBatchState { @@ -39,21 +39,21 @@ pub unsafe extern "C" fn cass_batch_new(type_: CassBatchType) -> *mut CassBatch exec_profile: None, })) } else { - std::ptr::null_mut() + BoxFFI::null_mut() } } #[no_mangle] -pub unsafe extern "C" fn cass_batch_free(batch: *mut CassBatch) { +pub unsafe extern "C" fn cass_batch_free(batch: CassOwnedMutPtr) { BoxFFI::free(batch); } #[no_mangle] pub unsafe extern "C" fn cass_batch_set_consistency( - batch: *mut CassBatch, + batch: CassBorrowedMutPtr, consistency: CassConsistency, ) -> CassError { - let batch = BoxFFI::as_mut_ref(batch); + let batch = BoxFFI::as_mut_ref(batch).unwrap(); let consistency = match consistency.try_into().ok() { Some(c) => c, None => return CassError::CASS_ERROR_LIB_BAD_PARAMS, @@ -67,10 +67,10 @@ pub unsafe extern "C" fn cass_batch_set_consistency( #[no_mangle] pub unsafe extern "C" fn cass_batch_set_serial_consistency( - batch: *mut CassBatch, + batch: CassBorrowedMutPtr, serial_consistency: CassConsistency, ) -> CassError { - let batch = BoxFFI::as_mut_ref(batch); + let batch = BoxFFI::as_mut_ref(batch).unwrap(); let serial_consistency = match serial_consistency.try_into().ok() { Some(c) => c, None => return CassError::CASS_ERROR_LIB_BAD_PARAMS, @@ -84,13 +84,13 @@ pub unsafe extern "C" fn cass_batch_set_serial_consistency( #[no_mangle] pub unsafe extern "C" fn cass_batch_set_retry_policy( - batch: *mut CassBatch, - retry_policy: *const CassRetryPolicy, + batch: CassBorrowedMutPtr, + retry_policy: CassBorrowedPtr, ) -> CassError { - let batch = BoxFFI::as_mut_ref(batch); + let batch = BoxFFI::as_mut_ref(batch).unwrap(); let maybe_arced_retry_policy: Option> = - ArcFFI::as_maybe_ref(retry_policy).map(|policy| match policy { + ArcFFI::as_ref(retry_policy).map(|policy| match policy { CassRetryPolicy::DefaultRetryPolicy(default) => { default.clone() as Arc } @@ -107,10 +107,10 @@ pub unsafe extern "C" fn cass_batch_set_retry_policy( #[no_mangle] pub unsafe extern "C" fn cass_batch_set_timestamp( - batch: *mut CassBatch, + batch: CassBorrowedMutPtr, timestamp: cass_int64_t, ) -> CassError { - let batch = BoxFFI::as_mut_ref(batch); + let batch = BoxFFI::as_mut_ref(batch).unwrap(); Arc::make_mut(&mut batch.state) .batch @@ -121,10 +121,10 @@ pub unsafe extern "C" fn cass_batch_set_timestamp( #[no_mangle] pub unsafe extern "C" fn cass_batch_set_request_timeout( - batch: *mut CassBatch, + batch: CassBorrowedMutPtr, timeout_ms: cass_uint64_t, ) -> CassError { - let batch = BoxFFI::as_mut_ref(batch); + let batch = BoxFFI::as_mut_ref(batch).unwrap(); batch.batch_request_timeout_ms = Some(timeout_ms); CassError::CASS_OK @@ -132,10 +132,10 @@ pub unsafe extern "C" fn cass_batch_set_request_timeout( #[no_mangle] pub unsafe extern "C" fn cass_batch_set_is_idempotent( - batch: *mut CassBatch, + batch: CassBorrowedMutPtr, is_idempotent: cass_bool_t, ) -> CassError { - let batch = BoxFFI::as_mut_ref(batch); + let batch = BoxFFI::as_mut_ref(batch).unwrap(); Arc::make_mut(&mut batch.state) .batch .set_is_idempotent(is_idempotent != 0); @@ -145,10 +145,10 @@ pub unsafe extern "C" fn cass_batch_set_is_idempotent( #[no_mangle] pub unsafe extern "C" fn cass_batch_set_tracing( - batch: *mut CassBatch, + batch: CassBorrowedMutPtr, enabled: cass_bool_t, ) -> CassError { - let batch = BoxFFI::as_mut_ref(batch); + let batch = BoxFFI::as_mut_ref(batch).unwrap(); Arc::make_mut(&mut batch.state) .batch .set_tracing(enabled != 0); @@ -158,12 +158,12 @@ pub unsafe extern "C" fn cass_batch_set_tracing( #[no_mangle] pub unsafe extern "C" fn cass_batch_add_statement( - batch: *mut CassBatch, - statement: *const CassStatement, + batch: CassBorrowedMutPtr, + statement: CassBorrowedPtr, ) -> CassError { - let batch = BoxFFI::as_mut_ref(batch); + let batch = BoxFFI::as_mut_ref(batch).unwrap(); let state = Arc::make_mut(&mut batch.state); - let statement = BoxFFI::as_ref(statement); + let statement = BoxFFI::as_ref(statement).unwrap(); match &statement.statement { BoundStatement::Simple(q) => { diff --git a/scylla-rust-wrapper/src/binding.rs b/scylla-rust-wrapper/src/binding.rs index 3049b936..5d02dedc 100644 --- a/scylla-rust-wrapper/src/binding.rs +++ b/scylla-rust-wrapper/src/binding.rs @@ -53,7 +53,7 @@ macro_rules! make_index_binder { #[no_mangle] #[allow(clippy::redundant_closure_call)] pub unsafe extern "C" fn $fn_by_idx( - this: *mut $this, + this: CassBorrowedMutPtr<$this>, index: size_t, $($arg: $t), * ) -> CassError { @@ -61,7 +61,7 @@ macro_rules! make_index_binder { #[allow(unused_imports)] use crate::value::CassCqlValue::*; match ($e)($($arg), *) { - Ok(v) => $consume_v(BoxFFI::as_mut_ref(this), index as usize, v), + Ok(v) => $consume_v(BoxFFI::as_mut_ref( this).unwrap(), index as usize, v), Err(e) => e, } } @@ -73,7 +73,7 @@ macro_rules! make_name_binder { #[no_mangle] #[allow(clippy::redundant_closure_call)] pub unsafe extern "C" fn $fn_by_name( - this: *mut $this, + this: CassBorrowedMutPtr<$this>, name: *const c_char, $($arg: $t), * ) -> CassError { @@ -82,7 +82,7 @@ macro_rules! make_name_binder { use crate::value::CassCqlValue::*; let name = ptr_to_cstr(name).unwrap(); match ($e)($($arg), *) { - Ok(v) => $consume_v(BoxFFI::as_mut_ref(this), name, v), + Ok(v) => $consume_v(BoxFFI::as_mut_ref( this).unwrap(), name, v), Err(e) => e, } } @@ -94,7 +94,7 @@ macro_rules! make_name_n_binder { #[no_mangle] #[allow(clippy::redundant_closure_call)] pub unsafe extern "C" fn $fn_by_name_n( - this: *mut $this, + this: CassBorrowedMutPtr<$this>, name: *const c_char, name_length: size_t, $($arg: $t), * @@ -104,7 +104,7 @@ macro_rules! make_name_n_binder { use crate::value::CassCqlValue::*; let name = ptr_to_cstr_n(name, name_length).unwrap(); match ($e)($($arg), *) { - Ok(v) => $consume_v(BoxFFI::as_mut_ref(this), name, v), + Ok(v) => $consume_v(BoxFFI::as_mut_ref( this).unwrap(), name, v), Err(e) => e, } } @@ -116,14 +116,14 @@ macro_rules! make_appender { #[no_mangle] #[allow(clippy::redundant_closure_call)] pub unsafe extern "C" fn $fn_append( - this: *mut $this, + this: CassBorrowedMutPtr<$this>, $($arg: $t), * ) -> CassError { // For some reason detected as unused, which is not true #[allow(unused_imports)] use crate::value::CassCqlValue::*; match ($e)($($arg), *) { - Ok(v) => $consume_v(BoxFFI::as_mut_ref(this), v), + Ok(v) => $consume_v(BoxFFI::as_mut_ref( this).unwrap(), v), Err(e) => e, } } @@ -302,13 +302,13 @@ macro_rules! invoke_binder_maker_macro_with_type { $this, $consume_v, $fn, - |p: *const crate::collection::CassCollection| { - match std::convert::TryInto::try_into(BoxFFI::as_ref(p)) { + |p: CassBorrowedPtr| { + match std::convert::TryInto::try_into(BoxFFI::as_ref(p).unwrap()) { Ok(v) => Ok(Some(v)), Err(_) => Err(CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE), } }, - [p @ *const crate::collection::CassCollection] + [p @ CassBorrowedPtr] ); }; (tuple, $macro_name:ident, $this:ty, $consume_v:expr, $fn:ident) => { @@ -316,10 +316,10 @@ macro_rules! invoke_binder_maker_macro_with_type { $this, $consume_v, $fn, - |p: *const crate::tuple::CassTuple| { - Ok(Some(BoxFFI::as_ref(p).into())) + |p: CassBorrowedPtr| { + Ok(Some(BoxFFI::as_ref(p).unwrap().into())) }, - [p @ *const crate::tuple::CassTuple] + [p @ CassBorrowedPtr] ); }; (user_type, $macro_name:ident, $this:ty, $consume_v:expr, $fn:ident) => { @@ -327,8 +327,10 @@ macro_rules! invoke_binder_maker_macro_with_type { $this, $consume_v, $fn, - |p: *const crate::user_type::CassUserType| Ok(Some(BoxFFI::as_ref(p).into())), - [p @ *const crate::user_type::CassUserType] + |p: CassBorrowedPtr| { + Ok(Some(BoxFFI::as_ref(p).unwrap().into())) + }, + [p @ CassBorrowedPtr] ); }; } diff --git a/scylla-rust-wrapper/src/cass_types.rs b/scylla-rust-wrapper/src/cass_types.rs index 6b479020..f0449a6d 100644 --- a/scylla-rust-wrapper/src/cass_types.rs +++ b/scylla-rust-wrapper/src/cass_types.rs @@ -9,7 +9,6 @@ use std::cell::UnsafeCell; use std::collections::HashMap; use std::convert::TryFrom; use std::os::raw::c_char; -use std::ptr; use std::sync::Arc; pub(crate) use crate::cass_batch_types::CassBatchType; @@ -552,12 +551,10 @@ pub fn get_column_type(column_type: &ColumnType) -> CassDataType { CassDataType::new(inner) } -// Changed return type to const ptr - ArcFFI::into_ptr is const. -// It's probably not a good idea - but cppdriver doesn't guarantee -// thread safety apart from CassSession and CassFuture. -// This comment also applies to other functions that create CassDataType. #[no_mangle] -pub unsafe extern "C" fn cass_data_type_new(value_type: CassValueType) -> *const CassDataType { +pub unsafe extern "C" fn cass_data_type_new( + value_type: CassValueType, +) -> CassOwnedPtr { let inner = match value_type { CassValueType::CASS_VALUE_TYPE_LIST => CassDataTypeInner::List { typ: None, @@ -574,49 +571,55 @@ pub unsafe extern "C" fn cass_data_type_new(value_type: CassValueType) -> *const }, CassValueType::CASS_VALUE_TYPE_UDT => CassDataTypeInner::UDT(UDTDataType::new()), CassValueType::CASS_VALUE_TYPE_CUSTOM => CassDataTypeInner::Custom("".to_string()), - CassValueType::CASS_VALUE_TYPE_UNKNOWN => return ptr::null_mut(), + CassValueType::CASS_VALUE_TYPE_UNKNOWN => return ArcFFI::null(), t if t < CassValueType::CASS_VALUE_TYPE_LAST_ENTRY => CassDataTypeInner::Value(t), - _ => return ptr::null_mut(), + _ => return ArcFFI::null(), }; ArcFFI::into_ptr(CassDataType::new_arced(inner)) } #[no_mangle] pub unsafe extern "C" fn cass_data_type_new_from_existing( - data_type: *const CassDataType, -) -> *const CassDataType { - let data_type = ArcFFI::as_ref(data_type); + data_type: CassBorrowedPtr, +) -> CassOwnedPtr { + let data_type = ArcFFI::as_ref(data_type).unwrap(); ArcFFI::into_ptr(CassDataType::new_arced(data_type.get_unchecked().clone())) } #[no_mangle] -pub unsafe extern "C" fn cass_data_type_new_tuple(item_count: size_t) -> *const CassDataType { +pub unsafe extern "C" fn cass_data_type_new_tuple( + item_count: size_t, +) -> CassOwnedPtr { ArcFFI::into_ptr(CassDataType::new_arced(CassDataTypeInner::Tuple( Vec::with_capacity(item_count as usize), ))) } #[no_mangle] -pub unsafe extern "C" fn cass_data_type_new_udt(field_count: size_t) -> *const CassDataType { +pub unsafe extern "C" fn cass_data_type_new_udt(field_count: size_t) -> CassOwnedPtr { ArcFFI::into_ptr(CassDataType::new_arced(CassDataTypeInner::UDT( UDTDataType::with_capacity(field_count as usize), ))) } #[no_mangle] -pub unsafe extern "C" fn cass_data_type_free(data_type: *mut CassDataType) { +pub unsafe extern "C" fn cass_data_type_free(data_type: CassOwnedPtr) { ArcFFI::free(data_type); } #[no_mangle] -pub unsafe extern "C" fn cass_data_type_type(data_type: *const CassDataType) -> CassValueType { - let data_type = ArcFFI::as_ref(data_type); +pub unsafe extern "C" fn cass_data_type_type( + data_type: CassBorrowedPtr, +) -> CassValueType { + let data_type = ArcFFI::as_ref(data_type).unwrap(); data_type.get_unchecked().get_value_type() } #[no_mangle] -pub unsafe extern "C" fn cass_data_type_is_frozen(data_type: *const CassDataType) -> cass_bool_t { - let data_type = ArcFFI::as_ref(data_type); +pub unsafe extern "C" fn cass_data_type_is_frozen( + data_type: CassBorrowedPtr, +) -> cass_bool_t { + let data_type = ArcFFI::as_ref(data_type).unwrap(); let is_frozen = match data_type.get_unchecked() { CassDataTypeInner::UDT(udt) => udt.frozen, CassDataTypeInner::List { frozen, .. } => *frozen, @@ -630,11 +633,11 @@ pub unsafe extern "C" fn cass_data_type_is_frozen(data_type: *const CassDataType #[no_mangle] pub unsafe extern "C" fn cass_data_type_type_name( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, type_name: *mut *const c_char, type_name_length: *mut size_t, ) -> CassError { - let data_type = ArcFFI::as_ref(data_type); + let data_type = ArcFFI::as_ref(data_type).unwrap(); match data_type.get_unchecked() { CassDataTypeInner::UDT(UDTDataType { name, .. }) => { write_str_to_c(name, type_name, type_name_length); @@ -646,7 +649,7 @@ pub unsafe extern "C" fn cass_data_type_type_name( #[no_mangle] pub unsafe extern "C" fn cass_data_type_set_type_name( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, type_name: *const c_char, ) -> CassError { cass_data_type_set_type_name_n(data_type, type_name, strlen(type_name)) @@ -654,11 +657,11 @@ pub unsafe extern "C" fn cass_data_type_set_type_name( #[no_mangle] pub unsafe extern "C" fn cass_data_type_set_type_name_n( - data_type_raw: *const CassDataType, + data_type_raw: CassBorrowedPtr, type_name: *const c_char, type_name_length: size_t, ) -> CassError { - let data_type = ArcFFI::as_ref(data_type_raw); + let data_type = ArcFFI::as_ref(data_type_raw).unwrap(); let type_name_string = ptr_to_cstr_n(type_name, type_name_length) .unwrap() .to_string(); @@ -674,11 +677,11 @@ pub unsafe extern "C" fn cass_data_type_set_type_name_n( #[no_mangle] pub unsafe extern "C" fn cass_data_type_keyspace( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, keyspace: *mut *const c_char, keyspace_length: *mut size_t, ) -> CassError { - let data_type = ArcFFI::as_ref(data_type); + let data_type = ArcFFI::as_ref(data_type).unwrap(); match data_type.get_unchecked() { CassDataTypeInner::UDT(UDTDataType { name, .. }) => { write_str_to_c(name, keyspace, keyspace_length); @@ -690,7 +693,7 @@ pub unsafe extern "C" fn cass_data_type_keyspace( #[no_mangle] pub unsafe extern "C" fn cass_data_type_set_keyspace( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, keyspace: *const c_char, ) -> CassError { cass_data_type_set_keyspace_n(data_type, keyspace, strlen(keyspace)) @@ -698,11 +701,11 @@ pub unsafe extern "C" fn cass_data_type_set_keyspace( #[no_mangle] pub unsafe extern "C" fn cass_data_type_set_keyspace_n( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, keyspace: *const c_char, keyspace_length: size_t, ) -> CassError { - let data_type = ArcFFI::as_ref(data_type); + let data_type = ArcFFI::as_ref(data_type).unwrap(); let keyspace_string = ptr_to_cstr_n(keyspace, keyspace_length) .unwrap() .to_string(); @@ -718,11 +721,11 @@ pub unsafe extern "C" fn cass_data_type_set_keyspace_n( #[no_mangle] pub unsafe extern "C" fn cass_data_type_class_name( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, class_name: *mut *const ::std::os::raw::c_char, class_name_length: *mut size_t, ) -> CassError { - let data_type = ArcFFI::as_ref(data_type); + let data_type = ArcFFI::as_ref(data_type).unwrap(); match data_type.get_unchecked() { CassDataTypeInner::Custom(name) => { write_str_to_c(name, class_name, class_name_length); @@ -734,7 +737,7 @@ pub unsafe extern "C" fn cass_data_type_class_name( #[no_mangle] pub unsafe extern "C" fn cass_data_type_set_class_name( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, class_name: *const ::std::os::raw::c_char, ) -> CassError { cass_data_type_set_class_name_n(data_type, class_name, strlen(class_name)) @@ -742,11 +745,11 @@ pub unsafe extern "C" fn cass_data_type_set_class_name( #[no_mangle] pub unsafe extern "C" fn cass_data_type_set_class_name_n( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, class_name: *const ::std::os::raw::c_char, class_name_length: size_t, ) -> CassError { - let data_type = ArcFFI::as_ref(data_type); + let data_type = ArcFFI::as_ref(data_type).unwrap(); let class_string = ptr_to_cstr_n(class_name, class_name_length) .unwrap() .to_string(); @@ -760,8 +763,10 @@ pub unsafe extern "C" fn cass_data_type_set_class_name_n( } #[no_mangle] -pub unsafe extern "C" fn cass_data_type_sub_type_count(data_type: *const CassDataType) -> size_t { - let data_type = ArcFFI::as_ref(data_type); +pub unsafe extern "C" fn cass_data_type_sub_type_count( + data_type: CassBorrowedPtr, +) -> size_t { + let data_type = ArcFFI::as_ref(data_type).unwrap(); match data_type.get_unchecked() { CassDataTypeInner::Value(..) => 0, CassDataTypeInner::UDT(udt_data_type) => udt_data_type.field_types.len() as size_t, @@ -779,21 +784,23 @@ pub unsafe extern "C" fn cass_data_type_sub_type_count(data_type: *const CassDat } #[no_mangle] -pub unsafe extern "C" fn cass_data_sub_type_count(data_type: *const CassDataType) -> size_t { +pub unsafe extern "C" fn cass_data_sub_type_count( + data_type: CassBorrowedPtr, +) -> size_t { cass_data_type_sub_type_count(data_type) } #[no_mangle] pub unsafe extern "C" fn cass_data_type_sub_data_type( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, index: size_t, -) -> *const CassDataType { - let data_type = ArcFFI::as_ref(data_type); +) -> CassBorrowedPtr { + let data_type = ArcFFI::as_ref(data_type).unwrap(); let sub_type: Option<&Arc> = data_type.get_unchecked().get_sub_data_type(index as usize); match sub_type { - None => std::ptr::null(), + None => ArcFFI::null(), // Semantic from cppdriver which also returns non-owning pointer Some(arc) => ArcFFI::as_ptr(arc), } @@ -801,37 +808,37 @@ pub unsafe extern "C" fn cass_data_type_sub_data_type( #[no_mangle] pub unsafe extern "C" fn cass_data_type_sub_data_type_by_name( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, name: *const ::std::os::raw::c_char, -) -> *const CassDataType { +) -> CassBorrowedPtr { cass_data_type_sub_data_type_by_name_n(data_type, name, strlen(name)) } #[no_mangle] pub unsafe extern "C" fn cass_data_type_sub_data_type_by_name_n( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, name: *const ::std::os::raw::c_char, name_length: size_t, -) -> *const CassDataType { - let data_type = ArcFFI::as_ref(data_type); +) -> CassBorrowedPtr { + let data_type = ArcFFI::as_ref(data_type).unwrap(); let name_str = ptr_to_cstr_n(name, name_length).unwrap(); match data_type.get_unchecked() { CassDataTypeInner::UDT(udt) => match udt.get_field_by_name(name_str) { - None => std::ptr::null(), + None => ArcFFI::null(), Some(t) => ArcFFI::as_ptr(t), }, - _ => std::ptr::null(), + _ => ArcFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_data_type_sub_type_name( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, index: size_t, name: *mut *const ::std::os::raw::c_char, name_length: *mut size_t, ) -> CassError { - let data_type = ArcFFI::as_ref(data_type); + let data_type = ArcFFI::as_ref(data_type).unwrap(); match data_type.get_unchecked() { CassDataTypeInner::UDT(udt) => match udt.field_types.get(index as usize) { None => CassError::CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS, @@ -846,13 +853,13 @@ pub unsafe extern "C" fn cass_data_type_sub_type_name( #[no_mangle] pub unsafe extern "C" fn cass_data_type_add_sub_type( - data_type: *const CassDataType, - sub_data_type: *const CassDataType, + data_type: CassBorrowedPtr, + sub_data_type: CassBorrowedPtr, ) -> CassError { - let data_type = ArcFFI::as_ref(data_type); + let data_type = ArcFFI::as_ref(data_type).unwrap(); match data_type .get_mut_unchecked() - .add_sub_data_type(ArcFFI::cloned_from_ptr(sub_data_type)) + .add_sub_data_type(ArcFFI::cloned_from_ptr(sub_data_type).unwrap()) { Ok(()) => CassError::CASS_OK, Err(e) => e, @@ -861,24 +868,24 @@ pub unsafe extern "C" fn cass_data_type_add_sub_type( #[no_mangle] pub unsafe extern "C" fn cass_data_type_add_sub_type_by_name( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, name: *const c_char, - sub_data_type: *const CassDataType, + sub_data_type: CassBorrowedPtr, ) -> CassError { cass_data_type_add_sub_type_by_name_n(data_type, name, strlen(name), sub_data_type) } #[no_mangle] pub unsafe extern "C" fn cass_data_type_add_sub_type_by_name_n( - data_type_raw: *const CassDataType, + data_type_raw: CassBorrowedPtr, name: *const c_char, name_length: size_t, - sub_data_type_raw: *const CassDataType, + sub_data_type_raw: CassBorrowedPtr, ) -> CassError { let name_string = ptr_to_cstr_n(name, name_length).unwrap().to_string(); - let sub_data_type = ArcFFI::cloned_from_ptr(sub_data_type_raw); + let sub_data_type = ArcFFI::cloned_from_ptr(sub_data_type_raw).unwrap(); - let data_type = ArcFFI::as_ref(data_type_raw); + let data_type = ArcFFI::as_ref(data_type_raw).unwrap(); match data_type.get_mut_unchecked() { CassDataTypeInner::UDT(udt_data_type) => { // The Cpp Driver does not check whether field_types size @@ -892,7 +899,7 @@ pub unsafe extern "C" fn cass_data_type_add_sub_type_by_name_n( #[no_mangle] pub unsafe extern "C" fn cass_data_type_add_sub_value_type( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, sub_value_type: CassValueType, ) -> CassError { let sub_data_type = CassDataType::new_arced(CassDataTypeInner::Value(sub_value_type)); @@ -901,7 +908,7 @@ pub unsafe extern "C" fn cass_data_type_add_sub_value_type( #[no_mangle] pub unsafe extern "C" fn cass_data_type_add_sub_value_type_by_name( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, name: *const c_char, sub_value_type: CassValueType, ) -> CassError { @@ -911,7 +918,7 @@ pub unsafe extern "C" fn cass_data_type_add_sub_value_type_by_name( #[no_mangle] pub unsafe extern "C" fn cass_data_type_add_sub_value_type_by_name_n( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, name: *const c_char, name_length: size_t, sub_value_type: CassValueType, diff --git a/scylla-rust-wrapper/src/cluster.rs b/scylla-rust-wrapper/src/cluster.rs index bde792b8..6009e466 100644 --- a/scylla-rust-wrapper/src/cluster.rs +++ b/scylla-rust-wrapper/src/cluster.rs @@ -194,7 +194,7 @@ pub fn build_session_builder( } #[no_mangle] -pub unsafe extern "C" fn cass_cluster_new() -> *mut CassCluster { +pub unsafe extern "C" fn cass_cluster_new() -> CassOwnedMutPtr { let default_execution_profile_builder = ExecutionProfileBuilder::default() .consistency(DEFAULT_CONSISTENCY) .request_timeout(Some(DEFAULT_REQUEST_TIMEOUT)); @@ -234,13 +234,13 @@ pub unsafe extern "C" fn cass_cluster_new() -> *mut CassCluster { } #[no_mangle] -pub unsafe extern "C" fn cass_cluster_free(cluster: *mut CassCluster) { +pub unsafe extern "C" fn cass_cluster_free(cluster: CassOwnedMutPtr) { BoxFFI::free(cluster); } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_contact_points( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, contact_points: *const c_char, ) -> CassError { cass_cluster_set_contact_points_n(cluster, contact_points, strlen(contact_points)) @@ -248,7 +248,7 @@ pub unsafe extern "C" fn cass_cluster_set_contact_points( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_contact_points_n( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, contact_points: *const c_char, contact_points_length: size_t, ) -> CassError { @@ -259,11 +259,11 @@ pub unsafe extern "C" fn cass_cluster_set_contact_points_n( } unsafe fn cluster_set_contact_points( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, contact_points_raw: *const c_char, contact_points_length: size_t, ) -> Result<(), CassError> { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); let mut contact_points = ptr_to_cstr_n(contact_points_raw, contact_points_length) .ok_or(CassError::CASS_ERROR_LIB_BAD_PARAMS)? .split(',') @@ -289,7 +289,7 @@ unsafe fn cluster_set_contact_points( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_use_randomized_contact_points( - _cluster_raw: *mut CassCluster, + _cluster_raw: CassBorrowedMutPtr, _enabled: cass_bool_t, ) -> CassError { // FIXME: should set `use_randomized_contact_points` flag in cluster config @@ -299,7 +299,7 @@ pub unsafe extern "C" fn cass_cluster_set_use_randomized_contact_points( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_application_name( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, app_name: *const c_char, ) { cass_cluster_set_application_name_n(cluster_raw, app_name, strlen(app_name)) @@ -307,11 +307,11 @@ pub unsafe extern "C" fn cass_cluster_set_application_name( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_application_name_n( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, app_name: *const c_char, app_name_len: size_t, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); let app_name = ptr_to_cstr_n(app_name, app_name_len).unwrap().to_string(); cluster @@ -323,7 +323,7 @@ pub unsafe extern "C" fn cass_cluster_set_application_name_n( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_application_version( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, app_version: *const c_char, ) { cass_cluster_set_application_version_n(cluster_raw, app_version, strlen(app_version)) @@ -331,11 +331,11 @@ pub unsafe extern "C" fn cass_cluster_set_application_version( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_application_version_n( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, app_version: *const c_char, app_version_len: size_t, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); let app_version = ptr_to_cstr_n(app_version, app_version_len) .unwrap() .to_string(); @@ -349,10 +349,10 @@ pub unsafe extern "C" fn cass_cluster_set_application_version_n( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_client_id( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, client_id: CassUuid, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); let client_uuid: uuid::Uuid = client_id.into(); let client_uuid_str = client_uuid.to_string(); @@ -367,29 +367,29 @@ pub unsafe extern "C" fn cass_cluster_set_client_id( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_use_schema( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, enabled: cass_bool_t, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster.session_builder.config.fetch_schema_metadata = enabled != 0; } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_tcp_nodelay( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, enabled: cass_bool_t, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster.session_builder.config.tcp_nodelay = enabled != 0; } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_tcp_keepalive( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, enabled: cass_bool_t, delay_secs: c_uint, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); let enabled = enabled != 0; let tcp_keepalive_interval = enabled.then(|| Duration::from_secs(delay_secs as u64)); @@ -398,10 +398,10 @@ pub unsafe extern "C" fn cass_cluster_set_tcp_keepalive( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_connection_heartbeat_interval( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, interval_secs: c_uint, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); let keepalive_interval = (interval_secs > 0).then(|| Duration::from_secs(interval_secs as u64)); cluster.session_builder.config.keepalive_interval = keepalive_interval; @@ -409,10 +409,10 @@ pub unsafe extern "C" fn cass_cluster_set_connection_heartbeat_interval( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_connection_idle_timeout( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, timeout_secs: c_uint, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); let keepalive_timeout = (timeout_secs > 0).then(|| Duration::from_secs(timeout_secs as u64)); cluster.session_builder.config.keepalive_timeout = keepalive_timeout; @@ -420,19 +420,19 @@ pub unsafe extern "C" fn cass_cluster_set_connection_idle_timeout( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_connect_timeout( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, timeout_ms: c_uint, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster.session_builder.config.connect_timeout = Duration::from_millis(timeout_ms.into()); } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_request_timeout( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, timeout_ms: c_uint, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); exec_profile_builder_modify(&mut cluster.default_execution_profile_builder, |builder| { // 0 -> no timeout @@ -442,10 +442,10 @@ pub unsafe extern "C" fn cass_cluster_set_request_timeout( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_max_schema_wait_time( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, wait_time_ms: c_uint, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster.session_builder.config.schema_agreement_timeout = Duration::from_millis(wait_time_ms.into()); @@ -453,10 +453,10 @@ pub unsafe extern "C" fn cass_cluster_set_max_schema_wait_time( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_schema_agreement_interval( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, interval_ms: c_uint, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster.session_builder.config.schema_agreement_interval = Duration::from_millis(interval_ms.into()); @@ -464,21 +464,21 @@ pub unsafe extern "C" fn cass_cluster_set_schema_agreement_interval( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_port( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, port: c_int, ) -> CassError { if port <= 0 { return CassError::CASS_ERROR_LIB_BAD_PARAMS; } - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster.port = port as u16; CassError::CASS_OK } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_credentials( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, username: *const c_char, password: *const c_char, ) { @@ -493,7 +493,7 @@ pub unsafe extern "C" fn cass_cluster_set_credentials( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_credentials_n( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, username_raw: *const c_char, username_length: size_t, password_raw: *const c_char, @@ -503,20 +503,22 @@ pub unsafe extern "C" fn cass_cluster_set_credentials_n( let username = ptr_to_cstr_n(username_raw, username_length).unwrap(); let password = ptr_to_cstr_n(password_raw, password_length).unwrap(); - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster.auth_username = Some(username.to_string()); cluster.auth_password = Some(password.to_string()); } #[no_mangle] -pub unsafe extern "C" fn cass_cluster_set_load_balance_round_robin(cluster_raw: *mut CassCluster) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); +pub unsafe extern "C" fn cass_cluster_set_load_balance_round_robin( + cluster_raw: CassBorrowedMutPtr, +) { + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster.load_balancing_config.load_balancing_kind = Some(LoadBalancingKind::RoundRobin); } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_load_balance_dc_aware( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, local_dc: *const c_char, used_hosts_per_remote_dc: c_uint, allow_remote_dcs_for_local_cl: cass_bool_t, @@ -557,13 +559,13 @@ pub(crate) unsafe fn set_load_balance_dc_aware_n( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_load_balance_dc_aware_n( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, local_dc_raw: *const c_char, local_dc_length: size_t, used_hosts_per_remote_dc: c_uint, allow_remote_dcs_for_local_cl: cass_bool_t, ) -> CassError { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); set_load_balance_dc_aware_n( &mut cluster.load_balancing_config, @@ -576,7 +578,7 @@ pub unsafe extern "C" fn cass_cluster_set_load_balance_dc_aware_n( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_load_balance_rack_aware( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, local_dc_raw: *const c_char, local_rack_raw: *const c_char, ) -> CassError { @@ -591,13 +593,13 @@ pub unsafe extern "C" fn cass_cluster_set_load_balance_rack_aware( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_load_balance_rack_aware_n( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, local_dc_raw: *const c_char, local_dc_length: size_t, local_rack_raw: *const c_char, local_rack_length: size_t, ) -> CassError { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); set_load_balance_rack_aware_n( &mut cluster.load_balancing_config, @@ -638,7 +640,7 @@ pub(crate) unsafe fn set_load_balance_rack_aware_n( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_cloud_secure_connection_bundle_n( - _cluster_raw: *mut CassCluster, + _cluster_raw: CassBorrowedMutPtr, path: *const c_char, path_length: size_t, ) -> CassError { @@ -654,7 +656,7 @@ pub unsafe extern "C" fn cass_cluster_set_cloud_secure_connection_bundle_n( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_exponential_reconnect( - _cluster_raw: *mut CassCluster, + _cluster_raw: CassBorrowedMutPtr, base_delay_ms: cass_uint64_t, max_delay_ms: cass_uint64_t, ) -> CassError { @@ -689,7 +691,7 @@ pub extern "C" fn cass_custom_payload_new() -> *const CassCustomPayload { #[no_mangle] pub extern "C" fn cass_future_custom_payload_item( - _future: *mut CassFuture, + _future: CassBorrowedMutPtr, _i: size_t, _name: *const c_char, _name_length: size_t, @@ -700,16 +702,18 @@ pub extern "C" fn cass_future_custom_payload_item( } #[no_mangle] -pub extern "C" fn cass_future_custom_payload_item_count(_future: *mut CassFuture) -> size_t { +pub extern "C" fn cass_future_custom_payload_item_count( + _future: CassBorrowedMutPtr, +) -> size_t { 0 } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_use_beta_protocol_version( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, enable: cass_bool_t, ) -> CassError { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster.use_beta_protocol_version = enable == cass_true; CassError::CASS_OK @@ -717,10 +721,10 @@ pub unsafe extern "C" fn cass_cluster_set_use_beta_protocol_version( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_protocol_version( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, protocol_version: c_int, ) -> CassError { - let cluster = BoxFFI::as_ref(cluster_raw); + let cluster = BoxFFI::as_ref(cluster_raw).unwrap(); if protocol_version == 4 && !cluster.use_beta_protocol_version { // Rust Driver supports only protocol version 4 @@ -732,7 +736,7 @@ pub unsafe extern "C" fn cass_cluster_set_protocol_version( #[no_mangle] pub extern "C" fn cass_cluster_set_queue_size_event( - _cluster: *mut CassCluster, + _cluster: CassBorrowedMutPtr, _queue_size: c_uint, ) -> CassError { // In Cpp Driver this function is also a no-op... @@ -741,7 +745,7 @@ pub extern "C" fn cass_cluster_set_queue_size_event( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_constant_speculative_execution_policy( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, constant_delay_ms: cass_int64_t, max_speculative_executions: c_int, ) -> CassError { @@ -749,7 +753,7 @@ pub unsafe extern "C" fn cass_cluster_set_constant_speculative_execution_policy( return CassError::CASS_ERROR_LIB_BAD_PARAMS; } - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); let policy = SimpleSpeculativeExecutionPolicy { max_retry_count: max_speculative_executions as usize, @@ -765,9 +769,9 @@ pub unsafe extern "C" fn cass_cluster_set_constant_speculative_execution_policy( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_no_speculative_execution_policy( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, ) -> CassError { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); exec_profile_builder_modify(&mut cluster.default_execution_profile_builder, |builder| { builder.speculative_execution_policy(None) @@ -778,19 +782,19 @@ pub unsafe extern "C" fn cass_cluster_set_no_speculative_execution_policy( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_token_aware_routing( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, enabled: cass_bool_t, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster.load_balancing_config.token_awareness_enabled = enabled != 0; } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_token_aware_routing_shuffle_replicas( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedMutPtr, enabled: cass_bool_t, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); cluster .load_balancing_config @@ -799,12 +803,12 @@ pub unsafe extern "C" fn cass_cluster_set_token_aware_routing_shuffle_replicas( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_retry_policy( - cluster_raw: *mut CassCluster, - retry_policy: *const CassRetryPolicy, + cluster_raw: CassBorrowedMutPtr, + retry_policy: CassBorrowedPtr, ) { - let cluster = BoxFFI::as_mut_ref(cluster_raw); + let cluster = BoxFFI::as_mut_ref(cluster_raw).unwrap(); - let retry_policy: Arc = match ArcFFI::as_ref(retry_policy) { + let retry_policy: Arc = match ArcFFI::as_ref(retry_policy).unwrap() { DefaultRetryPolicy(default) => Arc::clone(default) as _, FallthroughRetryPolicy(fallthrough) => Arc::clone(fallthrough) as _, DowngradingConsistencyRetryPolicy(downgrading) => Arc::clone(downgrading) as _, @@ -816,9 +820,12 @@ pub unsafe extern "C" fn cass_cluster_set_retry_policy( } #[no_mangle] -pub unsafe extern "C" fn cass_cluster_set_ssl(cluster: *mut CassCluster, ssl: *mut CassSsl) { - let cluster_from_raw = BoxFFI::as_mut_ref(cluster); - let cass_ssl = ArcFFI::cloned_from_ptr(ssl); +pub unsafe extern "C" fn cass_cluster_set_ssl( + cluster: CassBorrowedMutPtr, + ssl: CassBorrowedPtr, +) { + let cluster_from_raw = BoxFFI::as_mut_ref(cluster).unwrap(); + let cass_ssl = ArcFFI::cloned_from_ptr(ssl).unwrap(); let ssl_context_builder = SslContextBuilder::from_ptr(cass_ssl.ssl_context); // Reference count is increased as tokio_openssl will try to free `ssl_context` when calling `SSL_free`. @@ -829,10 +836,10 @@ pub unsafe extern "C" fn cass_cluster_set_ssl(cluster: *mut CassCluster, ssl: *m #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_compression( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, compression_type: CassCompressionType, ) { - let cluster_from_raw = BoxFFI::as_mut_ref(cluster); + let cluster_from_raw = BoxFFI::as_mut_ref(cluster).unwrap(); let compression = match compression_type { CassCompressionType::CASS_COMPRESSION_LZ4 => Some(Compression::Lz4), CassCompressionType::CASS_COMPRESSION_SNAPPY => Some(Compression::Snappy), @@ -844,23 +851,23 @@ pub unsafe extern "C" fn cass_cluster_set_compression( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_latency_aware_routing( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, enabled: cass_bool_t, ) { - let cluster = BoxFFI::as_mut_ref(cluster); + let cluster = BoxFFI::as_mut_ref(cluster).unwrap(); cluster.load_balancing_config.latency_awareness_enabled = enabled != 0; } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_latency_aware_routing_settings( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, exclusion_threshold: cass_double_t, scale_ms: cass_uint64_t, retry_period_ms: cass_uint64_t, update_rate_ms: cass_uint64_t, min_measured: cass_uint64_t, ) { - let cluster = BoxFFI::as_mut_ref(cluster); + let cluster = BoxFFI::as_mut_ref(cluster).unwrap(); cluster.load_balancing_config.latency_awareness_builder = LatencyAwarenessBuilder::new() .exclusion_threshold(exclusion_threshold) .scale(Duration::from_millis(scale_ms)) @@ -871,10 +878,10 @@ pub unsafe extern "C" fn cass_cluster_set_latency_aware_routing_settings( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_consistency( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, consistency: CassConsistency, ) -> CassError { - let cluster = BoxFFI::as_mut_ref(cluster); + let cluster = BoxFFI::as_mut_ref(cluster).unwrap(); let consistency: Consistency = match consistency.try_into() { Ok(c) => c, Err(_) => return CassError::CASS_ERROR_LIB_BAD_PARAMS, @@ -889,10 +896,10 @@ pub unsafe extern "C" fn cass_cluster_set_consistency( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_serial_consistency( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, serial_consistency: CassConsistency, ) -> CassError { - let cluster = BoxFFI::as_mut_ref(cluster); + let cluster = BoxFFI::as_mut_ref(cluster).unwrap(); let serial_consistency: SerialConsistency = match serial_consistency.try_into() { Ok(c) => c, Err(_) => return CassError::CASS_ERROR_LIB_BAD_PARAMS, @@ -907,21 +914,21 @@ pub unsafe extern "C" fn cass_cluster_set_serial_consistency( #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_execution_profile( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, name: *const c_char, - profile: *const CassExecProfile, + profile: CassBorrowedPtr, ) -> CassError { cass_cluster_set_execution_profile_n(cluster, name, strlen(name), profile) } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_execution_profile_n( - cluster: *mut CassCluster, + cluster: CassBorrowedMutPtr, name: *const c_char, name_length: size_t, - profile: *const CassExecProfile, + profile: CassBorrowedPtr, ) -> CassError { - let cluster = BoxFFI::as_mut_ref(cluster); + let cluster = BoxFFI::as_mut_ref(cluster).unwrap(); let name = if let Some(name) = ptr_to_cstr_n(name, name_length).and_then(|name| name.to_owned().try_into().ok()) { @@ -930,7 +937,7 @@ pub unsafe extern "C" fn cass_cluster_set_execution_profile_n( // Got NULL or empty string, which is invalid name for a profile. return CassError::CASS_ERROR_LIB_BAD_PARAMS; }; - let profile = if let Some(profile) = BoxFFI::as_maybe_ref(profile) { + let profile = if let Some(profile) = BoxFFI::as_ref(profile) { profile.clone() } else { return CassError::CASS_ERROR_LIB_BAD_PARAMS; @@ -962,26 +969,31 @@ mod tests { #[ntest::timeout(100)] fn test_load_balancing_config() { unsafe { - let cluster_raw = cass_cluster_new(); + let mut cluster_raw = cass_cluster_new(); { /* Test valid configurations */ - let cluster = BoxFFI::as_ref(cluster_raw); { + let cluster = BoxFFI::as_ref(cluster_raw.borrow()).unwrap(); assert_matches!(cluster.load_balancing_config.load_balancing_kind, None); assert!(cluster.load_balancing_config.token_awareness_enabled); assert!(!cluster.load_balancing_config.latency_awareness_enabled); } { - cass_cluster_set_token_aware_routing(cluster_raw, 0); + cass_cluster_set_token_aware_routing(cluster_raw.borrow_mut(), 0); assert_cass_error_eq!( - cass_cluster_set_load_balance_dc_aware(cluster_raw, c"eu".as_ptr(), 0, 0), + cass_cluster_set_load_balance_dc_aware( + cluster_raw.borrow_mut(), + c"eu".as_ptr(), + 0, + 0 + ), CassError::CASS_OK ); - cass_cluster_set_latency_aware_routing(cluster_raw, 1); + cass_cluster_set_latency_aware_routing(cluster_raw.borrow_mut(), 1); // These values cannot currently be tested to be set properly in the latency awareness builder, // but at least we test that the function completed successfully. cass_cluster_set_latency_aware_routing_settings( - cluster_raw, + cluster_raw.borrow_mut(), 2., 1, 2000, @@ -989,6 +1001,7 @@ mod tests { 40, ); + let cluster = BoxFFI::as_ref(cluster_raw.borrow()).unwrap(); let load_balancing_kind = &cluster.load_balancing_config.load_balancing_kind; match load_balancing_kind { Some(LoadBalancingKind::DcAware { local_dc }) => { @@ -1002,13 +1015,14 @@ mod tests { // set preferred rack+dc assert_cass_error_eq!( cass_cluster_set_load_balance_rack_aware( - cluster_raw, + cluster_raw.borrow_mut(), c"eu-east".as_ptr(), c"rack1".as_ptr(), ), CassError::CASS_OK ); + let cluster = BoxFFI::as_ref(cluster_raw.borrow()).unwrap(); let node_location_preference = &cluster.load_balancing_config.load_balancing_kind; match node_location_preference { @@ -1024,10 +1038,16 @@ mod tests { // set back to preferred dc assert_cass_error_eq!( - cass_cluster_set_load_balance_dc_aware(cluster_raw, c"eu".as_ptr(), 0, 0), + cass_cluster_set_load_balance_dc_aware( + cluster_raw.borrow_mut(), + c"eu".as_ptr(), + 0, + 0 + ), CassError::CASS_OK ); + let cluster = BoxFFI::as_ref(cluster_raw.borrow()).unwrap(); let node_location_preference = &cluster.load_balancing_config.load_balancing_kind; match node_location_preference { @@ -1041,22 +1061,37 @@ mod tests { { // Nonzero deprecated parameters assert_cass_error_eq!( - cass_cluster_set_load_balance_dc_aware(cluster_raw, c"eu".as_ptr(), 1, 0), + cass_cluster_set_load_balance_dc_aware( + cluster_raw.borrow_mut(), + c"eu".as_ptr(), + 1, + 0 + ), CassError::CASS_ERROR_LIB_BAD_PARAMS ); assert_cass_error_eq!( - cass_cluster_set_load_balance_dc_aware(cluster_raw, c"eu".as_ptr(), 0, 1), + cass_cluster_set_load_balance_dc_aware( + cluster_raw.borrow_mut(), + c"eu".as_ptr(), + 0, + 1 + ), CassError::CASS_ERROR_LIB_BAD_PARAMS ); // null pointers assert_cass_error_eq!( - cass_cluster_set_load_balance_dc_aware(cluster_raw, std::ptr::null(), 0, 0), + cass_cluster_set_load_balance_dc_aware( + cluster_raw.borrow_mut(), + std::ptr::null(), + 0, + 0 + ), CassError::CASS_ERROR_LIB_BAD_PARAMS ); assert_cass_error_eq!( cass_cluster_set_load_balance_rack_aware( - cluster_raw, + cluster_raw.borrow_mut(), c"eu".as_ptr(), std::ptr::null(), ), @@ -1064,7 +1099,7 @@ mod tests { ); assert_cass_error_eq!( cass_cluster_set_load_balance_rack_aware( - cluster_raw, + cluster_raw.borrow_mut(), std::ptr::null(), c"rack".as_ptr(), ), @@ -1076,12 +1111,17 @@ mod tests { #[allow(clippy::manual_c_str_literals)] let empty_str = "\0".as_ptr() as *const i8; assert_cass_error_eq!( - cass_cluster_set_load_balance_dc_aware(cluster_raw, std::ptr::null(), 0, 0), + cass_cluster_set_load_balance_dc_aware( + cluster_raw.borrow_mut(), + std::ptr::null(), + 0, + 0 + ), CassError::CASS_ERROR_LIB_BAD_PARAMS ); assert_cass_error_eq!( cass_cluster_set_load_balance_rack_aware( - cluster_raw, + cluster_raw.borrow_mut(), c"eu".as_ptr(), empty_str, ), @@ -1089,7 +1129,7 @@ mod tests { ); assert_cass_error_eq!( cass_cluster_set_load_balance_rack_aware( - cluster_raw, + cluster_raw.borrow_mut(), empty_str, c"rack".as_ptr(), ), @@ -1106,23 +1146,25 @@ mod tests { #[ntest::timeout(100)] fn test_register_exec_profile() { unsafe { - let cluster_raw = cass_cluster_new(); + let mut cluster_raw = cass_cluster_new(); let exec_profile_raw = cass_execution_profile_new(); { /* Test valid configurations */ - let cluster = BoxFFI::as_ref(cluster_raw); { + let cluster = BoxFFI::as_ref(cluster_raw.borrow()).unwrap(); assert!(cluster.execution_profile_map.is_empty()); } { assert_cass_error_eq!( cass_cluster_set_execution_profile( - cluster_raw, + cluster_raw.borrow_mut(), make_c_str!("profile1"), - exec_profile_raw + exec_profile_raw.borrow() ), CassError::CASS_OK ); + + let cluster = BoxFFI::as_ref(cluster_raw.borrow()).unwrap(); assert!(cluster.execution_profile_map.len() == 1); let _profile = cluster .execution_profile_map @@ -1132,13 +1174,15 @@ mod tests { let (c_str, c_strlen) = str_to_c_str_n("profile1"); assert_cass_error_eq!( cass_cluster_set_execution_profile_n( - cluster_raw, + cluster_raw.borrow_mut(), c_str, c_strlen, - exec_profile_raw + exec_profile_raw.borrow() ), CassError::CASS_OK ); + + let cluster = BoxFFI::as_ref(cluster_raw.borrow()).unwrap(); assert!(cluster.execution_profile_map.len() == 1); let _profile = cluster .execution_profile_map @@ -1147,12 +1191,14 @@ mod tests { assert_cass_error_eq!( cass_cluster_set_execution_profile( - cluster_raw, + cluster_raw.borrow_mut(), make_c_str!("profile2"), - exec_profile_raw + exec_profile_raw.borrow() ), CassError::CASS_OK ); + + let cluster = BoxFFI::as_ref(cluster_raw.borrow()).unwrap(); assert!(cluster.execution_profile_map.len() == 2); let _profile = cluster .execution_profile_map @@ -1165,9 +1211,9 @@ mod tests { // NULL name assert_cass_error_eq!( cass_cluster_set_execution_profile( - cluster_raw, + cluster_raw.borrow_mut(), std::ptr::null(), - exec_profile_raw + exec_profile_raw.borrow() ), CassError::CASS_ERROR_LIB_BAD_PARAMS ); @@ -1176,9 +1222,9 @@ mod tests { // empty name assert_cass_error_eq!( cass_cluster_set_execution_profile( - cluster_raw, + cluster_raw.borrow_mut(), make_c_str!(""), - exec_profile_raw + exec_profile_raw.borrow() ), CassError::CASS_ERROR_LIB_BAD_PARAMS ); @@ -1187,14 +1233,16 @@ mod tests { // NULL profile assert_cass_error_eq!( cass_cluster_set_execution_profile( - cluster_raw, + cluster_raw.borrow_mut(), make_c_str!("profile1"), - std::ptr::null() + BoxFFI::null(), ), CassError::CASS_ERROR_LIB_BAD_PARAMS ); } // Make sure that invalid configuration did not influence the profile map + + let cluster = BoxFFI::as_ref(cluster_raw.borrow()).unwrap(); assert_eq!( cluster .execution_profile_map diff --git a/scylla-rust-wrapper/src/collection.rs b/scylla-rust-wrapper/src/collection.rs index 8f5621ad..b59a9c61 100644 --- a/scylla-rust-wrapper/src/collection.rs +++ b/scylla-rust-wrapper/src/collection.rs @@ -137,7 +137,7 @@ impl TryFrom<&CassCollection> for CassCqlValue { pub unsafe extern "C" fn cass_collection_new( collection_type: CassCollectionType, item_count: size_t, -) -> *mut CassCollection { +) -> CassOwnedMutPtr { let capacity = match collection_type { // Maps consist of a key and a value, so twice // the number of CassCqlValue will be stored. @@ -155,10 +155,10 @@ pub unsafe extern "C" fn cass_collection_new( #[no_mangle] unsafe extern "C" fn cass_collection_new_from_data_type( - data_type: *const CassDataType, + data_type: CassBorrowedPtr, item_count: size_t, -) -> *mut CassCollection { - let data_type = ArcFFI::cloned_from_ptr(data_type); +) -> CassOwnedMutPtr { + let data_type = ArcFFI::cloned_from_ptr(data_type).unwrap(); let (capacity, collection_type) = match data_type.get_unchecked() { CassDataTypeInner::List { .. } => { (item_count, CassCollectionType::CASS_COLLECTION_TYPE_LIST) @@ -169,7 +169,7 @@ unsafe extern "C" fn cass_collection_new_from_data_type( CassDataTypeInner::Map { .. } => { (item_count * 2, CassCollectionType::CASS_COLLECTION_TYPE_MAP) } - _ => return std::ptr::null_mut(), + _ => return BoxFFI::null_mut(), }; let capacity = capacity as usize; @@ -183,9 +183,9 @@ unsafe extern "C" fn cass_collection_new_from_data_type( #[no_mangle] unsafe extern "C" fn cass_collection_data_type( - collection: *const CassCollection, -) -> *const CassDataType { - let collection_ref = BoxFFI::as_ref(collection); + collection: CassBorrowedPtr, +) -> CassBorrowedPtr { + let collection_ref = BoxFFI::as_ref(collection).unwrap(); match &collection_ref.data_type { Some(dt) => ArcFFI::as_ptr(dt), @@ -203,7 +203,7 @@ unsafe extern "C" fn cass_collection_data_type( } #[no_mangle] -pub unsafe extern "C" fn cass_collection_free(collection: *mut CassCollection) { +pub unsafe extern "C" fn cass_collection_free(collection: CassOwnedMutPtr) { BoxFFI::free(collection); } @@ -253,22 +253,22 @@ mod tests { unsafe { // untyped map (via cass_collection_new, Collection's data type is None). { - let untyped_map = + let mut untyped_map = cass_collection_new(CassCollectionType::CASS_COLLECTION_TYPE_MAP, 2); assert_cass_error_eq!( - cass_collection_append_bool(untyped_map, false as cass_bool_t), + cass_collection_append_bool(untyped_map.borrow_mut(), false as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_int16(untyped_map, 42), + cass_collection_append_int16(untyped_map.borrow_mut(), 42), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_double(untyped_map, 42.42), + cass_collection_append_double(untyped_map.borrow_mut(), 42.42), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_float(untyped_map, 42.42), + cass_collection_append_float(untyped_map.borrow_mut(), 42.42), CassError::CASS_OK ); cass_collection_free(untyped_map); @@ -282,22 +282,22 @@ mod tests { }); let dt_ptr = ArcFFI::into_ptr(dt); - let untyped_map = cass_collection_new_from_data_type(dt_ptr, 2); + let mut untyped_map = cass_collection_new_from_data_type(dt_ptr.borrow(), 2); assert_cass_error_eq!( - cass_collection_append_bool(untyped_map, false as cass_bool_t), + cass_collection_append_bool(untyped_map.borrow_mut(), false as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_int16(untyped_map, 42), + cass_collection_append_int16(untyped_map.borrow_mut(), 42), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_double(untyped_map, 42.42), + cass_collection_append_double(untyped_map.borrow_mut(), 42.42), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_float(untyped_map, 42.42), + cass_collection_append_float(untyped_map.borrow_mut(), 42.42), CassError::CASS_OK ); cass_collection_free(untyped_map); @@ -313,30 +313,30 @@ mod tests { }); let dt_ptr = ArcFFI::into_ptr(dt); - let half_typed_map = cass_collection_new_from_data_type(dt_ptr, 2); + let mut half_typed_map = cass_collection_new_from_data_type(dt_ptr.borrow(), 2); assert_cass_error_eq!( - cass_collection_append_bool(half_typed_map, false as cass_bool_t), + cass_collection_append_bool(half_typed_map.borrow_mut(), false as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_int16(half_typed_map, 42), + cass_collection_append_int16(half_typed_map.borrow_mut(), 42), CassError::CASS_OK ); // Second entry -> key typecheck failed. assert_cass_error_eq!( - cass_collection_append_double(half_typed_map, 42.42), + cass_collection_append_double(half_typed_map.borrow_mut(), 42.42), CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE ); // Second entry -> typecheck succesful. assert_cass_error_eq!( - cass_collection_append_bool(half_typed_map, true as cass_bool_t), + cass_collection_append_bool(half_typed_map.borrow_mut(), true as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_double(half_typed_map, 42.42), + cass_collection_append_double(half_typed_map.borrow_mut(), 42.42), CassError::CASS_OK ); cass_collection_free(half_typed_map); @@ -356,31 +356,31 @@ mod tests { frozen: false, }); let dt_ptr = ArcFFI::into_ptr(dt); - let bool_to_i16_map = cass_collection_new_from_data_type(dt_ptr, 2); + let mut bool_to_i16_map = cass_collection_new_from_data_type(dt_ptr.borrow(), 2); // First entry -> typecheck successful. assert_cass_error_eq!( - cass_collection_append_bool(bool_to_i16_map, false as cass_bool_t), + cass_collection_append_bool(bool_to_i16_map.borrow_mut(), false as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_int16(bool_to_i16_map, 42), + cass_collection_append_int16(bool_to_i16_map.borrow_mut(), 42), CassError::CASS_OK ); // Second entry -> key typecheck failed. assert_cass_error_eq!( - cass_collection_append_float(bool_to_i16_map, 42.42), + cass_collection_append_float(bool_to_i16_map.borrow_mut(), 42.42), CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE ); // Third entry -> value typecheck failed. assert_cass_error_eq!( - cass_collection_append_bool(bool_to_i16_map, true as cass_bool_t), + cass_collection_append_bool(bool_to_i16_map.borrow_mut(), true as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_float(bool_to_i16_map, 42.42), + cass_collection_append_float(bool_to_i16_map.borrow_mut(), 42.42), CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE ); @@ -390,14 +390,14 @@ mod tests { // untyped set (via cass_collection_new, collection's type is None) { - let untyped_set = + let mut untyped_set = cass_collection_new(CassCollectionType::CASS_COLLECTION_TYPE_SET, 2); assert_cass_error_eq!( - cass_collection_append_bool(untyped_set, false as cass_bool_t), + cass_collection_append_bool(untyped_set.borrow_mut(), false as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_int16(untyped_set, 42), + cass_collection_append_int16(untyped_set.borrow_mut(), 42), CassError::CASS_OK ); cass_collection_free(untyped_set); @@ -411,14 +411,14 @@ mod tests { }); let dt_ptr = ArcFFI::into_ptr(dt); - let untyped_set = cass_collection_new_from_data_type(dt_ptr, 2); + let mut untyped_set = cass_collection_new_from_data_type(dt_ptr.borrow(), 2); assert_cass_error_eq!( - cass_collection_append_bool(untyped_set, false as cass_bool_t), + cass_collection_append_bool(untyped_set.borrow_mut(), false as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_int16(untyped_set, 42), + cass_collection_append_int16(untyped_set.borrow_mut(), 42), CassError::CASS_OK ); cass_collection_free(untyped_set); @@ -433,14 +433,14 @@ mod tests { frozen: false, }); let dt_ptr = ArcFFI::into_ptr(dt); - let bool_set = cass_collection_new_from_data_type(dt_ptr, 2); + let mut bool_set = cass_collection_new_from_data_type(dt_ptr.borrow(), 2); assert_cass_error_eq!( - cass_collection_append_bool(bool_set, true as cass_bool_t), + cass_collection_append_bool(bool_set.borrow_mut(), true as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_float(bool_set, 42.42), + cass_collection_append_float(bool_set.borrow_mut(), 42.42), CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE ); @@ -450,14 +450,14 @@ mod tests { // untyped list (via cass_collection_new, collection's type is None) { - let untyped_list = + let mut untyped_list = cass_collection_new(CassCollectionType::CASS_COLLECTION_TYPE_LIST, 2); assert_cass_error_eq!( - cass_collection_append_bool(untyped_list, false as cass_bool_t), + cass_collection_append_bool(untyped_list.borrow_mut(), false as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_int16(untyped_list, 42), + cass_collection_append_int16(untyped_list.borrow_mut(), 42), CassError::CASS_OK ); cass_collection_free(untyped_list); @@ -471,14 +471,14 @@ mod tests { }); let dt_ptr = ArcFFI::into_ptr(dt); - let untyped_list = cass_collection_new_from_data_type(dt_ptr, 2); + let mut untyped_list = cass_collection_new_from_data_type(dt_ptr.borrow(), 2); assert_cass_error_eq!( - cass_collection_append_bool(untyped_list, false as cass_bool_t), + cass_collection_append_bool(untyped_list.borrow_mut(), false as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_int16(untyped_list, 42), + cass_collection_append_int16(untyped_list.borrow_mut(), 42), CassError::CASS_OK ); cass_collection_free(untyped_list); @@ -493,14 +493,14 @@ mod tests { frozen: false, }); let dt_ptr = ArcFFI::into_ptr(dt); - let bool_list = cass_collection_new_from_data_type(dt_ptr, 2); + let mut bool_list = cass_collection_new_from_data_type(dt_ptr.borrow(), 2); assert_cass_error_eq!( - cass_collection_append_bool(bool_list, true as cass_bool_t), + cass_collection_append_bool(bool_list.borrow_mut(), true as cass_bool_t), CassError::CASS_OK ); assert_cass_error_eq!( - cass_collection_append_float(bool_list, 42.42), + cass_collection_append_float(bool_list.borrow_mut(), 42.42), CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE ); @@ -519,16 +519,14 @@ mod tests { let empty_list = cass_collection_new(CassCollectionType::CASS_COLLECTION_TYPE_LIST, 2); // This would previously return a non Arc-based pointer. - let empty_list_dt = cass_collection_data_type(empty_list); + let empty_list_dt = cass_collection_data_type(empty_list.borrow()); let empty_set_dt = cass_data_type_new(CassValueType::CASS_VALUE_TYPE_SET); // This will try to increment the reference count of `empty_list_dt`. // Previously, this would fail, because `empty_list_dt` did not originate from an Arc allocation. - cass_data_type_add_sub_type(empty_set_dt, empty_list_dt); + cass_data_type_add_sub_type(empty_set_dt.borrow(), empty_list_dt); - // Cast to *mut, because `cass_data_type_new` returns a *const. See the comment - // in this function to see why. - cass_data_type_free(empty_set_dt as *mut _) + cass_data_type_free(empty_set_dt) } } } diff --git a/scylla-rust-wrapper/src/exec_profile.rs b/scylla-rust-wrapper/src/exec_profile.rs index 281d9a3f..5ab3064b 100644 --- a/scylla-rust-wrapper/src/exec_profile.rs +++ b/scylla-rust-wrapper/src/exec_profile.rs @@ -13,7 +13,9 @@ use scylla::retry_policy::RetryPolicy; use scylla::speculative_execution::SimpleSpeculativeExecutionPolicy; use scylla::statement::Consistency; -use crate::argconv::{ptr_to_cstr_n, strlen, ArcFFI, BoxFFI}; +use crate::argconv::{ + ptr_to_cstr_n, strlen, ArcFFI, BoxFFI, CassBorrowedMutPtr, CassBorrowedPtr, CassOwnedMutPtr, +}; use crate::batch::CassBatch; use crate::cass_error::CassError; use crate::cass_types::CassConsistency; @@ -171,12 +173,12 @@ pub(crate) enum PerStatementExecProfileInner { } #[no_mangle] -pub unsafe extern "C" fn cass_execution_profile_new() -> *mut CassExecProfile { +pub unsafe extern "C" fn cass_execution_profile_new() -> CassOwnedMutPtr { BoxFFI::into_ptr(Box::new(CassExecProfile::new())) } #[no_mangle] -pub unsafe extern "C" fn cass_execution_profile_free(profile: *mut CassExecProfile) { +pub unsafe extern "C" fn cass_execution_profile_free(profile: CassOwnedMutPtr) { BoxFFI::free(profile); } @@ -184,7 +186,7 @@ pub unsafe extern "C" fn cass_execution_profile_free(profile: *mut CassExecProfi #[no_mangle] pub unsafe extern "C" fn cass_statement_set_execution_profile( - statement: *mut CassStatement, + statement: CassBorrowedMutPtr, name: *const c_char, ) -> CassError { cass_statement_set_execution_profile_n(statement, name, strlen(name)) @@ -192,11 +194,11 @@ pub unsafe extern "C" fn cass_statement_set_execution_profile( #[no_mangle] pub unsafe extern "C" fn cass_statement_set_execution_profile_n( - statement: *mut CassStatement, + statement: CassBorrowedMutPtr, name: *const c_char, name_length: size_t, ) -> CassError { - let statement = BoxFFI::as_mut_ref(statement); + let statement = BoxFFI::as_mut_ref(statement).unwrap(); let name: Option = ptr_to_cstr_n(name, name_length).and_then(|name| name.to_owned().try_into().ok()); statement.exec_profile = name.map(PerStatementExecProfile::new_unresolved); @@ -206,7 +208,7 @@ pub unsafe extern "C" fn cass_statement_set_execution_profile_n( #[no_mangle] pub unsafe extern "C" fn cass_batch_set_execution_profile( - batch: *mut CassBatch, + batch: CassBorrowedMutPtr, name: *const c_char, ) -> CassError { cass_batch_set_execution_profile_n(batch, name, strlen(name)) @@ -214,11 +216,11 @@ pub unsafe extern "C" fn cass_batch_set_execution_profile( #[no_mangle] pub unsafe extern "C" fn cass_batch_set_execution_profile_n( - batch: *mut CassBatch, + batch: CassBorrowedMutPtr, name: *const c_char, name_length: size_t, ) -> CassError { - let batch = BoxFFI::as_mut_ref(batch); + let batch = BoxFFI::as_mut_ref(batch).unwrap(); let name: Option = ptr_to_cstr_n(name, name_length).and_then(|name| name.to_owned().try_into().ok()); batch.exec_profile = name.map(PerStatementExecProfile::new_unresolved); @@ -248,10 +250,10 @@ impl CassExecProfile { #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_consistency( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, consistency: CassConsistency, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); let consistency: Consistency = match consistency.try_into() { Ok(c) => c, Err(_) => return CassError::CASS_ERROR_LIB_BAD_PARAMS, @@ -264,9 +266,9 @@ pub unsafe extern "C" fn cass_execution_profile_set_consistency( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_no_speculative_execution_policy( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); profile_builder.modify_in_place(|builder| builder.speculative_execution_policy(None)); @@ -275,11 +277,11 @@ pub unsafe extern "C" fn cass_execution_profile_set_no_speculative_execution_pol #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_constant_speculative_execution_policy( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, constant_delay_ms: cass_int64_t, max_speculative_executions: cass_int32_t, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); if constant_delay_ms < 0 || max_speculative_executions < 0 { return CassError::CASS_ERROR_LIB_BAD_PARAMS; } @@ -297,10 +299,10 @@ pub unsafe extern "C" fn cass_execution_profile_set_constant_speculative_executi #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_latency_aware_routing( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, enabled: cass_bool_t, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); profile_builder .load_balancing_config .latency_awareness_enabled = enabled != 0; @@ -310,14 +312,14 @@ pub unsafe extern "C" fn cass_execution_profile_set_latency_aware_routing( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_latency_aware_routing_settings( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, exclusion_threshold: cass_double_t, _scale_ms: cass_uint64_t, // Currently ignored, TODO: add this parameter to Rust driver retry_period_ms: cass_uint64_t, update_rate_ms: cass_uint64_t, min_measured: cass_uint64_t, ) { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); profile_builder .load_balancing_config .latency_awareness_builder = LatencyAwarenessBuilder::new() @@ -329,7 +331,7 @@ pub unsafe extern "C" fn cass_execution_profile_set_latency_aware_routing_settin #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_load_balance_dc_aware( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, local_dc: *const c_char, used_hosts_per_remote_dc: cass_uint32_t, allow_remote_dcs_for_local_cl: cass_bool_t, @@ -345,13 +347,13 @@ pub unsafe extern "C" fn cass_execution_profile_set_load_balance_dc_aware( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_load_balance_dc_aware_n( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, local_dc: *const c_char, local_dc_length: size_t, used_hosts_per_remote_dc: cass_uint32_t, allow_remote_dcs_for_local_cl: cass_bool_t, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); set_load_balance_dc_aware_n( &mut profile_builder.load_balancing_config, @@ -364,7 +366,7 @@ pub unsafe extern "C" fn cass_execution_profile_set_load_balance_dc_aware_n( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_load_balance_rack_aware( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, local_dc_raw: *const c_char, local_rack_raw: *const c_char, ) -> CassError { @@ -379,13 +381,13 @@ pub unsafe extern "C" fn cass_execution_profile_set_load_balance_rack_aware( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_load_balance_rack_aware_n( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, local_dc_raw: *const c_char, local_dc_length: size_t, local_rack_raw: *const c_char, local_rack_length: size_t, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); set_load_balance_rack_aware_n( &mut profile_builder.load_balancing_config, @@ -398,9 +400,9 @@ pub unsafe extern "C" fn cass_execution_profile_set_load_balance_rack_aware_n( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_load_balance_round_robin( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); profile_builder.load_balancing_config.load_balancing_kind = Some(LoadBalancingKind::RoundRobin); CassError::CASS_OK @@ -408,10 +410,10 @@ pub unsafe extern "C" fn cass_execution_profile_set_load_balance_round_robin( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_request_timeout( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, timeout_ms: cass_uint64_t, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); profile_builder.modify_in_place(|builder| { builder.request_timeout(Some(std::time::Duration::from_millis(timeout_ms))) }); @@ -421,15 +423,15 @@ pub unsafe extern "C" fn cass_execution_profile_set_request_timeout( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_retry_policy( - profile: *mut CassExecProfile, - retry_policy: *const CassRetryPolicy, + profile: CassBorrowedMutPtr, + retry_policy: CassBorrowedPtr, ) -> CassError { - let retry_policy: Arc = match ArcFFI::as_ref(retry_policy) { + let retry_policy: Arc = match ArcFFI::as_ref(retry_policy).unwrap() { DefaultRetryPolicy(default) => Arc::clone(default) as _, FallthroughRetryPolicy(fallthrough) => Arc::clone(fallthrough) as _, DowngradingConsistencyRetryPolicy(downgrading) => Arc::clone(downgrading) as _, }; - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); profile_builder.modify_in_place(|builder| builder.retry_policy(retry_policy)); CassError::CASS_OK @@ -437,10 +439,10 @@ pub unsafe extern "C" fn cass_execution_profile_set_retry_policy( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_serial_consistency( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, serial_consistency: CassConsistency, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); let maybe_serial_consistency = if serial_consistency == CassConsistency::CASS_CONSISTENCY_UNKNOWN { @@ -458,10 +460,10 @@ pub unsafe extern "C" fn cass_execution_profile_set_serial_consistency( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_token_aware_routing( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, enabled: cass_bool_t, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); profile_builder .load_balancing_config .token_awareness_enabled = enabled != 0; @@ -471,10 +473,10 @@ pub unsafe extern "C" fn cass_execution_profile_set_token_aware_routing( #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_token_aware_routing_shuffle_replicas( - profile: *mut CassExecProfile, + profile: CassBorrowedMutPtr, enabled: cass_bool_t, ) -> CassError { - let profile_builder = BoxFFI::as_mut_ref(profile); + let profile_builder = BoxFFI::as_mut_ref(profile).unwrap(); profile_builder .load_balancing_config .token_aware_shuffling_replicas_enabled = enabled != 0; @@ -516,31 +518,31 @@ mod tests { #[ntest::timeout(100)] fn test_load_balancing_config() { unsafe { - let profile_raw = cass_execution_profile_new(); + let mut profile_raw = cass_execution_profile_new(); { /* Test valid configurations */ - let profile = BoxFFI::as_ref(profile_raw); { + let profile = BoxFFI::as_ref(profile_raw.borrow()).unwrap(); assert_matches!(profile.load_balancing_config.load_balancing_kind, None); assert!(profile.load_balancing_config.token_awareness_enabled); assert!(!profile.load_balancing_config.latency_awareness_enabled); } { - cass_execution_profile_set_token_aware_routing(profile_raw, 0); + cass_execution_profile_set_token_aware_routing(profile_raw.borrow_mut(), 0); assert_cass_error_eq!( cass_execution_profile_set_load_balance_dc_aware( - profile_raw, + profile_raw.borrow_mut(), c"eu".as_ptr(), 0, 0 ), CassError::CASS_OK ); - cass_execution_profile_set_latency_aware_routing(profile_raw, 1); + cass_execution_profile_set_latency_aware_routing(profile_raw.borrow_mut(), 1); // These values cannot currently be tested to be set properly in the latency awareness builder, // but at least we test that the function completed successfully. cass_execution_profile_set_latency_aware_routing_settings( - profile_raw, + profile_raw.borrow_mut(), 2., 1, 2000, @@ -548,6 +550,7 @@ mod tests { 40, ); + let profile = BoxFFI::as_ref(profile_raw.borrow()).unwrap(); let load_balancing_kind = &profile.load_balancing_config.load_balancing_kind; match load_balancing_kind { Some(LoadBalancingKind::DcAware { local_dc }) => { @@ -563,7 +566,7 @@ mod tests { // Nonzero deprecated parameters assert_cass_error_eq!( cass_execution_profile_set_load_balance_dc_aware( - profile_raw, + profile_raw.borrow_mut(), c"eu".as_ptr(), 1, 0 @@ -572,7 +575,7 @@ mod tests { ); assert_cass_error_eq!( cass_execution_profile_set_load_balance_dc_aware( - profile_raw, + profile_raw.borrow_mut(), c"eu".as_ptr(), 0, 1 @@ -615,18 +618,18 @@ mod tests { fn test_statement_and_batch_set_exec_profile() { unsafe { let empty_query = make_c_str!(""); - let statement_raw = cass_statement_new(empty_query, 0); - let batch_raw = cass_batch_new(CassBatchType::CASS_BATCH_TYPE_LOGGED); + let mut statement_raw = cass_statement_new(empty_query, 0); + let mut batch_raw = cass_batch_new(CassBatchType::CASS_BATCH_TYPE_LOGGED); assert_cass_error_eq!( - cass_batch_add_statement(batch_raw, statement_raw), + cass_batch_add_statement(batch_raw.borrow_mut(), statement_raw.borrow()), CassError::CASS_OK ); { /* Test valid configurations */ - let statement = BoxFFI::as_ref(statement_raw); - let batch = BoxFFI::as_ref(batch_raw); { + let statement = BoxFFI::as_ref(statement_raw.borrow()).unwrap(); + let batch = BoxFFI::as_ref(batch_raw.borrow()).unwrap(); assert!(statement.exec_profile.is_none()); assert!(batch.exec_profile.is_none()); } @@ -634,13 +637,19 @@ mod tests { let valid_name = "profile"; let valid_name_c_str = make_c_str!("profile"); assert_cass_error_eq!( - cass_statement_set_execution_profile(statement_raw, valid_name_c_str,), + cass_statement_set_execution_profile( + statement_raw.borrow_mut(), + valid_name_c_str, + ), CassError::CASS_OK ); assert_cass_error_eq!( - cass_batch_set_execution_profile(batch_raw, valid_name_c_str,), + cass_batch_set_execution_profile(batch_raw.borrow_mut(), valid_name_c_str,), CassError::CASS_OK ); + + let statement = BoxFFI::as_ref(statement_raw.borrow()).unwrap(); + let batch = BoxFFI::as_ref(batch_raw.borrow()).unwrap(); assert_eq!( statement .exec_profile @@ -669,13 +678,22 @@ mod tests { { // NULL name sets exec profile to None assert_cass_error_eq!( - cass_statement_set_execution_profile(statement_raw, std::ptr::null::()), + cass_statement_set_execution_profile( + statement_raw.borrow_mut(), + std::ptr::null::() + ), CassError::CASS_OK ); assert_cass_error_eq!( - cass_batch_set_execution_profile(batch_raw, std::ptr::null::()), + cass_batch_set_execution_profile( + batch_raw.borrow_mut(), + std::ptr::null::() + ), CassError::CASS_OK ); + + let statement = BoxFFI::as_ref(statement_raw.borrow()).unwrap(); + let batch = BoxFFI::as_ref(batch_raw.borrow()).unwrap(); assert!(statement.exec_profile.is_none()); assert!(batch.exec_profile.is_none()); } @@ -685,7 +703,7 @@ mod tests { let (valid_name_c_str, valid_name_len) = str_to_c_str_n(valid_name); assert_cass_error_eq!( cass_statement_set_execution_profile_n( - statement_raw, + statement_raw.borrow_mut(), valid_name_c_str, valid_name_len, ), @@ -693,12 +711,15 @@ mod tests { ); assert_cass_error_eq!( cass_batch_set_execution_profile_n( - batch_raw, + batch_raw.borrow_mut(), valid_name_c_str, valid_name_len, ), CassError::CASS_OK ); + + let statement = BoxFFI::as_ref(statement_raw.borrow()).unwrap(); + let batch = BoxFFI::as_ref(batch_raw.borrow()).unwrap(); assert_eq!( statement .exec_profile @@ -727,13 +748,19 @@ mod tests { { // empty name sets exec profile to None assert_cass_error_eq!( - cass_statement_set_execution_profile(statement_raw, make_c_str!("")), + cass_statement_set_execution_profile( + statement_raw.borrow_mut(), + make_c_str!("") + ), CassError::CASS_OK ); assert_cass_error_eq!( - cass_batch_set_execution_profile(batch_raw, make_c_str!("")), + cass_batch_set_execution_profile(batch_raw.borrow_mut(), make_c_str!("")), CassError::CASS_OK ); + + let statement = BoxFFI::as_ref(statement_raw.borrow()).unwrap(); + let batch = BoxFFI::as_ref(batch_raw.borrow()).unwrap(); assert!(statement.exec_profile.is_none()); assert!(batch.exec_profile.is_none()); } diff --git a/scylla-rust-wrapper/src/future.rs b/scylla-rust-wrapper/src/future.rs index 328f764b..d28d55d3 100644 --- a/scylla-rust-wrapper/src/future.rs +++ b/scylla-rust-wrapper/src/future.rs @@ -28,7 +28,7 @@ type CassFutureError = (CassError, String); pub type CassFutureResult = Result; pub type CassFutureCallback = - Option; + Option, data: *mut c_void)>; struct BoundCallback { pub cb: CassFutureCallback, @@ -40,7 +40,7 @@ struct BoundCallback { unsafe impl Send for BoundCallback {} impl BoundCallback { - fn invoke(self, fut_ptr: *const CassFuture) { + fn invoke(self, fut_ptr: CassBorrowedPtr) { unsafe { self.cb.unwrap()(fut_ptr, self.data); } @@ -75,8 +75,8 @@ struct JoinHandleTimeout(JoinHandle<()>); impl CassFuture { pub fn make_raw( fut: impl Future + Send + 'static, - ) -> *mut CassFuture { - Self::new_from_future(fut).into_raw() as *mut _ + ) -> CassOwnedPtr { + Self::new_from_future(fut).into_raw() } pub fn new_from_future( @@ -261,7 +261,7 @@ impl CassFuture { pub fn set_callback( &self, - self_ptr: *const CassFuture, + self_ptr: CassBorrowedPtr, cb: CassFutureCallback, data: *mut c_void, ) -> CassError { @@ -282,7 +282,7 @@ impl CassFuture { CassError::CASS_OK } - fn into_raw(self: Arc) -> *const Self { + fn into_raw(self: Arc) -> CassOwnedPtr { ArcFFI::into_ptr(self) } } @@ -295,31 +295,36 @@ impl CheckSendSync for CassFuture {} #[no_mangle] pub unsafe extern "C" fn cass_future_set_callback( - future_raw: *const CassFuture, + future_raw: CassBorrowedPtr, callback: CassFutureCallback, data: *mut ::std::os::raw::c_void, ) -> CassError { - ArcFFI::as_ref(future_raw).set_callback(future_raw, callback, data) + ArcFFI::as_ref(future_raw.borrow()) + .unwrap() + .set_callback(future_raw.borrow(), callback, data) } #[no_mangle] -pub unsafe extern "C" fn cass_future_wait(future_raw: *const CassFuture) { - ArcFFI::as_ref(future_raw).with_waited_result(|_| ()); +pub unsafe extern "C" fn cass_future_wait(future_raw: CassBorrowedPtr) { + ArcFFI::as_ref(future_raw) + .unwrap() + .with_waited_result(|_| ()); } #[no_mangle] pub unsafe extern "C" fn cass_future_wait_timed( - future_raw: *const CassFuture, + future_raw: CassBorrowedPtr, timeout_us: cass_duration_t, ) -> cass_bool_t { ArcFFI::as_ref(future_raw) + .unwrap() .with_waited_result_timed(|_| (), Duration::from_micros(timeout_us)) .is_ok() as cass_bool_t } #[no_mangle] -pub unsafe extern "C" fn cass_future_ready(future_raw: *const CassFuture) -> cass_bool_t { - let state_guard = ArcFFI::as_ref(future_raw).state.lock().unwrap(); +pub unsafe extern "C" fn cass_future_ready(future_raw: CassBorrowedPtr) -> cass_bool_t { + let state_guard = ArcFFI::as_ref(future_raw).unwrap().state.lock().unwrap(); match state_guard.value { None => cass_false, Some(_) => cass_true, @@ -327,95 +332,106 @@ pub unsafe extern "C" fn cass_future_ready(future_raw: *const CassFuture) -> cas } #[no_mangle] -pub unsafe extern "C" fn cass_future_error_code(future_raw: *const CassFuture) -> CassError { - ArcFFI::as_ref(future_raw).with_waited_result(|r: &mut CassFutureResult| match r { - Ok(CassResultValue::QueryError(err)) => err.to_cass_error(), - Err((err, _)) => *err, - _ => CassError::CASS_OK, - }) +pub unsafe extern "C" fn cass_future_error_code( + future_raw: CassBorrowedPtr, +) -> CassError { + ArcFFI::as_ref(future_raw) + .unwrap() + .with_waited_result(|r: &mut CassFutureResult| match r { + Ok(CassResultValue::QueryError(err)) => err.to_cass_error(), + Err((err, _)) => *err, + _ => CassError::CASS_OK, + }) } #[no_mangle] pub unsafe extern "C" fn cass_future_error_message( - future: *mut CassFuture, + future: CassBorrowedPtr, message: *mut *const ::std::os::raw::c_char, message_length: *mut size_t, ) { - ArcFFI::as_ref(future).with_waited_state(|state: &mut CassFutureState| { - let value = &state.value; - let msg = state - .err_string - .get_or_insert_with(|| match value.as_ref().unwrap() { - Ok(CassResultValue::QueryError(err)) => err.msg(), - Err((_, s)) => s.msg(), - _ => "".to_string(), - }); - write_str_to_c(msg.as_str(), message, message_length); - }); + ArcFFI::as_ref(future) + .unwrap() + .with_waited_state(|state: &mut CassFutureState| { + let value = &state.value; + let msg = state + .err_string + .get_or_insert_with(|| match value.as_ref().unwrap() { + Ok(CassResultValue::QueryError(err)) => err.msg(), + Err((_, s)) => s.msg(), + _ => "".to_string(), + }); + write_str_to_c(msg.as_str(), message, message_length); + }); } #[no_mangle] -pub unsafe extern "C" fn cass_future_free(future_raw: *const CassFuture) { +pub unsafe extern "C" fn cass_future_free(future_raw: CassOwnedPtr) { ArcFFI::free(future_raw); } #[no_mangle] pub unsafe extern "C" fn cass_future_get_result( - future_raw: *const CassFuture, -) -> *const CassResult { + future_raw: CassBorrowedPtr, +) -> CassOwnedPtr { ArcFFI::as_ref(future_raw) + .unwrap() .with_waited_result(|r: &mut CassFutureResult| -> Option> { match r.as_ref().ok()? { CassResultValue::QueryResult(qr) => Some(qr.clone()), _ => None, } }) - .map_or(std::ptr::null(), ArcFFI::into_ptr) + .map_or(ArcFFI::null(), ArcFFI::into_ptr) } #[no_mangle] pub unsafe extern "C" fn cass_future_get_error_result( - future_raw: *const CassFuture, -) -> *const CassErrorResult { + future_raw: CassBorrowedPtr, +) -> CassOwnedPtr { ArcFFI::as_ref(future_raw) + .unwrap() .with_waited_result(|r: &mut CassFutureResult| -> Option> { match r.as_ref().ok()? { CassResultValue::QueryError(qr) => Some(qr.clone()), _ => None, } }) - .map_or(std::ptr::null(), ArcFFI::into_ptr) + .map_or(ArcFFI::null(), ArcFFI::into_ptr) } #[no_mangle] pub unsafe extern "C" fn cass_future_get_prepared( - future_raw: *mut CassFuture, -) -> *const CassPrepared { + future_raw: CassBorrowedPtr, +) -> CassOwnedPtr { ArcFFI::as_ref(future_raw) + .unwrap() .with_waited_result(|r: &mut CassFutureResult| -> Option> { match r.as_ref().ok()? { CassResultValue::Prepared(p) => Some(p.clone()), _ => None, } }) - .map_or(std::ptr::null(), ArcFFI::into_ptr) + .map_or(ArcFFI::null(), ArcFFI::into_ptr) } #[no_mangle] pub unsafe extern "C" fn cass_future_tracing_id( - future: *const CassFuture, + future: CassBorrowedPtr, tracing_id: *mut CassUuid, ) -> CassError { - ArcFFI::as_ref(future).with_waited_result(|r: &mut CassFutureResult| match r { - Ok(CassResultValue::QueryResult(result)) => match result.tracing_id { - Some(id) => { - *tracing_id = CassUuid::from(id); - CassError::CASS_OK - } - None => CassError::CASS_ERROR_LIB_NO_TRACING_ID, - }, - _ => CassError::CASS_ERROR_LIB_INVALID_FUTURE_TYPE, - }) + ArcFFI::as_ref(future) + .unwrap() + .with_waited_result(|r: &mut CassFutureResult| match r { + Ok(CassResultValue::QueryResult(result)) => match result.tracing_id { + Some(id) => { + *tracing_id = CassUuid::from(id); + CassError::CASS_OK + } + None => CassError::CASS_ERROR_LIB_NO_TRACING_ID, + }, + _ => CassError::CASS_ERROR_LIB_INVALID_FUTURE_TYPE, + }) } #[cfg(test)] @@ -443,12 +459,18 @@ mod tests { }; let cass_fut = CassFuture::make_raw(fut); - struct PtrWrapper(*mut CassFuture); + struct PtrWrapper(CassBorrowedPtr<'static, CassFuture>); unsafe impl Send for PtrWrapper {} - let wrapped_cass_fut = PtrWrapper(cass_fut); unsafe { + // transmute to erase the lifetime to 'static, so the reference + // can be passed to an async block. + let static_cass_fut_ref = std::mem::transmute::< + CassBorrowedPtr<'_, CassFuture>, + CassBorrowedPtr<'static, CassFuture>, + >(cass_fut.borrow()); + let wrapped_cass_fut = PtrWrapper(static_cass_fut_ref); let handle = thread::spawn(move || { - let wrapper = wrapped_cass_fut; + let wrapper = &wrapped_cass_fut; let PtrWrapper(cass_fut) = wrapper; assert_cass_future_error_message_eq!(cass_fut, Some(ERROR_MSG)); }); @@ -474,11 +496,13 @@ mod tests { unsafe { // This should timeout on tokio::time::timeout. - let timed_result = cass_future_wait_timed(cass_fut, HUNDRED_MILLIS_IN_MICROS / 5); + let timed_result = + cass_future_wait_timed(cass_fut.borrow(), HUNDRED_MILLIS_IN_MICROS / 5); assert_eq!(0, timed_result); // This should timeout as well. - let timed_result = cass_future_wait_timed(cass_fut, HUNDRED_MILLIS_IN_MICROS / 5); + let timed_result = + cass_future_wait_timed(cass_fut.borrow(), HUNDRED_MILLIS_IN_MICROS / 5); assert_eq!(0, timed_result); // Verify that future eventually resolves, even though timeouts occurred before. @@ -502,7 +526,10 @@ mod tests { const HUNDRED_MILLIS_IN_MICROS: u64 = 100 * 1000; let create_future_and_flag = || { - unsafe extern "C" fn mark_flag_cb(_fut: *const CassFuture, data: *mut c_void) { + unsafe extern "C" fn mark_flag_cb( + _fut: CassBorrowedPtr, + data: *mut c_void, + ) { let flag = data as *mut bool; *flag = true; } @@ -516,7 +543,11 @@ mod tests { let flag_ptr = Box::into_raw(flag); assert_cass_error_eq!( - cass_future_set_callback(cass_fut, Some(mark_flag_cb), flag_ptr as *mut c_void), + cass_future_set_callback( + cass_fut.borrow(), + Some(mark_flag_cb), + flag_ptr as *mut c_void + ), CassError::CASS_OK ); @@ -526,7 +557,7 @@ mod tests { // Callback executed after awaiting. { let (cass_fut, flag_ptr) = create_future_and_flag(); - cass_future_wait(cass_fut); + cass_future_wait(cass_fut.borrow()); assert_cass_future_error_message_eq!(cass_fut, Some(ERROR_MSG)); assert!(*flag_ptr); @@ -551,10 +582,12 @@ mod tests { let (cass_fut, flag_ptr) = create_future_and_flag(); // This should timeout on tokio::time::timeout. - let timed_result = cass_future_wait_timed(cass_fut, HUNDRED_MILLIS_IN_MICROS / 5); + let timed_result = + cass_future_wait_timed(cass_fut.borrow(), HUNDRED_MILLIS_IN_MICROS / 5); assert_eq!(0, timed_result); // This should timeout as well. - let timed_result = cass_future_wait_timed(cass_fut, HUNDRED_MILLIS_IN_MICROS / 5); + let timed_result = + cass_future_wait_timed(cass_fut.borrow(), HUNDRED_MILLIS_IN_MICROS / 5); assert_eq!(0, timed_result); // Await and check result. diff --git a/scylla-rust-wrapper/src/integration_testing.rs b/scylla-rust-wrapper/src/integration_testing.rs index 0fd4007f..b8682b32 100644 --- a/scylla-rust-wrapper/src/integration_testing.rs +++ b/scylla-rust-wrapper/src/integration_testing.rs @@ -1,34 +1,36 @@ use std::ffi::{c_char, CString}; use crate::{ - argconv::BoxFFI, + argconv::{BoxFFI, CassBorrowedPtr}, cluster::CassCluster, types::{cass_int32_t, cass_uint16_t, size_t}, }; #[no_mangle] pub unsafe extern "C" fn testing_cluster_get_connect_timeout( - cluster_raw: *const CassCluster, + cluster_raw: CassBorrowedPtr, ) -> cass_uint16_t { - let cluster = BoxFFI::as_ref(cluster_raw); + let cluster = BoxFFI::as_ref(cluster_raw).unwrap(); cluster.get_session_config().connect_timeout.as_millis() as cass_uint16_t } #[no_mangle] -pub unsafe extern "C" fn testing_cluster_get_port(cluster_raw: *const CassCluster) -> cass_int32_t { - let cluster = BoxFFI::as_ref(cluster_raw); +pub unsafe extern "C" fn testing_cluster_get_port( + cluster_raw: CassBorrowedPtr, +) -> cass_int32_t { + let cluster = BoxFFI::as_ref(cluster_raw).unwrap(); cluster.get_port() as cass_int32_t } #[no_mangle] pub unsafe extern "C" fn testing_cluster_get_contact_points( - cluster_raw: *const CassCluster, + cluster_raw: CassBorrowedPtr, contact_points: *mut *mut c_char, contact_points_length: *mut size_t, ) { - let cluster = BoxFFI::as_ref(cluster_raw); + let cluster = BoxFFI::as_ref(cluster_raw).unwrap(); let contact_points_string = cluster.get_contact_points().join(","); let length = contact_points_string.len(); diff --git a/scylla-rust-wrapper/src/lib.rs b/scylla-rust-wrapper/src/lib.rs index 27121109..976a08c9 100644 --- a/scylla-rust-wrapper/src/lib.rs +++ b/scylla-rust-wrapper/src/lib.rs @@ -8,7 +8,7 @@ use tokio::runtime::Runtime; #[macro_use] mod binding; -mod argconv; +pub mod argconv; pub mod batch; pub mod cass_error; pub mod cass_types; diff --git a/scylla-rust-wrapper/src/logging.rs b/scylla-rust-wrapper/src/logging.rs index c1a43f82..603aa4af 100644 --- a/scylla-rust-wrapper/src/logging.rs +++ b/scylla-rust-wrapper/src/logging.rs @@ -1,4 +1,4 @@ -use crate::argconv::{arr_to_cstr, ptr_to_cstr, str_to_arr, RefFFI}; +use crate::argconv::{arr_to_cstr, ptr_to_cstr, str_to_arr, CassBorrowedPtr, RefFFI}; use crate::cass_log_types::{CassLogLevel, CassLogMessage}; use crate::types::size_t; use crate::LOGGER; @@ -17,9 +17,13 @@ use tracing_subscriber::Layer; impl RefFFI for CassLogMessage {} pub type CassLogCallback = - Option; + Option, data: *mut c_void)>; -unsafe extern "C" fn noop_log_callback(_message: *const CassLogMessage, _data: *mut c_void) {} +unsafe extern "C" fn noop_log_callback( + _message: CassBorrowedPtr, + _data: *mut c_void, +) { +} pub struct Logger { pub cb: CassLogCallback, @@ -64,8 +68,11 @@ impl TryFrom for Level { pub const CASS_LOG_MAX_MESSAGE_SIZE: usize = 1024; -pub unsafe extern "C" fn stderr_log_callback(message: *const CassLogMessage, _data: *mut c_void) { - let message = RefFFI::as_ref(message); +pub unsafe extern "C" fn stderr_log_callback( + message: CassBorrowedPtr, + _data: *mut c_void, +) { + let message = RefFFI::as_ref(message).unwrap(); eprintln!( "{} [{}] ({}:{}) {}", @@ -132,7 +139,7 @@ where if let Some(log_cb) = logger.cb { unsafe { - log_cb(&log_message as *const CassLogMessage, logger.data); + log_cb(RefFFI::as_ptr(&log_message), logger.data); } } } diff --git a/scylla-rust-wrapper/src/metadata.rs b/scylla-rust-wrapper/src/metadata.rs index 2965c74c..a66c95b2 100644 --- a/scylla-rust-wrapper/src/metadata.rs +++ b/scylla-rust-wrapper/src/metadata.rs @@ -97,68 +97,68 @@ pub unsafe fn create_table_metadata( } #[no_mangle] -pub unsafe extern "C" fn cass_schema_meta_free(schema_meta: *mut CassSchemaMeta) { +pub unsafe extern "C" fn cass_schema_meta_free(schema_meta: CassOwnedMutPtr) { BoxFFI::free(schema_meta); } #[no_mangle] pub unsafe extern "C" fn cass_schema_meta_keyspace_by_name( - schema_meta: *const CassSchemaMeta, + schema_meta: CassBorrowedPtr, keyspace_name: *const c_char, -) -> *const CassKeyspaceMeta { +) -> CassBorrowedPtr { cass_schema_meta_keyspace_by_name_n(schema_meta, keyspace_name, strlen(keyspace_name)) } #[no_mangle] pub unsafe extern "C" fn cass_schema_meta_keyspace_by_name_n( - schema_meta: *const CassSchemaMeta, + schema_meta: CassBorrowedPtr, keyspace_name: *const c_char, keyspace_name_length: size_t, -) -> *const CassKeyspaceMeta { +) -> CassBorrowedPtr { if keyspace_name.is_null() { - return std::ptr::null(); + return RefFFI::null(); } - let metadata = BoxFFI::as_ref(schema_meta); + let metadata = BoxFFI::as_ref(schema_meta).unwrap(); let keyspace = ptr_to_cstr_n(keyspace_name, keyspace_name_length).unwrap(); let keyspace_meta = metadata.keyspaces.get(keyspace); match keyspace_meta { - Some(meta) => meta as *const CassKeyspaceMeta, - None => std::ptr::null(), + Some(meta) => RefFFI::as_ptr(meta), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_keyspace_meta_name( - keyspace_meta: *const CassKeyspaceMeta, + keyspace_meta: CassBorrowedPtr, name: *mut *const c_char, name_length: *mut size_t, ) { - let keyspace_meta = RefFFI::as_ref(keyspace_meta); + let keyspace_meta = RefFFI::as_ref(keyspace_meta).unwrap(); write_str_to_c(keyspace_meta.name.as_str(), name, name_length) } #[no_mangle] pub unsafe extern "C" fn cass_keyspace_meta_user_type_by_name( - keyspace_meta: *const CassKeyspaceMeta, + keyspace_meta: CassBorrowedPtr, type_: *const c_char, -) -> *const CassDataType { +) -> CassBorrowedPtr { cass_keyspace_meta_user_type_by_name_n(keyspace_meta, type_, strlen(type_)) } #[no_mangle] pub unsafe extern "C" fn cass_keyspace_meta_user_type_by_name_n( - keyspace_meta: *const CassKeyspaceMeta, + keyspace_meta: CassBorrowedPtr, type_: *const c_char, type_length: size_t, -) -> *const CassDataType { +) -> CassBorrowedPtr { if type_.is_null() { - return std::ptr::null(); + return ArcFFI::null(); } - let keyspace_meta = RefFFI::as_ref(keyspace_meta); + let keyspace_meta = RefFFI::as_ref(keyspace_meta).unwrap(); let user_type_name = ptr_to_cstr_n(type_, type_length).unwrap(); match keyspace_meta @@ -166,294 +166,293 @@ pub unsafe extern "C" fn cass_keyspace_meta_user_type_by_name_n( .get(user_type_name) { Some(udt) => ArcFFI::as_ptr(udt), - None => std::ptr::null(), + None => ArcFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_keyspace_meta_table_by_name( - keyspace_meta: *const CassKeyspaceMeta, + keyspace_meta: CassBorrowedPtr, table: *const c_char, -) -> *const CassTableMeta { +) -> CassBorrowedPtr { cass_keyspace_meta_table_by_name_n(keyspace_meta, table, strlen(table)) } #[no_mangle] pub unsafe extern "C" fn cass_keyspace_meta_table_by_name_n( - keyspace_meta: *const CassKeyspaceMeta, + keyspace_meta: CassBorrowedPtr, table: *const c_char, table_length: size_t, -) -> *const CassTableMeta { +) -> CassBorrowedPtr { if table.is_null() { - return std::ptr::null(); + return RefFFI::null(); } - let keyspace_meta = RefFFI::as_ref(keyspace_meta); + let keyspace_meta = RefFFI::as_ref(keyspace_meta).unwrap(); let table_name = ptr_to_cstr_n(table, table_length).unwrap(); let table_meta = keyspace_meta.tables.get(table_name); match table_meta { Some(meta) => RefFFI::as_ptr(meta), - None => std::ptr::null(), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_name( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, name: *mut *const c_char, name_length: *mut size_t, ) { - let table_meta = RefFFI::as_ref(table_meta); + let table_meta = RefFFI::as_ref(table_meta).unwrap(); write_str_to_c(table_meta.name.as_str(), name, name_length) } #[no_mangle] -pub unsafe extern "C" fn cass_table_meta_column_count(table_meta: *const CassTableMeta) -> size_t { - let table_meta = RefFFI::as_ref(table_meta); +pub unsafe extern "C" fn cass_table_meta_column_count( + table_meta: CassBorrowedPtr, +) -> size_t { + let table_meta = RefFFI::as_ref(table_meta).unwrap(); table_meta.columns_metadata.len() as size_t } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_partition_key( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, index: size_t, -) -> *const CassColumnMeta { - let table_meta = RefFFI::as_ref(table_meta); +) -> CassBorrowedPtr { + let table_meta = RefFFI::as_ref(table_meta).unwrap(); match table_meta.partition_keys.get(index as usize) { Some(column_name) => match table_meta.columns_metadata.get(column_name) { - Some(column_meta) => column_meta as *const CassColumnMeta, - None => std::ptr::null(), + Some(column_meta) => RefFFI::as_ptr(column_meta), + None => RefFFI::null(), }, - None => std::ptr::null(), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_partition_key_count( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, ) -> size_t { - let table_meta = RefFFI::as_ref(table_meta); + let table_meta = RefFFI::as_ref(table_meta).unwrap(); table_meta.partition_keys.len() as size_t } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_clustering_key( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, index: size_t, -) -> *const CassColumnMeta { - let table_meta = RefFFI::as_ref(table_meta); +) -> CassBorrowedPtr { + let table_meta = RefFFI::as_ref(table_meta).unwrap(); match table_meta.clustering_keys.get(index as usize) { Some(column_name) => match table_meta.columns_metadata.get(column_name) { - Some(column_meta) => column_meta as *const CassColumnMeta, - None => std::ptr::null(), + Some(column_meta) => RefFFI::as_ptr(column_meta), + None => RefFFI::null(), }, - None => std::ptr::null(), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_clustering_key_count( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, ) -> size_t { - let table_meta = RefFFI::as_ref(table_meta); + let table_meta = RefFFI::as_ref(table_meta).unwrap(); table_meta.clustering_keys.len() as size_t } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_column_by_name( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, column: *const c_char, -) -> *const CassColumnMeta { +) -> CassBorrowedPtr { cass_table_meta_column_by_name_n(table_meta, column, strlen(column)) } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_column_by_name_n( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, column: *const c_char, column_length: size_t, -) -> *const CassColumnMeta { +) -> CassBorrowedPtr { if column.is_null() { - return std::ptr::null(); + return RefFFI::null(); } - let table_meta = RefFFI::as_ref(table_meta); + let table_meta = RefFFI::as_ref(table_meta).unwrap(); let column_name = ptr_to_cstr_n(column, column_length).unwrap(); match table_meta.columns_metadata.get(column_name) { - Some(column_meta) => column_meta as *const CassColumnMeta, - None => std::ptr::null(), + Some(column_meta) => RefFFI::as_ptr(column_meta), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_column_meta_name( - column_meta: *const CassColumnMeta, + column_meta: CassBorrowedPtr, name: *mut *const c_char, name_length: *mut size_t, ) { - let column_meta = RefFFI::as_ref(column_meta); + let column_meta = RefFFI::as_ref(column_meta).unwrap(); write_str_to_c(column_meta.name.as_str(), name, name_length) } #[no_mangle] pub unsafe extern "C" fn cass_column_meta_data_type( - column_meta: *const CassColumnMeta, -) -> *const CassDataType { - let column_meta = RefFFI::as_ref(column_meta); + column_meta: CassBorrowedPtr, +) -> CassBorrowedPtr { + let column_meta = RefFFI::as_ref(column_meta).unwrap(); ArcFFI::as_ptr(&column_meta.column_type) } #[no_mangle] pub unsafe extern "C" fn cass_column_meta_type( - column_meta: *const CassColumnMeta, + column_meta: CassBorrowedPtr, ) -> CassColumnType { - let column_meta = RefFFI::as_ref(column_meta); + let column_meta = RefFFI::as_ref(column_meta).unwrap(); column_meta.column_kind } #[no_mangle] pub unsafe extern "C" fn cass_keyspace_meta_materialized_view_by_name( - keyspace_meta: *const CassKeyspaceMeta, + keyspace_meta: CassBorrowedPtr, view: *const c_char, -) -> *const CassMaterializedViewMeta { +) -> CassBorrowedPtr { cass_keyspace_meta_materialized_view_by_name_n(keyspace_meta, view, strlen(view)) } #[no_mangle] pub unsafe extern "C" fn cass_keyspace_meta_materialized_view_by_name_n( - keyspace_meta: *const CassKeyspaceMeta, + keyspace_meta: CassBorrowedPtr, view: *const c_char, view_length: size_t, -) -> *const CassMaterializedViewMeta { +) -> CassBorrowedPtr { if view.is_null() { - return std::ptr::null(); + return RefFFI::null(); } - let keyspace_meta = RefFFI::as_ref(keyspace_meta); + let keyspace_meta = RefFFI::as_ref(keyspace_meta).unwrap(); let view_name = ptr_to_cstr_n(view, view_length).unwrap(); match keyspace_meta.views.get(view_name) { Some(view_meta) => RefFFI::as_ptr(view_meta.as_ref()), - None => std::ptr::null(), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_materialized_view_by_name( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, view: *const c_char, -) -> *const CassMaterializedViewMeta { +) -> CassBorrowedPtr { cass_table_meta_materialized_view_by_name_n(table_meta, view, strlen(view)) } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_materialized_view_by_name_n( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, view: *const c_char, view_length: size_t, -) -> *const CassMaterializedViewMeta { +) -> CassBorrowedPtr { if view.is_null() { - return std::ptr::null(); + return RefFFI::null(); } - let table_meta = RefFFI::as_ref(table_meta); + let table_meta = RefFFI::as_ref(table_meta).unwrap(); let view_name = ptr_to_cstr_n(view, view_length).unwrap(); match table_meta.views.get(view_name) { Some(view_meta) => RefFFI::as_ptr(view_meta.as_ref()), - None => std::ptr::null(), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_materialized_view_count( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, ) -> size_t { - let table_meta = RefFFI::as_ref(table_meta); + let table_meta = RefFFI::as_ref(table_meta).unwrap(); table_meta.views.len() as size_t } #[no_mangle] pub unsafe extern "C" fn cass_table_meta_materialized_view( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedPtr, index: size_t, -) -> *const CassMaterializedViewMeta { - let table_meta = RefFFI::as_ref(table_meta); +) -> CassBorrowedPtr { + let table_meta = RefFFI::as_ref(table_meta).unwrap(); match table_meta.views.iter().nth(index as usize) { Some(view_meta) => RefFFI::as_ptr(view_meta.1.as_ref()), - None => std::ptr::null(), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_materialized_view_meta_column_by_name( - view_meta: *const CassMaterializedViewMeta, + view_meta: CassBorrowedPtr, column: *const c_char, -) -> *const CassColumnMeta { +) -> CassBorrowedPtr { cass_materialized_view_meta_column_by_name_n(view_meta, column, strlen(column)) } #[no_mangle] pub unsafe extern "C" fn cass_materialized_view_meta_column_by_name_n( - view_meta: *const CassMaterializedViewMeta, + view_meta: CassBorrowedPtr, column: *const c_char, column_length: size_t, -) -> *const CassColumnMeta { +) -> CassBorrowedPtr { if column.is_null() { - return std::ptr::null(); + return RefFFI::null(); } - let view_meta = RefFFI::as_ref(view_meta); + let view_meta = RefFFI::as_ref(view_meta).unwrap(); let column_name = ptr_to_cstr_n(column, column_length).unwrap(); match view_meta.view_metadata.columns_metadata.get(column_name) { - Some(column_meta) => column_meta as *const CassColumnMeta, - None => std::ptr::null(), + Some(column_meta) => RefFFI::as_ptr(column_meta), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_materialized_view_meta_name( - view_meta: *const CassMaterializedViewMeta, + view_meta: CassBorrowedPtr, name: *mut *const c_char, name_length: *mut size_t, ) { - let view_meta = RefFFI::as_ref(view_meta); + let view_meta = RefFFI::as_ref(view_meta).unwrap(); write_str_to_c(view_meta.name.as_str(), name, name_length) } #[no_mangle] pub unsafe extern "C" fn cass_materialized_view_meta_base_table( - view_meta: *const CassMaterializedViewMeta, -) -> *const CassTableMeta { - let view_meta = RefFFI::as_ref(view_meta); + view_meta: CassBorrowedPtr, +) -> CassBorrowedPtr { + let view_meta = RefFFI::as_ref(view_meta).unwrap(); - match view_meta.base_table.upgrade() { - Some(arc) => RefFFI::as_ptr(&arc), - None => std::ptr::null(), - } + RefFFI::weak_as_ptr(&view_meta.base_table) } #[no_mangle] pub unsafe extern "C" fn cass_materialized_view_meta_column_count( - view_meta: *const CassMaterializedViewMeta, + view_meta: CassBorrowedPtr, ) -> size_t { - let view_meta = RefFFI::as_ref(view_meta); + let view_meta = RefFFI::as_ref(view_meta).unwrap(); view_meta.view_metadata.columns_metadata.len() as size_t } #[no_mangle] pub unsafe extern "C" fn cass_materialized_view_meta_column( - view_meta: *const CassMaterializedViewMeta, + view_meta: CassBorrowedPtr, index: size_t, -) -> *const CassColumnMeta { - let view_meta = RefFFI::as_ref(view_meta); +) -> CassBorrowedPtr { + let view_meta = RefFFI::as_ref(view_meta).unwrap(); match view_meta .view_metadata @@ -461,53 +460,53 @@ pub unsafe extern "C" fn cass_materialized_view_meta_column( .iter() .nth(index as usize) { - Some(column_entry) => column_entry.1 as *const CassColumnMeta, - None => std::ptr::null(), + Some(column_entry) => RefFFI::as_ptr(column_entry.1), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_materialized_view_meta_partition_key_count( - view_meta: *const CassMaterializedViewMeta, + view_meta: CassBorrowedPtr, ) -> size_t { - let view_meta = RefFFI::as_ref(view_meta); + let view_meta = RefFFI::as_ref(view_meta).unwrap(); view_meta.view_metadata.partition_keys.len() as size_t } pub unsafe extern "C" fn cass_materialized_view_meta_partition_key( - view_meta: *const CassMaterializedViewMeta, + view_meta: CassBorrowedPtr, index: size_t, -) -> *const CassColumnMeta { - let view_meta = RefFFI::as_ref(view_meta); +) -> CassBorrowedPtr { + let view_meta = RefFFI::as_ref(view_meta).unwrap(); match view_meta.view_metadata.partition_keys.get(index as usize) { Some(column_name) => match view_meta.view_metadata.columns_metadata.get(column_name) { - Some(column_meta) => column_meta as *const CassColumnMeta, - None => std::ptr::null(), + Some(column_meta) => RefFFI::as_ptr(column_meta), + None => RefFFI::null(), }, - None => std::ptr::null(), + None => RefFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_materialized_view_meta_clustering_key_count( - view_meta: *const CassMaterializedViewMeta, + view_meta: CassBorrowedPtr, ) -> size_t { - let view_meta = RefFFI::as_ref(view_meta); + let view_meta = RefFFI::as_ref(view_meta).unwrap(); view_meta.view_metadata.clustering_keys.len() as size_t } pub unsafe extern "C" fn cass_materialized_view_meta_clustering_key( - view_meta: *const CassMaterializedViewMeta, + view_meta: CassBorrowedPtr, index: size_t, -) -> *const CassColumnMeta { - let view_meta = RefFFI::as_ref(view_meta); +) -> CassBorrowedPtr { + let view_meta = RefFFI::as_ref(view_meta).unwrap(); match view_meta.view_metadata.clustering_keys.get(index as usize) { Some(column_name) => match view_meta.view_metadata.columns_metadata.get(column_name) { - Some(column_meta) => column_meta as *const CassColumnMeta, - None => std::ptr::null(), + Some(column_meta) => RefFFI::as_ptr(column_meta), + None => RefFFI::null(), }, - None => std::ptr::null(), + None => RefFFI::null(), } } diff --git a/scylla-rust-wrapper/src/prepared.rs b/scylla-rust-wrapper/src/prepared.rs index d9370018..edfb7d29 100644 --- a/scylla-rust-wrapper/src/prepared.rs +++ b/scylla-rust-wrapper/src/prepared.rs @@ -75,15 +75,15 @@ impl CassPrepared { impl ArcFFI for CassPrepared {} #[no_mangle] -pub unsafe extern "C" fn cass_prepared_free(prepared_raw: *const CassPrepared) { +pub unsafe extern "C" fn cass_prepared_free(prepared_raw: CassOwnedPtr) { ArcFFI::free(prepared_raw); } #[no_mangle] pub unsafe extern "C" fn cass_prepared_bind( - prepared_raw: *const CassPrepared, -) -> *mut CassStatement { - let prepared: Arc<_> = ArcFFI::cloned_from_ptr(prepared_raw); + prepared_raw: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let prepared: Arc<_> = ArcFFI::cloned_from_ptr(prepared_raw).unwrap(); let bound_values_size = prepared.statement.get_variable_col_specs().len(); // cloning prepared statement's arc, because creating CassStatement should not invalidate @@ -106,12 +106,12 @@ pub unsafe extern "C" fn cass_prepared_bind( #[no_mangle] pub unsafe extern "C" fn cass_prepared_parameter_name( - prepared_raw: *const CassPrepared, + prepared_raw: CassBorrowedPtr, index: size_t, name: *mut *const c_char, name_length: *mut size_t, ) -> CassError { - let prepared = ArcFFI::as_ref(prepared_raw); + let prepared = ArcFFI::as_ref(prepared_raw).unwrap(); match prepared .statement @@ -128,38 +128,38 @@ pub unsafe extern "C" fn cass_prepared_parameter_name( #[no_mangle] pub unsafe extern "C" fn cass_prepared_parameter_data_type( - prepared_raw: *const CassPrepared, + prepared_raw: CassBorrowedPtr, index: size_t, -) -> *const CassDataType { - let prepared = ArcFFI::as_ref(prepared_raw); +) -> CassBorrowedPtr { + let prepared = ArcFFI::as_ref(prepared_raw).unwrap(); match prepared.variable_col_data_types.get(index as usize) { Some(dt) => ArcFFI::as_ptr(dt), - None => std::ptr::null(), + None => ArcFFI::null(), } } #[no_mangle] pub unsafe extern "C" fn cass_prepared_parameter_data_type_by_name( - prepared_raw: *const CassPrepared, + prepared_raw: CassBorrowedPtr, name: *const c_char, -) -> *const CassDataType { +) -> CassBorrowedPtr { cass_prepared_parameter_data_type_by_name_n(prepared_raw, name, strlen(name)) } #[no_mangle] pub unsafe extern "C" fn cass_prepared_parameter_data_type_by_name_n( - prepared_raw: *const CassPrepared, + prepared_raw: CassBorrowedPtr, name: *const c_char, name_length: size_t, -) -> *const CassDataType { - let prepared = ArcFFI::as_ref(prepared_raw); +) -> CassBorrowedPtr { + let prepared = ArcFFI::as_ref(prepared_raw).unwrap(); let parameter_name = ptr_to_cstr_n(name, name_length).expect("Prepared parameter name is not UTF-8"); let data_type = prepared.get_variable_data_type_by_name(parameter_name); match data_type { Some(dt) => ArcFFI::as_ptr(dt), - None => std::ptr::null(), + None => ArcFFI::null(), } } diff --git a/scylla-rust-wrapper/src/query_error.rs b/scylla-rust-wrapper/src/query_error.rs index a6aa376f..753c7d1a 100644 --- a/scylla-rust-wrapper/src/query_error.rs +++ b/scylla-rust-wrapper/src/query_error.rs @@ -56,21 +56,23 @@ impl From<&WriteType> for CassWriteType { } #[no_mangle] -pub unsafe extern "C" fn cass_error_result_free(error_result: *const CassErrorResult) { +pub unsafe extern "C" fn cass_error_result_free(error_result: CassOwnedPtr) { ArcFFI::free(error_result); } #[no_mangle] -pub unsafe extern "C" fn cass_error_result_code(error_result: *const CassErrorResult) -> CassError { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); +pub unsafe extern "C" fn cass_error_result_code( + error_result: CassBorrowedPtr, +) -> CassError { + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); error_result.to_cass_error() } #[no_mangle] pub unsafe extern "C" fn cass_error_result_consistency( - error_result: *const CassErrorResult, + error_result: CassBorrowedPtr, ) -> CassConsistency { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError( DbError::Unavailable { consistency, .. }, @@ -98,9 +100,9 @@ pub unsafe extern "C" fn cass_error_result_consistency( #[no_mangle] pub unsafe extern "C" fn cass_error_result_responses_received( - error_result: *const CassErrorResult, + error_result: CassBorrowedPtr, ) -> cass_int32_t { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError(DbError::Unavailable { alive, .. }, _)) => { *alive @@ -123,9 +125,9 @@ pub unsafe extern "C" fn cass_error_result_responses_received( #[no_mangle] pub unsafe extern "C" fn cass_error_result_responses_required( - error_result: *const CassErrorResult, + error_result: CassBorrowedPtr, ) -> cass_int32_t { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError(DbError::Unavailable { required, .. }, _)) => { *required @@ -148,9 +150,9 @@ pub unsafe extern "C" fn cass_error_result_responses_required( #[no_mangle] pub unsafe extern "C" fn cass_error_result_num_failures( - error_result: *const CassErrorResult, + error_result: CassBorrowedPtr, ) -> cass_int32_t { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError( DbError::ReadFailure { numfailures, .. }, @@ -166,9 +168,9 @@ pub unsafe extern "C" fn cass_error_result_num_failures( #[no_mangle] pub unsafe extern "C" fn cass_error_result_data_present( - error_result: *const CassErrorResult, + error_result: CassBorrowedPtr, ) -> cass_bool_t { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError( DbError::ReadTimeout { data_present, .. }, @@ -196,9 +198,9 @@ pub unsafe extern "C" fn cass_error_result_data_present( #[no_mangle] pub unsafe extern "C" fn cass_error_result_write_type( - error_result: *const CassErrorResult, + error_result: CassBorrowedPtr, ) -> CassWriteType { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError( DbError::WriteTimeout { write_type, .. }, @@ -214,11 +216,11 @@ pub unsafe extern "C" fn cass_error_result_write_type( #[no_mangle] pub unsafe extern "C" fn cass_error_result_keyspace( - error_result: *const CassErrorResult, + error_result: CassBorrowedPtr, c_keyspace: *mut *const ::std::os::raw::c_char, c_keyspace_len: *mut size_t, ) -> CassError { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError(DbError::AlreadyExists { keyspace, .. }, _)) => { write_str_to_c(keyspace.as_str(), c_keyspace, c_keyspace_len); @@ -237,11 +239,11 @@ pub unsafe extern "C" fn cass_error_result_keyspace( #[no_mangle] pub unsafe extern "C" fn cass_error_result_table( - error_result: *const CassErrorResult, + error_result: CassBorrowedPtr, c_table: *mut *const ::std::os::raw::c_char, c_table_len: *mut size_t, ) -> CassError { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError(DbError::AlreadyExists { table, .. }, _)) => { write_str_to_c(table.as_str(), c_table, c_table_len); @@ -253,11 +255,11 @@ pub unsafe extern "C" fn cass_error_result_table( #[no_mangle] pub unsafe extern "C" fn cass_error_result_function( - error_result: *const CassErrorResult, + error_result: CassBorrowedPtr, c_function: *mut *const ::std::os::raw::c_char, c_function_len: *mut size_t, ) -> CassError { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError( DbError::FunctionFailure { function, .. }, @@ -271,8 +273,10 @@ pub unsafe extern "C" fn cass_error_result_function( } #[no_mangle] -pub unsafe extern "C" fn cass_error_num_arg_types(error_result: *const CassErrorResult) -> size_t { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); +pub unsafe extern "C" fn cass_error_num_arg_types( + error_result: CassBorrowedPtr, +) -> size_t { + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError( DbError::FunctionFailure { arg_types, .. }, @@ -284,12 +288,12 @@ pub unsafe extern "C" fn cass_error_num_arg_types(error_result: *const CassError #[no_mangle] pub unsafe extern "C" fn cass_error_result_arg_type( - error_result: *const CassErrorResult, + error_result: CassBorrowedPtr, index: size_t, arg_type: *mut *const ::std::os::raw::c_char, arg_type_length: *mut size_t, ) -> CassError { - let error_result: &CassErrorResult = ArcFFI::as_ref(error_result); + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(QueryError::DbError( DbError::FunctionFailure { arg_types, .. }, diff --git a/scylla-rust-wrapper/src/query_result.rs b/scylla-rust-wrapper/src/query_result.rs index 18d860d5..b57924d1 100644 --- a/scylla-rust-wrapper/src/query_result.rs +++ b/scylla-rust-wrapper/src/query_result.rs @@ -370,14 +370,16 @@ pub enum CassIterator<'result_or_schema> { impl BoxFFI for CassIterator<'_> {} #[no_mangle] -pub unsafe extern "C" fn cass_iterator_free(iterator: *mut CassIterator) { +pub unsafe extern "C" fn cass_iterator_free(iterator: CassOwnedMutPtr) { BoxFFI::free(iterator); } // After creating an iterator we have to call next() before accessing the value #[no_mangle] -pub unsafe extern "C" fn cass_iterator_next(iterator: *mut CassIterator) -> cass_bool_t { - let mut iter = BoxFFI::as_mut_ref(iterator); +pub unsafe extern "C" fn cass_iterator_next( + iterator: CassBorrowedMutPtr, +) -> cass_bool_t { + let mut iter = BoxFFI::as_mut_ref(iterator).unwrap(); match &mut iter { CassIterator::CassResultIterator(result_iterator) => { @@ -476,66 +478,68 @@ pub unsafe extern "C" fn cass_iterator_next(iterator: *mut CassIterator) -> cass } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_row(iterator: *const CassIterator) -> *const CassRow { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_row<'result>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'result, CassRow> { + let iter = BoxFFI::as_ref(iterator).unwrap(); // Defined only for result iterator, for other types should return null if let CassIterator::CassResultIterator(result_iterator) = iter { let iter_position = match result_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let CassResultKind::Rows(CassRowsResult { rows, .. }) = &result_iterator.result.kind else { - return std::ptr::null(); + return RefFFI::null(); }; let row: &CassRow = match rows.get(iter_position) { Some(row) => row, - None => return std::ptr::null(), + None => return RefFFI::null(), }; - return row; + return RefFFI::as_ptr(row); } - std::ptr::null() + RefFFI::null() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_column( - iterator: *const CassIterator, -) -> *const CassValue { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_column<'result>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'result, CassValue> { + let iter = BoxFFI::as_ref(iterator).unwrap(); // Defined only for row iterator, for other types should return null if let CassIterator::CassRowIterator(row_iterator) = iter { let iter_position = match row_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let value = match row_iterator.row.columns.get(iter_position) { Some(col) => col, - None => return std::ptr::null(), + None => return RefFFI::null(), }; - return value as *const CassValue; + return RefFFI::as_ptr(value); } - std::ptr::null() + RefFFI::null() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_value( - iterator: *const CassIterator, -) -> *const CassValue { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_value<'result>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'result, CassValue> { + let iter = BoxFFI::as_ref(iterator).unwrap(); // Defined only for collections(list, set and map) or tuple iterator, for other types should return null if let CassIterator::CassCollectionIterator(collection_iterator) = iter { let iter_position = match collection_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let value = match &collection_iterator.value.value { @@ -549,80 +553,80 @@ pub unsafe extern "C" fn cass_iterator_get_value( map.get(map_entry_index) .map(|(key, value)| if iter_position % 2 == 0 { key } else { value }) } - _ => return std::ptr::null(), + _ => return RefFFI::null(), }; if value.is_none() { - return std::ptr::null(); + return RefFFI::null(); } - return value.unwrap() as *const CassValue; + return RefFFI::as_ptr(value.unwrap()); } - std::ptr::null() + RefFFI::null() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_map_key( - iterator: *const CassIterator, -) -> *const CassValue { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_map_key<'result>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'result, CassValue> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::CassMapIterator(map_iterator) = iter { let iter_position = match map_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let entry = match &map_iterator.value.value { Some(Value::CollectionValue(Collection::Map(map))) => map.get(iter_position), - _ => return std::ptr::null(), + _ => return RefFFI::null(), }; if entry.is_none() { - return std::ptr::null(); + return RefFFI::null(); } - return &entry.unwrap().0 as *const CassValue; + return RefFFI::as_ptr(&entry.unwrap().0); } - std::ptr::null() + RefFFI::null() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_map_value( - iterator: *const CassIterator, -) -> *const CassValue { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_map_value<'result>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'result, CassValue> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::CassMapIterator(map_iterator) = iter { let iter_position = match map_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let entry = match &map_iterator.value.value { Some(Value::CollectionValue(Collection::Map(map))) => map.get(iter_position), - _ => return std::ptr::null(), + _ => return RefFFI::null(), }; if entry.is_none() { - return std::ptr::null(); + return RefFFI::null(); } - return &entry.unwrap().1 as *const CassValue; + return RefFFI::as_ptr(&entry.unwrap().1); } - std::ptr::null() + RefFFI::null() } #[no_mangle] pub unsafe extern "C" fn cass_iterator_get_user_type_field_name( - iterator: *const CassIterator, + iterator: CassBorrowedPtr, name: *mut *const c_char, name_length: *mut size_t, ) -> CassError { - let iter = BoxFFI::as_ref(iterator); + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::CassUdtIterator(udt_iterator) = iter { let iter_position = match udt_iterator.position { @@ -652,46 +656,46 @@ pub unsafe extern "C" fn cass_iterator_get_user_type_field_name( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_user_type_field_value( - iterator: *const CassIterator, -) -> *const CassValue { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_user_type_field_value<'result>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'result, CassValue> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::CassUdtIterator(udt_iterator) = iter { let iter_position = match udt_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let udt_entry_opt = match &udt_iterator.value.value { Some(Value::CollectionValue(Collection::UserDefinedType { fields, .. })) => { fields.get(iter_position) } - _ => return std::ptr::null(), + _ => return RefFFI::null(), }; return match udt_entry_opt { Some(udt_entry) => match &udt_entry.1 { - Some(value) => value as *const CassValue, - None => std::ptr::null(), + Some(value) => RefFFI::as_ptr(value), + None => RefFFI::null(), }, - None => std::ptr::null(), + None => RefFFI::null(), }; } - std::ptr::null() + RefFFI::null() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_keyspace_meta( - iterator: *const CassIterator, -) -> *const CassKeyspaceMeta { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_keyspace_meta<'schema>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'schema, CassKeyspaceMeta> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::CassSchemaMetaIterator(schema_meta_iterator) = iter { let iter_position = match schema_meta_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let schema_meta_entry_opt = &schema_meta_iterator @@ -701,24 +705,24 @@ pub unsafe extern "C" fn cass_iterator_get_keyspace_meta( .nth(iter_position); return match schema_meta_entry_opt { - Some(schema_meta_entry) => schema_meta_entry.1 as *const CassKeyspaceMeta, - None => std::ptr::null(), + Some(schema_meta_entry) => RefFFI::as_ptr(schema_meta_entry.1), + None => RefFFI::null(), }; } - std::ptr::null() + RefFFI::null() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_table_meta( - iterator: *const CassIterator, -) -> *const CassTableMeta { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_table_meta<'schema>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'schema, CassTableMeta> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::CassKeyspaceMetaTableIterator(keyspace_meta_iterator) = iter { let iter_position = match keyspace_meta_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let table_meta_entry_opt = keyspace_meta_iterator @@ -729,23 +733,23 @@ pub unsafe extern "C" fn cass_iterator_get_table_meta( return match table_meta_entry_opt { Some(table_meta_entry) => RefFFI::as_ptr(table_meta_entry.1.as_ref()), - None => std::ptr::null(), + None => RefFFI::null(), }; } - std::ptr::null() + RefFFI::null() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_user_type( - iterator: *const CassIterator, -) -> *const CassDataType { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_user_type<'result>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'result, CassDataType> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::CassKeyspaceMetaUserTypeIterator(keyspace_meta_iterator) = iter { let iter_position = match keyspace_meta_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return ArcFFI::null(), }; let udt_to_type_entry_opt = keyspace_meta_iterator @@ -756,24 +760,24 @@ pub unsafe extern "C" fn cass_iterator_get_user_type( return match udt_to_type_entry_opt { Some(udt_to_type_entry) => ArcFFI::as_ptr(udt_to_type_entry.1), - None => std::ptr::null(), + None => ArcFFI::null(), }; } - std::ptr::null() + ArcFFI::null() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_column_meta( - iterator: *const CassIterator, -) -> *const CassColumnMeta { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_column_meta<'schema>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'schema, CassColumnMeta> { + let iter = BoxFFI::as_ref(iterator).unwrap(); match iter { CassIterator::CassTableMetaIterator(table_meta_iterator) => { let iter_position = match table_meta_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let column_meta_entry_opt = table_meta_iterator @@ -783,14 +787,14 @@ pub unsafe extern "C" fn cass_iterator_get_column_meta( .nth(iter_position); match column_meta_entry_opt { - Some(column_meta_entry) => column_meta_entry.1 as *const CassColumnMeta, - None => std::ptr::null(), + Some(column_meta_entry) => RefFFI::as_ptr(column_meta_entry.1), + None => RefFFI::null(), } } CassIterator::CassViewMetaIterator(view_meta_iterator) => { let iter_position = match view_meta_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let column_meta_entry_opt = view_meta_iterator @@ -801,56 +805,56 @@ pub unsafe extern "C" fn cass_iterator_get_column_meta( .nth(iter_position); match column_meta_entry_opt { - Some(column_meta_entry) => column_meta_entry.1 as *const CassColumnMeta, - None => std::ptr::null(), + Some(column_meta_entry) => RefFFI::as_ptr(column_meta_entry.1), + None => RefFFI::null(), } } - _ => std::ptr::null(), + _ => RefFFI::null(), } } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_get_materialized_view_meta( - iterator: *const CassIterator, -) -> *const CassMaterializedViewMeta { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_get_materialized_view_meta<'schema>( + iterator: CassBorrowedPtr>, +) -> CassBorrowedPtr<'schema, CassMaterializedViewMeta> { + let iter = BoxFFI::as_ref(iterator).unwrap(); match iter { CassIterator::CassKeyspaceMetaViewIterator(keyspace_meta_iterator) => { let iter_position = match keyspace_meta_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let view_meta_entry_opt = keyspace_meta_iterator.value.views.iter().nth(iter_position); match view_meta_entry_opt { Some(view_meta_entry) => RefFFI::as_ptr(view_meta_entry.1.as_ref()), - None => std::ptr::null(), + None => RefFFI::null(), } } CassIterator::CassTableMetaIterator(table_meta_iterator) => { let iter_position = match table_meta_iterator.position { Some(pos) => pos, - None => return std::ptr::null(), + None => return RefFFI::null(), }; let view_meta_entry_opt = table_meta_iterator.value.views.iter().nth(iter_position); match view_meta_entry_opt { Some(view_meta_entry) => RefFFI::as_ptr(view_meta_entry.1.as_ref()), - None => std::ptr::null(), + None => RefFFI::null(), } } - _ => std::ptr::null(), + _ => RefFFI::null(), } } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_from_result<'result>( - result: *const CassResult, -) -> *mut CassIterator<'result> { - let result_from_raw = ArcFFI::as_ref(result); +pub unsafe extern "C" fn cass_iterator_from_result( + result: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let result_from_raw = ArcFFI::as_ref(result).unwrap(); let iterator = CassResultIterator { result: result_from_raw, @@ -861,10 +865,10 @@ pub unsafe extern "C" fn cass_iterator_from_result<'result>( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_from_row<'result>( - row: *const CassRow, -) -> *mut CassIterator<'result> { - let row_from_raw = RefFFI::as_ref(row); +pub unsafe extern "C" fn cass_iterator_from_row( + row: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let row_from_raw = RefFFI::as_ref(row).unwrap(); let iterator = CassRowIterator { row: row_from_raw, @@ -875,21 +879,21 @@ pub unsafe extern "C" fn cass_iterator_from_row<'result>( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_from_collection<'result>( - value: *const CassValue, -) -> *mut CassIterator<'result> { - let is_collection = cass_value_is_collection(value) != 0; +pub unsafe extern "C" fn cass_iterator_from_collection( + value: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let is_collection = cass_value_is_collection(value.borrow()) != 0; - if value.is_null() || !is_collection { - return std::ptr::null_mut(); + if RefFFI::is_null(&value) || !is_collection { + return BoxFFI::null_mut(); } - let val = RefFFI::as_ref(value); - let item_count = cass_value_item_count(value); - let item_count = match cass_value_type(value) { + let item_count = cass_value_item_count(value.borrow()); + let item_count = match cass_value_type(value.borrow()) { CassValueType::CASS_VALUE_TYPE_MAP => item_count * 2, _ => item_count, }; + let val = RefFFI::as_ref(value).unwrap(); let iterator = CassCollectionIterator { value: val, @@ -901,10 +905,10 @@ pub unsafe extern "C" fn cass_iterator_from_collection<'result>( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_from_tuple<'result>( - value: *const CassValue, -) -> *mut CassIterator<'result> { - let tuple = RefFFI::as_ref(value); +pub unsafe extern "C" fn cass_iterator_from_tuple( + value: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let tuple = RefFFI::as_ref(value).unwrap(); if let Some(Value::CollectionValue(Collection::Tuple(val))) = &tuple.value { let item_count = val.len(); @@ -917,14 +921,14 @@ pub unsafe extern "C" fn cass_iterator_from_tuple<'result>( return BoxFFI::into_ptr(Box::new(CassIterator::CassCollectionIterator(iterator))); } - std::ptr::null_mut() + BoxFFI::null_mut() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_from_map<'result>( - value: *const CassValue, -) -> *mut CassIterator<'result> { - let map = RefFFI::as_ref(value); +pub unsafe extern "C" fn cass_iterator_from_map( + value: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let map = RefFFI::as_ref(value).unwrap(); if let Some(Value::CollectionValue(Collection::Map(val))) = &map.value { let item_count = val.len(); @@ -937,14 +941,14 @@ pub unsafe extern "C" fn cass_iterator_from_map<'result>( return BoxFFI::into_ptr(Box::new(CassIterator::CassMapIterator(iterator))); } - std::ptr::null_mut() + BoxFFI::null_mut() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_fields_from_user_type<'result>( - value: *const CassValue, -) -> *mut CassIterator<'result> { - let udt = RefFFI::as_ref(value); +pub unsafe extern "C" fn cass_iterator_fields_from_user_type( + value: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let udt = RefFFI::as_ref(value).unwrap(); if let Some(Value::CollectionValue(Collection::UserDefinedType { fields, .. })) = &udt.value { let item_count = fields.len(); @@ -957,14 +961,14 @@ pub unsafe extern "C" fn cass_iterator_fields_from_user_type<'result>( return BoxFFI::into_ptr(Box::new(CassIterator::CassUdtIterator(iterator))); } - std::ptr::null_mut() + BoxFFI::null_mut() } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_keyspaces_from_schema_meta<'schema>( - schema_meta: *const CassSchemaMeta, -) -> *mut CassIterator<'schema> { - let metadata = BoxFFI::as_ref(schema_meta); +pub unsafe extern "C" fn cass_iterator_keyspaces_from_schema_meta( + schema_meta: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let metadata = BoxFFI::as_ref(schema_meta).unwrap(); let iterator = CassSchemaMetaIterator { value: metadata, @@ -976,10 +980,10 @@ pub unsafe extern "C" fn cass_iterator_keyspaces_from_schema_meta<'schema>( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_tables_from_keyspace_meta<'schema>( - keyspace_meta: *const CassKeyspaceMeta, -) -> *mut CassIterator<'schema> { - let metadata = RefFFI::as_ref(keyspace_meta); +pub unsafe extern "C" fn cass_iterator_tables_from_keyspace_meta( + keyspace_meta: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let metadata = RefFFI::as_ref(keyspace_meta).unwrap(); let iterator = CassKeyspaceMetaIterator { value: metadata, @@ -993,10 +997,10 @@ pub unsafe extern "C" fn cass_iterator_tables_from_keyspace_meta<'schema>( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_materialized_views_from_keyspace_meta<'schema>( - keyspace_meta: *const CassKeyspaceMeta, -) -> *mut CassIterator<'schema> { - let metadata = RefFFI::as_ref(keyspace_meta); +pub unsafe extern "C" fn cass_iterator_materialized_views_from_keyspace_meta( + keyspace_meta: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let metadata = RefFFI::as_ref(keyspace_meta).unwrap(); let iterator = CassKeyspaceMetaIterator { value: metadata, @@ -1010,10 +1014,10 @@ pub unsafe extern "C" fn cass_iterator_materialized_views_from_keyspace_meta<'sc } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_user_types_from_keyspace_meta<'schema>( - keyspace_meta: *const CassKeyspaceMeta, -) -> *mut CassIterator<'schema> { - let metadata = RefFFI::as_ref(keyspace_meta); +pub unsafe extern "C" fn cass_iterator_user_types_from_keyspace_meta( + keyspace_meta: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let metadata = RefFFI::as_ref(keyspace_meta).unwrap(); let iterator = CassKeyspaceMetaIterator { value: metadata, @@ -1027,10 +1031,10 @@ pub unsafe extern "C" fn cass_iterator_user_types_from_keyspace_meta<'schema>( } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_columns_from_table_meta<'schema>( - table_meta: *const CassTableMeta, -) -> *mut CassIterator<'schema> { - let metadata = RefFFI::as_ref(table_meta); +pub unsafe extern "C" fn cass_iterator_columns_from_table_meta( + table_meta: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let metadata = RefFFI::as_ref(table_meta).unwrap(); let iterator = CassTableMetaIterator { value: metadata, @@ -1041,10 +1045,10 @@ pub unsafe extern "C" fn cass_iterator_columns_from_table_meta<'schema>( BoxFFI::into_ptr(Box::new(CassIterator::CassTableMetaIterator(iterator))) } -pub unsafe extern "C" fn cass_iterator_materialized_views_from_table_meta<'schema>( - table_meta: *const CassTableMeta, -) -> *mut CassIterator<'schema> { - let metadata = RefFFI::as_ref(table_meta); +pub unsafe extern "C" fn cass_iterator_materialized_views_from_table_meta( + table_meta: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let metadata = RefFFI::as_ref(table_meta).unwrap(); let iterator = CassTableMetaIterator { value: metadata, @@ -1055,10 +1059,10 @@ pub unsafe extern "C" fn cass_iterator_materialized_views_from_table_meta<'schem BoxFFI::into_ptr(Box::new(CassIterator::CassTableMetaIterator(iterator))) } -pub unsafe extern "C" fn cass_iterator_columns_from_materialized_view_meta<'schema>( - view_meta: *const CassMaterializedViewMeta, -) -> *mut CassIterator<'schema> { - let metadata = RefFFI::as_ref(view_meta); +pub unsafe extern "C" fn cass_iterator_columns_from_materialized_view_meta( + view_meta: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let metadata = RefFFI::as_ref(view_meta).unwrap(); let iterator = CassViewMetaIterator { value: metadata, @@ -1070,37 +1074,43 @@ pub unsafe extern "C" fn cass_iterator_columns_from_materialized_view_meta<'sche } #[no_mangle] -pub unsafe extern "C" fn cass_result_free(result_raw: *const CassResult) { +pub unsafe extern "C" fn cass_result_free(result_raw: CassOwnedPtr) { ArcFFI::free(result_raw); } #[no_mangle] -pub unsafe extern "C" fn cass_result_has_more_pages(result: *const CassResult) -> cass_bool_t { - let result = ArcFFI::as_ref(result); +pub unsafe extern "C" fn cass_result_has_more_pages( + result: CassBorrowedPtr, +) -> cass_bool_t { + result_has_more_pages(&result) +} + +unsafe fn result_has_more_pages(result: &CassBorrowedPtr) -> cass_bool_t { + let result = ArcFFI::as_ref(result.borrow()).unwrap(); (!result.paging_state_response.finished()) as cass_bool_t } #[no_mangle] pub unsafe extern "C" fn cass_row_get_column( - row_raw: *const CassRow, + row_raw: CassBorrowedPtr, index: size_t, -) -> *const CassValue { - let row: &CassRow = RefFFI::as_ref(row_raw); +) -> CassBorrowedPtr { + let row: &CassRow = RefFFI::as_ref(row_raw).unwrap(); let index_usize: usize = index.try_into().unwrap(); let column_value = match row.columns.get(index_usize) { Some(val) => val, - None => return std::ptr::null(), + None => return RefFFI::null(), }; - column_value as *const CassValue + RefFFI::as_ptr(column_value) } #[no_mangle] pub unsafe extern "C" fn cass_row_get_column_by_name( - row: *const CassRow, + row: CassBorrowedPtr, name: *const c_char, -) -> *const CassValue { +) -> CassBorrowedPtr { let name_str = ptr_to_cstr(name).unwrap(); let name_length = name_str.len(); @@ -1109,11 +1119,11 @@ pub unsafe extern "C" fn cass_row_get_column_by_name( #[no_mangle] pub unsafe extern "C" fn cass_row_get_column_by_name_n( - row: *const CassRow, + row: CassBorrowedPtr, name: *const c_char, name_length: size_t, -) -> *const CassValue { - let row_from_raw = RefFFI::as_ref(row); +) -> CassBorrowedPtr { + let row_from_raw = RefFFI::as_ref(row).unwrap(); let mut name_str = ptr_to_cstr_n(name, name_length).unwrap(); let mut is_case_sensitive = false; @@ -1133,20 +1143,20 @@ pub unsafe extern "C" fn cass_row_get_column_by_name_n( || !is_case_sensitive && col_spec.name.eq_ignore_ascii_case(name_str) }) .map(|(index, _)| match row_from_raw.columns.get(index) { - Some(value) => value as *const CassValue, - None => std::ptr::null(), + Some(value) => RefFFI::as_ptr(value), + None => RefFFI::null(), }) - .unwrap_or(std::ptr::null()) + .unwrap_or(RefFFI::null()) } #[no_mangle] pub unsafe extern "C" fn cass_result_column_name( - result: *const CassResult, + result: CassBorrowedPtr, index: size_t, name: *mut *const c_char, name_length: *mut size_t, ) -> CassError { - let result_from_raw = ArcFFI::as_ref(result); + let result_from_raw = ArcFFI::as_ref(result).unwrap(); let index_usize: usize = index.try_into().unwrap(); let CassResultKind::Rows(CassRowsResult { metadata, .. }) = &result_from_raw.kind else { @@ -1166,11 +1176,11 @@ pub unsafe extern "C" fn cass_result_column_name( #[no_mangle] pub unsafe extern "C" fn cass_result_column_type( - result: *const CassResult, + result: CassBorrowedPtr, index: size_t, ) -> CassValueType { let data_type_ptr = cass_result_column_data_type(result, index); - if data_type_ptr.is_null() { + if ArcFFI::is_null(&data_type_ptr) { return CassValueType::CASS_VALUE_TYPE_UNKNOWN; } cass_data_type_type(data_type_ptr) @@ -1178,51 +1188,53 @@ pub unsafe extern "C" fn cass_result_column_type( #[no_mangle] pub unsafe extern "C" fn cass_result_column_data_type( - result: *const CassResult, + result: CassBorrowedPtr, index: size_t, -) -> *const CassDataType { - let result_from_raw: &CassResult = ArcFFI::as_ref(result); +) -> CassBorrowedPtr { + let result_from_raw: &CassResult = ArcFFI::as_ref(result).unwrap(); let index_usize: usize = index .try_into() .expect("Provided index is out of bounds. Max possible value is usize::MAX"); let CassResultKind::Rows(CassRowsResult { metadata, .. }) = &result_from_raw.kind else { - return std::ptr::null(); + return ArcFFI::null(); }; metadata .col_specs .get(index_usize) .map(|col_spec| ArcFFI::as_ptr(&col_spec.data_type)) - .unwrap_or(std::ptr::null()) + .unwrap_or(ArcFFI::null()) } #[no_mangle] -pub unsafe extern "C" fn cass_value_type(value: *const CassValue) -> CassValueType { - let value_from_raw = RefFFI::as_ref(value); - +pub unsafe extern "C" fn cass_value_type(value: CassBorrowedPtr) -> CassValueType { + let value_from_raw = RefFFI::as_ref(value).unwrap(); cass_data_type_type(ArcFFI::as_ptr(&value_from_raw.value_type)) } #[no_mangle] -pub unsafe extern "C" fn cass_value_data_type(value: *const CassValue) -> *const CassDataType { - let value_from_raw = RefFFI::as_ref(value); +pub unsafe extern "C" fn cass_value_data_type( + value: CassBorrowedPtr, +) -> CassBorrowedPtr { + let value_from_raw = RefFFI::as_ref(value).unwrap(); ArcFFI::as_ptr(&value_from_raw.value_type) } macro_rules! val_ptr_to_ref_ensure_non_null { ($ptr:ident) => {{ - if $ptr.is_null() { - return CassError::CASS_ERROR_LIB_NULL_VALUE; + let maybe_ref = RefFFI::as_ref($ptr); + match maybe_ref { + Some(r) => r, + None => return CassError::CASS_ERROR_LIB_NULL_VALUE, } - RefFFI::as_ref($ptr) }}; } #[no_mangle] pub unsafe extern "C" fn cass_value_get_float( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut cass_float_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -1237,7 +1249,7 @@ pub unsafe extern "C" fn cass_value_get_float( #[no_mangle] pub unsafe extern "C" fn cass_value_get_double( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut cass_double_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -1252,7 +1264,7 @@ pub unsafe extern "C" fn cass_value_get_double( #[no_mangle] pub unsafe extern "C" fn cass_value_get_bool( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut cass_bool_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -1269,7 +1281,7 @@ pub unsafe extern "C" fn cass_value_get_bool( #[no_mangle] pub unsafe extern "C" fn cass_value_get_int8( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut cass_int8_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -1284,7 +1296,7 @@ pub unsafe extern "C" fn cass_value_get_int8( #[no_mangle] pub unsafe extern "C" fn cass_value_get_int16( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut cass_int16_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -1299,7 +1311,7 @@ pub unsafe extern "C" fn cass_value_get_int16( #[no_mangle] pub unsafe extern "C" fn cass_value_get_uint32( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut cass_uint32_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -1314,7 +1326,7 @@ pub unsafe extern "C" fn cass_value_get_uint32( #[no_mangle] pub unsafe extern "C" fn cass_value_get_int32( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut cass_int32_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -1329,7 +1341,7 @@ pub unsafe extern "C" fn cass_value_get_int32( #[no_mangle] pub unsafe extern "C" fn cass_value_get_int64( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut cass_int64_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -1351,7 +1363,7 @@ pub unsafe extern "C" fn cass_value_get_int64( #[no_mangle] pub unsafe extern "C" fn cass_value_get_uuid( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut CassUuid, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -1369,7 +1381,7 @@ pub unsafe extern "C" fn cass_value_get_uuid( #[no_mangle] pub unsafe extern "C" fn cass_value_get_inet( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut CassInet, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -1384,12 +1396,12 @@ pub unsafe extern "C" fn cass_value_get_inet( #[no_mangle] pub unsafe extern "C" fn cass_value_get_decimal( - value: *const CassValue, + value: CassBorrowedPtr, varint: *mut *const cass_byte_t, varint_size: *mut size_t, scale: *mut cass_int32_t, ) -> CassError { - let val: &CassValue = RefFFI::as_ref(value); + let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); let decimal = match &val.value { Some(Value::RegularValue(CqlValue::Decimal(decimal))) => decimal, Some(_) => return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE, @@ -1406,7 +1418,7 @@ pub unsafe extern "C" fn cass_value_get_decimal( #[no_mangle] pub unsafe extern "C" fn cass_value_get_string( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut *const c_char, output_size: *mut size_t, ) -> CassError { @@ -1431,7 +1443,7 @@ pub unsafe extern "C" fn cass_value_get_string( #[no_mangle] pub unsafe extern "C" fn cass_value_get_duration( - value: *const CassValue, + value: CassBorrowedPtr, months: *mut cass_int32_t, days: *mut cass_int32_t, nanos: *mut cass_int64_t, @@ -1453,7 +1465,7 @@ pub unsafe extern "C" fn cass_value_get_duration( #[no_mangle] pub unsafe extern "C" fn cass_value_get_bytes( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut *const cass_byte_t, output_size: *mut size_t, ) -> CassError { @@ -1479,14 +1491,16 @@ pub unsafe extern "C" fn cass_value_get_bytes( } #[no_mangle] -pub unsafe extern "C" fn cass_value_is_null(value: *const CassValue) -> cass_bool_t { - let val: &CassValue = RefFFI::as_ref(value); +pub unsafe extern "C" fn cass_value_is_null(value: CassBorrowedPtr) -> cass_bool_t { + let val: &CassValue = RefFFI::as_ref(value).unwrap(); val.value.is_none() as cass_bool_t } #[no_mangle] -pub unsafe extern "C" fn cass_value_is_collection(value: *const CassValue) -> cass_bool_t { - let val = RefFFI::as_ref(value); +pub unsafe extern "C" fn cass_value_is_collection( + value: CassBorrowedPtr, +) -> cass_bool_t { + let val = RefFFI::as_ref(value).unwrap(); matches!( val.value_type.get_unchecked().get_value_type(), @@ -1497,16 +1511,16 @@ pub unsafe extern "C" fn cass_value_is_collection(value: *const CassValue) -> ca } #[no_mangle] -pub unsafe extern "C" fn cass_value_is_duration(value: *const CassValue) -> cass_bool_t { - let val = RefFFI::as_ref(value); +pub unsafe extern "C" fn cass_value_is_duration(value: CassBorrowedPtr) -> cass_bool_t { + let val = RefFFI::as_ref(value).unwrap(); (val.value_type.get_unchecked().get_value_type() == CassValueType::CASS_VALUE_TYPE_DURATION) as cass_bool_t } #[no_mangle] -pub unsafe extern "C" fn cass_value_item_count(collection: *const CassValue) -> size_t { - let val = RefFFI::as_ref(collection); +pub unsafe extern "C" fn cass_value_item_count(collection: CassBorrowedPtr) -> size_t { + let val = RefFFI::as_ref(collection).unwrap(); match &val.value { Some(Value::CollectionValue(Collection::List(list))) => list.len() as size_t, @@ -1522,9 +1536,9 @@ pub unsafe extern "C" fn cass_value_item_count(collection: *const CassValue) -> #[no_mangle] pub unsafe extern "C" fn cass_value_primary_sub_type( - collection: *const CassValue, + collection: CassBorrowedPtr, ) -> CassValueType { - let val = RefFFI::as_ref(collection); + let val = RefFFI::as_ref(collection).unwrap(); match val.value_type.get_unchecked() { CassDataTypeInner::List { @@ -1541,9 +1555,9 @@ pub unsafe extern "C" fn cass_value_primary_sub_type( #[no_mangle] pub unsafe extern "C" fn cass_value_secondary_sub_type( - collection: *const CassValue, + collection: CassBorrowedPtr, ) -> CassValueType { - let val = RefFFI::as_ref(collection); + let val = RefFFI::as_ref(collection).unwrap(); match val.value_type.get_unchecked() { CassDataTypeInner::Map { @@ -1555,8 +1569,8 @@ pub unsafe extern "C" fn cass_value_secondary_sub_type( } #[no_mangle] -pub unsafe extern "C" fn cass_result_row_count(result_raw: *const CassResult) -> size_t { - let result = ArcFFI::as_ref(result_raw); +pub unsafe extern "C" fn cass_result_row_count(result_raw: CassBorrowedPtr) -> size_t { + let result = ArcFFI::as_ref(result_raw).unwrap(); let CassResultKind::Rows(CassRowsResult { rows, .. }) = &result.kind else { return 0; @@ -1566,8 +1580,10 @@ pub unsafe extern "C" fn cass_result_row_count(result_raw: *const CassResult) -> } #[no_mangle] -pub unsafe extern "C" fn cass_result_column_count(result_raw: *const CassResult) -> size_t { - let result = ArcFFI::as_ref(result_raw); +pub unsafe extern "C" fn cass_result_column_count( + result_raw: CassBorrowedPtr, +) -> size_t { + let result = ArcFFI::as_ref(result_raw).unwrap(); let CassResultKind::Rows(CassRowsResult { metadata, .. }) = &result.kind else { return 0; @@ -1577,29 +1593,29 @@ pub unsafe extern "C" fn cass_result_column_count(result_raw: *const CassResult) } #[no_mangle] -pub unsafe extern "C" fn cass_result_first_row(result_raw: *const CassResult) -> *const CassRow { - let result = ArcFFI::as_ref(result_raw); +pub unsafe extern "C" fn cass_result_first_row( + result_raw: CassBorrowedPtr, +) -> CassBorrowedPtr { + let result = ArcFFI::as_ref(result_raw).unwrap(); let CassResultKind::Rows(CassRowsResult { rows, .. }) = &result.kind else { - return std::ptr::null(); + return RefFFI::null(); }; - rows.first() - .map(|row| row as *const CassRow) - .unwrap_or(std::ptr::null()) + rows.first().map(RefFFI::as_ptr).unwrap_or(RefFFI::null()) } #[no_mangle] pub unsafe extern "C" fn cass_result_paging_state_token( - result: *const CassResult, + result: CassBorrowedPtr, paging_state: *mut *const c_char, paging_state_size: *mut size_t, ) -> CassError { - if cass_result_has_more_pages(result) == cass_false { + if result_has_more_pages(&result) == cass_false { return CassError::CASS_ERROR_LIB_NO_PAGING_STATE; } - let result_from_raw = ArcFFI::as_ref(result); + let result_from_raw = ArcFFI::as_ref(result).unwrap(); match &result_from_raw.paging_state_response { PagingStateResponse::HasMorePages { state } => match state.as_bytes_slice() { @@ -1631,7 +1647,7 @@ mod tests { }; use crate::{ - argconv::ArcFFI, + argconv::{ArcFFI, RefFFI}, cass_error::CassError, cass_types::{CassDataType, CassDataTypeInner, CassValueType}, query_result::{ @@ -1641,8 +1657,8 @@ mod tests { }; use super::{ - cass_result_column_count, cass_result_column_type, create_cass_rows_from_rows, CassResult, - CassResultKind, CassResultMetadata, CassRowsResult, + cass_result_column_count, cass_result_column_type, create_cass_rows_from_rows, + CassBorrowedPtr, CassResult, CassResultKind, CassResultMetadata, CassRowsResult, }; fn col_spec(name: &'static str, typ: ColumnType<'static>) -> ColumnSpec<'static> { @@ -1685,7 +1701,7 @@ mod tests { } unsafe fn cass_result_column_name_rust_str( - result_ptr: *const CassResult, + result_ptr: CassBorrowedPtr, column_index: u64, ) -> Option<&'static str> { let mut name_ptr: *const c_char = std::ptr::null(); @@ -1702,36 +1718,39 @@ mod tests { #[test] fn rows_cass_result_api_test() { - let result = create_cass_rows_result(); + let result = Arc::new(create_cass_rows_result()); unsafe { - let result_ptr = std::ptr::addr_of!(result); + let result_ptr = ArcFFI::as_ptr(&result); // cass_result_column_count test { - let column_count = cass_result_column_count(result_ptr); + let column_count = cass_result_column_count(result_ptr.borrow()); assert_eq!(3, column_count); } // cass_result_column_name test { - let first_column_name = cass_result_column_name_rust_str(result_ptr, 0).unwrap(); + let first_column_name = + cass_result_column_name_rust_str(result_ptr.borrow(), 0).unwrap(); assert_eq!(FIRST_COLUMN_NAME, first_column_name); - let second_column_name = cass_result_column_name_rust_str(result_ptr, 1).unwrap(); + let second_column_name = + cass_result_column_name_rust_str(result_ptr.borrow(), 1).unwrap(); assert_eq!(SECOND_COLUMN_NAME, second_column_name); - let third_column_name = cass_result_column_name_rust_str(result_ptr, 2).unwrap(); + let third_column_name = + cass_result_column_name_rust_str(result_ptr.borrow(), 2).unwrap(); assert_eq!(THIRD_COLUMN_NAME, third_column_name); } // cass_result_column_type test { - let first_col_type = cass_result_column_type(result_ptr, 0); + let first_col_type = cass_result_column_type(result_ptr.borrow(), 0); assert_eq!(CassValueType::CASS_VALUE_TYPE_BIGINT, first_col_type); - let second_col_type = cass_result_column_type(result_ptr, 1); + let second_col_type = cass_result_column_type(result_ptr.borrow(), 1); assert_eq!(CassValueType::CASS_VALUE_TYPE_VARINT, second_col_type); - let third_col_type = cass_result_column_type(result_ptr, 2); + let third_col_type = cass_result_column_type(result_ptr.borrow(), 2); assert_eq!(CassValueType::CASS_VALUE_TYPE_LIST, third_col_type); - let out_of_bound_col_type = cass_result_column_type(result_ptr, 555); + let out_of_bound_col_type = cass_result_column_type(result_ptr.borrow(), 555); assert_eq!( CassValueType::CASS_VALUE_TYPE_UNKNOWN, out_of_bound_col_type @@ -1740,24 +1759,24 @@ mod tests { // cass_result_column_data_type test { - let first_col_data_type = - ArcFFI::as_ref(cass_result_column_data_type(result_ptr, 0)); + let first_col_data_type_ptr = cass_result_column_data_type(result_ptr.borrow(), 0); + let first_col_data_type = ArcFFI::as_ref(first_col_data_type_ptr).unwrap(); assert_eq!( &CassDataType::new(CassDataTypeInner::Value( CassValueType::CASS_VALUE_TYPE_BIGINT )), first_col_data_type ); - let second_col_data_type = - ArcFFI::as_ref(cass_result_column_data_type(result_ptr, 1)); + let second_col_data_type_ptr = cass_result_column_data_type(result_ptr.borrow(), 1); + let second_col_data_type = ArcFFI::as_ref(second_col_data_type_ptr).unwrap(); assert_eq!( &CassDataType::new(CassDataTypeInner::Value( CassValueType::CASS_VALUE_TYPE_VARINT )), second_col_data_type ); - let third_col_data_type = - ArcFFI::as_ref(cass_result_column_data_type(result_ptr, 2)); + let third_col_data_type_ptr = cass_result_column_data_type(result_ptr.borrow(), 2); + let third_col_data_type = ArcFFI::as_ref(third_col_data_type_ptr).unwrap(); assert_eq!( &CassDataType::new(CassDataTypeInner::List { typ: Some(CassDataType::new_arced(CassDataTypeInner::Value( @@ -1767,8 +1786,9 @@ mod tests { }), third_col_data_type ); - let out_of_bound_col_data_type = cass_result_column_data_type(result_ptr, 555); - assert!(out_of_bound_col_data_type.is_null()); + let out_of_bound_col_data_type = + cass_result_column_data_type(result_ptr.borrow(), 555); + assert!(ArcFFI::is_null(&out_of_bound_col_data_type)); } } } @@ -1783,19 +1803,22 @@ mod tests { #[test] fn non_rows_cass_result_api_test() { - let result = create_non_rows_cass_result(); + let result = Arc::new(create_non_rows_cass_result()); // Check that API functions do not panic when rows are empty - e.g. for INSERT queries. unsafe { - let result_ptr = std::ptr::addr_of!(result); + let result_ptr = ArcFFI::as_ptr(&result); - assert_eq!(0, cass_result_column_count(result_ptr)); + assert_eq!(0, cass_result_column_count(result_ptr.borrow())); assert_eq!( CassValueType::CASS_VALUE_TYPE_UNKNOWN, - cass_result_column_type(result_ptr, 0) + cass_result_column_type(result_ptr.borrow(), 0) ); - assert!(cass_result_column_data_type(result_ptr, 0).is_null()); - assert!(cass_result_first_row(result_ptr).is_null()); + assert!(ArcFFI::is_null(&cass_result_column_data_type( + result_ptr.borrow(), + 0 + ))); + assert!(RefFFI::is_null(&cass_result_first_row(result_ptr.borrow()))); { let mut name_ptr: *const c_char = std::ptr::null(); @@ -1817,41 +1840,41 @@ mod tests { extern "C" { pub fn cass_statement_set_paging_state( statement: *mut CassStatement, - result: *const CassResult, + result: CassBorrowedPtr, ) -> CassError; } extern "C" { - pub fn cass_result_row_count(result: *const CassResult) -> size_t; + pub fn cass_result_row_count(result: CassBorrowedPtr) -> size_t; } extern "C" { - pub fn cass_result_column_count(result: *const CassResult) -> size_t; + pub fn cass_result_column_count(result: CassBorrowedPtr) -> size_t; } extern "C" { pub fn cass_result_column_name( - result: *const CassResult, + result: CassBorrowedPtr, index: size_t, name: *mut *const ::std::os::raw::c_char, name_length: *mut size_t, ) -> CassError; } extern "C" { - pub fn cass_result_column_type(result: *const CassResult, index: size_t) -> CassValueType; + pub fn cass_result_column_type(result: CassBorrowedPtr, index: size_t) -> CassValueType; } extern "C" { pub fn cass_result_column_data_type( - result: *const CassResult, + result: CassBorrowedPtr, index: size_t, ) -> *const CassDataType; } extern "C" { - pub fn cass_result_first_row(result: *const CassResult) -> *const CassRow; + pub fn cass_result_first_row(result: CassBorrowedPtr) -> CassBorrowedPtr; } extern "C" { - pub fn cass_result_has_more_pages(result: *const CassResult) -> cass_bool_t; + pub fn cass_result_has_more_pages(result: CassBorrowedPtr) -> cass_bool_t; } extern "C" { pub fn cass_result_paging_state_token( - result: *const CassResult, + result: CassBorrowedPtr, paging_state: *mut *const ::std::os::raw::c_char, paging_state_size: *mut size_t, ) -> CassError; @@ -1861,120 +1884,120 @@ extern "C" { // CassIterator functions: /* extern "C" { - pub fn cass_iterator_type(iterator: *mut CassIterator) -> CassIteratorType; + pub fn cass_iterator_type(iterator: CassBorrowedMutPtr) -> CassIteratorType; } extern "C" { - pub fn cass_iterator_from_row(row: *const CassRow) -> *mut CassIterator; + pub fn cass_iterator_from_row(row: CassBorrowedPtr) -> CassBorrowedMutPtr; } extern "C" { - pub fn cass_iterator_from_collection(value: *const CassValue) -> *mut CassIterator; + pub fn cass_iterator_from_collection(value: CassBorrowedPtr) -> CassBorrowedMutPtr; } extern "C" { - pub fn cass_iterator_from_map(value: *const CassValue) -> *mut CassIterator; + pub fn cass_iterator_from_map(value: CassBorrowedPtr) -> CassBorrowedMutPtr; } extern "C" { - pub fn cass_iterator_from_tuple(value: *const CassValue) -> *mut CassIterator; + pub fn cass_iterator_from_tuple(value: CassBorrowedPtr) -> CassBorrowedMutPtr; } extern "C" { - pub fn cass_iterator_fields_from_user_type(value: *const CassValue) -> *mut CassIterator; + pub fn cass_iterator_fields_from_user_type(value: CassBorrowedPtr) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_keyspaces_from_schema_meta( schema_meta: *const CassSchemaMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_tables_from_keyspace_meta( keyspace_meta: *const CassKeyspaceMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_materialized_views_from_keyspace_meta( keyspace_meta: *const CassKeyspaceMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_user_types_from_keyspace_meta( keyspace_meta: *const CassKeyspaceMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_functions_from_keyspace_meta( keyspace_meta: *const CassKeyspaceMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_aggregates_from_keyspace_meta( keyspace_meta: *const CassKeyspaceMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_fields_from_keyspace_meta( keyspace_meta: *const CassKeyspaceMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_columns_from_table_meta( table_meta: *const CassTableMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_indexes_from_table_meta( table_meta: *const CassTableMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_materialized_views_from_table_meta( table_meta: *const CassTableMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_fields_from_table_meta( table_meta: *const CassTableMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_columns_from_materialized_view_meta( view_meta: *const CassMaterializedViewMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_fields_from_materialized_view_meta( view_meta: *const CassMaterializedViewMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_fields_from_column_meta( column_meta: *const CassColumnMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_fields_from_index_meta( index_meta: *const CassIndexMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_fields_from_function_meta( function_meta: *const CassFunctionMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { pub fn cass_iterator_fields_from_aggregate_meta( aggregate_meta: *const CassAggregateMeta, - ) -> *mut CassIterator; + ) -> CassBorrowedMutPtr; } extern "C" { - pub fn cass_iterator_get_column(iterator: *const CassIterator) -> *const CassValue; + pub fn cass_iterator_get_column(iterator: *const CassIterator) -> CassBorrowedPtr; } extern "C" { - pub fn cass_iterator_get_value(iterator: *const CassIterator) -> *const CassValue; + pub fn cass_iterator_get_value(iterator: *const CassIterator) -> CassBorrowedPtr; } extern "C" { - pub fn cass_iterator_get_map_key(iterator: *const CassIterator) -> *const CassValue; + pub fn cass_iterator_get_map_key(iterator: *const CassIterator) -> CassBorrowedPtr; } extern "C" { - pub fn cass_iterator_get_map_value(iterator: *const CassIterator) -> *const CassValue; + pub fn cass_iterator_get_map_value(iterator: *const CassIterator) -> CassBorrowedPtr; } extern "C" { pub fn cass_iterator_get_user_type_field_name( @@ -1986,7 +2009,7 @@ extern "C" { extern "C" { pub fn cass_iterator_get_user_type_field_value( iterator: *const CassIterator, - ) -> *const CassValue; + ) -> CassBorrowedPtr; } extern "C" { pub fn cass_iterator_get_keyspace_meta( @@ -2028,7 +2051,7 @@ extern "C" { ) -> CassError; } extern "C" { - pub fn cass_iterator_get_meta_field_value(iterator: *const CassIterator) -> *const CassValue; + pub fn cass_iterator_get_meta_field_value(iterator: *const CassIterator) -> CassBorrowedPtr; } */ @@ -2036,16 +2059,16 @@ extern "C" { /* extern "C" { pub fn cass_row_get_column_by_name( - row: *const CassRow, + row: CassBorrowedPtr, name: *const ::std::os::raw::c_char, - ) -> *const CassValue; + ) -> CassBorrowedPtr; } extern "C" { pub fn cass_row_get_column_by_name_n( - row: *const CassRow, + row: CassBorrowedPtr, name: *const ::std::os::raw::c_char, name_length: size_t, - ) -> *const CassValue; + ) -> CassBorrowedPtr; } */ @@ -2053,24 +2076,24 @@ extern "C" { /* #[no_mangle] pub unsafe extern "C" fn cass_value_get_bytes( - value: *const CassValue, + value: CassBorrowedPtr, output: *mut *const cass_byte_t, output_size: *mut size_t, ) -> CassError { } extern "C" { - pub fn cass_value_data_type(value: *const CassValue) -> *const CassDataType; + pub fn cass_value_data_type(value: CassBorrowedPtr) -> *const CassDataType; } extern "C" { - pub fn cass_value_type(value: *const CassValue) -> CassValueType; + pub fn cass_value_type(value: CassBorrowedPtr) -> CassValueType; } extern "C" { - pub fn cass_value_item_count(collection: *const CassValue) -> size_t; + pub fn cass_value_item_count(collection: CassBorrowedPtr) -> size_t; } extern "C" { - pub fn cass_value_primary_sub_type(collection: *const CassValue) -> CassValueType; + pub fn cass_value_primary_sub_type(collection: CassBorrowedPtr) -> CassValueType; } extern "C" { - pub fn cass_value_secondary_sub_type(collection: *const CassValue) -> CassValueType; + pub fn cass_value_secondary_sub_type(collection: CassBorrowedPtr) -> CassValueType; } */ diff --git a/scylla-rust-wrapper/src/retry_policy.rs b/scylla-rust-wrapper/src/retry_policy.rs index 6945c32a..43b5f40b 100644 --- a/scylla-rust-wrapper/src/retry_policy.rs +++ b/scylla-rust-wrapper/src/retry_policy.rs @@ -2,7 +2,7 @@ use scylla::retry_policy::{DefaultRetryPolicy, FallthroughRetryPolicy}; use scylla::transport::downgrading_consistency_retry_policy::DowngradingConsistencyRetryPolicy; use std::sync::Arc; -use crate::argconv::ArcFFI; +use crate::argconv::{ArcFFI, CassOwnedPtr}; pub enum RetryPolicy { DefaultRetryPolicy(Arc), @@ -15,27 +15,28 @@ pub type CassRetryPolicy = RetryPolicy; impl ArcFFI for CassRetryPolicy {} #[no_mangle] -pub extern "C" fn cass_retry_policy_default_new() -> *const CassRetryPolicy { +pub extern "C" fn cass_retry_policy_default_new() -> CassOwnedPtr { ArcFFI::into_ptr(Arc::new(RetryPolicy::DefaultRetryPolicy(Arc::new( DefaultRetryPolicy, )))) } #[no_mangle] -pub extern "C" fn cass_retry_policy_downgrading_consistency_new() -> *const CassRetryPolicy { +pub extern "C" fn cass_retry_policy_downgrading_consistency_new( +) -> CassOwnedPtr { ArcFFI::into_ptr(Arc::new(RetryPolicy::DowngradingConsistencyRetryPolicy( Arc::new(DowngradingConsistencyRetryPolicy), ))) } #[no_mangle] -pub extern "C" fn cass_retry_policy_fallthrough_new() -> *const CassRetryPolicy { +pub extern "C" fn cass_retry_policy_fallthrough_new() -> CassOwnedPtr { ArcFFI::into_ptr(Arc::new(RetryPolicy::FallthroughRetryPolicy(Arc::new( FallthroughRetryPolicy, )))) } #[no_mangle] -pub unsafe extern "C" fn cass_retry_policy_free(retry_policy: *const CassRetryPolicy) { +pub unsafe extern "C" fn cass_retry_policy_free(retry_policy: CassOwnedPtr) { ArcFFI::free(retry_policy); } diff --git a/scylla-rust-wrapper/src/session.rs b/scylla-rust-wrapper/src/session.rs index 38abfbfc..5a5ddde8 100644 --- a/scylla-rust-wrapper/src/session.rs +++ b/scylla-rust-wrapper/src/session.rs @@ -74,7 +74,7 @@ impl CassSessionInner { session_opt: Arc>>, cluster: &CassCluster, keyspace: Option, - ) -> *const CassFuture { + ) -> CassOwnedPtr { let session_builder = build_session_builder(cluster); let exec_profile_map = cluster.execution_profile_map().clone(); @@ -141,40 +141,40 @@ pub type CassSession = RwLock>; impl ArcFFI for CassSession {} #[no_mangle] -pub unsafe extern "C" fn cass_session_new() -> *mut CassSession { +pub unsafe extern "C" fn cass_session_new() -> CassOwnedPtr { let session = Arc::new(RwLock::new(None::)); - ArcFFI::into_ptr(session) as *mut CassSession + ArcFFI::into_ptr(session) } #[no_mangle] pub unsafe extern "C" fn cass_session_connect( - session_raw: *mut CassSession, - cluster_raw: *const CassCluster, -) -> *const CassFuture { - let session_opt = ArcFFI::cloned_from_ptr(session_raw); - let cluster: &CassCluster = BoxFFI::as_ref(cluster_raw); + session_raw: CassBorrowedPtr, + cluster_raw: CassBorrowedPtr, +) -> CassOwnedPtr { + let session_opt = ArcFFI::cloned_from_ptr(session_raw).unwrap(); + let cluster: &CassCluster = BoxFFI::as_ref(cluster_raw).unwrap(); CassSessionInner::connect(session_opt, cluster, None) } #[no_mangle] pub unsafe extern "C" fn cass_session_connect_keyspace( - session_raw: *mut CassSession, - cluster_raw: *const CassCluster, + session_raw: CassBorrowedPtr, + cluster_raw: CassBorrowedPtr, keyspace: *const c_char, -) -> *const CassFuture { +) -> CassOwnedPtr { cass_session_connect_keyspace_n(session_raw, cluster_raw, keyspace, strlen(keyspace)) } #[no_mangle] pub unsafe extern "C" fn cass_session_connect_keyspace_n( - session_raw: *mut CassSession, - cluster_raw: *const CassCluster, + session_raw: CassBorrowedPtr, + cluster_raw: CassBorrowedPtr, keyspace: *const c_char, keyspace_length: size_t, -) -> *const CassFuture { - let session_opt = ArcFFI::cloned_from_ptr(session_raw); - let cluster: &CassCluster = BoxFFI::as_ref(cluster_raw); +) -> CassOwnedPtr { + let session_opt = ArcFFI::cloned_from_ptr(session_raw).unwrap(); + let cluster: &CassCluster = BoxFFI::as_ref(cluster_raw).unwrap(); let keyspace = ptr_to_cstr_n(keyspace, keyspace_length).map(ToOwned::to_owned); CassSessionInner::connect(session_opt, cluster, keyspace) @@ -182,11 +182,11 @@ pub unsafe extern "C" fn cass_session_connect_keyspace_n( #[no_mangle] pub unsafe extern "C" fn cass_session_execute_batch( - session_raw: *mut CassSession, - batch_raw: *const CassBatch, -) -> *const CassFuture { - let session_opt = ArcFFI::cloned_from_ptr(session_raw); - let batch_from_raw = BoxFFI::as_ref(batch_raw); + session_raw: CassBorrowedPtr, + batch_raw: CassBorrowedPtr, +) -> CassOwnedPtr { + let session_opt = ArcFFI::cloned_from_ptr(session_raw).unwrap(); + let batch_from_raw = BoxFFI::as_ref(batch_raw).unwrap(); let mut state = batch_from_raw.state.clone(); let request_timeout_ms = batch_from_raw.batch_request_timeout_ms; @@ -248,13 +248,13 @@ async fn request_with_timeout( #[no_mangle] pub unsafe extern "C" fn cass_session_execute( - session_raw: *mut CassSession, - statement_raw: *const CassStatement, -) -> *const CassFuture { - let session_opt = ArcFFI::cloned_from_ptr(session_raw); + session_raw: CassBorrowedPtr, + statement_raw: CassBorrowedPtr, +) -> CassOwnedPtr { + let session_opt = ArcFFI::cloned_from_ptr(session_raw).unwrap(); // DO NOT refer to `statement_opt` inside the async block, as I've done just to face a segfault. - let statement_opt = BoxFFI::as_ref(statement_raw); + let statement_opt = BoxFFI::as_ref(statement_raw).unwrap(); let paging_state = statement_opt.paging_state.clone(); let paging_enabled = statement_opt.paging_enabled; let request_timeout_ms = statement_opt.request_timeout_ms; @@ -383,11 +383,11 @@ pub unsafe extern "C" fn cass_session_execute( #[no_mangle] pub unsafe extern "C" fn cass_session_prepare_from_existing( - cass_session: *mut CassSession, - statement: *const CassStatement, -) -> *const CassFuture { - let session = ArcFFI::cloned_from_ptr(cass_session); - let cass_statement = BoxFFI::as_ref(statement); + cass_session: CassBorrowedPtr, + statement: CassBorrowedPtr, +) -> CassOwnedPtr { + let session = ArcFFI::cloned_from_ptr(cass_session).unwrap(); + let cass_statement = BoxFFI::as_ref(statement).unwrap(); let statement = cass_statement.statement.clone(); CassFuture::make_raw(async move { @@ -419,18 +419,18 @@ pub unsafe extern "C" fn cass_session_prepare_from_existing( #[no_mangle] pub unsafe extern "C" fn cass_session_prepare( - session: *mut CassSession, + session: CassBorrowedPtr, query: *const c_char, -) -> *const CassFuture { +) -> CassOwnedPtr { cass_session_prepare_n(session, query, strlen(query)) } #[no_mangle] pub unsafe extern "C" fn cass_session_prepare_n( - cass_session_raw: *mut CassSession, + cass_session_raw: CassBorrowedPtr, query: *const c_char, query_length: size_t, -) -> *const CassFuture { +) -> CassOwnedPtr { let query_str = ptr_to_cstr_n(query, query_length) // Apparently nullptr denotes an empty statement string. // It seems to be intended (for some weird reason, why not save a round-trip???) @@ -438,7 +438,7 @@ pub unsafe extern "C" fn cass_session_prepare_n( // There is a test for this: `NullStringApiArgsTest.Integration_Cassandra_PrepareNullQuery`. .unwrap_or_default(); let query = Query::new(query_str.to_string()); - let cass_session = ArcFFI::cloned_from_ptr(cass_session_raw); + let cass_session = ArcFFI::cloned_from_ptr(cass_session_raw).unwrap(); CassFuture::make_raw(async move { let session_guard = cass_session.read().await; @@ -465,13 +465,15 @@ pub unsafe extern "C" fn cass_session_prepare_n( } #[no_mangle] -pub unsafe extern "C" fn cass_session_free(session_raw: *mut CassSession) { +pub unsafe extern "C" fn cass_session_free(session_raw: CassOwnedPtr) { ArcFFI::free(session_raw); } #[no_mangle] -pub unsafe extern "C" fn cass_session_close(session: *mut CassSession) -> *const CassFuture { - let session_opt = ArcFFI::cloned_from_ptr(session); +pub unsafe extern "C" fn cass_session_close( + session: CassBorrowedPtr, +) -> CassOwnedPtr { + let session_opt = ArcFFI::cloned_from_ptr(session).unwrap(); CassFuture::make_raw(async move { let mut session_guard = session_opt.write().await; @@ -489,8 +491,10 @@ pub unsafe extern "C" fn cass_session_close(session: *mut CassSession) -> *const } #[no_mangle] -pub unsafe extern "C" fn cass_session_get_client_id(session: *const CassSession) -> CassUuid { - let cass_session = ArcFFI::as_ref(session); +pub unsafe extern "C" fn cass_session_get_client_id( + session: CassBorrowedPtr, +) -> CassUuid { + let cass_session = ArcFFI::as_ref(session).unwrap(); let client_id: uuid::Uuid = cass_session.blocking_read().as_ref().unwrap().client_id; client_id.into() @@ -498,9 +502,9 @@ pub unsafe extern "C" fn cass_session_get_client_id(session: *const CassSession) #[no_mangle] pub unsafe extern "C" fn cass_session_get_schema_meta( - session: *const CassSession, -) -> *const CassSchemaMeta { - let cass_session = ArcFFI::as_ref(session); + session: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let cass_session = ArcFFI::as_ref(session).unwrap(); let mut keyspaces: HashMap = HashMap::new(); for (keyspace_name, keyspace) in cass_session @@ -609,7 +613,9 @@ mod tests { future::{ cass_future_error_code, cass_future_error_message, cass_future_free, cass_future_wait, }, - retry_policy::{cass_retry_policy_default_new, cass_retry_policy_fallthrough_new}, + retry_policy::{ + cass_retry_policy_default_new, cass_retry_policy_fallthrough_new, CassRetryPolicy, + }, statement::{cass_statement_free, cass_statement_new, cass_statement_set_retry_policy}, testing::assert_cass_error_eq, types::cass_bool_t, @@ -630,15 +636,15 @@ mod tests { .try_init(); } - unsafe fn cass_future_wait_check_and_free(fut: *const CassFuture) { - cass_future_wait(fut); - if cass_future_error_code(fut) != CassError::CASS_OK { + unsafe fn cass_future_wait_check_and_free(fut: CassOwnedPtr) { + cass_future_wait(fut.borrow()); + if cass_future_error_code(fut.borrow()) != CassError::CASS_OK { let mut message: *const c_char = std::ptr::null(); let mut message_len: size_t = 0; - cass_future_error_message(fut as *mut CassFuture, &mut message, &mut message_len); + cass_future_error_message(fut.borrow(), &mut message, &mut message_len); eprintln!("{:?}", ptr_to_cstr_n(message, message_len)); } - assert_cass_error_eq!(cass_future_error_code(fut), CassError::CASS_OK); + assert_cass_error_eq!(cass_future_error_code(fut.borrow()), CassError::CASS_OK); cass_future_free(fut); } @@ -716,41 +722,54 @@ mod tests { proxy: RunningProxy, ) -> RunningProxy { unsafe { - let cluster_raw = cass_cluster_new(); + let mut cluster_raw = cass_cluster_new(); let ip = node_addr.ip().to_string(); let (c_ip, c_ip_len) = str_to_c_str_n(ip.as_str()); assert_cass_error_eq!( - cass_cluster_set_contact_points_n(cluster_raw, c_ip, c_ip_len), + cass_cluster_set_contact_points_n(cluster_raw.borrow_mut(), c_ip, c_ip_len), CassError::CASS_OK ); let session_raw = cass_session_new(); let profile_raw = cass_execution_profile_new(); { - cass_future_wait_check_and_free(cass_session_connect(session_raw, cluster_raw)); + cass_future_wait_check_and_free(cass_session_connect( + session_raw.borrow(), + cluster_raw.borrow(), + )); // Initially, the profile map is empty. - assert!(ArcFFI::as_ref(session_raw) + assert!(ArcFFI::as_ref(session_raw.borrow()) + .unwrap() .blocking_read() .as_ref() .unwrap() .exec_profile_map .is_empty()); - cass_cluster_set_execution_profile(cluster_raw, make_c_str!("prof"), profile_raw); + cass_cluster_set_execution_profile( + cluster_raw.borrow_mut(), + make_c_str!("prof"), + profile_raw.borrow(), + ); // Mutations in cluster do not affect the session that was connected before. - assert!(ArcFFI::as_ref(session_raw) + assert!(ArcFFI::as_ref(session_raw.borrow()) + .unwrap() .blocking_read() .as_ref() .unwrap() .exec_profile_map .is_empty()); - cass_future_wait_check_and_free(cass_session_close(session_raw)); + cass_future_wait_check_and_free(cass_session_close(session_raw.borrow())); // Mutations in cluster are now propagated to the session. - cass_future_wait_check_and_free(cass_session_connect(session_raw, cluster_raw)); - let profile_map_keys = ArcFFI::as_ref(session_raw) + cass_future_wait_check_and_free(cass_session_connect( + session_raw.borrow(), + cluster_raw.borrow(), + )); + let profile_map_keys = ArcFFI::as_ref(session_raw.borrow()) + .unwrap() .blocking_read() .as_ref() .unwrap() @@ -763,7 +782,7 @@ mod tests { std::iter::once(ExecProfileName::try_from("prof".to_owned()).unwrap()) .collect::>() ); - cass_future_wait_check_and_free(cass_session_close(session_raw)); + cass_future_wait_check_and_free(cass_session_close(session_raw.borrow())); } cass_execution_profile_free(profile_raw); cass_session_free(session_raw); @@ -800,12 +819,12 @@ mod tests { proxy: RunningProxy, ) -> RunningProxy { unsafe { - let cluster_raw = cass_cluster_new(); + let mut cluster_raw = cass_cluster_new(); let ip = node_addr.ip().to_string(); let (c_ip, c_ip_len) = str_to_c_str_n(ip.as_str()); assert_cass_error_eq!( - cass_cluster_set_contact_points_n(cluster_raw, c_ip, c_ip_len), + cass_cluster_set_contact_points_n(cluster_raw.borrow_mut(), c_ip, c_ip_len), CassError::CASS_OK ); @@ -821,36 +840,49 @@ mod tests { // Inserting into virtual system tables is prohibited and results in WriteFailure error. let invalid_query = make_c_str!("INSERT INTO system.runtime_info (group, item, value) VALUES ('bindings_test', 'bindings_test', 'bindings_test')"); - let statement_raw = cass_statement_new(invalid_query, 0); - let batch_raw = cass_batch_new(CassBatchType::CASS_BATCH_TYPE_LOGGED); + let mut statement_raw = cass_statement_new(invalid_query, 0); + let mut batch_raw = cass_batch_new(CassBatchType::CASS_BATCH_TYPE_LOGGED); assert_cass_error_eq!( - cass_batch_add_statement(batch_raw, statement_raw), + cass_batch_add_statement(batch_raw.borrow_mut(), statement_raw.borrow()), CassError::CASS_OK ); assert_cass_error_eq!( - cass_cluster_set_execution_profile(cluster_raw, valid_name_c_str, profile_raw,), + cass_cluster_set_execution_profile( + cluster_raw.borrow_mut(), + valid_name_c_str, + profile_raw.borrow(), + ), CassError::CASS_OK ); - cass_future_wait_check_and_free(cass_session_connect(session_raw, cluster_raw)); + cass_future_wait_check_and_free(cass_session_connect( + session_raw.borrow(), + cluster_raw.borrow(), + )); { /* Test valid configurations */ - let statement = BoxFFI::as_ref(statement_raw); - let batch = BoxFFI::as_ref(batch_raw); { + let statement = BoxFFI::as_ref(statement_raw.borrow()).unwrap(); + let batch = BoxFFI::as_ref(batch_raw.borrow()).unwrap(); assert!(statement.exec_profile.is_none()); assert!(batch.exec_profile.is_none()); // Set exec profile - it is not yet resolved. assert_cass_error_eq!( - cass_statement_set_execution_profile(statement_raw, valid_name_c_str,), + cass_statement_set_execution_profile( + statement_raw.borrow_mut(), + valid_name_c_str, + ), CassError::CASS_OK ); assert_cass_error_eq!( - cass_batch_set_execution_profile(batch_raw, valid_name_c_str,), + cass_batch_set_execution_profile(batch_raw.borrow_mut(), valid_name_c_str,), CassError::CASS_OK ); + + let statement = BoxFFI::as_ref(statement_raw.borrow()).unwrap(); + let batch = BoxFFI::as_ref(batch_raw.borrow()).unwrap(); assert_eq!( statement .exec_profile @@ -878,7 +910,10 @@ mod tests { // Make a query - this should resolve the profile. assert_cass_error_eq!( - cass_future_error_code(cass_session_execute(session_raw, statement_raw)), + cass_future_error_code( + cass_session_execute(session_raw.borrow(), statement_raw.borrow()) + .borrow() + ), CassError::CASS_ERROR_SERVER_WRITE_FAILURE ); assert!(statement @@ -891,7 +926,10 @@ mod tests { .as_handle() .is_some()); assert_cass_error_eq!( - cass_future_error_code(cass_session_execute_batch(session_raw, batch_raw,)), + cass_future_error_code( + cass_session_execute_batch(session_raw.borrow(), batch_raw.borrow(),) + .borrow() + ), CassError::CASS_ERROR_SERVER_WRITE_FAILURE ); assert!(batch @@ -906,20 +944,29 @@ mod tests { // NULL name sets exec profile to None assert_cass_error_eq!( - cass_statement_set_execution_profile(statement_raw, std::ptr::null::()), + cass_statement_set_execution_profile( + statement_raw.borrow_mut(), + std::ptr::null::() + ), CassError::CASS_OK ); assert_cass_error_eq!( - cass_batch_set_execution_profile(batch_raw, std::ptr::null::()), + cass_batch_set_execution_profile( + batch_raw.borrow_mut(), + std::ptr::null::() + ), CassError::CASS_OK ); + + let statement = BoxFFI::as_ref(statement_raw.borrow()).unwrap(); + let batch = BoxFFI::as_ref(batch_raw.borrow()).unwrap(); assert!(statement.exec_profile.is_none()); assert!(batch.exec_profile.is_none()); // valid name again, but of nonexisting profile! assert_cass_error_eq!( cass_statement_set_execution_profile_n( - statement_raw, + statement_raw.borrow_mut(), nonexisting_name_c_str, nonexisting_name_len, ), @@ -927,12 +974,15 @@ mod tests { ); assert_cass_error_eq!( cass_batch_set_execution_profile_n( - batch_raw, + batch_raw.borrow_mut(), nonexisting_name_c_str, nonexisting_name_len, ), CassError::CASS_OK ); + + let statement = BoxFFI::as_ref(statement_raw.borrow()).unwrap(); + let batch = BoxFFI::as_ref(batch_raw.borrow()).unwrap(); assert_eq!( statement .exec_profile @@ -960,7 +1010,10 @@ mod tests { // So when we now issue a query, it should end with error and leave exec_profile_handle uninitialised. assert_cass_error_eq!( - cass_future_error_code(cass_session_execute(session_raw, statement_raw)), + cass_future_error_code( + cass_session_execute(session_raw.borrow(), statement_raw.borrow()) + .borrow() + ), CassError::CASS_ERROR_LIB_EXECUTION_PROFILE_INVALID ); assert_eq!( @@ -976,7 +1029,10 @@ mod tests { &nonexisting_name.to_owned().try_into().unwrap() ); assert_cass_error_eq!( - cass_future_error_code(cass_session_execute_batch(session_raw, batch_raw)), + cass_future_error_code( + cass_session_execute_batch(session_raw.borrow(), batch_raw.borrow()) + .borrow() + ), CassError::CASS_ERROR_LIB_EXECUTION_PROFILE_INVALID ); assert_eq!( @@ -994,7 +1050,7 @@ mod tests { } } - cass_future_wait_check_and_free(cass_session_close(session_raw)); + cass_future_wait_check_and_free(cass_session_close(session_raw.borrow())); cass_execution_profile_free(profile_raw); cass_statement_free(statement_raw); cass_batch_free(batch_raw); @@ -1064,49 +1120,71 @@ mod tests { mut proxy: RunningProxy, ) -> RunningProxy { unsafe { - let cluster_raw = cass_cluster_new(); + let mut cluster_raw = cass_cluster_new(); let ip = node_addr.ip().to_string(); let (c_ip, c_ip_len) = str_to_c_str_n(ip.as_str()); assert_cass_error_eq!( - cass_cluster_set_contact_points_n(cluster_raw, c_ip, c_ip_len,), + cass_cluster_set_contact_points_n(cluster_raw.borrow_mut(), c_ip, c_ip_len,), CassError::CASS_OK ); let fallthrough_policy = cass_retry_policy_fallthrough_new(); let default_policy = cass_retry_policy_default_new(); - cass_cluster_set_retry_policy(cluster_raw, fallthrough_policy); + cass_cluster_set_retry_policy(cluster_raw.borrow_mut(), fallthrough_policy.borrow()); let session_raw = cass_session_new(); - let profile_raw = cass_execution_profile_new(); + let mut profile_raw = cass_execution_profile_new(); // A name of a profile that will have been registered in the Cluster. let profile_name_c_str = make_c_str!("profile"); assert_cass_error_eq!( - cass_execution_profile_set_retry_policy(profile_raw, default_policy), + cass_execution_profile_set_retry_policy( + profile_raw.borrow_mut(), + default_policy.borrow() + ), CassError::CASS_OK ); let query = make_c_str!("SELECT host_id FROM system.local"); - let statement_raw = cass_statement_new(query, 0); - let batch_raw = cass_batch_new(CassBatchType::CASS_BATCH_TYPE_LOGGED); + let mut statement_raw = cass_statement_new(query, 0); + let mut batch_raw = cass_batch_new(CassBatchType::CASS_BATCH_TYPE_LOGGED); assert_cass_error_eq!( - cass_batch_add_statement(batch_raw, statement_raw), + cass_batch_add_statement(batch_raw.borrow_mut(), statement_raw.borrow()), CassError::CASS_OK ); assert_cass_error_eq!( - cass_cluster_set_execution_profile(cluster_raw, profile_name_c_str, profile_raw,), + cass_cluster_set_execution_profile( + cluster_raw.borrow_mut(), + profile_name_c_str, + profile_raw.borrow(), + ), CassError::CASS_OK ); - cass_future_wait_check_and_free(cass_session_connect(session_raw, cluster_raw)); + cass_future_wait_check_and_free(cass_session_connect( + session_raw.borrow(), + cluster_raw.borrow(), + )); { - let execute_query = - || cass_future_error_code(cass_session_execute(session_raw, statement_raw)); - let execute_batch = - || cass_future_error_code(cass_session_execute_batch(session_raw, batch_raw)); + unsafe fn execute_query( + session_raw: CassBorrowedPtr, + statement_raw: CassBorrowedPtr, + ) -> CassError { + cass_future_error_code( + cass_session_execute(session_raw, statement_raw).borrow(), + ) + } + unsafe fn execute_batch( + session_raw: CassBorrowedPtr, + batch_raw: CassBorrowedPtr, + ) -> CassError { + cass_future_error_code( + cass_session_execute_batch(session_raw, batch_raw).borrow(), + ) + } fn reset_proxy_rules(proxy: &mut RunningProxy) { proxy.running_nodes[0].change_request_rules(Some( @@ -1116,33 +1194,47 @@ mod tests { )) } - let assert_query_with_fallthrough_policy = |proxy: &mut RunningProxy| { + unsafe fn assert_query_with_fallthrough_policy( + proxy: &mut RunningProxy, + session_raw: CassBorrowedPtr, + statement_raw: CassBorrowedPtr, + batch_raw: CassBorrowedPtr, + ) { reset_proxy_rules(&mut *proxy); assert_cass_error_eq!( - execute_query(), + execute_query(session_raw.borrow(), statement_raw), CassError::CASS_ERROR_SERVER_READ_TIMEOUT, ); reset_proxy_rules(&mut *proxy); assert_cass_error_eq!( - execute_batch(), + execute_batch(session_raw, batch_raw), CassError::CASS_ERROR_SERVER_READ_TIMEOUT, ); - }; + } - let assert_query_with_default_policy = |proxy: &mut RunningProxy| { + unsafe fn assert_query_with_default_policy( + proxy: &mut RunningProxy, + session_raw: CassBorrowedPtr, + statement_raw: CassBorrowedPtr, + batch_raw: CassBorrowedPtr, + ) { reset_proxy_rules(&mut *proxy); assert_cass_error_eq!( - execute_query(), + execute_query(session_raw.borrow(), statement_raw), CassError::CASS_ERROR_SERVER_READ_FAILURE ); reset_proxy_rules(&mut *proxy); assert_cass_error_eq!( - execute_batch(), + execute_batch(session_raw, batch_raw), CassError::CASS_ERROR_SERVER_READ_FAILURE ); - }; + } - let set_provided_exec_profile = |name| { + unsafe fn set_provided_exec_profile( + name: *const i8, + statement_raw: CassBorrowedMutPtr, + batch_raw: CassBorrowedMutPtr, + ) { // Set statement/batch exec profile. assert_cass_error_eq!( cass_statement_set_execution_profile(statement_raw, name,), @@ -1152,26 +1244,40 @@ mod tests { cass_batch_set_execution_profile(batch_raw, name,), CassError::CASS_OK ); - }; - let set_exec_profile = || { - set_provided_exec_profile(profile_name_c_str); - }; - let unset_exec_profile = || { - set_provided_exec_profile(std::ptr::null::()); - }; - let set_retry_policy_on_stmt = |policy| { + } + unsafe fn set_exec_profile( + profile_name_c_str: *const c_char, + statement_raw: CassBorrowedMutPtr, + batch_raw: CassBorrowedMutPtr, + ) { + set_provided_exec_profile(profile_name_c_str, statement_raw, batch_raw); + } + unsafe fn unset_exec_profile( + statement_raw: CassBorrowedMutPtr, + batch_raw: CassBorrowedMutPtr, + ) { + set_provided_exec_profile(std::ptr::null::(), statement_raw, batch_raw); + } + unsafe fn set_retry_policy_on_stmt( + policy: CassBorrowedPtr, + statement_raw: CassBorrowedMutPtr, + batch_raw: CassBorrowedMutPtr, + ) { assert_cass_error_eq!( - cass_statement_set_retry_policy(statement_raw, policy,), + cass_statement_set_retry_policy(statement_raw, policy.borrow(),), CassError::CASS_OK ); assert_cass_error_eq!( cass_batch_set_retry_policy(batch_raw, policy,), CassError::CASS_OK ); - }; - let unset_retry_policy_on_stmt = || { - set_retry_policy_on_stmt(std::ptr::null()); - }; + } + unsafe fn unset_retry_policy_on_stmt( + statement_raw: CassBorrowedMutPtr, + batch_raw: CassBorrowedMutPtr, + ) { + set_retry_policy_on_stmt(ArcFFI::null(), statement_raw, batch_raw); + } // ### START TESTING @@ -1179,62 +1285,164 @@ mod tests { // the default cluster-wide retry policy should be used: in this case, fallthrough. // F - - - assert_query_with_fallthrough_policy(&mut proxy); + assert_query_with_fallthrough_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F D - - set_exec_profile(); - assert_query_with_default_policy(&mut proxy); + set_exec_profile( + profile_name_c_str, + statement_raw.borrow_mut(), + batch_raw.borrow_mut(), + ); + assert_query_with_default_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F - - - unset_exec_profile(); - assert_query_with_fallthrough_policy(&mut proxy); + unset_exec_profile(statement_raw.borrow_mut(), batch_raw.borrow_mut()); + assert_query_with_fallthrough_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F - F - set_retry_policy_on_stmt(fallthrough_policy); - assert_query_with_fallthrough_policy(&mut proxy); + set_retry_policy_on_stmt( + fallthrough_policy.borrow(), + statement_raw.borrow_mut(), + batch_raw.borrow_mut(), + ); + assert_query_with_fallthrough_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F D F - set_exec_profile(); - assert_query_with_fallthrough_policy(&mut proxy); + set_exec_profile( + profile_name_c_str, + statement_raw.borrow_mut(), + batch_raw.borrow_mut(), + ); + assert_query_with_fallthrough_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F D - - unset_retry_policy_on_stmt(); - assert_query_with_default_policy(&mut proxy); + unset_retry_policy_on_stmt(statement_raw.borrow_mut(), batch_raw.borrow_mut()); + assert_query_with_default_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F D F - set_retry_policy_on_stmt(fallthrough_policy); - assert_query_with_fallthrough_policy(&mut proxy); + set_retry_policy_on_stmt( + fallthrough_policy.borrow(), + statement_raw.borrow_mut(), + batch_raw.borrow_mut(), + ); + assert_query_with_fallthrough_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F D D - set_retry_policy_on_stmt(default_policy); - assert_query_with_default_policy(&mut proxy); + set_retry_policy_on_stmt( + default_policy.borrow(), + statement_raw.borrow_mut(), + batch_raw.borrow_mut(), + ); + assert_query_with_default_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F D F - set_retry_policy_on_stmt(fallthrough_policy); - assert_query_with_fallthrough_policy(&mut proxy); + set_retry_policy_on_stmt( + fallthrough_policy.borrow(), + statement_raw.borrow_mut(), + batch_raw.borrow_mut(), + ); + assert_query_with_fallthrough_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F - F - unset_exec_profile(); - assert_query_with_fallthrough_policy(&mut proxy); + unset_exec_profile(statement_raw.borrow_mut(), batch_raw.borrow_mut()); + assert_query_with_fallthrough_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F - - - unset_retry_policy_on_stmt(); - assert_query_with_fallthrough_policy(&mut proxy); + unset_retry_policy_on_stmt(statement_raw.borrow_mut(), batch_raw.borrow_mut()); + assert_query_with_fallthrough_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F - D - set_retry_policy_on_stmt(default_policy); - assert_query_with_default_policy(&mut proxy); + set_retry_policy_on_stmt( + default_policy.borrow(), + statement_raw.borrow_mut(), + batch_raw.borrow_mut(), + ); + assert_query_with_default_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F D D - set_exec_profile(); - assert_query_with_default_policy(&mut proxy); + set_exec_profile( + profile_name_c_str, + statement_raw.borrow_mut(), + batch_raw.borrow_mut(), + ); + assert_query_with_default_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); // F D - - unset_retry_policy_on_stmt(); - assert_query_with_default_policy(&mut proxy); + unset_retry_policy_on_stmt(statement_raw.borrow_mut(), batch_raw.borrow_mut()); + assert_query_with_default_policy( + &mut proxy, + session_raw.borrow(), + statement_raw.borrow(), + batch_raw.borrow(), + ); } - cass_future_wait_check_and_free(cass_session_close(session_raw)); + cass_future_wait_check_and_free(cass_session_close(session_raw.borrow())); cass_execution_profile_free(profile_raw); cass_statement_free(statement_raw); cass_batch_free(batch_raw); @@ -1248,28 +1456,35 @@ mod tests { #[ntest::timeout(5000)] fn session_with_latency_aware_load_balancing_does_not_panic() { unsafe { - let cluster_raw = cass_cluster_new(); + let mut cluster_raw = cass_cluster_new(); // An IP with very little chance of having a Scylla node listening let ip = "127.0.1.231"; let (c_ip, c_ip_len) = str_to_c_str_n(ip); assert_cass_error_eq!( - cass_cluster_set_contact_points_n(cluster_raw, c_ip, c_ip_len), + cass_cluster_set_contact_points_n(cluster_raw.borrow_mut(), c_ip, c_ip_len), CassError::CASS_OK ); - cass_cluster_set_latency_aware_routing(cluster_raw, true as cass_bool_t); + cass_cluster_set_latency_aware_routing(cluster_raw.borrow_mut(), true as cass_bool_t); let session_raw = cass_session_new(); - let profile_raw = cass_execution_profile_new(); + let mut profile_raw = cass_execution_profile_new(); assert_cass_error_eq!( - cass_execution_profile_set_latency_aware_routing(profile_raw, true as cass_bool_t), + cass_execution_profile_set_latency_aware_routing( + profile_raw.borrow_mut(), + true as cass_bool_t + ), CassError::CASS_OK ); let profile_name = make_c_str!("latency_aware"); - cass_cluster_set_execution_profile(cluster_raw, profile_name, profile_raw); + cass_cluster_set_execution_profile( + cluster_raw.borrow_mut(), + profile_name, + profile_raw.borrow(), + ); { - let cass_future = cass_session_connect(session_raw, cluster_raw); - cass_future_wait(cass_future); + let cass_future = cass_session_connect(session_raw.borrow(), cluster_raw.borrow()); + cass_future_wait(cass_future.borrow()); // The exact outcome is not important, we only test that we don't panic. } cass_execution_profile_free(profile_raw); @@ -1288,27 +1503,27 @@ mod tests { let profile_name = make_c_str!("latency_aware"); unsafe { - let cluster_raw = cass_cluster_new(); + let mut cluster_raw = cass_cluster_new(); assert_cass_error_eq!( - cass_cluster_set_contact_points_n(cluster_raw, c_ip, c_ip_len), + cass_cluster_set_contact_points_n(cluster_raw.borrow_mut(), c_ip, c_ip_len), CassError::CASS_OK ); - cass_cluster_set_latency_aware_routing(cluster_raw, true as cass_bool_t); + cass_cluster_set_latency_aware_routing(cluster_raw.borrow_mut(), true as cass_bool_t); let session_raw = cass_session_new(); - let profile_raw = cass_execution_profile_new(); + let mut profile_raw = cass_execution_profile_new(); assert_cass_error_eq!( - cass_execution_profile_set_latency_aware_routing(profile_raw, true as cass_bool_t), + cass_execution_profile_set_latency_aware_routing(profile_raw.borrow_mut(), true as cass_bool_t), CassError::CASS_OK ); - cass_cluster_set_execution_profile(cluster_raw, profile_name, profile_raw); + cass_cluster_set_execution_profile(cluster_raw.borrow_mut(), profile_name, profile_raw.borrow()); { - let cass_future = cass_session_connect(session_raw, cluster_raw); + let cass_future = cass_session_connect(session_raw.borrow(), cluster_raw.borrow()); // This checks that we don't use-after-free the cluster inside the future. cass_cluster_free(cluster_raw); - cass_future_wait(cass_future); + cass_future_wait(cass_future.borrow()); // The exact outcome is not important, we only test that we don't segfault. } cass_execution_profile_free(profile_raw); diff --git a/scylla-rust-wrapper/src/ssl.rs b/scylla-rust-wrapper/src/ssl.rs index ba14a24b..1da668ae 100644 --- a/scylla-rust-wrapper/src/ssl.rs +++ b/scylla-rust-wrapper/src/ssl.rs @@ -1,4 +1,6 @@ use crate::argconv::ArcFFI; +use crate::argconv::CassBorrowedPtr; +use crate::argconv::CassOwnedPtr; use crate::cass_error::CassError; use crate::types::size_t; use libc::{c_int, strlen}; @@ -27,13 +29,13 @@ pub const CASS_SSL_VERIFY_PEER_IDENTITY: i32 = 0x02; pub const CASS_SSL_VERIFY_PEER_IDENTITY_DNS: i32 = 0x04; #[no_mangle] -pub unsafe extern "C" fn cass_ssl_new() -> *const CassSsl { +pub unsafe extern "C" fn cass_ssl_new() -> CassOwnedPtr { openssl_sys::init(); cass_ssl_new_no_lib_init() } #[no_mangle] -pub unsafe extern "C" fn cass_ssl_new_no_lib_init() -> *const CassSsl { +pub unsafe extern "C" fn cass_ssl_new_no_lib_init() -> CassOwnedPtr { let ssl_context: *mut SSL_CTX = SSL_CTX_new(TLS_method()); let trusted_store: *mut X509_STORE = X509_STORE_new(); @@ -64,7 +66,7 @@ impl Drop for CassSsl { } #[no_mangle] -pub unsafe extern "C" fn cass_ssl_free(ssl: *mut CassSsl) { +pub unsafe extern "C" fn cass_ssl_free(ssl: CassOwnedPtr) { ArcFFI::free(ssl); } @@ -96,7 +98,7 @@ unsafe extern "C" fn pem_password_callback( #[no_mangle] pub unsafe extern "C" fn cass_ssl_add_trusted_cert( - ssl: *mut CassSsl, + ssl: CassBorrowedPtr, cert: *const c_char, ) -> CassError { if cert.is_null() { @@ -108,11 +110,11 @@ pub unsafe extern "C" fn cass_ssl_add_trusted_cert( #[no_mangle] pub unsafe extern "C" fn cass_ssl_add_trusted_cert_n( - ssl: *mut CassSsl, + ssl: CassBorrowedPtr, cert: *const c_char, cert_length: size_t, ) -> CassError { - let ssl = ArcFFI::cloned_from_ptr(ssl); + let ssl = ArcFFI::cloned_from_ptr(ssl).unwrap(); let bio = BIO_new_mem_buf(cert as *const c_void, cert_length.try_into().unwrap()); if bio.is_null() { @@ -139,8 +141,8 @@ pub unsafe extern "C" fn cass_ssl_add_trusted_cert_n( } #[no_mangle] -pub unsafe extern "C" fn cass_ssl_set_verify_flags(ssl: *mut CassSsl, flags: i32) { - let ssl = ArcFFI::cloned_from_ptr(ssl); +pub unsafe extern "C" fn cass_ssl_set_verify_flags(ssl: CassBorrowedPtr, flags: i32) { + let ssl = ArcFFI::cloned_from_ptr(ssl).unwrap(); match flags { CASS_SSL_VERIFY_NONE => { @@ -164,7 +166,10 @@ pub unsafe extern "C" fn cass_ssl_set_verify_flags(ssl: *mut CassSsl, flags: i32 } #[no_mangle] -pub unsafe extern "C" fn cass_ssl_set_cert(ssl: *mut CassSsl, cert: *const c_char) -> CassError { +pub unsafe extern "C" fn cass_ssl_set_cert( + ssl: CassBorrowedPtr, + cert: *const c_char, +) -> CassError { if cert.is_null() { return CassError::CASS_ERROR_SSL_INVALID_CERT; } @@ -174,11 +179,11 @@ pub unsafe extern "C" fn cass_ssl_set_cert(ssl: *mut CassSsl, cert: *const c_cha #[no_mangle] pub unsafe extern "C" fn cass_ssl_set_cert_n( - ssl: *mut CassSsl, + ssl: CassBorrowedPtr, cert: *const c_char, cert_length: size_t, ) -> CassError { - let ssl = ArcFFI::cloned_from_ptr(ssl); + let ssl = ArcFFI::cloned_from_ptr(ssl).unwrap(); let bio = BIO_new_mem_buf(cert as *const c_void, cert_length.try_into().unwrap()); if bio.is_null() { @@ -246,7 +251,7 @@ unsafe extern "C" fn SSL_CTX_use_certificate_chain_bio( #[no_mangle] pub unsafe extern "C" fn cass_ssl_set_private_key( - ssl: *mut CassSsl, + ssl: CassBorrowedPtr, key: *const c_char, password: *mut c_char, ) -> CassError { @@ -265,13 +270,13 @@ pub unsafe extern "C" fn cass_ssl_set_private_key( #[no_mangle] pub unsafe extern "C" fn cass_ssl_set_private_key_n( - ssl: *mut CassSsl, + ssl: CassBorrowedPtr, key: *const c_char, key_length: size_t, password: *mut c_char, _password_length: size_t, ) -> CassError { - let ssl = ArcFFI::cloned_from_ptr(ssl); + let ssl = ArcFFI::cloned_from_ptr(ssl).unwrap(); let bio = BIO_new_mem_buf(key as *const c_void, key_length.try_into().unwrap()); if bio.is_null() { diff --git a/scylla-rust-wrapper/src/statement.rs b/scylla-rust-wrapper/src/statement.rs index dd476391..775414fc 100644 --- a/scylla-rust-wrapper/src/statement.rs +++ b/scylla-rust-wrapper/src/statement.rs @@ -262,7 +262,7 @@ impl CassStatement { pub unsafe extern "C" fn cass_statement_new( query: *const c_char, parameter_count: size_t, -) -> *mut CassStatement { +) -> CassOwnedMutPtr { cass_statement_new_n(query, strlen(query), parameter_count) } @@ -271,10 +271,10 @@ pub unsafe extern "C" fn cass_statement_new_n( query: *const c_char, query_length: size_t, parameter_count: size_t, -) -> *mut CassStatement { +) -> CassOwnedMutPtr { let query_str = match ptr_to_cstr_n(query, query_length) { Some(v) => v, - None => return std::ptr::null_mut(), + None => return BoxFFI::null_mut(), }; let query = Query::new(query_str.to_string()); @@ -296,19 +296,19 @@ pub unsafe extern "C" fn cass_statement_new_n( } #[no_mangle] -pub unsafe extern "C" fn cass_statement_free(statement_raw: *mut CassStatement) { +pub unsafe extern "C" fn cass_statement_free(statement_raw: CassOwnedMutPtr) { BoxFFI::free(statement_raw); } #[no_mangle] pub unsafe extern "C" fn cass_statement_set_consistency( - statement: *mut CassStatement, + statement: CassBorrowedMutPtr, consistency: CassConsistency, ) -> CassError { let consistency_opt = get_consistency_from_cass_consistency(consistency); if let Some(consistency) = consistency_opt { - match &mut BoxFFI::as_mut_ref(statement).statement { + match &mut BoxFFI::as_mut_ref(statement).unwrap().statement { BoundStatement::Simple(inner) => inner.query.set_consistency(consistency), BoundStatement::Prepared(inner) => Arc::make_mut(&mut inner.statement) .statement @@ -321,10 +321,10 @@ pub unsafe extern "C" fn cass_statement_set_consistency( #[no_mangle] pub unsafe extern "C" fn cass_statement_set_paging_size( - statement_raw: *mut CassStatement, + statement_raw: CassBorrowedMutPtr, page_size: c_int, ) -> CassError { - let statement = BoxFFI::as_mut_ref(statement_raw); + let statement = BoxFFI::as_mut_ref(statement_raw).unwrap(); if page_size <= 0 { // Cpp driver sets the page size flag only for positive page size provided by user. statement.paging_enabled = false; @@ -343,11 +343,11 @@ pub unsafe extern "C" fn cass_statement_set_paging_size( #[no_mangle] pub unsafe extern "C" fn cass_statement_set_paging_state( - statement: *mut CassStatement, - result: *const CassResult, + statement: CassBorrowedMutPtr, + result: CassBorrowedPtr, ) -> CassError { - let statement = BoxFFI::as_mut_ref(statement); - let result = ArcFFI::as_ref(result); + let statement = BoxFFI::as_mut_ref(statement).unwrap(); + let result = ArcFFI::as_ref(result).unwrap(); match &result.paging_state_response { PagingStateResponse::HasMorePages { state } => statement.paging_state.clone_from(state), @@ -358,11 +358,11 @@ pub unsafe extern "C" fn cass_statement_set_paging_state( #[no_mangle] pub unsafe extern "C" fn cass_statement_set_paging_state_token( - statement: *mut CassStatement, + statement: CassBorrowedMutPtr, paging_state: *const c_char, paging_state_size: size_t, ) -> CassError { - let statement_from_raw = BoxFFI::as_mut_ref(statement); + let statement_from_raw = BoxFFI::as_mut_ref(statement).unwrap(); if paging_state.is_null() { statement_from_raw.paging_state = PagingState::start(); @@ -377,10 +377,10 @@ pub unsafe extern "C" fn cass_statement_set_paging_state_token( #[no_mangle] pub unsafe extern "C" fn cass_statement_set_is_idempotent( - statement_raw: *mut CassStatement, + statement_raw: CassBorrowedMutPtr, is_idempotent: cass_bool_t, ) -> CassError { - match &mut BoxFFI::as_mut_ref(statement_raw).statement { + match &mut BoxFFI::as_mut_ref(statement_raw).unwrap().statement { BoundStatement::Simple(inner) => inner.query.set_is_idempotent(is_idempotent != 0), BoundStatement::Prepared(inner) => Arc::make_mut(&mut inner.statement) .statement @@ -392,10 +392,10 @@ pub unsafe extern "C" fn cass_statement_set_is_idempotent( #[no_mangle] pub unsafe extern "C" fn cass_statement_set_tracing( - statement_raw: *mut CassStatement, + statement_raw: CassBorrowedMutPtr, enabled: cass_bool_t, ) -> CassError { - match &mut BoxFFI::as_mut_ref(statement_raw).statement { + match &mut BoxFFI::as_mut_ref(statement_raw).unwrap().statement { BoundStatement::Simple(inner) => inner.query.set_tracing(enabled != 0), BoundStatement::Prepared(inner) => Arc::make_mut(&mut inner.statement) .statement @@ -407,11 +407,11 @@ pub unsafe extern "C" fn cass_statement_set_tracing( #[no_mangle] pub unsafe extern "C" fn cass_statement_set_retry_policy( - statement: *mut CassStatement, - retry_policy: *const CassRetryPolicy, + statement: CassBorrowedMutPtr, + retry_policy: CassBorrowedPtr, ) -> CassError { let maybe_arced_retry_policy: Option> = - ArcFFI::as_maybe_ref(retry_policy).map(|policy| match policy { + ArcFFI::as_ref(retry_policy).map(|policy| match policy { CassRetryPolicy::DefaultRetryPolicy(default) => { default.clone() as Arc } @@ -419,7 +419,7 @@ pub unsafe extern "C" fn cass_statement_set_retry_policy( CassRetryPolicy::DowngradingConsistencyRetryPolicy(downgrading) => downgrading.clone(), }); - match &mut BoxFFI::as_mut_ref(statement).statement { + match &mut BoxFFI::as_mut_ref(statement).unwrap().statement { BoundStatement::Simple(inner) => inner.query.set_retry_policy(maybe_arced_retry_policy), BoundStatement::Prepared(inner) => Arc::make_mut(&mut inner.statement) .statement @@ -431,7 +431,7 @@ pub unsafe extern "C" fn cass_statement_set_retry_policy( #[no_mangle] pub unsafe extern "C" fn cass_statement_set_serial_consistency( - statement: *mut CassStatement, + statement: CassBorrowedMutPtr, serial_consistency: CassConsistency, ) -> CassError { // cpp-driver doesn't validate passed value in any way. @@ -448,7 +448,7 @@ pub unsafe extern "C" fn cass_statement_set_serial_consistency( _ => return CassError::CASS_ERROR_LIB_BAD_PARAMS, }; - match &mut BoxFFI::as_mut_ref(statement).statement { + match &mut BoxFFI::as_mut_ref(statement).unwrap().statement { BoundStatement::Simple(inner) => inner.query.set_serial_consistency(Some(consistency)), BoundStatement::Prepared(inner) => Arc::make_mut(&mut inner.statement) .statement @@ -477,10 +477,10 @@ fn get_consistency_from_cass_consistency(consistency: CassConsistency) -> Option #[no_mangle] pub unsafe extern "C" fn cass_statement_set_timestamp( - statement: *mut CassStatement, + statement: CassBorrowedMutPtr, timestamp: cass_int64_t, ) -> CassError { - match &mut BoxFFI::as_mut_ref(statement).statement { + match &mut BoxFFI::as_mut_ref(statement).unwrap().statement { BoundStatement::Simple(inner) => inner.query.set_timestamp(Some(timestamp)), BoundStatement::Prepared(inner) => Arc::make_mut(&mut inner.statement) .statement @@ -492,7 +492,7 @@ pub unsafe extern "C" fn cass_statement_set_timestamp( #[no_mangle] pub unsafe extern "C" fn cass_statement_set_request_timeout( - statement: *mut CassStatement, + statement: CassBorrowedMutPtr, timeout_ms: cass_uint64_t, ) -> CassError { // The maximum duration for a sleep is 68719476734 milliseconds (approximately 2.2 years). @@ -503,7 +503,7 @@ pub unsafe extern "C" fn cass_statement_set_request_timeout( return CassError::CASS_ERROR_LIB_BAD_PARAMS; } - let statement_from_raw = BoxFFI::as_mut_ref(statement); + let statement_from_raw = BoxFFI::as_mut_ref(statement).unwrap(); statement_from_raw.request_timeout_ms = Some(timeout_ms); CassError::CASS_OK @@ -511,10 +511,10 @@ pub unsafe extern "C" fn cass_statement_set_request_timeout( #[no_mangle] pub unsafe extern "C" fn cass_statement_reset_parameters( - statement_raw: *mut CassStatement, + statement_raw: CassBorrowedMutPtr, count: size_t, ) -> CassError { - let statement = BoxFFI::as_mut_ref(statement_raw); + let statement = BoxFFI::as_mut_ref(statement_raw).unwrap(); statement.reset_bound_values(count as usize); CassError::CASS_OK diff --git a/scylla-rust-wrapper/src/testing.rs b/scylla-rust-wrapper/src/testing.rs index 344d228c..596ce744 100644 --- a/scylla-rust-wrapper/src/testing.rs +++ b/scylla-rust-wrapper/src/testing.rs @@ -21,7 +21,7 @@ macro_rules! assert_cass_future_error_message_eq { let mut ___message: *const c_char = ::std::ptr::null(); let mut ___msg_len: size_t = 0; - cass_future_error_message($cass_fut, &mut ___message, &mut ___msg_len); + cass_future_error_message($cass_fut.borrow(), &mut ___message, &mut ___msg_len); assert_eq!(ptr_to_cstr_n(___message, ___msg_len), $error_msg_opt); }; } diff --git a/scylla-rust-wrapper/src/tuple.rs b/scylla-rust-wrapper/src/tuple.rs index 288d5c67..83d9c394 100644 --- a/scylla-rust-wrapper/src/tuple.rs +++ b/scylla-rust-wrapper/src/tuple.rs @@ -63,7 +63,7 @@ impl From<&CassTuple> for CassCqlValue { } #[no_mangle] -pub unsafe extern "C" fn cass_tuple_new(item_count: size_t) -> *mut CassTuple { +pub unsafe extern "C" fn cass_tuple_new(item_count: size_t) -> CassOwnedMutPtr { BoxFFI::into_ptr(Box::new(CassTuple { data_type: None, items: vec![None; item_count as usize], @@ -72,12 +72,12 @@ pub unsafe extern "C" fn cass_tuple_new(item_count: size_t) -> *mut CassTuple { #[no_mangle] unsafe extern "C" fn cass_tuple_new_from_data_type( - data_type: *const CassDataType, -) -> *mut CassTuple { - let data_type = ArcFFI::cloned_from_ptr(data_type); + data_type: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let data_type = ArcFFI::cloned_from_ptr(data_type).unwrap(); let item_count = match data_type.get_unchecked() { CassDataTypeInner::Tuple(v) => v.len(), - _ => return std::ptr::null_mut(), + _ => return BoxFFI::null_mut(), }; BoxFFI::into_ptr(Box::new(CassTuple { data_type: Some(data_type), @@ -86,13 +86,15 @@ unsafe extern "C" fn cass_tuple_new_from_data_type( } #[no_mangle] -unsafe extern "C" fn cass_tuple_free(tuple: *mut CassTuple) { +unsafe extern "C" fn cass_tuple_free(tuple: CassOwnedMutPtr) { BoxFFI::free(tuple); } #[no_mangle] -unsafe extern "C" fn cass_tuple_data_type(tuple: *const CassTuple) -> *const CassDataType { - match &BoxFFI::as_ref(tuple).data_type { +unsafe extern "C" fn cass_tuple_data_type( + tuple: CassBorrowedPtr, +) -> CassBorrowedPtr { + match &BoxFFI::as_ref(tuple).unwrap().data_type { Some(t) => ArcFFI::as_ptr(t), None => ArcFFI::as_ptr(&UNTYPED_TUPLE_TYPE), } @@ -136,16 +138,14 @@ mod tests { let empty_tuple = cass_tuple_new(2); // This would previously return a non Arc-based pointer. - let empty_tuple_dt = cass_tuple_data_type(empty_tuple); + let empty_tuple_dt = cass_tuple_data_type(empty_tuple.borrow()); let empty_set_dt = cass_data_type_new(CassValueType::CASS_VALUE_TYPE_SET); // This will try to increment the reference count of `empty_tuple_dt`. // Previously, this would fail, because `empty_tuple_dt` did not originate from an Arc allocation. - cass_data_type_add_sub_type(empty_set_dt, empty_tuple_dt); + cass_data_type_add_sub_type(empty_set_dt.borrow(), empty_tuple_dt); - // Cast to *mut, because `cass_data_type_new` returns a *const. See the comment - // in this function to see why. - cass_data_type_free(empty_set_dt as *mut _) + cass_data_type_free(empty_set_dt) } } } diff --git a/scylla-rust-wrapper/src/user_type.rs b/scylla-rust-wrapper/src/user_type.rs index 9335bfac..5761d4b5 100644 --- a/scylla-rust-wrapper/src/user_type.rs +++ b/scylla-rust-wrapper/src/user_type.rs @@ -83,9 +83,9 @@ impl From<&CassUserType> for CassCqlValue { #[no_mangle] pub unsafe extern "C" fn cass_user_type_new_from_data_type( - data_type_raw: *const CassDataType, -) -> *mut CassUserType { - let data_type = ArcFFI::cloned_from_ptr(data_type_raw); + data_type_raw: CassBorrowedPtr, +) -> CassOwnedMutPtr { + let data_type = ArcFFI::cloned_from_ptr(data_type_raw).unwrap(); match data_type.get_unchecked() { CassDataTypeInner::UDT(udt_data_type) => { @@ -95,19 +95,19 @@ pub unsafe extern "C" fn cass_user_type_new_from_data_type( field_values, })) } - _ => std::ptr::null_mut(), + _ => BoxFFI::null_mut(), } } #[no_mangle] -pub unsafe extern "C" fn cass_user_type_free(user_type: *mut CassUserType) { +pub unsafe extern "C" fn cass_user_type_free(user_type: CassOwnedMutPtr) { BoxFFI::free(user_type); } #[no_mangle] pub unsafe extern "C" fn cass_user_type_data_type( - user_type: *const CassUserType, -) -> *const CassDataType { - ArcFFI::as_ptr(&BoxFFI::as_ref(user_type).data_type) + user_type: CassBorrowedPtr, +) -> CassBorrowedPtr { + ArcFFI::as_ptr(&BoxFFI::as_ref(user_type).unwrap().data_type) } prepare_binders_macro!(@index_and_name CassUserType, diff --git a/scylla-rust-wrapper/src/uuid.rs b/scylla-rust-wrapper/src/uuid.rs index b2343803..8aaa6dab 100644 --- a/scylla-rust-wrapper/src/uuid.rs +++ b/scylla-rust-wrapper/src/uuid.rs @@ -98,7 +98,7 @@ pub unsafe extern "C" fn cass_uuid_max_from_time(timestamp: cass_uint64_t, outpu } #[no_mangle] -pub unsafe extern "C" fn cass_uuid_gen_new() -> *mut CassUuidGen { +pub unsafe extern "C" fn cass_uuid_gen_new() -> CassOwnedMutPtr { // Inspired by C++ driver implementation in its intent. // The original driver tries to generate a number that // uniquely identifies this machine and the current process. @@ -122,7 +122,9 @@ pub unsafe extern "C" fn cass_uuid_gen_new() -> *mut CassUuidGen { } #[no_mangle] -pub unsafe extern "C" fn cass_uuid_gen_new_with_node(node: cass_uint64_t) -> *mut CassUuidGen { +pub unsafe extern "C" fn cass_uuid_gen_new_with_node( + node: cass_uint64_t, +) -> CassOwnedMutPtr { BoxFFI::into_ptr(Box::new(CassUuidGen { clock_seq_and_node: rand_clock_seq_and_node(node & 0x0000FFFFFFFFFFFF), last_timestamp: AtomicU64::new(0), @@ -130,8 +132,11 @@ pub unsafe extern "C" fn cass_uuid_gen_new_with_node(node: cass_uint64_t) -> *mu } #[no_mangle] -pub unsafe extern "C" fn cass_uuid_gen_time(uuid_gen: *mut CassUuidGen, output: *mut CassUuid) { - let uuid_gen = BoxFFI::as_mut_ref(uuid_gen); +pub unsafe extern "C" fn cass_uuid_gen_time( + uuid_gen: CassBorrowedMutPtr, + output: *mut CassUuid, +) { + let uuid_gen = BoxFFI::as_mut_ref(uuid_gen).unwrap(); let uuid = CassUuid { time_and_version: set_version(monotonic_timestamp(&mut uuid_gen.last_timestamp), 1), @@ -157,11 +162,11 @@ pub unsafe extern "C" fn cass_uuid_gen_random(_uuid_gen: *mut CassUuidGen, outpu #[no_mangle] pub unsafe extern "C" fn cass_uuid_gen_from_time( - uuid_gen: *mut CassUuidGen, + uuid_gen: CassBorrowedMutPtr, timestamp: cass_uint64_t, output: *mut CassUuid, ) { - let uuid_gen = BoxFFI::as_mut_ref(uuid_gen); + let uuid_gen = BoxFFI::as_mut_ref(uuid_gen).unwrap(); let uuid = CassUuid { time_and_version: set_version(from_unix_timestamp(timestamp), 1), @@ -250,6 +255,6 @@ pub unsafe extern "C" fn cass_uuid_from_string_n( } #[no_mangle] -pub unsafe extern "C" fn cass_uuid_gen_free(uuid_gen: *mut CassUuidGen) { +pub unsafe extern "C" fn cass_uuid_gen_free(uuid_gen: CassOwnedMutPtr) { BoxFFI::free(uuid_gen); } From 69d46b300bd1f5125102f743e185932d5ed69407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Fri, 29 Nov 2024 13:43:23 +0100 Subject: [PATCH 12/12] argconv: make FFI implementation mutually exclusive Disallow implementing two different APIs for specific type. --- scylla-rust-wrapper/src/argconv.rs | 110 +++++++++++++++++++++--- scylla-rust-wrapper/src/batch.rs | 8 +- scylla-rust-wrapper/src/cass_types.rs | 4 +- scylla-rust-wrapper/src/cluster.rs | 4 +- scylla-rust-wrapper/src/collection.rs | 4 +- scylla-rust-wrapper/src/exec_profile.rs | 5 +- scylla-rust-wrapper/src/future.rs | 4 +- scylla-rust-wrapper/src/logging.rs | 6 +- scylla-rust-wrapper/src/metadata.rs | 20 +++-- scylla-rust-wrapper/src/prepared.rs | 4 +- scylla-rust-wrapper/src/query_error.rs | 4 +- scylla-rust-wrapper/src/query_result.rs | 16 +++- scylla-rust-wrapper/src/retry_policy.rs | 9 +- scylla-rust-wrapper/src/session.rs | 4 +- scylla-rust-wrapper/src/ssl.rs | 6 +- scylla-rust-wrapper/src/statement.rs | 4 +- scylla-rust-wrapper/src/tuple.rs | 4 +- scylla-rust-wrapper/src/user_type.rs | 4 +- scylla-rust-wrapper/src/uuid.rs | 4 +- 19 files changed, 181 insertions(+), 43 deletions(-) diff --git a/scylla-rust-wrapper/src/argconv.rs b/scylla-rust-wrapper/src/argconv.rs index 311f616b..bdfe48fd 100644 --- a/scylla-rust-wrapper/src/argconv.rs +++ b/scylla-rust-wrapper/src/argconv.rs @@ -276,12 +276,18 @@ impl CassPtr<'_, T, (Mut,)> { } } +mod origin_sealed { + pub trait FromBoxSealed {} + pub trait FromArcSealed {} + pub trait FromRefSealed {} +} + /// Defines a pointer manipulation API for non-shared heap-allocated data. /// /// Implement this trait for types that are allocated by the driver via [`Box::new`], /// and then returned to the user as a pointer. The user is responsible for freeing /// the memory associated with the pointer using corresponding driver's API function. -pub trait BoxFFI: Sized { +pub trait BoxFFI: Sized + origin_sealed::FromBoxSealed { /// Consumes the Box and returns a pointer with exclusive ownership. /// The pointer needs to be freed. See [`BoxFFI::free()`]. fn into_ptr(self: Box) -> CassPtr<'static, Self, (M,)> { @@ -348,7 +354,7 @@ pub trait BoxFFI: Sized { /// The data should be allocated via [`Arc::new`], and then returned to the user as a pointer. /// The user is responsible for freeing the memory associated /// with the pointer using corresponding driver's API function. -pub trait ArcFFI: Sized { +pub trait ArcFFI: Sized + origin_sealed::FromArcSealed { /// Creates a pointer from a valid reference to Arc-allocated data. /// Holder of the pointer borrows the pointee. fn as_ptr<'a>(self: &'a Arc) -> CassPtr<'a, Self, (Const,)> { @@ -438,7 +444,7 @@ pub trait ArcFFI: Sized { /// For example: lifetime of CassRow is bound by the lifetime of CassResult. /// There is no API function that frees the CassRow. It should be automatically /// freed when user calls cass_result_free. -pub trait RefFFI: Sized { +pub trait RefFFI: Sized + origin_sealed::FromRefSealed { /// Creates a borrowed pointer from a valid reference. #[allow(clippy::needless_lifetimes)] fn as_ptr<'a>(&'a self) -> CassPtr<'a, Self, (Const,)> { @@ -482,11 +488,81 @@ pub trait RefFFI: Sized { } } +/// This trait should be implemented for types that are passed between +/// C and Rust API. We currently distinguish 3 kinds of implementors, +/// wrt. the origin of the pointer. The implementor should pick one of the 3 ownership +/// kinds as the associated type: +/// - [`FromBox`] +/// - [`FromArc`] +/// - [`FromRef`] +#[allow(clippy::upper_case_acronyms)] +pub trait FFI { + type Origin; +} + +/// Represents types with an exclusive ownership. +/// +/// Use this associated type for implementors that require: +/// - owned exclusive pointer manipulation via [`BoxFFI`] +/// - exclusive ownership of the corresponding object +/// - potential mutability of the corresponding object +/// - manual memory freeing +/// +/// C API user should be responsible for freeing associated memory manually +/// via corresponding API call. +/// +/// An example of such implementor would be [`CassCluster`](crate::cluster::CassCluster): +/// - it is allocated on the heap via [`Box::new`] +/// - user is the exclusive owner of the CassCluster object +/// - there is no API to increase a reference count of CassCluster object +/// - CassCluster is mutable via some API methods (`cass_cluster_set_*`) +/// - user is responsible for freeing the associated memory (`cass_cluster_free`) +pub struct FromBox; +impl origin_sealed::FromBoxSealed for T where T: FFI {} +impl BoxFFI for T where T: FFI {} + +/// Represents types with a shared ownership. +/// +/// Use this associated type for implementors that require: +/// - pointer with shared ownership manipulation via [`ArcFFI`] +/// - shared ownership of the corresponding object +/// - manual memory freeing +/// +/// C API user should be responsible for freeing (decreasing reference count of) +/// associated memory manually via corresponding API call. +/// +/// An example of such implementor would be [`CassDataType`](crate::cass_types::CassDataType): +/// - it is allocated on the heap via [`Arc::new`] +/// - there are multiple owners of the shared CassDataType object +/// - some API functions require to increase a reference count of the object +/// - user is responsible for freeing (decreasing RC of) the associated memory (`cass_data_type_free`) +pub struct FromArc; +impl origin_sealed::FromArcSealed for T where T: FFI {} +impl ArcFFI for T where T: FFI {} + +/// Represents borrowed types. +/// +/// Use this associated type for implementors that do not require any assumptions +/// about the pointer type (apart from validity). +/// The implementation will enable [`CassBorrowedPtr`] manipulation via [`RefFFI`] +/// +/// C API user is not responsible for freeing associated memory manually. The memory +/// should be freed automatically, when the owner is being dropped. +/// +/// An example of such implementor would be [`CassRow`](crate::query_result::CassRow): +/// - its lifetime is tied to the lifetime of CassResult +/// - user only "borrows" the pointer - he is not responsible for freeing the memory +pub struct FromRef; +impl origin_sealed::FromRefSealed for T where T: FFI {} +impl RefFFI for T where T: FFI {} + /// ```compile_fail,E0499 /// # use scylla_cpp_driver::argconv::{CassOwnedMutPtr, CassBorrowedMutPtr}; -/// # use scylla_cpp_driver::argconv::BoxFFI; +/// # use scylla_cpp_driver::argconv::{FFI, BoxFFI, FromBox}; /// struct Foo; -/// impl BoxFFI for Foo {} +/// impl FFI for Foo { +/// type Origin = FromBox; +/// } /// /// let mut ptr: CassOwnedMutPtr = BoxFFI::into_ptr(Box::new(Foo)); /// let borrowed_mut_ptr1: CassBorrowedMutPtr = ptr.borrow_mut(); @@ -498,9 +574,11 @@ fn _test_box_ffi_cannot_have_two_mutable_references() {} /// ```compile_fail,E0502 /// # use scylla_cpp_driver::argconv::{CassOwnedMutPtr, CassBorrowedPtr, CassBorrowedMutPtr}; -/// # use scylla_cpp_driver::argconv::BoxFFI; +/// # use scylla_cpp_driver::argconv::{FFI, BoxFFI, FromBox}; /// struct Foo; -/// impl BoxFFI for Foo {} +/// impl FFI for Foo { +/// type Origin = FromBox; +/// } /// /// let mut ptr: CassOwnedMutPtr = BoxFFI::into_ptr(Box::new(Foo)); /// let borrowed_mut_ptr: CassBorrowedMutPtr = ptr.borrow_mut(); @@ -512,9 +590,11 @@ fn _test_box_ffi_cannot_have_mutable_and_immutable_references_at_the_same_time() /// ```compile_fail,E0505 /// # use scylla_cpp_driver::argconv::{CassOwnedMutPtr, CassBorrowedPtr}; -/// # use scylla_cpp_driver::argconv::BoxFFI; +/// # use scylla_cpp_driver::argconv::{FFI, BoxFFI, FromBox}; /// struct Foo; -/// impl BoxFFI for Foo {} +/// impl FFI for Foo { +/// type Origin = FromBox; +/// } /// /// let ptr: CassOwnedMutPtr = BoxFFI::into_ptr(Box::new(Foo)); /// let borrowed_ptr: CassBorrowedPtr = ptr.borrow(); @@ -525,10 +605,12 @@ fn _test_box_ffi_cannot_free_while_having_borrowed_pointer() {} /// ```compile_fail,E0505 /// # use scylla_cpp_driver::argconv::{CassOwnedPtr, CassBorrowedPtr}; -/// # use scylla_cpp_driver::argconv::ArcFFI; +/// # use scylla_cpp_driver::argconv::{FFI, ArcFFI, FromArc}; /// # use std::sync::Arc; /// struct Foo; -/// impl ArcFFI for Foo {} +/// impl FFI for Foo { +/// type Origin = FromArc; +/// } /// /// let ptr: CassOwnedPtr = ArcFFI::into_ptr(Arc::new(Foo)); /// let borrowed_ptr: CassBorrowedPtr = ptr.borrow(); @@ -539,10 +621,12 @@ fn _test_arc_ffi_cannot_clone_after_free() {} /// ```compile_fail,E0505 /// # use scylla_cpp_driver::argconv::{CassBorrowedPtr}; -/// # use scylla_cpp_driver::argconv::ArcFFI; +/// # use scylla_cpp_driver::argconv::{FFI, ArcFFI, FromArc}; /// # use std::sync::Arc; /// struct Foo; -/// impl ArcFFI for Foo {} +/// impl FFI for Foo { +/// type Origin = FromArc; +/// } /// /// let arc = Arc::new(Foo); /// let borrowed_ptr: CassBorrowedPtr = ArcFFI::as_ptr(&arc); diff --git a/scylla-rust-wrapper/src/batch.rs b/scylla-rust-wrapper/src/batch.rs index 076be38b..3688b1ef 100644 --- a/scylla-rust-wrapper/src/batch.rs +++ b/scylla-rust-wrapper/src/batch.rs @@ -1,4 +1,6 @@ -use crate::argconv::{ArcFFI, BoxFFI, CassBorrowedMutPtr, CassBorrowedPtr, CassOwnedMutPtr}; +use crate::argconv::{ + ArcFFI, BoxFFI, CassBorrowedMutPtr, CassBorrowedPtr, CassOwnedMutPtr, FromBox, FFI, +}; use crate::cass_error::CassError; use crate::cass_types::CassConsistency; use crate::cass_types::{make_batch_type, CassBatchType}; @@ -19,7 +21,9 @@ pub struct CassBatch { pub(crate) exec_profile: Option, } -impl BoxFFI for CassBatch {} +impl FFI for CassBatch { + type Origin = FromBox; +} #[derive(Clone)] pub struct CassBatchState { diff --git a/scylla-rust-wrapper/src/cass_types.rs b/scylla-rust-wrapper/src/cass_types.rs index f0449a6d..e848816c 100644 --- a/scylla-rust-wrapper/src/cass_types.rs +++ b/scylla-rust-wrapper/src/cass_types.rs @@ -175,7 +175,9 @@ pub enum CassDataTypeInner { Custom(String), } -impl ArcFFI for CassDataType {} +impl FFI for CassDataType { + type Origin = FromArc; +} impl CassDataTypeInner { /// Checks for equality during typechecks. diff --git a/scylla-rust-wrapper/src/cluster.rs b/scylla-rust-wrapper/src/cluster.rs index 6009e466..5769d96c 100644 --- a/scylla-rust-wrapper/src/cluster.rs +++ b/scylla-rust-wrapper/src/cluster.rs @@ -165,7 +165,9 @@ impl CassCluster { } } -impl BoxFFI for CassCluster {} +impl FFI for CassCluster { + type Origin = FromBox; +} pub struct CassCustomPayload; diff --git a/scylla-rust-wrapper/src/collection.rs b/scylla-rust-wrapper/src/collection.rs index b59a9c61..2035f20b 100644 --- a/scylla-rust-wrapper/src/collection.rs +++ b/scylla-rust-wrapper/src/collection.rs @@ -36,7 +36,9 @@ pub struct CassCollection { pub items: Vec, } -impl BoxFFI for CassCollection {} +impl FFI for CassCollection { + type Origin = FromBox; +} impl CassCollection { fn typecheck_on_append(&self, value: &Option) -> CassError { diff --git a/scylla-rust-wrapper/src/exec_profile.rs b/scylla-rust-wrapper/src/exec_profile.rs index 5ab3064b..b4d6f226 100644 --- a/scylla-rust-wrapper/src/exec_profile.rs +++ b/scylla-rust-wrapper/src/exec_profile.rs @@ -15,6 +15,7 @@ use scylla::statement::Consistency; use crate::argconv::{ ptr_to_cstr_n, strlen, ArcFFI, BoxFFI, CassBorrowedMutPtr, CassBorrowedPtr, CassOwnedMutPtr, + FromBox, FFI, }; use crate::batch::CassBatch; use crate::cass_error::CassError; @@ -39,7 +40,9 @@ pub struct CassExecProfile { load_balancing_config: LoadBalancingConfig, } -impl BoxFFI for CassExecProfile {} +impl FFI for CassExecProfile { + type Origin = FromBox; +} impl CassExecProfile { fn new() -> Self { diff --git a/scylla-rust-wrapper/src/future.rs b/scylla-rust-wrapper/src/future.rs index d28d55d3..1ac80cae 100644 --- a/scylla-rust-wrapper/src/future.rs +++ b/scylla-rust-wrapper/src/future.rs @@ -60,7 +60,9 @@ pub struct CassFuture { wait_for_value: Condvar, } -impl ArcFFI for CassFuture {} +impl FFI for CassFuture { + type Origin = FromArc; +} /// An error that can appear during `cass_future_wait_timed`. enum FutureError { diff --git a/scylla-rust-wrapper/src/logging.rs b/scylla-rust-wrapper/src/logging.rs index 603aa4af..16c17870 100644 --- a/scylla-rust-wrapper/src/logging.rs +++ b/scylla-rust-wrapper/src/logging.rs @@ -1,4 +1,4 @@ -use crate::argconv::{arr_to_cstr, ptr_to_cstr, str_to_arr, CassBorrowedPtr, RefFFI}; +use crate::argconv::{arr_to_cstr, ptr_to_cstr, str_to_arr, CassBorrowedPtr, FromRef, RefFFI, FFI}; use crate::cass_log_types::{CassLogLevel, CassLogMessage}; use crate::types::size_t; use crate::LOGGER; @@ -14,7 +14,9 @@ use tracing_subscriber::layer::Context; use tracing_subscriber::prelude::*; use tracing_subscriber::Layer; -impl RefFFI for CassLogMessage {} +impl FFI for CassLogMessage { + type Origin = FromRef; +} pub type CassLogCallback = Option, data: *mut c_void)>; diff --git a/scylla-rust-wrapper/src/metadata.rs b/scylla-rust-wrapper/src/metadata.rs index a66c95b2..3489a219 100644 --- a/scylla-rust-wrapper/src/metadata.rs +++ b/scylla-rust-wrapper/src/metadata.rs @@ -13,7 +13,9 @@ pub struct CassSchemaMeta { pub keyspaces: HashMap, } -impl BoxFFI for CassSchemaMeta {} +impl FFI for CassSchemaMeta { + type Origin = FromBox; +} pub struct CassKeyspaceMeta { pub name: String, @@ -25,7 +27,9 @@ pub struct CassKeyspaceMeta { } // Owned by CassSchemaMeta -impl RefFFI for CassKeyspaceMeta {} +impl FFI for CassKeyspaceMeta { + type Origin = FromRef; +} pub struct CassTableMeta { pub name: String, @@ -38,7 +42,9 @@ pub struct CassTableMeta { // Either: // - owned by CassMaterializedViewMeta - won't be given to user // - Owned by CassKeyspaceMeta (in Arc), referenced (Weak) by CassMaterializedViewMeta -impl RefFFI for CassTableMeta {} +impl FFI for CassTableMeta { + type Origin = FromRef; +} pub struct CassMaterializedViewMeta { pub name: String, @@ -47,7 +53,9 @@ pub struct CassMaterializedViewMeta { } // Shared ownership by CassKeyspaceMeta and CassTableMeta -impl RefFFI for CassMaterializedViewMeta {} +impl FFI for CassMaterializedViewMeta { + type Origin = FromRef; +} pub struct CassColumnMeta { pub name: String, @@ -56,7 +64,9 @@ pub struct CassColumnMeta { } // Owned by CassTableMeta -impl RefFFI for CassColumnMeta {} +impl FFI for CassColumnMeta { + type Origin = FromRef; +} pub unsafe fn create_table_metadata( keyspace_name: &str, diff --git a/scylla-rust-wrapper/src/prepared.rs b/scylla-rust-wrapper/src/prepared.rs index edfb7d29..37f4b044 100644 --- a/scylla-rust-wrapper/src/prepared.rs +++ b/scylla-rust-wrapper/src/prepared.rs @@ -72,7 +72,9 @@ impl CassPrepared { } } -impl ArcFFI for CassPrepared {} +impl FFI for CassPrepared { + type Origin = FromArc; +} #[no_mangle] pub unsafe extern "C" fn cass_prepared_free(prepared_raw: CassOwnedPtr) { diff --git a/scylla-rust-wrapper/src/query_error.rs b/scylla-rust-wrapper/src/query_error.rs index 753c7d1a..9041eef0 100644 --- a/scylla-rust-wrapper/src/query_error.rs +++ b/scylla-rust-wrapper/src/query_error.rs @@ -19,7 +19,9 @@ pub enum CassErrorResult { Deserialization(#[from] DeserializationError), } -impl ArcFFI for CassErrorResult {} +impl FFI for CassErrorResult { + type Origin = FromArc; +} impl From for CassConsistency { fn from(c: Consistency) -> CassConsistency { diff --git a/scylla-rust-wrapper/src/query_result.rs b/scylla-rust-wrapper/src/query_result.rs index b57924d1..cfa5fc7d 100644 --- a/scylla-rust-wrapper/src/query_result.rs +++ b/scylla-rust-wrapper/src/query_result.rs @@ -95,7 +95,9 @@ impl CassResult { } } -impl ArcFFI for CassResult {} +impl FFI for CassResult { + type Origin = FromArc; +} #[derive(Debug)] pub struct CassResultMetadata { @@ -149,7 +151,9 @@ pub struct CassRow { pub result_metadata: Arc, } -impl RefFFI for CassRow {} +impl FFI for CassRow { + type Origin = FromRef; +} pub fn create_cass_rows_from_rows( rows: Vec, @@ -185,7 +189,9 @@ pub struct CassValue { pub value_type: Arc, } -impl RefFFI for CassValue {} +impl FFI for CassValue { + type Origin = FromRef; +} fn create_cass_row_columns(row: Row, metadata: &Arc) -> Vec { row.columns @@ -367,7 +373,9 @@ pub enum CassIterator<'result_or_schema> { CassViewMetaIterator(CassViewMetaIterator<'result_or_schema>), } -impl BoxFFI for CassIterator<'_> {} +impl FFI for CassIterator<'_> { + type Origin = FromBox; +} #[no_mangle] pub unsafe extern "C" fn cass_iterator_free(iterator: CassOwnedMutPtr) { diff --git a/scylla-rust-wrapper/src/retry_policy.rs b/scylla-rust-wrapper/src/retry_policy.rs index 43b5f40b..940546dc 100644 --- a/scylla-rust-wrapper/src/retry_policy.rs +++ b/scylla-rust-wrapper/src/retry_policy.rs @@ -2,7 +2,7 @@ use scylla::retry_policy::{DefaultRetryPolicy, FallthroughRetryPolicy}; use scylla::transport::downgrading_consistency_retry_policy::DowngradingConsistencyRetryPolicy; use std::sync::Arc; -use crate::argconv::{ArcFFI, CassOwnedPtr}; +use crate::argconv::{ArcFFI, CassOwnedPtr, FromArc, FFI}; pub enum RetryPolicy { DefaultRetryPolicy(Arc), @@ -12,7 +12,9 @@ pub enum RetryPolicy { pub type CassRetryPolicy = RetryPolicy; -impl ArcFFI for CassRetryPolicy {} +impl FFI for CassRetryPolicy { + type Origin = FromArc; +} #[no_mangle] pub extern "C" fn cass_retry_policy_default_new() -> CassOwnedPtr { @@ -22,8 +24,7 @@ pub extern "C" fn cass_retry_policy_default_new() -> CassOwnedPtr CassOwnedPtr { +pub extern "C" fn cass_retry_policy_downgrading_consistency_new() -> CassOwnedPtr { ArcFFI::into_ptr(Arc::new(RetryPolicy::DowngradingConsistencyRetryPolicy( Arc::new(DowngradingConsistencyRetryPolicy), ))) diff --git a/scylla-rust-wrapper/src/session.rs b/scylla-rust-wrapper/src/session.rs index 5a5ddde8..961f58f8 100644 --- a/scylla-rust-wrapper/src/session.rs +++ b/scylla-rust-wrapper/src/session.rs @@ -138,7 +138,9 @@ impl CassSessionInner { pub type CassSession = RwLock>; -impl ArcFFI for CassSession {} +impl FFI for CassSession { + type Origin = FromArc; +} #[no_mangle] pub unsafe extern "C" fn cass_session_new() -> CassOwnedPtr { diff --git a/scylla-rust-wrapper/src/ssl.rs b/scylla-rust-wrapper/src/ssl.rs index 1da668ae..0a0f2d28 100644 --- a/scylla-rust-wrapper/src/ssl.rs +++ b/scylla-rust-wrapper/src/ssl.rs @@ -1,6 +1,8 @@ use crate::argconv::ArcFFI; use crate::argconv::CassBorrowedPtr; use crate::argconv::CassOwnedPtr; +use crate::argconv::FromArc; +use crate::argconv::FFI; use crate::cass_error::CassError; use crate::types::size_t; use libc::{c_int, strlen}; @@ -21,7 +23,9 @@ pub struct CassSsl { pub(crate) trusted_store: *mut X509_STORE, } -impl ArcFFI for CassSsl {} +impl FFI for CassSsl { + type Origin = FromArc; +} pub const CASS_SSL_VERIFY_NONE: i32 = 0x00; pub const CASS_SSL_VERIFY_PEER_CERT: i32 = 0x01; diff --git a/scylla-rust-wrapper/src/statement.rs b/scylla-rust-wrapper/src/statement.rs index 775414fc..597bf2e6 100644 --- a/scylla-rust-wrapper/src/statement.rs +++ b/scylla-rust-wrapper/src/statement.rs @@ -216,7 +216,9 @@ pub struct CassStatement { pub(crate) exec_profile: Option, } -impl BoxFFI for CassStatement {} +impl FFI for CassStatement { + type Origin = FromBox; +} impl CassStatement { fn bind_cql_value(&mut self, index: usize, value: Option) -> CassError { diff --git a/scylla-rust-wrapper/src/tuple.rs b/scylla-rust-wrapper/src/tuple.rs index 83d9c394..1ac77b18 100644 --- a/scylla-rust-wrapper/src/tuple.rs +++ b/scylla-rust-wrapper/src/tuple.rs @@ -17,7 +17,9 @@ pub struct CassTuple { pub items: Vec>, } -impl BoxFFI for CassTuple {} +impl FFI for CassTuple { + type Origin = FromBox; +} impl CassTuple { fn get_types(&self) -> Option<&Vec>> { diff --git a/scylla-rust-wrapper/src/user_type.rs b/scylla-rust-wrapper/src/user_type.rs index 5761d4b5..aa927259 100644 --- a/scylla-rust-wrapper/src/user_type.rs +++ b/scylla-rust-wrapper/src/user_type.rs @@ -14,7 +14,9 @@ pub struct CassUserType { pub field_values: Vec>, } -impl BoxFFI for CassUserType {} +impl FFI for CassUserType { + type Origin = FromBox; +} impl CassUserType { fn set_field_by_index(&mut self, index: usize, value: Option) -> CassError { diff --git a/scylla-rust-wrapper/src/uuid.rs b/scylla-rust-wrapper/src/uuid.rs index 8aaa6dab..a3dd4a10 100644 --- a/scylla-rust-wrapper/src/uuid.rs +++ b/scylla-rust-wrapper/src/uuid.rs @@ -17,7 +17,9 @@ pub struct CassUuidGen { pub last_timestamp: AtomicU64, } -impl BoxFFI for CassUuidGen {} +impl FFI for CassUuidGen { + type Origin = FromBox; +} // Implementation directly ported from Cpp Driver implementation: