Skip to content

Commit 1985150

Browse files
committed
chore(ffi): introduce AsyncRuntimeDropped helper
This avoids proliferation of `ManuallyDrop` in the code base, by having a single type that's used for dropping under an async runtime.
1 parent 8aaaf23 commit 1985150

File tree

4 files changed

+54
-45
lines changed

4 files changed

+54
-45
lines changed

bindings/matrix-sdk-ffi/src/client.rs

+3-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::{
22
collections::HashMap,
33
fmt::Debug,
4-
mem::ManuallyDrop,
54
path::Path,
65
sync::{Arc, RwLock},
76
};
@@ -79,6 +78,7 @@ use crate::{
7978
ruma::AuthData,
8079
sync_service::{SyncService, SyncServiceBuilder},
8180
task_handle::TaskHandle,
81+
utils::AsyncRuntimeDropped,
8282
ClientError,
8383
};
8484

@@ -184,26 +184,12 @@ impl From<matrix_sdk::TransmissionProgress> for TransmissionProgress {
184184

185185
#[derive(uniffi::Object)]
186186
pub struct Client {
187-
pub(crate) inner: ManuallyDrop<MatrixClient>,
187+
pub(crate) inner: AsyncRuntimeDropped<MatrixClient>,
188188
delegate: RwLock<Option<Arc<dyn ClientDelegate>>>,
189189
session_verification_controller:
190190
Arc<tokio::sync::RwLock<Option<SessionVerificationController>>>,
191191
}
192192

193-
impl Drop for Client {
194-
fn drop(&mut self) {
195-
// Dropping the inner OlmMachine must happen within a tokio context
196-
// because deadpool drops sqlite connections in the DB pool on tokio's
197-
// blocking threadpool to avoid blocking async worker threads.
198-
let _guard = RUNTIME.enter();
199-
// SAFETY: self.inner is never used again, which is the only requirement
200-
// for ManuallyDrop::drop to be used safely.
201-
unsafe {
202-
ManuallyDrop::drop(&mut self.inner);
203-
}
204-
}
205-
}
206-
207193
impl Client {
208194
pub async fn new(
209195
sdk_client: MatrixClient,
@@ -224,7 +210,7 @@ impl Client {
224210
});
225211

226212
let client = Client {
227-
inner: ManuallyDrop::new(sdk_client),
213+
inner: AsyncRuntimeDropped::new(sdk_client),
228214
delegate: RwLock::new(None),
229215
session_verification_controller,
230216
};

bindings/matrix-sdk-ffi/src/room_list.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
#![allow(deprecated)]
22

3-
use std::{
4-
fmt::Debug,
5-
mem::{ManuallyDrop, MaybeUninit},
6-
ptr::addr_of_mut,
7-
sync::Arc,
8-
time::Duration,
9-
};
3+
use std::{fmt::Debug, mem::MaybeUninit, ptr::addr_of_mut, sync::Arc, time::Duration};
104

115
use eyeball_im::VectorDiff;
126
use futures_util::{pin_mut, StreamExt, TryFutureExt};
@@ -34,6 +28,7 @@ use crate::{
3428
room_preview::RoomPreview,
3529
timeline::{EventTimelineItem, Timeline},
3630
timeline_event_filter::TimelineEventTypeFilter,
31+
utils::AsyncRuntimeDropped,
3732
TaskHandle, RUNTIME,
3833
};
3934

@@ -635,7 +630,7 @@ impl RoomListItem {
635630

636631
let room_preview = client.get_room_preview(&room_or_alias_id, server_names).await?;
637632

638-
Ok(RoomPreview::new(ManuallyDrop::new(client), room_preview))
633+
Ok(RoomPreview::new(AsyncRuntimeDropped::new(client), room_preview))
639634
}
640635

641636
/// Build a full `Room` FFI object, filling its associated timeline.

bindings/matrix-sdk-ffi/src/room_preview.rs

+3-20
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,16 @@
1-
use std::mem::ManuallyDrop;
2-
31
use anyhow::Context as _;
4-
use async_compat::TOKIO1 as RUNTIME;
52
use matrix_sdk::{room_preview::RoomPreview as SdkRoomPreview, Client};
63
use ruma::space::SpaceRoomJoinRule;
74
use tracing::warn;
85

9-
use crate::{client::JoinRule, error::ClientError, room::Membership};
6+
use crate::{client::JoinRule, error::ClientError, room::Membership, utils::AsyncRuntimeDropped};
107

118
/// A room preview for a room. It's intended to be used to represent rooms that
129
/// aren't joined yet.
1310
#[derive(uniffi::Object)]
1411
pub struct RoomPreview {
1512
inner: SdkRoomPreview,
16-
client: ManuallyDrop<Client>,
17-
}
18-
19-
impl Drop for RoomPreview {
20-
fn drop(&mut self) {
21-
// Dropping the inner OlmMachine must happen within a tokio context
22-
// because deadpool drops sqlite connections in the DB pool on tokio's
23-
// blocking threadpool to avoid blocking async worker threads.
24-
let _guard = RUNTIME.enter();
25-
// SAFETY: self.client is never used again, which is the only requirement
26-
// for ManuallyDrop::drop to be used safely.
27-
unsafe {
28-
ManuallyDrop::drop(&mut self.client);
29-
}
30-
}
13+
client: AsyncRuntimeDropped<Client>,
3114
}
3215

3316
#[matrix_sdk_ffi_macros::export]
@@ -65,7 +48,7 @@ impl RoomPreview {
6548
}
6649

6750
impl RoomPreview {
68-
pub(crate) fn new(client: ManuallyDrop<Client>, inner: SdkRoomPreview) -> Self {
51+
pub(crate) fn new(client: AsyncRuntimeDropped<Client>, inner: SdkRoomPreview) -> Self {
6952
Self { client, inner }
7053
}
7154
}

bindings/matrix-sdk-ffi/src/utils.rs

+45
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use std::{mem::ManuallyDrop, ops::Deref};
16+
17+
use async_compat::TOKIO1 as RUNTIME;
1518
use ruma::UInt;
1619
use tracing::warn;
1720

@@ -21,3 +24,45 @@ pub(crate) fn u64_to_uint(u: u64) -> UInt {
2124
UInt::MAX
2225
})
2326
}
27+
28+
/// Tiny wrappers for data types that must be dropped in the context of an async
29+
/// runtime.
30+
///
31+
/// This is useful whenever such a data type may transitively call some
32+
/// runtime's `block_on` function in their `Drop` impl (since we lack async drop
33+
/// at the moment), like done in some `deadpool` drop impls.
34+
pub(crate) struct AsyncRuntimeDropped<T>(ManuallyDrop<T>);
35+
36+
impl<T> AsyncRuntimeDropped<T> {
37+
/// Create a new wrapper for this type that will be dropped under an async
38+
/// runtime.
39+
pub fn new(val: T) -> Self {
40+
Self(ManuallyDrop::new(val))
41+
}
42+
}
43+
44+
impl<T> Drop for AsyncRuntimeDropped<T> {
45+
fn drop(&mut self) {
46+
let _guard = RUNTIME.enter();
47+
// SAFETY: self.inner is never used again, which is the only requirement
48+
// for ManuallyDrop::drop to be used safely.
49+
unsafe {
50+
ManuallyDrop::drop(&mut self.0);
51+
}
52+
}
53+
}
54+
55+
// What is an `AsyncRuntimeDropped<T>`, if not a `T` in disguise?
56+
impl<T> Deref for AsyncRuntimeDropped<T> {
57+
type Target = T;
58+
59+
fn deref(&self) -> &Self::Target {
60+
&self.0
61+
}
62+
}
63+
64+
impl<T: Clone> Clone for AsyncRuntimeDropped<T> {
65+
fn clone(&self) -> Self {
66+
Self(self.0.clone())
67+
}
68+
}

0 commit comments

Comments
 (0)