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 ce7b3cb8..889b73aa 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: