safer_ffi/arc.rs
1//! `#[repr(C)]` [`Arc`][`rust::Arc`]ed types.
2//!
3//! Like [`crate::boxed`], but for [`Arc`][`rust::Arc`].
4//!
5//! # When to use [`repr_c::Arc<T>`] _vs._ [`ThinArc<T>`]?
6//!
7//! In `fn` signatures, prefer [`repr_c::Arc<T>`], since it reads more nicely.
8//!
9//! But [`repr_c::Arc<T>`], by virtue of having been defined as a type alias rather than its own,
10//! dedicated, new-type wrapper `struct` (for historical reasons, the author wishes to fix this in
11//! some future version), comes with a couple limitations of which to be mindful:
12//!
13//! - you cannot use associated functions on [`repr_c::Arc<T>`]:
14//!
15//! ```rust ,compile_fail
16//! use ::safer_ffi::prelude::*;
17//!
18//! repr_c::Arc::new(42); // Error!
19//! ```
20//!
21//! ```rust ,ignore
22//! # /*
23//! error[E0599]: no function or associated item named `new` found for type
24//! `_` in the current scope --> src/arc.rs:19:14
25//! |
26//! 7 | repr_c::Arc::new(42); // Error!
27//! | ^^^ function or associated item not found in `_`
28//! |
29//! = help: items from traits can only be used if the trait is in scope
30//! # */
31//! ```
32//!
33//! - you should not `impl Trait for repr_c::Arc<T> {`. Indeed, the `type` alias is defined as an
34//! associated type "output" [through a `trait`][tr], and from the point of view of _coherence_
35//! (the SemVer-aware overlapping-`impl`s checker), when from within a downstream crate, such as
36//! yours (🫵), this is treated as a fully _blanket_ (generic) type param.
37//!
38//! ```rust ,compile_fail
39//! use ::safer_ffi::prelude::*;
40//!
41//! trait MyFancyTrait {}
42//!
43//! impl MyFancyTrait for i32 {}
44//!
45//! // Error, *potentially*-overlapping `impl` in the future: what if
46//! // `safer-ffi` were to define the assoc type of `FitForCArc` as `i32`?
47//! //
48//! // Anyhow, this is treated the same as if it had been:
49//! // `impl<T> MyFancyTrait for T {}`, hence the overlap with `i32` above.
50//! impl MyFancyTrait for repr_c::Arc<bool> {}
51//! ```
52//!
53//! ```rust ,ignore
54//! # /*
55//! error[E0119]: conflicting implementations of trait `MyFancyTrait` for type `i32`
56//! --> src/arc.rs:44:1
57//! |
58//! 9 | impl MyFancyTrait for i32 {}
59//! | ------------------------- first implementation here
60//! ...
61//! 16 | impl MyFancyTrait for repr_c::Arc<bool> {}
62//! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
63//! # */
64//! ```
65//!
66//! - To be completely honest, I don't feel like this failing is _that_ justified, and it may
67//! just be a bug in _coherence_, but oh well, it is what it is 🤷.
68//!
69//! In either of these situations, you may want to directly target [`ThinArc<T>`] instead.
70//!
71//! [tr]: [`FitForCArc`]
72
73use_prelude!();
74
75ReprC! {
76 /// An FFI-safe representation of a standard-library `Arc<T>`, as a thin pointer to its `T`.
77 ///
78 /// # When to use [`repr_c::Arc<T>`] _vs._ [`ThinArc<T>`]?
79 ///
80 /// See [the module docs][self]
81 #[repr(transparent)]
82 pub
83 struct ThinArc[T] (
84 ptr::NonNullOwned<T>,
85 );
86}
87
88impl<T> From<rust::Arc<T>> for ThinArc<T> {
89 #[inline]
90 fn from(arced: rust::Arc<T>) -> Arc<T> {
91 let raw = rust::Arc::into_raw(arced);
92 Self(ptr::NonNull::new(raw.cast_mut()).unwrap().into())
93 }
94}
95
96impl<T> ThinArc<T> {
97 #[inline]
98 pub fn new(value: T) -> Self {
99 rust::Arc::new(value).into()
100 }
101
102 #[inline]
103 pub fn into(self: ThinArc<T>) -> rust::Arc<T> {
104 let mut this = mem::ManuallyDrop::new(self);
105 unsafe { rust::Arc::from_raw(this.0.as_mut_ptr()) }
106 }
107
108 /// See [`rust::Arc<T>::as_ptr()`].
109 #[inline]
110 pub fn as_ptr(this: &Self) -> *const T {
111 this.0.as_ptr()
112 }
113
114 /// See [`rust::Arc<T>::into_raw()`].
115 #[inline]
116 pub fn into_raw(self) -> *const T {
117 Self::as_ptr(&*::core::mem::ManuallyDrop::new(self))
118 }
119
120 /// See [`rust::Arc<T>::from_raw()`].
121 #[inline]
122 pub unsafe fn from_raw(ptr: *const T) -> Self {
123 Self(unsafe { ptr::NonNull::new_unchecked(ptr.cast_mut()) }.into())
124 }
125
126 /// Morally, a <code>\&[ThinArc\<T\>][`ThinArc`] -> \&[Arc\<T\>][`rust::Arc`]</code> conversion.
127 ///
128 /// For lifetime reasons, this is exposed as a scoped / callback / CPS API.
129 ///
130 /// # Example
131 ///
132 /// ```rust
133 /// use ::safer_ffi::prelude::*;
134 /// use ::std::sync::Arc;
135 ///
136 /// fn increment_strong_count<T>(a: &repr_c::Arc<T>) {
137 /// a.with_rust(|a: &Arc<T>| unsafe {
138 /// # //
139 /// Arc::<T>::increment_strong_count(Arc::as_ptr(&a))
140 /// })
141 /// }
142 /// ```
143 #[inline]
144 pub fn with_rust<R>(
145 &self,
146 scope: impl FnOnce(&rust::Arc<T>) -> R,
147 ) -> R {
148 let yield_ = scope;
149 let arc: &rust::Arc<T> =
150 &*::core::mem::ManuallyDrop::new(unsafe { rust::Arc::from_raw(ThinArc::as_ptr(self)) });
151 yield_(arc)
152 }
153}
154
155impl<T> Drop for ThinArc<T> {
156 #[inline]
157 fn drop(self: &'_ mut ThinArc<T>) {
158 unsafe {
159 drop::<rust::Arc<T>>(rust::Arc::from_raw(self.0.as_mut_ptr()));
160 }
161 }
162}
163
164impl<T> Deref for ThinArc<T> {
165 type Target = T;
166
167 #[inline]
168 fn deref(self: &'_ ThinArc<T>) -> &'_ T {
169 unsafe { &*self.0.as_ptr() }
170 }
171}
172
173unsafe impl<T> Send for ThinArc<T> where rust::Arc<T>: Send {}
174
175unsafe impl<T> Sync for ThinArc<T> where rust::Arc<T>: Sync {}
176
177impl<T> Clone for ThinArc<T> {
178 #[inline]
179 fn clone(self: &'_ Self) -> Self {
180 self.with_rust(rust::Arc::clone).into()
181 }
182}
183
184impl<T: fmt::Debug> fmt::Debug for ThinArc<T> {
185 fn fmt(
186 self: &'_ Self,
187 fmt: &'_ mut fmt::Formatter<'_>,
188 ) -> fmt::Result {
189 T::fmt(&**self, fmt)
190 }
191}
192
193/// A `?Sized`-aware alias, for convenience:
194///
195/// - when `T : Sized`, this is [`ThinArc<T>`];
196/// - when `T = dyn 'static + Send + Sync + Fn(…) -> _`, this is [the dedicated hand-rolled
197/// FFI-safe `dyn` "closure" struct of the given arity][crate::closure::arc].
198///
199/// # When to use [`repr_c::Arc<T>`] _vs._ [`ThinArc<T>`]?
200///
201/// See [the module docs][self]
202pub type Arc<T> = <T as FitForCArc>::CArcWrapped;
203
204/// Helper trait enabling the definition of [`Arc<T>`].
205pub trait FitForCArc {
206 type CArcWrapped;
207}
208
209impl<T: Sized> FitForCArc for T {
210 type CArcWrapped = ThinArc<T>;
211}