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}