From f3c4db97349ee30d941cc5a331b8e14d04481236 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 1/5] future: pass future pointer to callback directly Before this commit, 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); ``` Since some methods started accepting a pointer, they are marked as unsafe, because they assume that pointer is valid. We will be able to remove unsafes once CassPtr is introduced - the type will give enough guarantees for these methods to be safe. In this PR, there was a question regarding CassFuture::set_callback: Q: Here self_ptr should refer to the same CassFuture as self, right? Can you instead make the receiver of this function an arc? self: &Arc A: I don't see a good reason behind it. We get a pointer in cass_future_set_callback, then we would need to convert it to Arc (increase a refcount), just to then convert it back to pointer (decrease refcount) and pass the ponter to callback. --- scylla-rust-wrapper/src/future.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/scylla-rust-wrapper/src/future.rs b/scylla-rust-wrapper/src/future.rs index 99f4fc4f..3601a58c 100644 --- a/scylla-rust-wrapper/src/future.rs +++ b/scylla-rust-wrapper/src/future.rs @@ -40,10 +40,8 @@ struct BoundCallback { unsafe impl Send for BoundCallback {} impl BoundCallback { - fn invoke(self, fut: &CassFuture) { - unsafe { - self.cb.unwrap()((fut as *const _) as *mut _, self.data); - } + unsafe fn invoke(self, fut_ptr: *mut CassFuture) { + self.cb.unwrap()(fut_ptr, self.data); } } @@ -96,7 +94,11 @@ 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) as *mut _; + // Safety: pointer is valid, because we get it from arc allocation. + unsafe { + bound_cb.invoke(fut_ptr); + } } cass_fut_clone.wait_for_value.notify_all(); @@ -258,7 +260,12 @@ impl CassFuture { } } - pub fn set_callback(&self, cb: CassFutureCallback, data: *mut c_void) -> CassError { + pub unsafe fn set_callback( + &self, + self_ptr: *mut 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 +275,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 +300,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 5e22a9c3904783db2933cf446f92e1866bb7e114 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 2/5] 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 | 255 +++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) diff --git a/scylla-rust-wrapper/src/argconv.rs b/scylla-rust-wrapper/src/argconv.rs index b6e881ef..428e9e5e 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,259 @@ macro_rules! make_c_str { #[cfg(test)] pub(crate) use make_c_str; +mod sealed { + pub trait Sealed {} +} + +/// A trait representing ownership (i.e. Rust mutability) of the pointer. +/// +/// Pointer can either be [`Exclusive`] or [`Shared`]. +/// +/// ## Shared pointers +/// Shared 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. +/// +/// ## Exclusive pointers +/// Exclusive pointers can be converted to both immutable and mutable Rust referential types. +pub trait Ownership: sealed::Sealed {} + +/// Represents shared (immutable) pointer. +pub struct Shared; +impl sealed::Sealed for Shared {} +impl Ownership for Shared {} + +/// Represents exclusive (mutable) pointer. +pub struct Exclusive; +impl sealed::Sealed for Exclusive {} +impl Ownership for Exclusive {} + +/// A trait representing mutability of the pointer in C semantics. +/// +/// Pointer can be either [`CConst`] or [`CMut`]. +/// +/// The semantics of this property are very simple: it tells whether +/// the pointer is const or not on the C side. If the pointer is `T*`, then +/// corresponding [`CassPtr`] is [`CMut`], and if the pointer is `const T*`, then +/// corresponding [`CassPtr`] is [`CConst`]. +/// +/// ## Why [`Ownership`] property is not enough? +/// This is because mutability semantics differ between C and Rust. +/// - In C/C++: mut = logically mutable, const = logically immutable +/// - In Rust: mut = exclusive ownership (e.g. Box, &mut), const = shared ownership (e.g. Arc, &) +/// +/// In cpp-driver API there are some types that are both shared and mutable. Take for example `CassDataType`. +/// From rust perspective, the pointer is always [`Shared`], because it is shared behind an [`Arc`]. +/// But there are some methods, e.g: +/// ```rust,ignore +/// cass_data_type_add_sub_type(CassDataType* data_type, const CassDataType* sub_data_type); +/// ``` +/// which accept a mutable pointer. Such method is implemented by employing interior mutability pattern (mutating a shared object). +/// If we did not have [`CMutability`] property defined, we would not be able to +/// distinguish between `CassDataType*` and `const CassDataType*`. In such case, user would be able to obtain +/// `const CassDataType*` pointer (e.g. from `cass_tuple_data_type`) and pass it to the method that expects `CassDataType*`. +/// +/// This property comes useful for implementing safe Rust unit tests where we play a role of C API user. +pub trait CMutability: sealed::Sealed {} + +/// Represents const C pointer. +pub struct CConst; +impl sealed::Sealed for CConst {} +impl CMutability for CConst {} + +/// Represents mutable (non-const) C pointer. +pub struct CMut; +impl sealed::Sealed for CMut {} +impl CMutability for CMut {} + +/// Represents additional properties of the pointer. +pub trait Properties: sealed::Sealed { + type Onwership: Ownership; + type CMutability: CMutability; +} + +impl sealed::Sealed for (O, CM) {} +impl Properties for (O, CM) { + type Onwership = O; + type CMutability = CM; +} + +/// 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: shared ([`Shared`]) and exclusive ([`Exclusive`]). +/// Shared pointers can be converted to immutable (&) references, while exclusive 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 tell whether the pointer +/// **owns** or **borrows** the pointee. 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, (Exclusive,)>`]. +/// `'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, (Shared,)>`]. It means that +/// holder of the created pointer **borrows** the pointee (with some lifetime `'a` +/// inherited from the immutable borrow `&'a T`). +/// +/// Both [`CassPtr::into_ref()`] and [`CassPtr::into_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::into_ref()`] and [`CassPtr::into_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 shared pointer. +/// Can be used for pointers with shared ownership - e.g. pointers coming from [`Arc`] allocation. +pub type CassOwnedSharedPtr = CassPtr<'static, T, (Shared, CM)>; + +/// Borrowed shared pointer. +/// Can be used for pointers created from some immutable reference. +pub type CassBorrowedSharedPtr<'a, T, CM> = CassPtr<'a, T, (Shared, CM)>; + +/// Owned exclusive pointer. +/// Can be used for pointers with exclusive ownership - e.g. pointers coming from [`Box`] allocation. +pub type CassOwnedExclusivePtr = CassPtr<'static, T, (Exclusive, CM)>; + +/// Borrowed exclusive pointer. +/// This can be for example obtained from mutable reborrow of some [`CassOwnedExclusivePtr`]. +pub type CassBorrowedExclusivePtr<'a, T, CM> = CassPtr<'a, T, (Exclusive, CM)>; + +/// Utility method for tests. Useful when some method returns `T*`, +/// and then another method accepts `const T*`. +#[cfg(test)] +impl<'a, T: Sized, P: Properties> CassPtr<'a, T, P> { + pub fn into_c_const(self) -> CassPtr<'a, T, (P::Onwership, CConst)> { + CassPtr { + ptr: self.ptr, + _phantom: PhantomData, + } + } +} + +/// 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 ownership 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 for to exclusive pointers. +impl CassPtr<'_, T, (Exclusive, CMut)> { + 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. + fn into_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, CM: CMutability> CassPtr<'a, T, (Exclusive, CM)> { + /// Converts a pointer to an optional valid mutable reference. + /// The reference inherits the lifetime of the pointer. + fn into_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, (Shared, P::CMutability)> { + CassPtr { + ptr: self.ptr, + _phantom: PhantomData, + } + } +} + +impl CassPtr<'_, T, (Exclusive, CMut)> { + /// 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, (Exclusive, CMut)> { + 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 b98c96914b51b6605e71fa836c660e63b065bd71 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 3/5] 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 | 304 ++++++++-- scylla-rust-wrapper/src/batch.rs | 52 +- scylla-rust-wrapper/src/binding.rs | 34 +- scylla-rust-wrapper/src/cass_types.rs | 137 +++-- scylla-rust-wrapper/src/cluster.rs | 282 +++++---- scylla-rust-wrapper/src/collection.rs | 104 ++-- scylla-rust-wrapper/src/exec_profile.rs | 151 +++-- scylla-rust-wrapper/src/future.rs | 172 +++--- .../src/integration_testing.rs | 22 +- scylla-rust-wrapper/src/iterator.rs | 322 +++++----- scylla-rust-wrapper/src/lib.rs | 3 +- scylla-rust-wrapper/src/logging.rs | 22 +- scylla-rust-wrapper/src/metadata.rs | 256 ++++---- scylla-rust-wrapper/src/prepared.rs | 34 +- scylla-rust-wrapper/src/query_error.rs | 56 +- scylla-rust-wrapper/src/query_result.rs | 232 ++++---- scylla-rust-wrapper/src/retry_policy.rs | 19 +- scylla-rust-wrapper/src/session.rs | 556 ++++++++++++------ scylla-rust-wrapper/src/ssl.rs | 40 +- scylla-rust-wrapper/src/statement.rs | 62 +- scylla-rust-wrapper/src/testing.rs | 2 +- scylla-rust-wrapper/src/tuple.rs | 24 +- scylla-rust-wrapper/src/user_type.rs | 16 +- scylla-rust-wrapper/src/uuid.rs | 19 +- 24 files changed, 1798 insertions(+), 1123 deletions(-) diff --git a/scylla-rust-wrapper/src/argconv.rs b/scylla-rust-wrapper/src/argconv.rs index 428e9e5e..aba4288a 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() @@ -331,30 +331,72 @@ impl CassPtr<'_, T, (Exclusive, CMut)> { /// 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, (Exclusive, CM)> { #[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. ownership - user becomes an exclusive owner of the pointee. Thus, it's ok + // for the pointer to be `Exclusive`. + unsafe { CassPtr::from_raw(ptr) } } - unsafe fn from_ptr(ptr: *mut Self) -> Box { - #[allow(clippy::disallowed_methods)] - Box::from_raw(ptr) - } - unsafe fn as_maybe_ref<'a>(ptr: *const Self) -> Option<&'a Self> { - #[allow(clippy::disallowed_methods)] - ptr.as_ref() + + /// Consumes the pointer with exclusive ownership back to the Box. + fn from_ptr( + ptr: CassPtr<'static, Self, (Exclusive, CM)>, + ) -> 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_ref<'a>(ptr: *const Self) -> &'a Self { - #[allow(clippy::disallowed_methods)] - ptr.as_ref().unwrap() + + /// Creates a reference from an exclusive pointer. + /// Reference inherits the lifetime of the pointer's borrow. + #[allow(clippy::needless_lifetimes)] + fn as_ref<'a, O: Ownership, CM: CMutability>( + ptr: CassPtr<'a, Self, (O, CM)>, + ) -> Option<&'a Self> { + ptr.into_ref() } - 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, CM: CMutability>( + ptr: CassPtr<'a, Self, (Exclusive, CM)>, + ) -> Option<&'a mut Self> { + ptr.into_mut_ref() } - unsafe fn free(ptr: *mut Self) { + + /// Frees the pointee. + fn free(ptr: CassPtr<'static, Self, (Exclusive, CM)>) { std::mem::drop(BoxFFI::from_ptr(ptr)); } + + // Currently used only in tests. + #[allow(dead_code)] + fn null<'a, CM: CMutability>() -> CassPtr<'a, Self, (Shared, CConst)> { + CassPtr::null() + } + + fn null_mut<'a>() -> CassPtr<'a, Self, (Exclusive, CMut)> { + CassPtr::null_mut() + } } /// Defines a pointer manipulation API for shared heap-allocated data. @@ -363,36 +405,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, CM: CMutability>(self: &'a Arc) -> CassPtr<'a, Self, (Shared, CM)> { #[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. ownership - we always create a `Shared` pointer. + unsafe { CassPtr::from_raw(ptr) } } - fn into_ptr(self: Arc) -> *const Self { - #[allow(clippy::disallowed_methods)] - Arc::into_raw(self) - } - unsafe fn from_ptr(ptr: *const Self) -> Arc { + + /// Creates a pointer from a valid Arc allocation. + fn into_ptr(self: Arc) -> CassPtr<'static, Self, (Shared, CM)> { #[allow(clippy::disallowed_methods)] - Arc::from_raw(ptr) + 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 decrement the RC of the pointer (and potentially free the memory) + // via ArcFFI::free(). + // 3. ownership - we always create a `Shared` pointer. + unsafe { CassPtr::from_raw(ptr) } } - 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) + + /// Converts shared owned pointer back to owned Arc. + fn from_ptr(ptr: CassPtr<'static, Self, (Shared, CM)>) -> 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 as_maybe_ref<'a>(ptr: *const Self) -> Option<&'a Self> { - #[allow(clippy::disallowed_methods)] - ptr.as_ref() + + /// Increases the reference count of the pointer, and returns an owned Arc. + fn cloned_from_ptr(ptr: CassPtr<'_, Self, (Shared, CM)>) -> 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 a 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_ref<'a>(ptr: *const Self) -> &'a Self { - #[allow(clippy::disallowed_methods)] - ptr.as_ref().unwrap() + + /// Converts a shared borrowed pointer to reference. + /// The reference inherits the lifetime of pointer's borrow. + #[allow(clippy::needless_lifetimes)] + fn as_ref<'a, CM: CMutability>(ptr: CassPtr<'a, Self, (Shared, CM)>) -> Option<&'a Self> { + ptr.into_ref() } - unsafe fn free(ptr: *const Self) { + + /// Decreases the reference count (and potentially frees) of the owned pointer. + fn free(ptr: CassPtr<'static, Self, (Shared, CM)>) { std::mem::drop(ArcFFI::from_ptr(ptr)); } + + fn null<'a, CM: CMutability>() -> CassPtr<'a, Self, (Shared, CM)> { + CassPtr::null() + } + + fn is_null(ptr: &CassPtr<'_, Self, (Shared, CM)>) -> bool { + ptr.is_null() + } } /// Defines a pointer manipulation API for data owned by some other object. @@ -403,12 +495,134 @@ 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, CM: CMutability>(&'a self) -> CassPtr<'a, Self, (Shared, CM)> { + // 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. ownerhsip - we always create a `Shared` 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. + /// + /// ## Why this method is unsafe? - Example + /// ``` + /// # use scylla_cpp_driver::argconv::{RefFFI, CConst, CassBorrowedSharedPtr}; + /// # use std::sync::{Arc, Weak}; + /// + /// struct Foo; + /// impl RefFFI for Foo {} + /// + /// let arc = Arc::new(Foo); + /// let weak = Arc::downgrade(&arc); + /// let ptr: CassBorrowedSharedPtr = unsafe { RefFFI::weak_as_ptr(&weak) }; + /// std::mem::drop(arc); + /// + /// // The ptr is now dangling. The user can "safely" dereference it using RefFFI API. + /// + /// ``` + #[allow(clippy::needless_lifetimes)] + unsafe fn weak_as_ptr<'a, CM: CMutability>( + w: &'a Weak, + ) -> CassPtr<'a, Self, (Shared, CM)> { + 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, CM: CMutability>(ptr: CassPtr<'a, Self, (Shared, CM)>) -> Option<&'a Self> { + ptr.into_ref() + } + + fn null<'a, CM: CMutability>() -> CassPtr<'a, Self, (Shared, CM)> { + CassPtr::null() + } + + fn is_null(ptr: &CassPtr<'_, Self, (Shared, CM)>) -> bool { + ptr.is_null() } } + +/// ```compile_fail,E0499 +/// # use scylla_cpp_driver::argconv::{CassOwnedExclusivePtr, CassBorrowedExclusivePtr, CMut}; +/// # use scylla_cpp_driver::argconv::BoxFFI; +/// struct Foo; +/// impl BoxFFI for Foo {} +/// +/// let mut ptr: CassOwnedExclusivePtr = BoxFFI::into_ptr(Box::new(Foo)); +/// let borrowed_mut_ptr1: CassBorrowedExclusivePtr = ptr.borrow_mut(); +/// let borrowed_mut_ptr2: CassBorrowedExclusivePtr = 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::{CassOwnedExclusivePtr, CassBorrowedSharedPtr, CassBorrowedExclusivePtr, CConst, CMut}; +/// # use scylla_cpp_driver::argconv::BoxFFI; +/// struct Foo; +/// impl BoxFFI for Foo {} +/// +/// let mut ptr: CassOwnedExclusivePtr = BoxFFI::into_ptr(Box::new(Foo)); +/// let borrowed_mut_ptr: CassBorrowedExclusivePtr = ptr.borrow_mut(); +/// let borrowed_ptr: CassBorrowedSharedPtr = 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::{CassOwnedExclusivePtr, CassBorrowedSharedPtr, CMut}; +/// # use scylla_cpp_driver::argconv::BoxFFI; +/// struct Foo; +/// impl BoxFFI for Foo {} +/// +/// let ptr: CassOwnedExclusivePtr = BoxFFI::into_ptr(Box::new(Foo)); +/// let borrowed_ptr: CassBorrowedSharedPtr = 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::{CassOwnedSharedPtr, CassBorrowedSharedPtr, CConst}; +/// # use scylla_cpp_driver::argconv::ArcFFI; +/// # use std::sync::Arc; +/// struct Foo; +/// impl ArcFFI for Foo {} +/// +/// let ptr: CassOwnedSharedPtr = ArcFFI::into_ptr(Arc::new(Foo)); +/// let borrowed_ptr: CassBorrowedSharedPtr = 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::{CassBorrowedSharedPtr, CConst}; +/// # use scylla_cpp_driver::argconv::ArcFFI; +/// # use std::sync::Arc; +/// struct Foo; +/// impl ArcFFI for Foo {} +/// +/// let arc = Arc::new(Foo); +/// let borrowed_ptr: CassBorrowedSharedPtr = 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 43b51b54..8475820f 100644 --- a/scylla-rust-wrapper/src/batch.rs +++ b/scylla-rust-wrapper/src/batch.rs @@ -1,4 +1,6 @@ -use crate::argconv::{ArcFFI, BoxFFI}; +use crate::argconv::{ + ArcFFI, BoxFFI, CMut, CassBorrowedExclusivePtr, CassBorrowedSharedPtr, CassOwnedExclusivePtr, +}; use crate::cass_error::CassError; use crate::cass_types::CassConsistency; use crate::cass_types::{make_batch_type, CassBatchType}; @@ -28,7 +30,9 @@ 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, +) -> CassOwnedExclusivePtr { if let Some(batch_type) = make_batch_type(type_) { BoxFFI::into_ptr(Box::new(CassBatch { state: Arc::new(CassBatchState { @@ -39,21 +43,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: CassOwnedExclusivePtr) { BoxFFI::free(batch); } #[no_mangle] pub unsafe extern "C" fn cass_batch_set_consistency( - batch: *mut CassBatch, + batch: CassBorrowedExclusivePtr, 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 +71,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: CassBorrowedExclusivePtr, 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 +88,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: CassBorrowedExclusivePtr, + retry_policy: CassBorrowedSharedPtr, ) -> 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 +111,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: CassBorrowedExclusivePtr, 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 +125,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: CassBorrowedExclusivePtr, 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 +136,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: CassBorrowedExclusivePtr, 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 +149,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: CassBorrowedExclusivePtr, 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 +162,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: CassBorrowedExclusivePtr, + statement: CassBorrowedSharedPtr, ) -> 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 e0ca9957..52766d8a 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: CassBorrowedExclusivePtr<$this, CMut>, 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: CassBorrowedExclusivePtr<$this, CMut>, 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: CassBorrowedExclusivePtr<$this, CMut>, 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: CassBorrowedExclusivePtr<$this, CMut>, $($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: CassBorrowedSharedPtr| { + 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 @ CassBorrowedSharedPtr] ); }; (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: CassBorrowedSharedPtr| { + Ok(Some(BoxFFI::as_ref(p).unwrap().into())) }, - [p @ *const crate::tuple::CassTuple] + [p @ CassBorrowedSharedPtr] ); }; (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: CassBorrowedSharedPtr| { + Ok(Some(BoxFFI::as_ref(p).unwrap().into())) + }, + [p @ CassBorrowedSharedPtr] ); }; } diff --git a/scylla-rust-wrapper/src/cass_types.rs b/scylla-rust-wrapper/src/cass_types.rs index af936d6c..722ba8ed 100644 --- a/scylla-rust-wrapper/src/cass_types.rs +++ b/scylla-rust-wrapper/src/cass_types.rs @@ -8,7 +8,6 @@ use scylla::statement::batch::BatchType; use std::cell::UnsafeCell; 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; @@ -447,7 +446,9 @@ pub fn get_column_type(column_type: &ColumnType) -> CassDataType { } #[no_mangle] -pub unsafe extern "C" fn cass_data_type_new(value_type: CassValueType) -> *mut CassDataType { +pub unsafe extern "C" fn cass_data_type_new( + value_type: CassValueType, +) -> CassOwnedSharedPtr { let inner = match value_type { CassValueType::CASS_VALUE_TYPE_LIST => CassDataTypeInner::List { typ: None, @@ -464,49 +465,57 @@ pub unsafe extern "C" fn cass_data_type_new(value_type: CassValueType) -> *mut C }, 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)) as *mut _ + ArcFFI::into_ptr(CassDataType::new_arced(inner)) } #[no_mangle] pub unsafe extern "C" fn cass_data_type_new_from_existing( - data_type: *const CassDataType, -) -> *mut CassDataType { - let data_type = ArcFFI::as_ref(data_type); - ArcFFI::into_ptr(CassDataType::new_arced(data_type.get_unchecked().clone())) as *mut _ + data_type: CassBorrowedSharedPtr, +) -> CassOwnedSharedPtr { + 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) -> *mut CassDataType { +pub unsafe extern "C" fn cass_data_type_new_tuple( + item_count: size_t, +) -> CassOwnedSharedPtr { ArcFFI::into_ptr(CassDataType::new_arced(CassDataTypeInner::Tuple( Vec::with_capacity(item_count as usize), - ))) as *mut _ + ))) } #[no_mangle] -pub unsafe extern "C" fn cass_data_type_new_udt(field_count: size_t) -> *mut CassDataType { +pub unsafe extern "C" fn cass_data_type_new_udt( + field_count: size_t, +) -> CassOwnedSharedPtr { ArcFFI::into_ptr(CassDataType::new_arced(CassDataTypeInner::UDT( UDTDataType::with_capacity(field_count as usize), - ))) as *mut _ + ))) } #[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: CassOwnedSharedPtr) { 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: CassBorrowedSharedPtr, +) -> 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: CassBorrowedSharedPtr, +) -> 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, @@ -520,11 +529,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: CassBorrowedSharedPtr, 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); @@ -536,7 +545,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: *mut CassDataType, + data_type: CassBorrowedSharedPtr, type_name: *const c_char, ) -> CassError { cass_data_type_set_type_name_n(data_type, type_name, strlen(type_name)) @@ -544,11 +553,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: *mut CassDataType, + data_type_raw: CassBorrowedSharedPtr, 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(); @@ -564,11 +573,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: CassBorrowedSharedPtr, 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); @@ -580,7 +589,7 @@ pub unsafe extern "C" fn cass_data_type_keyspace( #[no_mangle] pub unsafe extern "C" fn cass_data_type_set_keyspace( - data_type: *mut CassDataType, + data_type: CassBorrowedSharedPtr, keyspace: *const c_char, ) -> CassError { cass_data_type_set_keyspace_n(data_type, keyspace, strlen(keyspace)) @@ -588,11 +597,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: *mut CassDataType, + data_type: CassBorrowedSharedPtr, 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(); @@ -608,11 +617,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: CassBorrowedSharedPtr, 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); @@ -624,7 +633,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: *mut CassDataType, + data_type: CassBorrowedSharedPtr, class_name: *const ::std::os::raw::c_char, ) -> CassError { cass_data_type_set_class_name_n(data_type, class_name, strlen(class_name)) @@ -632,11 +641,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: *mut CassDataType, + data_type: CassBorrowedSharedPtr, 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(); @@ -650,8 +659,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: CassBorrowedSharedPtr, +) -> 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, @@ -669,21 +680,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: CassBorrowedSharedPtr, +) -> 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: CassBorrowedSharedPtr, index: size_t, -) -> *const CassDataType { - let data_type = ArcFFI::as_ref(data_type); +) -> CassBorrowedSharedPtr { + 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), } @@ -691,37 +704,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: CassBorrowedSharedPtr, name: *const ::std::os::raw::c_char, -) -> *const CassDataType { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, name: *const ::std::os::raw::c_char, name_length: size_t, -) -> *const CassDataType { - let data_type = ArcFFI::as_ref(data_type); +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, 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, @@ -736,13 +749,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: *mut CassDataType, - sub_data_type: *const CassDataType, + data_type: CassBorrowedSharedPtr, + sub_data_type: CassBorrowedSharedPtr, ) -> 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, @@ -751,24 +764,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: *mut CassDataType, + data_type: CassBorrowedSharedPtr, name: *const c_char, - sub_data_type: *const CassDataType, + sub_data_type: CassBorrowedSharedPtr, ) -> 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: *mut CassDataType, + data_type_raw: CassBorrowedSharedPtr, name: *const c_char, name_length: size_t, - sub_data_type_raw: *const CassDataType, + sub_data_type_raw: CassBorrowedSharedPtr, ) -> 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 @@ -782,7 +795,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: *mut CassDataType, + data_type: CassBorrowedSharedPtr, sub_value_type: CassValueType, ) -> CassError { let sub_data_type = CassDataType::new_arced(CassDataTypeInner::Value(sub_value_type)); @@ -791,7 +804,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: *mut CassDataType, + data_type: CassBorrowedSharedPtr, name: *const c_char, sub_value_type: CassValueType, ) -> CassError { @@ -801,7 +814,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: *mut CassDataType, + data_type: CassBorrowedSharedPtr, 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 cc7d731b..fddcf122 100644 --- a/scylla-rust-wrapper/src/cluster.rs +++ b/scylla-rust-wrapper/src/cluster.rs @@ -196,7 +196,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() -> CassOwnedExclusivePtr { let default_execution_profile_builder = ExecutionProfileBuilder::default() .consistency(DEFAULT_CONSISTENCY) .request_timeout(Some(DEFAULT_REQUEST_TIMEOUT)); @@ -236,13 +236,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: CassOwnedExclusivePtr) { BoxFFI::free(cluster); } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_contact_points( - cluster: *mut CassCluster, + cluster: CassBorrowedExclusivePtr, contact_points: *const c_char, ) -> CassError { cass_cluster_set_contact_points_n(cluster, contact_points, strlen(contact_points)) @@ -250,7 +250,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: CassBorrowedExclusivePtr, contact_points: *const c_char, contact_points_length: size_t, ) -> CassError { @@ -261,11 +261,11 @@ pub unsafe extern "C" fn cass_cluster_set_contact_points_n( } unsafe fn cluster_set_contact_points( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedExclusivePtr, 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(',') @@ -291,7 +291,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: CassBorrowedExclusivePtr, _enabled: cass_bool_t, ) -> CassError { // FIXME: should set `use_randomized_contact_points` flag in cluster config @@ -301,7 +301,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: CassBorrowedExclusivePtr, app_name: *const c_char, ) { cass_cluster_set_application_name_n(cluster_raw, app_name, strlen(app_name)) @@ -309,11 +309,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: CassBorrowedExclusivePtr, 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 @@ -325,7 +325,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: CassBorrowedExclusivePtr, app_version: *const c_char, ) { cass_cluster_set_application_version_n(cluster_raw, app_version, strlen(app_version)) @@ -333,11 +333,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: CassBorrowedExclusivePtr, 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(); @@ -351,10 +351,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: CassBorrowedExclusivePtr, 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(); @@ -369,29 +369,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: CassBorrowedExclusivePtr, 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: CassBorrowedExclusivePtr, 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: CassBorrowedExclusivePtr, 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)); @@ -400,10 +400,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: CassBorrowedExclusivePtr, 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; @@ -411,10 +411,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: CassBorrowedExclusivePtr, 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; @@ -422,19 +422,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: CassBorrowedExclusivePtr, 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: CassBorrowedExclusivePtr, 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 @@ -444,10 +444,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: CassBorrowedExclusivePtr, 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()); @@ -455,10 +455,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: CassBorrowedExclusivePtr, 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()); @@ -466,21 +466,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: CassBorrowedExclusivePtr, 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: CassBorrowedExclusivePtr, username: *const c_char, password: *const c_char, ) { @@ -495,7 +495,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: CassBorrowedExclusivePtr, username_raw: *const c_char, username_length: size_t, password_raw: *const c_char, @@ -505,20 +505,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: CassBorrowedExclusivePtr, +) { + 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: CassBorrowedExclusivePtr, local_dc: *const c_char, used_hosts_per_remote_dc: c_uint, allow_remote_dcs_for_local_cl: cass_bool_t, @@ -559,13 +561,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: CassBorrowedExclusivePtr, 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, @@ -578,7 +580,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: CassBorrowedExclusivePtr, local_dc_raw: *const c_char, local_rack_raw: *const c_char, ) -> CassError { @@ -593,13 +595,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: CassBorrowedExclusivePtr, 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, @@ -640,7 +642,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: CassBorrowedExclusivePtr, path: *const c_char, path_length: size_t, ) -> CassError { @@ -656,7 +658,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: CassBorrowedExclusivePtr, base_delay_ms: cass_uint64_t, max_delay_ms: cass_uint64_t, ) -> CassError { @@ -691,7 +693,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: CassBorrowedExclusivePtr, _i: size_t, _name: *const c_char, _name_length: size_t, @@ -702,16 +704,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: CassBorrowedExclusivePtr, +) -> size_t { 0 } #[no_mangle] pub unsafe extern "C" fn cass_cluster_set_use_beta_protocol_version( - cluster_raw: *mut CassCluster, + cluster_raw: CassBorrowedExclusivePtr, 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 @@ -719,10 +723,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: CassBorrowedExclusivePtr, 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 @@ -734,7 +738,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: CassBorrowedExclusivePtr, _queue_size: c_uint, ) -> CassError { // In Cpp Driver this function is also a no-op... @@ -743,7 +747,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: CassBorrowedExclusivePtr, constant_delay_ms: cass_int64_t, max_speculative_executions: c_int, ) -> CassError { @@ -751,7 +755,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, @@ -767,9 +771,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: CassBorrowedExclusivePtr, ) -> 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) @@ -780,19 +784,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: CassBorrowedExclusivePtr, 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: CassBorrowedExclusivePtr, 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 @@ -801,12 +805,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: CassBorrowedExclusivePtr, + retry_policy: CassBorrowedSharedPtr, ) { - 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 _, @@ -818,9 +822,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: CassBorrowedExclusivePtr, + ssl: CassBorrowedSharedPtr, +) { + 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`. @@ -831,10 +838,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: CassBorrowedExclusivePtr, 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), @@ -846,23 +853,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: CassBorrowedExclusivePtr, 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: CassBorrowedExclusivePtr, 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)) @@ -873,10 +880,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: CassBorrowedExclusivePtr, 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, @@ -891,10 +898,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: CassBorrowedExclusivePtr, 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, @@ -909,21 +916,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: CassBorrowedExclusivePtr, name: *const c_char, - profile: *const CassExecProfile, + profile: CassBorrowedExclusivePtr, ) -> 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: CassBorrowedExclusivePtr, name: *const c_char, name_length: size_t, - profile: *const CassExecProfile, + profile: CassBorrowedExclusivePtr, ) -> 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()) { @@ -932,7 +939,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; @@ -964,26 +971,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, @@ -991,6 +1003,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 }) => { @@ -1004,13 +1017,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 { @@ -1026,10 +1040,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 { @@ -1043,22 +1063,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(), ), @@ -1066,7 +1101,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(), ), @@ -1078,12 +1113,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, ), @@ -1091,7 +1131,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(), ), @@ -1108,23 +1148,25 @@ mod tests { #[ntest::timeout(100)] fn test_register_exec_profile() { unsafe { - let cluster_raw = cass_cluster_new(); - let exec_profile_raw = cass_execution_profile_new(); + let mut cluster_raw = cass_cluster_new(); + let mut 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_mut() ), 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 @@ -1134,13 +1176,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_mut() ), 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 @@ -1149,12 +1193,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_mut() ), 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 @@ -1167,9 +1213,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_mut() ), CassError::CASS_ERROR_LIB_BAD_PARAMS ); @@ -1178,9 +1224,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_mut() ), CassError::CASS_ERROR_LIB_BAD_PARAMS ); @@ -1189,14 +1235,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_mut(), ), 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 77628659..0586781f 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 { +) -> CassOwnedExclusivePtr { 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: CassBorrowedSharedPtr, item_count: size_t, -) -> *mut CassCollection { - let data_type = ArcFFI::cloned_from_ptr(data_type); +) -> CassOwnedExclusivePtr { + 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: CassBorrowedSharedPtr, +) -> CassBorrowedSharedPtr { + let collection_ref = BoxFFI::as_ref(collection).unwrap(); match &collection_ref.data_type { Some(dt) => ArcFFI::as_ptr(dt), @@ -203,7 +203,9 @@ 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: CassOwnedExclusivePtr, +) { BoxFFI::free(collection); } @@ -253,22 +255,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 +284,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 +315,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 +358,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 +392,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 +413,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 +435,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 +452,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 +473,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 +495,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,12 +521,12 @@ 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().into_c_const()); 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); 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 7aba480f..a61fd536 100644 --- a/scylla-rust-wrapper/src/exec_profile.rs +++ b/scylla-rust-wrapper/src/exec_profile.rs @@ -13,7 +13,10 @@ use scylla::policies::retry::RetryPolicy; use scylla::policies::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, CMut, CassBorrowedExclusivePtr, CassBorrowedSharedPtr, + CassOwnedExclusivePtr, +}; use crate::batch::CassBatch; use crate::cass_error::CassError; use crate::cass_types::CassConsistency; @@ -171,12 +174,15 @@ 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() -> CassOwnedExclusivePtr +{ 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: CassOwnedExclusivePtr, +) { BoxFFI::free(profile); } @@ -184,7 +190,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: CassBorrowedExclusivePtr, name: *const c_char, ) -> CassError { cass_statement_set_execution_profile_n(statement, name, strlen(name)) @@ -192,11 +198,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: CassBorrowedExclusivePtr, 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 +212,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: CassBorrowedExclusivePtr, name: *const c_char, ) -> CassError { cass_batch_set_execution_profile_n(batch, name, strlen(name)) @@ -214,11 +220,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: CassBorrowedExclusivePtr, 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 +254,10 @@ impl CassExecProfile { #[no_mangle] pub unsafe extern "C" fn cass_execution_profile_set_consistency( - profile: *mut CassExecProfile, + profile: CassBorrowedExclusivePtr, 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 +270,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: CassBorrowedExclusivePtr, ) -> 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 +281,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: CassBorrowedExclusivePtr, 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 +303,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: CassBorrowedExclusivePtr, 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 +316,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: CassBorrowedExclusivePtr, 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 +335,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: CassBorrowedExclusivePtr, local_dc: *const c_char, used_hosts_per_remote_dc: cass_uint32_t, allow_remote_dcs_for_local_cl: cass_bool_t, @@ -345,13 +351,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: CassBorrowedExclusivePtr, 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 +370,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: CassBorrowedExclusivePtr, local_dc_raw: *const c_char, local_rack_raw: *const c_char, ) -> CassError { @@ -379,13 +385,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: CassBorrowedExclusivePtr, 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 +404,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: CassBorrowedExclusivePtr, ) -> 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 +414,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: CassBorrowedExclusivePtr, 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 +427,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: CassBorrowedExclusivePtr, + retry_policy: CassBorrowedSharedPtr, ) -> 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 +443,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: CassBorrowedExclusivePtr, 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 +464,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: CassBorrowedExclusivePtr, 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 +477,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: CassBorrowedExclusivePtr, 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 +522,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 +554,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 +570,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 +579,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 +622,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 +641,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 +682,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 +707,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 +715,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 +752,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 3601a58c..ba008111 100644 --- a/scylla-rust-wrapper/src/future.rs +++ b/scylla-rust-wrapper/src/future.rs @@ -27,8 +27,9 @@ type CassFutureError = (CassError, String); pub type CassFutureResult = Result; -pub type CassFutureCallback = - Option; +pub type CassFutureCallback = Option< + unsafe extern "C" fn(future: CassBorrowedSharedPtr, data: *mut c_void), +>; struct BoundCallback { pub cb: CassFutureCallback, @@ -40,8 +41,10 @@ struct BoundCallback { unsafe impl Send for BoundCallback {} impl BoundCallback { - unsafe fn invoke(self, fut_ptr: *mut CassFuture) { - self.cb.unwrap()(fut_ptr, self.data); + fn invoke(self, fut_ptr: CassBorrowedSharedPtr) { + unsafe { + self.cb.unwrap()(fut_ptr, self.data); + } } } @@ -73,8 +76,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 _ + ) -> CassOwnedSharedPtr { + Self::new_from_future(fut).into_raw() } pub fn new_from_future( @@ -94,11 +97,9 @@ impl CassFuture { guard.callback.take() }; if let Some(bound_cb) = maybe_cb { - let fut_ptr = ArcFFI::as_ptr(&cass_fut_clone) as *mut _; + let fut_ptr = ArcFFI::as_ptr::(&cass_fut_clone); // Safety: pointer is valid, because we get it from arc allocation. - unsafe { - bound_cb.invoke(fut_ptr); - } + bound_cb.invoke(fut_ptr); } cass_fut_clone.wait_for_value.notify_all(); @@ -262,7 +263,7 @@ impl CassFuture { pub unsafe fn set_callback( &self, - self_ptr: *mut CassFuture, + self_ptr: CassBorrowedSharedPtr, cb: CassFutureCallback, data: *mut c_void, ) -> CassError { @@ -283,7 +284,7 @@ impl CassFuture { CassError::CASS_OK } - fn into_raw(self: Arc) -> *const Self { + fn into_raw(self: Arc) -> CassOwnedSharedPtr { ArcFFI::into_ptr(self) } } @@ -296,31 +297,38 @@ impl CheckSendSync for CassFuture {} #[no_mangle] pub unsafe extern "C" fn cass_future_set_callback( - future_raw: *mut CassFuture, + future_raw: CassBorrowedSharedPtr, 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: *mut CassFuture) { - ArcFFI::as_ref(future_raw).with_waited_result(|_| ()); +pub unsafe extern "C" fn cass_future_wait(future_raw: CassBorrowedSharedPtr) { + ArcFFI::as_ref(future_raw) + .unwrap() + .with_waited_result(|_| ()); } #[no_mangle] pub unsafe extern "C" fn cass_future_wait_timed( - future_raw: *mut CassFuture, + future_raw: CassBorrowedSharedPtr, 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: *mut 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: CassBorrowedSharedPtr, +) -> 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, @@ -328,93 +336,106 @@ pub unsafe extern "C" fn cass_future_ready(future_raw: *mut CassFuture) -> cass_ } #[no_mangle] -pub unsafe extern "C" fn cass_future_error_code(future_raw: *mut 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: CassBorrowedSharedPtr, +) -> 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: CassBorrowedSharedPtr, 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: *mut CassFuture) { +pub unsafe extern "C" fn cass_future_free(future_raw: CassOwnedSharedPtr) { ArcFFI::free(future_raw); } #[no_mangle] -pub unsafe extern "C" fn cass_future_get_result(future_raw: *mut CassFuture) -> *const CassResult { +pub unsafe extern "C" fn cass_future_get_result( + future_raw: CassBorrowedSharedPtr, +) -> CassOwnedSharedPtr { ArcFFI::as_ref(future_raw) + .unwrap() .with_waited_result(|r: &mut CassFutureResult| -> Option> { match r.as_ref().ok()? { CassResultValue::QueryResult(qr) => Some(Arc::clone(qr)), _ => 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: *mut CassFuture, -) -> *const CassErrorResult { + future_raw: CassBorrowedSharedPtr, +) -> CassOwnedSharedPtr { ArcFFI::as_ref(future_raw) + .unwrap() .with_waited_result(|r: &mut CassFutureResult| -> Option> { match r.as_ref().ok()? { CassResultValue::QueryError(qr) => Some(Arc::clone(qr)), _ => 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: CassBorrowedSharedPtr, +) -> CassOwnedSharedPtr { ArcFFI::as_ref(future_raw) + .unwrap() .with_waited_result(|r: &mut CassFutureResult| -> Option> { match r.as_ref().ok()? { CassResultValue::Prepared(p) => Some(Arc::clone(p)), _ => 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: *mut CassFuture, + future: CassBorrowedSharedPtr, 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)] @@ -442,12 +463,18 @@ mod tests { }; let cass_fut = CassFuture::make_raw(fut); - struct PtrWrapper(*mut CassFuture); + struct PtrWrapper(CassBorrowedSharedPtr<'static, CassFuture, CMut>); 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::< + CassBorrowedSharedPtr<'_, CassFuture, CMut>, + CassBorrowedSharedPtr<'static, CassFuture, CMut>, + >(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)); }); @@ -473,11 +500,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. @@ -501,7 +530,10 @@ mod tests { const HUNDRED_MILLIS_IN_MICROS: u64 = 100 * 1000; let create_future_and_flag = || { - unsafe extern "C" fn mark_flag_cb(_fut: *mut CassFuture, data: *mut c_void) { + unsafe extern "C" fn mark_flag_cb( + _fut: CassBorrowedSharedPtr, + data: *mut c_void, + ) { let flag = data as *mut bool; *flag = true; } @@ -515,7 +547,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 ); @@ -525,7 +561,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); @@ -550,10 +586,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..6bdb71aa 100644 --- a/scylla-rust-wrapper/src/integration_testing.rs +++ b/scylla-rust-wrapper/src/integration_testing.rs @@ -1,34 +1,34 @@ use std::ffi::{c_char, CString}; -use crate::{ - argconv::BoxFFI, - cluster::CassCluster, - types::{cass_int32_t, cass_uint16_t, size_t}, -}; +use crate::argconv::{BoxFFI, CMut, CassBorrowedExclusivePtr}; +use crate::cluster::CassCluster; +use crate::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: CassBorrowedExclusivePtr, ) -> 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: CassBorrowedExclusivePtr, +) -> 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: CassBorrowedExclusivePtr, 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/iterator.rs b/scylla-rust-wrapper/src/iterator.rs index 732af05e..43974ddd 100644 --- a/scylla-rust-wrapper/src/iterator.rs +++ b/scylla-rust-wrapper/src/iterator.rs @@ -1,4 +1,7 @@ -use crate::argconv::{write_str_to_c, ArcFFI, BoxFFI, RefFFI}; +use crate::argconv::{ + write_str_to_c, ArcFFI, BoxFFI, CConst, CMut, CassBorrowedExclusivePtr, CassBorrowedSharedPtr, + CassOwnedExclusivePtr, RefFFI, +}; use crate::cass_error::CassError; use crate::cass_types::{CassDataType, CassValueType}; use crate::metadata::{ @@ -117,13 +120,15 @@ 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: CassOwnedExclusivePtr) { BoxFFI::free(iterator); } #[no_mangle] -pub unsafe extern "C" fn cass_iterator_type(iterator: *mut CassIterator) -> CassIteratorType { - let iter = BoxFFI::as_ref(iterator); +pub unsafe extern "C" fn cass_iterator_type( + iterator: CassBorrowedExclusivePtr, +) -> CassIteratorType { + let iter = BoxFFI::as_ref(iterator).unwrap(); match iter { CassIterator::Result(_) => CassIteratorType::CASS_ITERATOR_TYPE_RESULT, @@ -144,8 +149,10 @@ pub unsafe extern "C" fn cass_iterator_type(iterator: *mut CassIterator) -> Cass // 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: CassBorrowedExclusivePtr, +) -> cass_bool_t { + let mut iter = BoxFFI::as_mut_ref(iterator).unwrap(); match &mut iter { CassIterator::Result(result_iterator) => { @@ -250,60 +257,62 @@ 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: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'result, CassRow, CConst> { + let iter = BoxFFI::as_ref(iterator).unwrap(); // Defined only for result iterator, for other types should return null if let CassIterator::Result(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: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'result, CassValue, CConst> { + let iter = BoxFFI::as_ref(iterator).unwrap(); // Defined only for row iterator, for other types should return null if let CassIterator::Row(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: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'result, CassValue, CConst> { + 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::Collection(collection_iterator) @@ -311,7 +320,7 @@ pub unsafe extern "C" fn cass_iterator_get_value( { 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 { @@ -325,80 +334,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: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'result, CassValue, CConst> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::Map(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: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'result, CassValue, CConst> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::Map(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: CassBorrowedSharedPtr, 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::UdtFields(udt_iterator) = iter { let iter_position = match udt_iterator.position { @@ -428,46 +437,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<'schema>( + iterator: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'schema, CassValue, CConst> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::UdtFields(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: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'schema, CassKeyspaceMeta, CConst> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::KeyspacesMeta(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 @@ -477,24 +486,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: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'schema, CassTableMeta, CConst> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::TablesMeta(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 @@ -505,23 +514,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<'schema>( + iterator: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'schema, CassDataType, CConst> { + let iter = BoxFFI::as_ref(iterator).unwrap(); if let CassIterator::UserTypes(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 @@ -532,24 +541,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: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'schema, CassColumnMeta, CConst> { + let iter = BoxFFI::as_ref(iterator).unwrap(); match iter { CassIterator::ColumnsMeta(CassColumnsMetaIterator::FromTable(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 @@ -559,14 +568,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::ColumnsMeta(CassColumnsMetaIterator::FromView(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 @@ -577,19 +586,19 @@ 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: CassBorrowedSharedPtr, CConst>, +) -> CassBorrowedSharedPtr<'schema, CassMaterializedViewMeta, CConst> { + let iter = BoxFFI::as_ref(iterator).unwrap(); match iter { CassIterator::MaterializedViewsMeta(CassMaterializedViewsMetaIterator::FromKeyspace( @@ -597,14 +606,14 @@ pub unsafe extern "C" fn cass_iterator_get_materialized_view_meta( )) => { 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::MaterializedViewsMeta(CassMaterializedViewsMetaIterator::FromTable( @@ -612,25 +621,26 @@ pub unsafe extern "C" fn cass_iterator_get_materialized_view_meta( )) => { 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] +#[allow(clippy::needless_lifetimes)] pub unsafe extern "C" fn cass_iterator_from_result<'result>( - result: *const CassResult, -) -> *mut CassIterator<'result> { - let result_from_raw = ArcFFI::as_ref(result); + result: CassBorrowedSharedPtr<'result, CassResult, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let result_from_raw = ArcFFI::as_ref(result).unwrap(); let iterator = CassResultIterator { result: result_from_raw, @@ -641,10 +651,11 @@ pub unsafe extern "C" fn cass_iterator_from_result<'result>( } #[no_mangle] +#[allow(clippy::needless_lifetimes)] pub unsafe extern "C" fn cass_iterator_from_row<'result>( - row: *const CassRow, -) -> *mut CassIterator<'result> { - let row_from_raw = RefFFI::as_ref(row); + row: CassBorrowedSharedPtr<'result, CassRow, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let row_from_raw = RefFFI::as_ref(row).unwrap(); let iterator = CassRowIterator { row: row_from_raw, @@ -655,21 +666,22 @@ pub unsafe extern "C" fn cass_iterator_from_row<'result>( } #[no_mangle] +#[allow(clippy::needless_lifetimes)] 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; + value: CassBorrowedSharedPtr<'result, CassValue, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + 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, @@ -681,10 +693,11 @@ pub unsafe extern "C" fn cass_iterator_from_collection<'result>( } #[no_mangle] +#[allow(clippy::needless_lifetimes)] pub unsafe extern "C" fn cass_iterator_from_tuple<'result>( - value: *const CassValue, -) -> *mut CassIterator<'result> { - let tuple = RefFFI::as_ref(value); + value: CassBorrowedSharedPtr<'result, CassValue, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let tuple = RefFFI::as_ref(value).unwrap(); if let Some(Value::CollectionValue(Collection::Tuple(val))) = &tuple.value { let item_count = val.len(); @@ -697,14 +710,15 @@ pub unsafe extern "C" fn cass_iterator_from_tuple<'result>( return BoxFFI::into_ptr(Box::new(CassIterator::Tuple(iterator))); } - std::ptr::null_mut() + BoxFFI::null_mut() } #[no_mangle] +#[allow(clippy::needless_lifetimes)] pub unsafe extern "C" fn cass_iterator_from_map<'result>( - value: *const CassValue, -) -> *mut CassIterator<'result> { - let map = RefFFI::as_ref(value); + value: CassBorrowedSharedPtr<'result, CassValue, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let map = RefFFI::as_ref(value).unwrap(); if let Some(Value::CollectionValue(Collection::Map(val))) = &map.value { let item_count = val.len(); @@ -717,14 +731,15 @@ pub unsafe extern "C" fn cass_iterator_from_map<'result>( return BoxFFI::into_ptr(Box::new(CassIterator::Map(iterator))); } - std::ptr::null_mut() + BoxFFI::null_mut() } #[no_mangle] +#[allow(clippy::needless_lifetimes)] pub unsafe extern "C" fn cass_iterator_fields_from_user_type<'result>( - value: *const CassValue, -) -> *mut CassIterator<'result> { - let udt = RefFFI::as_ref(value); + value: CassBorrowedSharedPtr<'result, CassValue, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let udt = RefFFI::as_ref(value).unwrap(); if let Some(Value::CollectionValue(Collection::UserDefinedType { fields, .. })) = &udt.value { let item_count = fields.len(); @@ -737,14 +752,15 @@ pub unsafe extern "C" fn cass_iterator_fields_from_user_type<'result>( return BoxFFI::into_ptr(Box::new(CassIterator::UdtFields(iterator))); } - std::ptr::null_mut() + BoxFFI::null_mut() } #[no_mangle] +#[allow(clippy::needless_lifetimes)] 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); + schema_meta: CassBorrowedSharedPtr<'schema, CassSchemaMeta, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let metadata = BoxFFI::as_ref(schema_meta).unwrap(); let iterator = CassSchemaMetaIterator { value: metadata, @@ -756,10 +772,11 @@ pub unsafe extern "C" fn cass_iterator_keyspaces_from_schema_meta<'schema>( } #[no_mangle] +#[allow(clippy::needless_lifetimes)] 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); + keyspace_meta: CassBorrowedSharedPtr<'schema, CassKeyspaceMeta, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let metadata = RefFFI::as_ref(keyspace_meta).unwrap(); let iterator = CassKeyspaceMetaIterator { value: metadata, @@ -771,10 +788,11 @@ pub unsafe extern "C" fn cass_iterator_tables_from_keyspace_meta<'schema>( } #[no_mangle] +#[allow(clippy::needless_lifetimes)] 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); + keyspace_meta: CassBorrowedSharedPtr<'schema, CassKeyspaceMeta, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let metadata = RefFFI::as_ref(keyspace_meta).unwrap(); let iterator = CassKeyspaceMetaIterator { value: metadata, @@ -788,10 +806,11 @@ pub unsafe extern "C" fn cass_iterator_materialized_views_from_keyspace_meta<'sc } #[no_mangle] +#[allow(clippy::needless_lifetimes)] 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); + keyspace_meta: CassBorrowedSharedPtr<'schema, CassKeyspaceMeta, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let metadata = RefFFI::as_ref(keyspace_meta).unwrap(); let iterator = CassKeyspaceMetaIterator { value: metadata, @@ -803,10 +822,11 @@ pub unsafe extern "C" fn cass_iterator_user_types_from_keyspace_meta<'schema>( } #[no_mangle] +#[allow(clippy::needless_lifetimes)] 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); + table_meta: CassBorrowedSharedPtr<'schema, CassTableMeta, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let metadata = RefFFI::as_ref(table_meta).unwrap(); let iterator = CassTableMetaIterator { value: metadata, @@ -819,10 +839,12 @@ pub unsafe extern "C" fn cass_iterator_columns_from_table_meta<'schema>( ))) } +#[no_mangle] +#[allow(clippy::needless_lifetimes)] 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); + table_meta: CassBorrowedSharedPtr<'schema, CassTableMeta, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let metadata = RefFFI::as_ref(table_meta).unwrap(); let iterator = CassTableMetaIterator { value: metadata, @@ -835,10 +857,12 @@ pub unsafe extern "C" fn cass_iterator_materialized_views_from_table_meta<'schem ))) } +#[no_mangle] +#[allow(clippy::needless_lifetimes)] 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); + view_meta: CassBorrowedSharedPtr<'schema, CassMaterializedViewMeta, CConst>, +) -> CassOwnedExclusivePtr, CMut> { + let metadata = RefFFI::as_ref(view_meta).unwrap(); let iterator = CassViewMetaIterator { value: metadata, diff --git a/scylla-rust-wrapper/src/lib.rs b/scylla-rust-wrapper/src/lib.rs index 76069616..f4dfa31b 100644 --- a/scylla-rust-wrapper/src/lib.rs +++ b/scylla-rust-wrapper/src/lib.rs @@ -8,7 +8,8 @@ use tokio::runtime::Runtime; #[macro_use] mod binding; -mod argconv; +// pub, because doctests defined in `argconv` module need to access it. +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..309dd07b 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, CConst, CassBorrowedSharedPtr, RefFFI}; use crate::cass_log_types::{CassLogLevel, CassLogMessage}; use crate::types::size_t; use crate::LOGGER; @@ -16,10 +16,15 @@ use tracing_subscriber::Layer; impl RefFFI for CassLogMessage {} -pub type CassLogCallback = - Option; +pub type CassLogCallback = Option< + unsafe extern "C" fn(message: CassBorrowedSharedPtr, 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: CassBorrowedSharedPtr, + _data: *mut c_void, +) { +} pub struct Logger { pub cb: CassLogCallback, @@ -64,8 +69,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: CassBorrowedSharedPtr, + _data: *mut c_void, +) { + let message = RefFFI::as_ref(message).unwrap(); eprintln!( "{} [{}] ({}:{}) {}", @@ -132,7 +140,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 c7e7b5f6..6219cb7b 100644 --- a/scylla-rust-wrapper/src/metadata.rs +++ b/scylla-rust-wrapper/src/metadata.rs @@ -107,68 +107,70 @@ pub fn create_table_metadata(table_name: &str, table_metadata: &Table) -> CassTa } #[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: CassOwnedExclusivePtr, +) { BoxFFI::free(schema_meta); } #[no_mangle] pub unsafe extern "C" fn cass_schema_meta_keyspace_by_name( - schema_meta: *const CassSchemaMeta, + schema_meta: CassBorrowedSharedPtr, keyspace_name: *const c_char, -) -> *const CassKeyspaceMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, keyspace_name: *const c_char, keyspace_name_length: size_t, -) -> *const CassKeyspaceMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, 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: CassBorrowedSharedPtr, type_: *const c_char, -) -> *const CassDataType { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, type_: *const c_char, type_length: size_t, -) -> *const CassDataType { +) -> CassBorrowedSharedPtr { 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 @@ -176,60 +178,62 @@ 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: CassBorrowedSharedPtr, table: *const c_char, -) -> *const CassTableMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, table: *const c_char, table_length: size_t, -) -> *const CassTableMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, 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: CassBorrowedSharedPtr, +) -> 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_column( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedSharedPtr, index: size_t, -) -> *const CassColumnMeta { +) -> CassBorrowedSharedPtr { // The order of columns in cpp-driver (and in DESCRIBE TABLE in cqlsh): // 1. partition keys sorted by position <- this is guaranteed by rust-driver. // Table::partition_keys is a Vector of pk names, sorted by position. @@ -248,7 +252,7 @@ pub unsafe extern "C" fn cass_table_meta_column( // Then cks by position: h, i // Then remaining columns alphabetically: b, c, f, g - let table_meta = RefFFI::as_ref(table_meta); + let table_meta = RefFFI::as_ref(table_meta).unwrap(); let index = index as usize; // Check if the index lands in partition keys. If so, simply return the corresponding column. @@ -272,7 +276,7 @@ pub unsafe extern "C" fn cass_table_meta_column( table_meta .non_key_sorted_columns .get(index) - .map_or(std::ptr::null(), |column_name| { + .map_or(RefFFI::null(), |column_name| { // unwrap: We guarantee that column_name exists in columns_metadata. See `create_table_metadata`. RefFFI::as_ptr(table_meta.columns_metadata.get(column_name).unwrap()) }) @@ -280,246 +284,244 @@ pub unsafe extern "C" fn cass_table_meta_column( #[no_mangle] pub unsafe extern "C" fn cass_table_meta_partition_key( - table_meta: *const CassTableMeta, + table_meta: CassBorrowedSharedPtr, index: size_t, -) -> *const CassColumnMeta { - let table_meta = RefFFI::as_ref(table_meta); +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, ) -> 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: CassBorrowedSharedPtr, index: size_t, -) -> *const CassColumnMeta { - let table_meta = RefFFI::as_ref(table_meta); +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, ) -> 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: CassBorrowedSharedPtr, column: *const c_char, -) -> *const CassColumnMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, column: *const c_char, column_length: size_t, -) -> *const CassColumnMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, 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: CassBorrowedSharedPtr, +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, ) -> 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: CassBorrowedSharedPtr, view: *const c_char, -) -> *const CassMaterializedViewMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, view: *const c_char, view_length: size_t, -) -> *const CassMaterializedViewMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, view: *const c_char, -) -> *const CassMaterializedViewMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, view: *const c_char, view_length: size_t, -) -> *const CassMaterializedViewMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, ) -> 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: CassBorrowedSharedPtr, index: size_t, -) -> *const CassMaterializedViewMeta { - let table_meta = RefFFI::as_ref(table_meta); +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, column: *const c_char, -) -> *const CassColumnMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, column: *const c_char, column_length: size_t, -) -> *const CassColumnMeta { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, 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); - - match view_meta.base_table.upgrade() { - Some(arc) => RefFFI::as_ptr(&arc), - None => { - tracing::error!("Failed to upgrade a weak reference to table metadata from materialized view metadata! This is a driver bug!"); - std::ptr::null() - } + view_meta: CassBorrowedSharedPtr, +) -> CassBorrowedSharedPtr { + let view_meta = RefFFI::as_ref(view_meta).unwrap(); + + let ptr = RefFFI::weak_as_ptr(&view_meta.base_table); + if RefFFI::is_null(&ptr) { + tracing::error!("Failed to upgrade a weak reference to table metadata from materialized view metadata! This is a driver bug!"); } + ptr } #[no_mangle] pub unsafe extern "C" fn cass_materialized_view_meta_column_count( - view_meta: *const CassMaterializedViewMeta, + view_meta: CassBorrowedSharedPtr, ) -> 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: CassBorrowedSharedPtr, index: size_t, -) -> *const CassColumnMeta { - let view_meta = RefFFI::as_ref(view_meta); +) -> CassBorrowedSharedPtr { + let view_meta = RefFFI::as_ref(view_meta).unwrap(); match view_meta .view_metadata @@ -527,53 +529,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: CassBorrowedSharedPtr, ) -> 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: CassBorrowedSharedPtr, index: size_t, -) -> *const CassColumnMeta { - let view_meta = RefFFI::as_ref(view_meta); +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, ) -> 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: CassBorrowedSharedPtr, index: size_t, -) -> *const CassColumnMeta { - let view_meta = RefFFI::as_ref(view_meta); +) -> CassBorrowedSharedPtr { + 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 b17ee666..0bb448ea 100644 --- a/scylla-rust-wrapper/src/prepared.rs +++ b/scylla-rust-wrapper/src/prepared.rs @@ -76,15 +76,17 @@ 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: CassOwnedSharedPtr, +) { 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: CassBorrowedSharedPtr, +) -> CassOwnedExclusivePtr { + 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 @@ -107,12 +109,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: CassBorrowedSharedPtr, 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 @@ -129,38 +131,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: CassBorrowedSharedPtr, index: size_t, -) -> *const CassDataType { - let prepared = ArcFFI::as_ref(prepared_raw); +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, name: *const c_char, -) -> *const CassDataType { +) -> CassBorrowedSharedPtr { 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: CassBorrowedSharedPtr, name: *const c_char, name_length: size_t, -) -> *const CassDataType { - let prepared = ArcFFI::as_ref(prepared_raw); +) -> CassBorrowedSharedPtr { + 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 9639cf57..19215b1f 100644 --- a/scylla-rust-wrapper/src/query_error.rs +++ b/scylla-rust-wrapper/src/query_error.rs @@ -56,21 +56,25 @@ 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: CassOwnedSharedPtr, +) { 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: CassBorrowedSharedPtr, +) -> 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: CassBorrowedSharedPtr, ) -> 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(ExecutionError::LastAttemptError( RequestAttemptError::DbError(DbError::Unavailable { consistency, .. }, _) @@ -85,9 +89,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: CassBorrowedSharedPtr, ) -> 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(ExecutionError::LastAttemptError(attempt_error)) => { match attempt_error { @@ -109,9 +113,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: CassBorrowedSharedPtr, ) -> 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(ExecutionError::LastAttemptError(attempt_error)) => { match attempt_error { @@ -133,9 +137,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: CassBorrowedSharedPtr, ) -> 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(ExecutionError::LastAttemptError(RequestAttemptError::DbError( DbError::ReadFailure { numfailures, .. }, @@ -151,9 +155,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: CassBorrowedSharedPtr, ) -> 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(ExecutionError::LastAttemptError(RequestAttemptError::DbError( DbError::ReadTimeout { data_present, .. }, @@ -181,9 +185,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: CassBorrowedSharedPtr, ) -> 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(ExecutionError::LastAttemptError(RequestAttemptError::DbError( DbError::WriteTimeout { write_type, .. }, @@ -199,11 +203,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: CassBorrowedSharedPtr, 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(ExecutionError::LastAttemptError(RequestAttemptError::DbError( DbError::AlreadyExists { keyspace, .. }, @@ -225,11 +229,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: CassBorrowedSharedPtr, 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(ExecutionError::LastAttemptError(RequestAttemptError::DbError( DbError::AlreadyExists { table, .. }, @@ -244,11 +248,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: CassBorrowedSharedPtr, 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(ExecutionError::LastAttemptError(RequestAttemptError::DbError( DbError::FunctionFailure { function, .. }, @@ -262,8 +266,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: CassBorrowedSharedPtr, +) -> size_t { + let error_result: &CassErrorResult = ArcFFI::as_ref(error_result).unwrap(); match error_result { CassErrorResult::Query(ExecutionError::LastAttemptError(RequestAttemptError::DbError( DbError::FunctionFailure { arg_types, .. }, @@ -275,12 +281,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: CassBorrowedSharedPtr, 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(ExecutionError::LastAttemptError(RequestAttemptError::DbError( DbError::FunctionFailure { arg_types, .. }, diff --git a/scylla-rust-wrapper/src/query_result.rs b/scylla-rust-wrapper/src/query_result.rs index 2883571a..7ba400c5 100644 --- a/scylla-rust-wrapper/src/query_result.rs +++ b/scylla-rust-wrapper/src/query_result.rs @@ -275,37 +275,43 @@ fn get_column_value(column: CqlValue, column_type: &Arc) -> Value } #[no_mangle] -pub unsafe extern "C" fn cass_result_free(result_raw: *const CassResult) { +pub unsafe extern "C" fn cass_result_free(result_raw: CassOwnedSharedPtr) { 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: CassBorrowedSharedPtr, +) -> cass_bool_t { + result_has_more_pages(&result) +} + +unsafe fn result_has_more_pages(result: &CassBorrowedSharedPtr) -> 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: CassBorrowedSharedPtr, index: size_t, -) -> *const CassValue { - let row: &CassRow = RefFFI::as_ref(row_raw); +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, name: *const c_char, -) -> *const CassValue { +) -> CassBorrowedSharedPtr { let name_str = ptr_to_cstr(name).unwrap(); let name_length = name_str.len(); @@ -314,11 +320,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: CassBorrowedSharedPtr, name: *const c_char, name_length: size_t, -) -> *const CassValue { - let row_from_raw = RefFFI::as_ref(row); +) -> CassBorrowedSharedPtr { + 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; @@ -338,20 +344,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: CassBorrowedSharedPtr, 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 { @@ -371,11 +377,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: CassBorrowedSharedPtr, 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) @@ -383,51 +389,55 @@ 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: CassBorrowedSharedPtr, index: size_t, -) -> *const CassDataType { - let result_from_raw: &CassResult = ArcFFI::as_ref(result); +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, +) -> 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: CassBorrowedSharedPtr, +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, output: *mut cass_float_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -442,7 +452,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: CassBorrowedSharedPtr, output: *mut cass_double_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -457,7 +467,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: CassBorrowedSharedPtr, output: *mut cass_bool_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -474,7 +484,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: CassBorrowedSharedPtr, output: *mut cass_int8_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -489,7 +499,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: CassBorrowedSharedPtr, output: *mut cass_int16_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -504,7 +514,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: CassBorrowedSharedPtr, output: *mut cass_uint32_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -519,7 +529,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: CassBorrowedSharedPtr, output: *mut cass_int32_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -534,7 +544,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: CassBorrowedSharedPtr, output: *mut cass_int64_t, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -556,7 +566,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: CassBorrowedSharedPtr, output: *mut CassUuid, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -574,7 +584,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: CassBorrowedSharedPtr, output: *mut CassInet, ) -> CassError { let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value); @@ -589,12 +599,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: CassBorrowedSharedPtr, 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, @@ -611,7 +621,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: CassBorrowedSharedPtr, output: *mut *const c_char, output_size: *mut size_t, ) -> CassError { @@ -636,7 +646,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: CassBorrowedSharedPtr, months: *mut cass_int32_t, days: *mut cass_int32_t, nanos: *mut cass_int64_t, @@ -658,7 +668,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: CassBorrowedSharedPtr, output: *mut *const cass_byte_t, output_size: *mut size_t, ) -> CassError { @@ -684,14 +694,18 @@ 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: CassBorrowedSharedPtr, +) -> 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: CassBorrowedSharedPtr, +) -> cass_bool_t { + let val = RefFFI::as_ref(value).unwrap(); matches!( val.value_type.get_unchecked().get_value_type(), @@ -702,16 +716,20 @@ 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: CassBorrowedSharedPtr, +) -> 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: CassBorrowedSharedPtr, +) -> size_t { + let val = RefFFI::as_ref(collection).unwrap(); match &val.value { Some(Value::CollectionValue(Collection::List(list))) => list.len() as size_t, @@ -727,9 +745,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: CassBorrowedSharedPtr, ) -> CassValueType { - let val = RefFFI::as_ref(collection); + let val = RefFFI::as_ref(collection).unwrap(); match val.value_type.get_unchecked() { CassDataTypeInner::List { @@ -746,9 +764,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: CassBorrowedSharedPtr, ) -> CassValueType { - let val = RefFFI::as_ref(collection); + let val = RefFFI::as_ref(collection).unwrap(); match val.value_type.get_unchecked() { CassDataTypeInner::Map { @@ -760,8 +778,10 @@ 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: CassBorrowedSharedPtr, +) -> size_t { + let result = ArcFFI::as_ref(result_raw).unwrap(); let CassResultKind::Rows(CassRowsResult { rows, .. }) = &result.kind else { return 0; @@ -771,8 +791,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: CassBorrowedSharedPtr, +) -> size_t { + let result = ArcFFI::as_ref(result_raw).unwrap(); let CassResultKind::Rows(CassRowsResult { metadata, .. }) = &result.kind else { return 0; @@ -782,29 +804,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: CassBorrowedSharedPtr, +) -> CassBorrowedSharedPtr { + 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: CassBorrowedSharedPtr, 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() { @@ -834,8 +856,9 @@ mod tests { use scylla::response::PagingStateResponse; use scylla::value::{CqlValue, Row}; + use crate::argconv::CConst; use crate::{ - argconv::ArcFFI, + argconv::{ArcFFI, RefFFI}, cass_error::CassError, cass_types::{CassDataType, CassDataTypeInner, CassValueType}, query_result::{ @@ -846,8 +869,8 @@ mod tests { use std::{ffi::c_char, ptr::addr_of_mut, sync::Arc}; 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, + CassBorrowedSharedPtr, CassResult, CassResultKind, CassResultMetadata, CassRowsResult, }; fn col_spec(name: &'static str, typ: ColumnType<'static>) -> ColumnSpec<'static> { @@ -893,7 +916,7 @@ mod tests { } unsafe fn cass_result_column_name_rust_str( - result_ptr: *const CassResult, + result_ptr: CassBorrowedSharedPtr, column_index: u64, ) -> Option<&'static str> { let mut name_ptr: *const c_char = std::ptr::null(); @@ -910,36 +933,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 @@ -948,24 +974,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( @@ -975,8 +1001,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)); } } } @@ -991,19 +1018,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(); diff --git a/scylla-rust-wrapper/src/retry_policy.rs b/scylla-rust-wrapper/src/retry_policy.rs index bb071450..0e3818a5 100644 --- a/scylla-rust-wrapper/src/retry_policy.rs +++ b/scylla-rust-wrapper/src/retry_policy.rs @@ -3,7 +3,7 @@ use scylla::policies::retry::{ }; use std::sync::Arc; -use crate::argconv::ArcFFI; +use crate::argconv::{ArcFFI, CMut, CassOwnedSharedPtr}; pub enum RetryPolicy { DefaultRetryPolicy(Arc), @@ -16,27 +16,30 @@ pub type CassRetryPolicy = RetryPolicy; impl ArcFFI for CassRetryPolicy {} #[no_mangle] -pub extern "C" fn cass_retry_policy_default_new() -> *mut CassRetryPolicy { +pub extern "C" fn cass_retry_policy_default_new() -> CassOwnedSharedPtr { ArcFFI::into_ptr(Arc::new(RetryPolicy::DefaultRetryPolicy(Arc::new( DefaultRetryPolicy, - )))) as *mut _ + )))) } #[no_mangle] -pub extern "C" fn cass_retry_policy_downgrading_consistency_new() -> *mut CassRetryPolicy { +pub extern "C" fn cass_retry_policy_downgrading_consistency_new( +) -> CassOwnedSharedPtr { ArcFFI::into_ptr(Arc::new(RetryPolicy::DowngradingConsistencyRetryPolicy( Arc::new(DowngradingConsistencyRetryPolicy), - ))) as *mut _ + ))) } #[no_mangle] -pub extern "C" fn cass_retry_policy_fallthrough_new() -> *mut CassRetryPolicy { +pub extern "C" fn cass_retry_policy_fallthrough_new() -> CassOwnedSharedPtr { ArcFFI::into_ptr(Arc::new(RetryPolicy::FallthroughRetryPolicy(Arc::new( FallthroughRetryPolicy, - )))) as *mut _ + )))) } #[no_mangle] -pub unsafe extern "C" fn cass_retry_policy_free(retry_policy: *mut CassRetryPolicy) { +pub unsafe extern "C" fn cass_retry_policy_free( + retry_policy: CassOwnedSharedPtr, +) { ArcFFI::free(retry_policy); } diff --git a/scylla-rust-wrapper/src/session.rs b/scylla-rust-wrapper/src/session.rs index a206ac6a..324d184c 100644 --- a/scylla-rust-wrapper/src/session.rs +++ b/scylla-rust-wrapper/src/session.rs @@ -73,7 +73,7 @@ impl CassSessionInner { session_opt: Arc>>, cluster: &CassCluster, keyspace: Option, - ) -> *mut CassFuture { + ) -> CassOwnedSharedPtr { let session_builder = build_session_builder(cluster); let exec_profile_map = cluster.execution_profile_map().clone(); @@ -140,52 +140,52 @@ 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() -> CassOwnedSharedPtr { 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, -) -> *mut CassFuture { - let session_opt = ArcFFI::cloned_from_ptr(session_raw); - let cluster: &CassCluster = BoxFFI::as_ref(cluster_raw); + session_raw: CassBorrowedSharedPtr, + cluster_raw: CassBorrowedSharedPtr, +) -> CassOwnedSharedPtr { + 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: CassBorrowedSharedPtr, + cluster_raw: CassBorrowedSharedPtr, keyspace: *const c_char, -) -> *mut CassFuture { - cass_session_connect_keyspace_n(session_raw, cluster_raw, keyspace, strlen(keyspace)) as *mut _ +) -> CassOwnedSharedPtr { + 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: CassBorrowedSharedPtr, + cluster_raw: CassBorrowedSharedPtr, keyspace: *const c_char, keyspace_length: size_t, -) -> *mut CassFuture { - let session_opt = ArcFFI::cloned_from_ptr(session_raw); - let cluster: &CassCluster = BoxFFI::as_ref(cluster_raw); +) -> CassOwnedSharedPtr { + 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) as *mut _ + CassSessionInner::connect(session_opt, cluster, keyspace) } #[no_mangle] pub unsafe extern "C" fn cass_session_execute_batch( - session_raw: *mut CassSession, - batch_raw: *const CassBatch, -) -> *mut CassFuture { - let session_opt = ArcFFI::cloned_from_ptr(session_raw); - let batch_from_raw = BoxFFI::as_ref(batch_raw); + session_raw: CassBorrowedSharedPtr, + batch_raw: CassBorrowedSharedPtr, +) -> CassOwnedSharedPtr { + 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; @@ -247,13 +247,13 @@ async fn request_with_timeout( #[no_mangle] pub unsafe extern "C" fn cass_session_execute( - session_raw: *mut CassSession, - statement_raw: *const CassStatement, -) -> *mut CassFuture { - let session_opt = ArcFFI::cloned_from_ptr(session_raw); + session_raw: CassBorrowedSharedPtr, + statement_raw: CassBorrowedSharedPtr, +) -> CassOwnedSharedPtr { + 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; @@ -382,11 +382,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, -) -> *mut CassFuture { - let session = ArcFFI::cloned_from_ptr(cass_session); - let cass_statement = BoxFFI::as_ref(statement); + cass_session: CassBorrowedSharedPtr, + statement: CassBorrowedSharedPtr, +) -> CassOwnedSharedPtr { + 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 { @@ -418,18 +418,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: CassBorrowedSharedPtr, query: *const c_char, -) -> *mut CassFuture { +) -> CassOwnedSharedPtr { 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: CassBorrowedSharedPtr, query: *const c_char, query_length: size_t, -) -> *mut CassFuture { +) -> CassOwnedSharedPtr { 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???) @@ -437,7 +437,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 = Statement::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; @@ -464,13 +464,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: CassOwnedSharedPtr) { ArcFFI::free(session_raw); } #[no_mangle] -pub unsafe extern "C" fn cass_session_close(session: *mut CassSession) -> *mut CassFuture { - let session_opt = ArcFFI::cloned_from_ptr(session); +pub unsafe extern "C" fn cass_session_close( + session: CassBorrowedSharedPtr, +) -> CassOwnedSharedPtr { + let session_opt = ArcFFI::cloned_from_ptr(session).unwrap(); CassFuture::make_raw(async move { let mut session_guard = session_opt.write().await; @@ -488,8 +490,10 @@ pub unsafe extern "C" fn cass_session_close(session: *mut CassSession) -> *mut C } #[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: CassBorrowedSharedPtr, +) -> 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() @@ -497,9 +501,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: CassBorrowedSharedPtr, +) -> CassOwnedExclusivePtr { + let cass_session = ArcFFI::as_ref(session).unwrap(); let mut keyspaces: HashMap = HashMap::new(); for (keyspace_name, keyspace) in cass_session @@ -597,7 +601,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, @@ -618,15 +624,15 @@ mod tests { .try_init(); } - unsafe fn cass_future_wait_check_and_free(fut: *mut CassFuture) { - cass_future_wait(fut); - if cass_future_error_code(fut) != CassError::CASS_OK { + unsafe fn cass_future_wait_check_and_free(fut: CassOwnedSharedPtr) { + 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, &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); } @@ -704,41 +710,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(); + let mut 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().into_c_const(), + )); // 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_mut(), + ); // 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().into_c_const(), + )); + let profile_map_keys = ArcFFI::as_ref(session_raw.borrow()) + .unwrap() .blocking_read() .as_ref() .unwrap() @@ -751,7 +770,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); @@ -788,18 +807,18 @@ 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(); + let mut profile_raw = cass_execution_profile_new(); // A name of a profile that will have been registered in the Cluster. let valid_name = "profile"; let valid_name_c_str = make_c_str!("profile"); @@ -809,36 +828,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_mut(), + ), 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().into_c_const(), + )); { /* 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 @@ -866,7 +898,13 @@ 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().into_c_const() + ) + .borrow() + ), CassError::CASS_ERROR_SERVER_WRITE_FAILURE ); assert!(statement @@ -879,7 +917,13 @@ 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().into_c_const(), + ) + .borrow() + ), CassError::CASS_ERROR_SERVER_WRITE_FAILURE ); assert!(batch @@ -894,20 +938,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, ), @@ -915,12 +968,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 @@ -948,7 +1004,13 @@ 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().into_c_const() + ) + .borrow() + ), CassError::CASS_ERROR_LIB_EXECUTION_PROFILE_INVALID ); assert_eq!( @@ -964,7 +1026,13 @@ 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().into_c_const() + ) + .borrow() + ), CassError::CASS_ERROR_LIB_EXECUTION_PROFILE_INVALID ); assert_eq!( @@ -982,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); @@ -1052,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 WHERE key='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_mut(), + ), 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().into_c_const(), + )); { - 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: CassBorrowedSharedPtr, + statement_raw: CassBorrowedSharedPtr, + ) -> CassError { + cass_future_error_code( + cass_session_execute(session_raw, statement_raw).borrow(), + ) + } + unsafe fn execute_batch( + session_raw: CassBorrowedSharedPtr, + batch_raw: CassBorrowedSharedPtr, + ) -> 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( @@ -1104,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: CassBorrowedSharedPtr, + statement_raw: CassBorrowedSharedPtr, + batch_raw: CassBorrowedSharedPtr, + ) { 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: CassBorrowedSharedPtr, + statement_raw: CassBorrowedSharedPtr, + batch_raw: CassBorrowedSharedPtr, + ) { 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: CassBorrowedExclusivePtr, + batch_raw: CassBorrowedExclusivePtr, + ) { // Set statement/batch exec profile. assert_cass_error_eq!( cass_statement_set_execution_profile(statement_raw, name,), @@ -1140,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: CassBorrowedExclusivePtr, + batch_raw: CassBorrowedExclusivePtr, + ) { + set_provided_exec_profile(profile_name_c_str, statement_raw, batch_raw); + } + unsafe fn unset_exec_profile( + statement_raw: CassBorrowedExclusivePtr, + batch_raw: CassBorrowedExclusivePtr, + ) { + set_provided_exec_profile(std::ptr::null::(), statement_raw, batch_raw); + } + unsafe fn set_retry_policy_on_stmt( + policy: CassBorrowedSharedPtr, + statement_raw: CassBorrowedExclusivePtr, + batch_raw: CassBorrowedExclusivePtr, + ) { 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: CassBorrowedExclusivePtr, + batch_raw: CassBorrowedExclusivePtr, + ) { + set_retry_policy_on_stmt(ArcFFI::null(), statement_raw, batch_raw); + } // ### START TESTING @@ -1167,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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); // 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().into_c_const(), + batch_raw.borrow().into_c_const(), + ); } - 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); @@ -1236,28 +1456,36 @@ 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_mut(), + ); { - 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().into_c_const()); + 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); @@ -1276,27 +1504,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_mut()); { - let cass_future = cass_session_connect(session_raw, cluster_raw); + let cass_future = cass_session_connect(session_raw.borrow(), cluster_raw.borrow().into_c_const()); // 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 26022719..8c758a4f 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::CassBorrowedSharedPtr; +use crate::argconv::CassOwnedSharedPtr; +use crate::argconv::{ArcFFI, CMut}; 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() -> *mut CassSsl { +pub unsafe extern "C" fn cass_ssl_new() -> CassOwnedSharedPtr { openssl_sys::init(); cass_ssl_new_no_lib_init() } #[no_mangle] -pub unsafe extern "C" fn cass_ssl_new_no_lib_init() -> *mut CassSsl { +pub unsafe extern "C" fn cass_ssl_new_no_lib_init() -> CassOwnedSharedPtr { let ssl_context: *mut SSL_CTX = SSL_CTX_new(TLS_method()); let trusted_store: *mut X509_STORE = X509_STORE_new(); @@ -45,7 +47,7 @@ pub unsafe extern "C" fn cass_ssl_new_no_lib_init() -> *mut CassSsl { trusted_store, }; - ArcFFI::into_ptr(Arc::new(ssl)) as *mut _ + ArcFFI::into_ptr(Arc::new(ssl)) } // This is required for the type system to impl Send + Sync for Arc. @@ -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: CassOwnedSharedPtr) { 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: CassBorrowedSharedPtr, 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: CassBorrowedSharedPtr, 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,11 @@ 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: CassBorrowedSharedPtr, + flags: i32, +) { + let ssl = ArcFFI::cloned_from_ptr(ssl).unwrap(); match flags { CASS_SSL_VERIFY_NONE => { @@ -164,7 +169,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: CassBorrowedSharedPtr, + cert: *const c_char, +) -> CassError { if cert.is_null() { return CassError::CASS_ERROR_SSL_INVALID_CERT; } @@ -174,11 +182,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: CassBorrowedSharedPtr, 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 +254,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: CassBorrowedSharedPtr, key: *const c_char, password: *mut c_char, ) -> CassError { @@ -265,13 +273,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: CassBorrowedSharedPtr, 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 7fccfaac..663431a2 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 { +) -> CassOwnedExclusivePtr { 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 { +) -> CassOwnedExclusivePtr { 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 = Statement::new(query_str.to_string()); @@ -296,19 +296,21 @@ 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: CassOwnedExclusivePtr, +) { BoxFFI::free(statement_raw); } #[no_mangle] pub unsafe extern "C" fn cass_statement_set_consistency( - statement: *mut CassStatement, + statement: CassBorrowedExclusivePtr, 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 +323,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: CassBorrowedExclusivePtr, 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 +345,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: CassBorrowedExclusivePtr, + result: CassBorrowedSharedPtr, ) -> 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 +360,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: CassBorrowedExclusivePtr, 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 +379,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: CassBorrowedExclusivePtr, 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 +394,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: CassBorrowedExclusivePtr, 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 +409,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: CassBorrowedExclusivePtr, + retry_policy: CassBorrowedSharedPtr, ) -> 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 +421,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 +433,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: CassBorrowedExclusivePtr, serial_consistency: CassConsistency, ) -> CassError { // cpp-driver doesn't validate passed value in any way. @@ -448,7 +450,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 +479,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: CassBorrowedExclusivePtr, 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 +494,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: CassBorrowedExclusivePtr, timeout_ms: cass_uint64_t, ) -> CassError { // The maximum duration for a sleep is 68719476734 milliseconds (approximately 2.2 years). @@ -503,7 +505,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 +513,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: CassBorrowedExclusivePtr, 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 cdf5cfa5..4a6d8fb6 100644 --- a/scylla-rust-wrapper/src/tuple.rs +++ b/scylla-rust-wrapper/src/tuple.rs @@ -63,7 +63,9 @@ 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, +) -> CassOwnedExclusivePtr { BoxFFI::into_ptr(Box::new(CassTuple { data_type: None, items: vec![None; item_count as usize], @@ -72,12 +74,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: CassBorrowedSharedPtr, +) -> CassOwnedExclusivePtr { + 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 +88,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: CassOwnedExclusivePtr) { 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: CassBorrowedSharedPtr, +) -> CassBorrowedSharedPtr { + match &BoxFFI::as_ref(tuple).unwrap().data_type { Some(t) => ArcFFI::as_ptr(t), None => ArcFFI::as_ptr(&UNTYPED_TUPLE_TYPE), } @@ -136,12 +140,12 @@ 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().into_c_const()); 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); 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..c5bd6063 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: CassBorrowedSharedPtr, +) -> CassOwnedExclusivePtr { + 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: CassOwnedExclusivePtr) { 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: CassBorrowedSharedPtr, +) -> CassBorrowedSharedPtr { + 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..a2653e18 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() -> CassOwnedExclusivePtr { // 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, +) -> CassOwnedExclusivePtr { 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: CassBorrowedExclusivePtr, + 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: CassBorrowedExclusivePtr, 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: CassOwnedExclusivePtr) { BoxFFI::free(uuid_gen); } From 4727e7553bce65dfff0969cc93f60eaa027445f8 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 4/5] argconv: make FFI implementation mutually exclusive Disallow implementing two different APIs for specific type. --- scylla-rust-wrapper/src/argconv.rs | 117 +++++++++++++++++++++--- scylla-rust-wrapper/src/batch.rs | 5 +- 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 | 6 +- scylla-rust-wrapper/src/future.rs | 4 +- scylla-rust-wrapper/src/iterator.rs | 6 +- scylla-rust-wrapper/src/logging.rs | 8 +- 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 | 12 ++- scylla-rust-wrapper/src/retry_policy.rs | 6 +- scylla-rust-wrapper/src/session.rs | 4 +- scylla-rust-wrapper/src/ssl.rs | 8 +- 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 +- 20 files changed, 185 insertions(+), 47 deletions(-) diff --git a/scylla-rust-wrapper/src/argconv.rs b/scylla-rust-wrapper/src/argconv.rs index aba4288a..dc35b703 100644 --- a/scylla-rust-wrapper/src/argconv.rs +++ b/scylla-rust-wrapper/src/argconv.rs @@ -326,12 +326,18 @@ impl CassPtr<'_, T, (Exclusive, CMut)> { } } +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, (Exclusive, CM)> { @@ -405,7 +411,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, CM: CMutability>(self: &'a Arc) -> CassPtr<'a, Self, (Shared, CM)> { @@ -495,7 +501,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, CM: CMutability>(&'a self) -> CassPtr<'a, Self, (Shared, CM)> { @@ -514,11 +520,14 @@ pub trait RefFFI: Sized { /// /// ## Why this method is unsafe? - Example /// ``` - /// # use scylla_cpp_driver::argconv::{RefFFI, CConst, CassBorrowedSharedPtr}; + /// # use scylla_cpp_driver::argconv::{CConst, CassBorrowedSharedPtr}; + /// # use scylla_cpp_driver::argconv::{FFI, FromRef, RefFFI}; /// # use std::sync::{Arc, Weak}; /// /// struct Foo; - /// impl RefFFI for Foo {} + /// impl FFI for Foo { + /// type Origin = FromRef; + /// } /// /// let arc = Arc::new(Foo); /// let weak = Arc::downgrade(&arc); @@ -558,11 +567,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::{CassOwnedExclusivePtr, CassBorrowedExclusivePtr, CMut}; -/// # 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: CassOwnedExclusivePtr = BoxFFI::into_ptr(Box::new(Foo)); /// let borrowed_mut_ptr1: CassBorrowedExclusivePtr = ptr.borrow_mut(); @@ -574,9 +653,11 @@ fn _test_box_ffi_cannot_have_two_mutable_references() {} /// ```compile_fail,E0502 /// # use scylla_cpp_driver::argconv::{CassOwnedExclusivePtr, CassBorrowedSharedPtr, CassBorrowedExclusivePtr, CConst, CMut}; -/// # 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: CassOwnedExclusivePtr = BoxFFI::into_ptr(Box::new(Foo)); /// let borrowed_mut_ptr: CassBorrowedExclusivePtr = ptr.borrow_mut(); @@ -588,9 +669,11 @@ fn _test_box_ffi_cannot_have_mutable_and_immutable_references_at_the_same_time() /// ```compile_fail,E0505 /// # use scylla_cpp_driver::argconv::{CassOwnedExclusivePtr, CassBorrowedSharedPtr, CMut}; -/// # 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: CassOwnedExclusivePtr = BoxFFI::into_ptr(Box::new(Foo)); /// let borrowed_ptr: CassBorrowedSharedPtr = ptr.borrow(); @@ -601,10 +684,12 @@ fn _test_box_ffi_cannot_free_while_having_borrowed_pointer() {} /// ```compile_fail,E0505 /// # use scylla_cpp_driver::argconv::{CassOwnedSharedPtr, CassBorrowedSharedPtr, CConst}; -/// # 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: CassOwnedSharedPtr = ArcFFI::into_ptr(Arc::new(Foo)); /// let borrowed_ptr: CassBorrowedSharedPtr = ptr.borrow(); @@ -615,10 +700,12 @@ fn _test_arc_ffi_cannot_clone_after_free() {} /// ```compile_fail,E0505 /// # use scylla_cpp_driver::argconv::{CassBorrowedSharedPtr, CConst}; -/// # 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: CassBorrowedSharedPtr = ArcFFI::as_ptr(&arc); diff --git a/scylla-rust-wrapper/src/batch.rs b/scylla-rust-wrapper/src/batch.rs index 8475820f..2c127fe4 100644 --- a/scylla-rust-wrapper/src/batch.rs +++ b/scylla-rust-wrapper/src/batch.rs @@ -1,5 +1,6 @@ use crate::argconv::{ ArcFFI, BoxFFI, CMut, CassBorrowedExclusivePtr, CassBorrowedSharedPtr, CassOwnedExclusivePtr, + FromBox, FFI, }; use crate::cass_error::CassError; use crate::cass_types::CassConsistency; @@ -21,7 +22,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 722ba8ed..3b52064f 100644 --- a/scylla-rust-wrapper/src/cass_types.rs +++ b/scylla-rust-wrapper/src/cass_types.rs @@ -145,7 +145,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 fddcf122..8de1a991 100644 --- a/scylla-rust-wrapper/src/cluster.rs +++ b/scylla-rust-wrapper/src/cluster.rs @@ -167,7 +167,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 0586781f..9e3dae6a 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 a61fd536..b407f701 100644 --- a/scylla-rust-wrapper/src/exec_profile.rs +++ b/scylla-rust-wrapper/src/exec_profile.rs @@ -15,7 +15,7 @@ use scylla::statement::Consistency; use crate::argconv::{ ptr_to_cstr_n, strlen, ArcFFI, BoxFFI, CMut, CassBorrowedExclusivePtr, CassBorrowedSharedPtr, - CassOwnedExclusivePtr, + CassOwnedExclusivePtr, FromBox, FFI, }; use crate::batch::CassBatch; use crate::cass_error::CassError; @@ -40,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 ba008111..c82c2d2d 100644 --- a/scylla-rust-wrapper/src/future.rs +++ b/scylla-rust-wrapper/src/future.rs @@ -61,7 +61,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/iterator.rs b/scylla-rust-wrapper/src/iterator.rs index 43974ddd..3c54827e 100644 --- a/scylla-rust-wrapper/src/iterator.rs +++ b/scylla-rust-wrapper/src/iterator.rs @@ -1,6 +1,6 @@ use crate::argconv::{ write_str_to_c, ArcFFI, BoxFFI, CConst, CMut, CassBorrowedExclusivePtr, CassBorrowedSharedPtr, - CassOwnedExclusivePtr, RefFFI, + CassOwnedExclusivePtr, FromBox, RefFFI, FFI, }; use crate::cass_error::CassError; use crate::cass_types::{CassDataType, CassValueType}; @@ -117,7 +117,9 @@ pub enum CassIterator<'result_or_schema> { ColumnsMeta(CassColumnsMetaIterator<'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: CassOwnedExclusivePtr) { diff --git a/scylla-rust-wrapper/src/logging.rs b/scylla-rust-wrapper/src/logging.rs index 309dd07b..1d05d35e 100644 --- a/scylla-rust-wrapper/src/logging.rs +++ b/scylla-rust-wrapper/src/logging.rs @@ -1,4 +1,6 @@ -use crate::argconv::{arr_to_cstr, ptr_to_cstr, str_to_arr, CConst, CassBorrowedSharedPtr, RefFFI}; +use crate::argconv::{ + arr_to_cstr, ptr_to_cstr, str_to_arr, CConst, CassBorrowedSharedPtr, FromRef, RefFFI, FFI, +}; use crate::cass_log_types::{CassLogLevel, CassLogMessage}; use crate::types::size_t; use crate::LOGGER; @@ -14,7 +16,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< unsafe extern "C" fn(message: CassBorrowedSharedPtr, data: *mut c_void), diff --git a/scylla-rust-wrapper/src/metadata.rs b/scylla-rust-wrapper/src/metadata.rs index 6219cb7b..c58a5942 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, @@ -40,7 +44,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, @@ -49,7 +55,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, @@ -58,7 +66,9 @@ pub struct CassColumnMeta { } // Owned by CassTableMeta -impl RefFFI for CassColumnMeta {} +impl FFI for CassColumnMeta { + type Origin = FromRef; +} pub fn create_table_metadata(table_name: &str, table_metadata: &Table) -> CassTableMeta { let mut columns_metadata = HashMap::new(); diff --git a/scylla-rust-wrapper/src/prepared.rs b/scylla-rust-wrapper/src/prepared.rs index 0bb448ea..e3e4cda8 100644 --- a/scylla-rust-wrapper/src/prepared.rs +++ b/scylla-rust-wrapper/src/prepared.rs @@ -73,7 +73,9 @@ impl CassPrepared { } } -impl ArcFFI for CassPrepared {} +impl FFI for CassPrepared { + type Origin = FromArc; +} #[no_mangle] pub unsafe extern "C" fn cass_prepared_free( diff --git a/scylla-rust-wrapper/src/query_error.rs b/scylla-rust-wrapper/src/query_error.rs index 19215b1f..6f6cb776 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 7ba400c5..ebc927f1 100644 --- a/scylla-rust-wrapper/src/query_result.rs +++ b/scylla-rust-wrapper/src/query_result.rs @@ -92,7 +92,9 @@ impl CassResult { } } -impl ArcFFI for CassResult {} +impl FFI for CassResult { + type Origin = FromArc; +} #[derive(Debug)] pub struct CassResultMetadata { @@ -122,7 +124,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, @@ -158,7 +162,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 diff --git a/scylla-rust-wrapper/src/retry_policy.rs b/scylla-rust-wrapper/src/retry_policy.rs index 0e3818a5..f3025d3d 100644 --- a/scylla-rust-wrapper/src/retry_policy.rs +++ b/scylla-rust-wrapper/src/retry_policy.rs @@ -3,7 +3,7 @@ use scylla::policies::retry::{ }; use std::sync::Arc; -use crate::argconv::{ArcFFI, CMut, CassOwnedSharedPtr}; +use crate::argconv::{ArcFFI, CMut, CassOwnedSharedPtr, FromArc, FFI}; pub enum RetryPolicy { DefaultRetryPolicy(Arc), @@ -13,7 +13,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() -> CassOwnedSharedPtr { diff --git a/scylla-rust-wrapper/src/session.rs b/scylla-rust-wrapper/src/session.rs index 324d184c..7177a87f 100644 --- a/scylla-rust-wrapper/src/session.rs +++ b/scylla-rust-wrapper/src/session.rs @@ -137,7 +137,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() -> CassOwnedSharedPtr { diff --git a/scylla-rust-wrapper/src/ssl.rs b/scylla-rust-wrapper/src/ssl.rs index 8c758a4f..015bec5b 100644 --- a/scylla-rust-wrapper/src/ssl.rs +++ b/scylla-rust-wrapper/src/ssl.rs @@ -1,6 +1,4 @@ -use crate::argconv::CassBorrowedSharedPtr; -use crate::argconv::CassOwnedSharedPtr; -use crate::argconv::{ArcFFI, CMut}; +use crate::argconv::{ArcFFI, CMut, CassBorrowedSharedPtr, CassOwnedSharedPtr, FromArc, FFI}; use crate::cass_error::CassError; use crate::types::size_t; use libc::{c_int, strlen}; @@ -21,7 +19,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 663431a2..e42c1ea5 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 4a6d8fb6..5ae65758 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 c5bd6063..f95e739b 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 a2653e18..1c5f0d66 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: From d5df8a122528592dad418505e5866735272ed911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Uzarski?= Date: Mon, 31 Mar 2025 14:20:42 +0200 Subject: [PATCH 5/5] CI: Point ccm to commit before the C* bug was introduced. See the issue linked in the comment. --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 780491d8..be6cb68d 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,8 @@ CASSANDRA_TEST_FILTER := $(subst ${SPACE},${EMPTY},ClusterTests.*\ endif ifndef CCM_COMMIT_ID - export CCM_COMMIT_ID := master + # TODO: change it back to master/next when https://github.com/scylladb/scylla-ccm/issues/646 is fixed. + export CCM_COMMIT_ID := 5392dd68 endif ifndef SCYLLA_VERSION