@@ -328,12 +328,18 @@ impl<T: Sized> CassPtr<'_, T, (Mut, CMut)> {
328
328
}
329
329
}
330
330
331
+ mod origin_sealed {
332
+ pub trait FromBoxSealed { }
333
+ pub trait FromArcSealed { }
334
+ pub trait FromRefSealed { }
335
+ }
336
+
331
337
/// Defines a pointer manipulation API for non-shared heap-allocated data.
332
338
///
333
339
/// Implement this trait for types that are allocated by the driver via [`Box::new`],
334
340
/// and then returned to the user as a pointer. The user is responsible for freeing
335
341
/// the memory associated with the pointer using corresponding driver's API function.
336
- pub trait BoxFFI : Sized {
342
+ pub trait BoxFFI : Sized + origin_sealed :: FromBoxSealed {
337
343
/// Consumes the Box and returns a pointer with exclusive ownership.
338
344
/// The pointer needs to be freed. See [`BoxFFI::free()`].
339
345
fn into_ptr < M : Mutability , CM : CMutability > (
@@ -406,7 +412,7 @@ pub trait BoxFFI: Sized {
406
412
/// The data should be allocated via [`Arc::new`], and then returned to the user as a pointer.
407
413
/// The user is responsible for freeing the memory associated
408
414
/// with the pointer using corresponding driver's API function.
409
- pub trait ArcFFI : Sized {
415
+ pub trait ArcFFI : Sized + origin_sealed :: FromArcSealed {
410
416
/// Creates a pointer from a valid reference to Arc-allocated data.
411
417
/// Holder of the pointer borrows the pointee.
412
418
fn as_ptr < ' a , CM : CMutability > ( self : & ' a Arc < Self > ) -> CassPtr < ' a , Self , ( Const , CM ) > {
@@ -496,7 +502,7 @@ pub trait ArcFFI: Sized {
496
502
/// For example: lifetime of CassRow is bound by the lifetime of CassResult.
497
503
/// There is no API function that frees the CassRow. It should be automatically
498
504
/// freed when user calls cass_result_free.
499
- pub trait RefFFI : Sized {
505
+ pub trait RefFFI : Sized + origin_sealed :: FromRefSealed {
500
506
/// Creates a borrowed pointer from a valid reference.
501
507
#[ allow( clippy:: needless_lifetimes) ]
502
508
fn as_ptr < ' a , CM : CMutability > ( & ' a self ) -> CassPtr < ' a , Self , ( Const , CM ) > {
@@ -542,11 +548,81 @@ pub trait RefFFI: Sized {
542
548
}
543
549
}
544
550
551
+ /// This trait should be implemented for types that are passed between
552
+ /// C and Rust API. We currently distinguish 3 kinds of implementors,
553
+ /// wrt. the origin of the pointer. The implementor should pick one of the 3 ownership
554
+ /// kinds as the associated type:
555
+ /// - [`FromBox`]
556
+ /// - [`FromArc`]
557
+ /// - [`FromRef`]
558
+ #[ allow( clippy:: upper_case_acronyms) ]
559
+ pub trait FFI {
560
+ type Origin ;
561
+ }
562
+
563
+ /// Represents types with an exclusive ownership.
564
+ ///
565
+ /// Use this associated type for implementors that require:
566
+ /// - owned exclusive pointer manipulation via [`BoxFFI`]
567
+ /// - exclusive ownership of the corresponding object
568
+ /// - potential mutability of the corresponding object
569
+ /// - manual memory freeing
570
+ ///
571
+ /// C API user should be responsible for freeing associated memory manually
572
+ /// via corresponding API call.
573
+ ///
574
+ /// An example of such implementor would be [`CassCluster`](crate::cluster::CassCluster):
575
+ /// - it is allocated on the heap via [`Box::new`]
576
+ /// - user is the exclusive owner of the CassCluster object
577
+ /// - there is no API to increase a reference count of CassCluster object
578
+ /// - CassCluster is mutable via some API methods (`cass_cluster_set_*`)
579
+ /// - user is responsible for freeing the associated memory (`cass_cluster_free`)
580
+ pub struct FromBox ;
581
+ impl < T > origin_sealed:: FromBoxSealed for T where T : FFI < Origin = FromBox > { }
582
+ impl < T > BoxFFI for T where T : FFI < Origin = FromBox > { }
583
+
584
+ /// Represents types with a shared ownership.
585
+ ///
586
+ /// Use this associated type for implementors that require:
587
+ /// - pointer with shared ownership manipulation via [`ArcFFI`]
588
+ /// - shared ownership of the corresponding object
589
+ /// - manual memory freeing
590
+ ///
591
+ /// C API user should be responsible for freeing (decreasing reference count of)
592
+ /// associated memory manually via corresponding API call.
593
+ ///
594
+ /// An example of such implementor would be [`CassDataType`](crate::cass_types::CassDataType):
595
+ /// - it is allocated on the heap via [`Arc::new`]
596
+ /// - there are multiple owners of the shared CassDataType object
597
+ /// - some API functions require to increase a reference count of the object
598
+ /// - user is responsible for freeing (decreasing RC of) the associated memory (`cass_data_type_free`)
599
+ pub struct FromArc ;
600
+ impl < T > origin_sealed:: FromArcSealed for T where T : FFI < Origin = FromArc > { }
601
+ impl < T > ArcFFI for T where T : FFI < Origin = FromArc > { }
602
+
603
+ /// Represents borrowed types.
604
+ ///
605
+ /// Use this associated type for implementors that do not require any assumptions
606
+ /// about the pointer type (apart from validity).
607
+ /// The implementation will enable [`CassBorrowedPtr`] manipulation via [`RefFFI`]
608
+ ///
609
+ /// C API user is not responsible for freeing associated memory manually. The memory
610
+ /// should be freed automatically, when the owner is being dropped.
611
+ ///
612
+ /// An example of such implementor would be [`CassRow`](crate::query_result::CassRow):
613
+ /// - its lifetime is tied to the lifetime of CassResult
614
+ /// - user only "borrows" the pointer - he is not responsible for freeing the memory
615
+ pub struct FromRef ;
616
+ impl < T > origin_sealed:: FromRefSealed for T where T : FFI < Origin = FromRef > { }
617
+ impl < T > RefFFI for T where T : FFI < Origin = FromRef > { }
618
+
545
619
/// ```compile_fail,E0499
546
620
/// # use scylla_cpp_driver::argconv::{CassOwnedMutPtr, CassBorrowedMutPtr, CMut};
547
- /// # use scylla_cpp_driver::argconv::BoxFFI;
621
+ /// # use scylla_cpp_driver::argconv::{FFI, BoxFFI, FromBox} ;
548
622
/// struct Foo;
549
- /// impl BoxFFI for Foo {}
623
+ /// impl FFI for Foo {
624
+ /// type Origin = FromBox;
625
+ /// }
550
626
///
551
627
/// let mut ptr: CassOwnedMutPtr<Foo, CMut> = BoxFFI::into_ptr(Box::new(Foo));
552
628
/// let borrowed_mut_ptr1: CassBorrowedMutPtr<Foo, CMut> = ptr.borrow_mut();
@@ -558,9 +634,11 @@ fn _test_box_ffi_cannot_have_two_mutable_references() {}
558
634
559
635
/// ```compile_fail,E0502
560
636
/// # use scylla_cpp_driver::argconv::{CassOwnedMutPtr, CassBorrowedPtr, CassBorrowedMutPtr, CConst, CMut};
561
- /// # use scylla_cpp_driver::argconv::BoxFFI;
637
+ /// # use scylla_cpp_driver::argconv::{FFI, BoxFFI, FromBox} ;
562
638
/// struct Foo;
563
- /// impl BoxFFI for Foo {}
639
+ /// impl FFI for Foo {
640
+ /// type Origin = FromBox;
641
+ /// }
564
642
///
565
643
/// let mut ptr: CassOwnedMutPtr<Foo, CMut> = BoxFFI::into_ptr(Box::new(Foo));
566
644
/// let borrowed_mut_ptr: CassBorrowedMutPtr<Foo, CMut> = ptr.borrow_mut();
@@ -572,9 +650,11 @@ fn _test_box_ffi_cannot_have_mutable_and_immutable_references_at_the_same_time()
572
650
573
651
/// ```compile_fail,E0505
574
652
/// # use scylla_cpp_driver::argconv::{CassOwnedMutPtr, CassBorrowedPtr, CMut};
575
- /// # use scylla_cpp_driver::argconv::BoxFFI;
653
+ /// # use scylla_cpp_driver::argconv::{FFI, BoxFFI, FromBox} ;
576
654
/// struct Foo;
577
- /// impl BoxFFI for Foo {}
655
+ /// impl FFI for Foo {
656
+ /// type Origin = FromBox;
657
+ /// }
578
658
///
579
659
/// let ptr: CassOwnedMutPtr<Foo, CMut> = BoxFFI::into_ptr(Box::new(Foo));
580
660
/// let borrowed_ptr: CassBorrowedPtr<Foo, CMut> = ptr.borrow();
@@ -585,10 +665,12 @@ fn _test_box_ffi_cannot_free_while_having_borrowed_pointer() {}
585
665
586
666
/// ```compile_fail,E0505
587
667
/// # use scylla_cpp_driver::argconv::{CassOwnedPtr, CassBorrowedPtr, CConst};
588
- /// # use scylla_cpp_driver::argconv::ArcFFI;
668
+ /// # use scylla_cpp_driver::argconv::{FFI, ArcFFI, FromArc} ;
589
669
/// # use std::sync::Arc;
590
670
/// struct Foo;
591
- /// impl ArcFFI for Foo {}
671
+ /// impl FFI for Foo {
672
+ /// type Origin = FromArc;
673
+ /// }
592
674
///
593
675
/// let ptr: CassOwnedPtr<Foo, CConst> = ArcFFI::into_ptr(Arc::new(Foo));
594
676
/// let borrowed_ptr: CassBorrowedPtr<Foo, CConst> = ptr.borrow();
@@ -599,10 +681,12 @@ fn _test_arc_ffi_cannot_clone_after_free() {}
599
681
600
682
/// ```compile_fail,E0505
601
683
/// # use scylla_cpp_driver::argconv::{CassBorrowedPtr, CConst};
602
- /// # use scylla_cpp_driver::argconv::ArcFFI;
684
+ /// # use scylla_cpp_driver::argconv::{FFI, ArcFFI, FromArc} ;
603
685
/// # use std::sync::Arc;
604
686
/// struct Foo;
605
- /// impl ArcFFI for Foo {}
687
+ /// impl FFI for Foo {
688
+ /// type Origin = FromArc;
689
+ /// }
606
690
///
607
691
/// let arc = Arc::new(Foo);
608
692
/// let borrowed_ptr: CassBorrowedPtr<Foo, CConst> = ArcFFI::as_ptr(&arc);
0 commit comments