libasync/callback_state.rs
1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Helpers for writing futures against the C-based async API
6
7use std::sync::Arc;
8
9/// Implements the basic pattern of a two-sided struct used by a system api
10/// that calls a callback (which uses the `C` generic) and a rust abstraction
11/// over that API to provide either rust callbacks or futures, where the two
12/// sides need to coordinate.
13///
14/// # Safety
15///
16/// This object relies on its layout being such that a pointer to its first
17/// member is also a pointer to the struct as a whole, so that references to
18/// it can be safely converted back and forth.
19#[repr(C)]
20pub struct CallbackSharedState<Base, Inner> {
21 /// The "base" type is the one that the C api expects to be at the beginning
22 /// of the struct it's given.
23 base: Base,
24 /// The "inner" type is the one that is used by the Rust wrappers to manage
25 /// state and resources.
26 inner: Inner,
27}
28
29impl<B, I> CallbackSharedState<B, I> {
30 /// Creates a new shared state object in an [`Arc`] that can be easily manipulated
31 /// into the pointer types needed for interaction with a C API.
32 ///
33 /// After calling this, the `base` value will be the one given to the C API and
34 /// will not be available to rust code without going through the pointer. The
35 /// idea is that while this object is alive, the C code owns that data. The `inner`
36 /// object can be accessed on this through the implementation of [`std::ops::Deref`].
37 pub fn new(base: B, inner: I) -> Arc<Self> {
38 Arc::new(Self { base, inner })
39 }
40
41 /// Transforms this reference to the CallbackSharedState into a pointer to the first
42 /// element of the struct that can be passed to the C API. Every call to
43 /// [`Self::make_raw_ptr`] must be paired with a corresponding call to either
44 /// [`Self::from_raw_ptr`] or [`Self::release_raw_ptr`] or the object will leak.
45 ///
46 /// Note that this returns a mutable pointer because that's usually what the
47 /// C API wants. The expectation is that the C API can have mutable access
48 /// to its own state object, but once we've done this we will not access
49 /// it from rust anymore until/unless we've reclaimed ownership of the
50 /// struct somehow.
51 pub fn make_raw_ptr(this: Arc<Self>) -> *mut B {
52 Arc::into_raw(this) as *mut B
53 }
54
55 /// Gets a raw pointer to the first element of this struct that can be passed to a C
56 /// API without affecting the reference count of the underlying [`Arc`].
57 ///
58 /// Note that this returns a mutable pointer because that's usually what the
59 /// C API wants. The expectation is that the C API can have mutable access
60 /// to its own state object, but once we've done this we will not access
61 /// it from rust anymore until/unless we've reclaimed ownership of the
62 /// struct somehow.
63 pub fn as_raw_ptr(this: &Arc<Self>) -> *mut B {
64 Arc::as_ptr(this) as *mut B
65 }
66
67 /// Converts the given pointer to the base type back to a fully owned
68 /// [`Arc`] to the [`CallbackSharedState`].
69 ///
70 /// This should be used when reclaiming
71 /// the state object after the callback has been called or synchronously
72 /// cancelled.
73 ///
74 /// # Safety
75 ///
76 /// This must only ever be called up to once for every [`Self::make_raw_ptr`]
77 /// that has been called. See the safety comments for [`Arc::from_raw`] for
78 /// more information.
79 pub unsafe fn from_raw_ptr(this: *mut B) -> Arc<Self> {
80 // SAFETY: The caller promises that this is a balanced use of this function.
81 unsafe { Arc::from_raw(this as *const Self) }
82 }
83
84 /// Releases the given pointer to the base type by decrementing the
85 /// reference count on the original Arc.
86 ///
87 /// This should be used when the callback has been called or synchronously
88 /// cancelled, but there's no need to access the base data.
89 ///
90 /// # Safety
91 ///
92 /// This must only ever be called up to once for every [`Self::make_raw_ptr`]
93 /// that has been called. See the safety comments for [`Arc::decrement_strong_count`] for
94 /// more information.
95 pub unsafe fn release_raw_ptr(this: *mut B) {
96 // SAFETY: The caller promises that this is a balanced use of this function.
97 unsafe { Arc::decrement_strong_count(this as *const Self) }
98 }
99}
100
101impl<B, I> std::ops::Deref for CallbackSharedState<B, I> {
102 type Target = I;
103
104 fn deref(&self) -> &Self::Target {
105 &self.inner
106 }
107}