fdomain_client/
handle.rs

1// Copyright 2024 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
5use self::unowned::Unowned;
6use crate::responder::Responder;
7use crate::{Client, Error, ordinals};
8use fidl_fuchsia_fdomain as proto;
9use futures::FutureExt;
10use std::future::Future;
11use std::pin::Pin;
12use std::sync::{Arc, Weak};
13use std::task::{Context, Poll};
14
15pub(crate) mod unowned;
16
17// TODO(https://fxbug.dev/465766514): remove
18pub type NullableHandle = Handle;
19
20/// A handle of unspecified type within a remote FDomain.
21#[derive(Debug)]
22pub struct Handle {
23    pub(crate) id: u32,
24    pub(crate) client: Weak<Client>,
25}
26
27impl Handle {
28    /// Returns the ID of the Handle. This should be unique to the handle for its lifetime.
29    pub fn id(&self) -> u32 {
30        self.id
31    }
32
33    /// Checks if there is an active client for this handle.
34    ///
35    /// Only really useful if you are doing something when this function returning `false`,
36    /// and you want to fail fast with a specific error.
37    pub fn has_client(&self) -> bool {
38        self.client.upgrade().is_some()
39    }
40
41    /// Get the FDomain client this handle belongs to.
42    pub(crate) fn client(&self) -> Arc<Client> {
43        self.client.upgrade().unwrap_or_else(|| Arc::clone(&*crate::DEAD_CLIENT))
44    }
45
46    /// Get an invalid handle.
47    pub fn invalid() -> Self {
48        Handle { id: 0, client: Weak::new() }
49    }
50
51    /// Convert this into an unowned handle (one that is borrowed and will not close when dropped).
52    ///
53    /// An example:
54    ///
55    /// ```
56    /// let handle: &Handle = /* ... */;
57    /// let socket = handle.as_unowned::<fdomain_client::Socket>();
58    /// let mut buf: [u8; 4096] = [0; 4096];
59    /// socket.read(&mut buf[..]).await?;
60    /// ```
61    ///
62    /// This is only really useful for contexts in which the handles are going to be stored and
63    /// retrieved from a data structure and potentially used as arbitrary handle-based data types.
64    pub fn as_unowned<H: HandleBased>(&self) -> Unowned<H> {
65        Unowned::from_handle(self)
66    }
67}
68
69impl std::cmp::PartialEq for Handle {
70    fn eq(&self, other: &Self) -> bool {
71        self.id == other.id && Weak::ptr_eq(&self.client, &other.client)
72    }
73}
74
75impl std::cmp::Eq for Handle {}
76
77impl std::cmp::PartialOrd for Handle {
78    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
79        Some(self.cmp(other))
80    }
81}
82
83impl std::cmp::Ord for Handle {
84    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
85        self.id.cmp(&other.id)
86    }
87}
88
89impl std::hash::Hash for Handle {
90    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
91        self.id.hash(state);
92    }
93}
94
95/// A reference to a [`Handle`]. Can be derived from a [`Handle`] or any other
96/// type implementing [`AsHandleRef`].
97#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
98pub struct HandleRef<'a>(&'a Handle);
99
100impl std::ops::Deref for HandleRef<'_> {
101    type Target = Handle;
102
103    fn deref(&self) -> &Self::Target {
104        self.0
105    }
106}
107
108impl HandleRef<'_> {
109    /// Replace this handle with a new handle to the same object, with different
110    /// rights.
111    pub fn duplicate(
112        &self,
113        rights: fidl::Rights,
114    ) -> impl Future<Output = Result<Handle, Error>> + 'static + use<> {
115        let client = self.0.client();
116        let handle = self.0.proto();
117        let new_handle = client.new_hid();
118        let id = new_handle.id;
119        client
120            .transaction(
121                ordinals::DUPLICATE,
122                proto::FDomainDuplicateRequest { handle, new_handle, rights },
123                Responder::Duplicate,
124            )
125            .map(move |res| res.map(|_| Handle { id, client: Arc::downgrade(&client) }))
126    }
127
128    /// Assert and deassert signals on this handle.
129    pub fn signal(
130        &self,
131        set: fidl::Signals,
132        clear: fidl::Signals,
133    ) -> impl Future<Output = Result<(), Error>> + use<> {
134        let handle = self.proto();
135        let client = self.client();
136
137        client.transaction(
138            ordinals::SIGNAL,
139            proto::FDomainSignalRequest { handle, set: set.bits(), clear: clear.bits() },
140            Responder::Signal,
141        )
142    }
143
144    pub fn get_koid(&self) -> impl Future<Output = Result<u64, Error>> {
145        let handle = self.proto();
146        let client = self.client();
147        client
148            .transaction(
149                ordinals::GET_KOID,
150                proto::FDomainGetKoidRequest { handle },
151                Responder::GetKoid,
152            )
153            .map(move |res| res.map(|r| r.koid))
154    }
155}
156
157/// Trait for turning handle-based types into [`HandleRef`], and for handle
158/// operations that can be performed on [`HandleRef`].
159pub trait AsHandleRef {
160    fn as_handle_ref(&self) -> HandleRef<'_>;
161    fn object_type() -> fidl::ObjectType;
162
163    fn u32_id(&self) -> u32 {
164        self.as_handle_ref().0.id
165    }
166
167    fn signal_handle(
168        &self,
169        set: fidl::Signals,
170        clear: fidl::Signals,
171    ) -> impl Future<Output = Result<(), Error>> {
172        self.as_handle_ref().signal(set, clear)
173    }
174
175    /// Get the client supporting this handle. See `fidl::Proxy::domain`.
176    fn domain(&self) -> Arc<Client> {
177        self.as_handle_ref().0.client()
178    }
179}
180
181impl AsHandleRef for Handle {
182    /// Get a [`HandleRef`] referring to the handle contained in `Self`
183    fn as_handle_ref(&self) -> HandleRef<'_> {
184        HandleRef(self)
185    }
186
187    /// Get the object type of this handle.
188    fn object_type() -> fidl::ObjectType {
189        fidl::ObjectType::NONE
190    }
191}
192
193/// Trait for handle-based types that have a peer.
194pub trait Peered: HandleBased {
195    /// Assert and deassert signals on this handle's peer.
196    fn signal_peer(
197        &self,
198        set: fidl::Signals,
199        clear: fidl::Signals,
200    ) -> impl Future<Output = Result<(), Error>> {
201        let handle = self.as_handle_ref().proto();
202        let client = self.as_handle_ref().client();
203
204        client.transaction(
205            ordinals::SIGNAL_PEER,
206            proto::FDomainSignalPeerRequest { handle, set: set.bits(), clear: clear.bits() },
207            Responder::SignalPeer,
208        )
209    }
210}
211
212pub trait HandleBased: AsHandleRef + From<Handle> + Into<Handle> {
213    /// Closes this handle. Surfaces errors that dropping the handle will not.
214    fn close(self) -> impl Future<Output = Result<(), Error>> {
215        let h = <Self as Into<Handle>>::into(self);
216        Handle::close(h)
217    }
218
219    /// Duplicate this handle.
220    fn duplicate_handle(&self, rights: fidl::Rights) -> impl Future<Output = Result<Self, Error>> {
221        let fut = self.as_handle_ref().duplicate(rights);
222        async move { fut.await.map(|handle| Self::from(handle)) }
223    }
224
225    /// Replace this handle with an equivalent one with different rights.
226    fn replace_handle(self, rights: fidl::Rights) -> impl Future<Output = Result<Self, Error>> {
227        let h = <Self as Into<Handle>>::into(self);
228        async move { h.replace(rights).await.map(|handle| Self::from(handle)) }
229    }
230
231    /// Convert this handle-based value into a pure [`Handle`].
232    fn into_handle(self) -> Handle {
233        self.into()
234    }
235
236    /// Construct a new handle-based value from a [`Handle`].
237    fn from_handle(handle: Handle) -> Self {
238        Self::from(handle)
239    }
240
241    /// Turn this handle-based value into one of a different type.
242    fn into_handle_based<H: HandleBased>(self) -> H {
243        H::from_handle(self.into_handle())
244    }
245
246    /// Turn another handle-based type into this one.
247    fn from_handle_based<H: HandleBased>(h: H) -> Self {
248        Self::from_handle(h.into_handle())
249    }
250
251    /// Drop ownership of this handle and make it invalid, without closing the handle.
252    fn invalidate(&mut self);
253}
254
255impl HandleBased for Handle {
256    fn invalidate(&mut self) {
257        // Detach from the client so we don't close the handle when we drop self.
258        self.client = Weak::new();
259    }
260}
261
262/// Future which waits for a particular set of signals to be asserted for a
263/// given handle.
264pub struct OnFDomainSignals {
265    fut: futures::future::BoxFuture<'static, Result<fidl::Signals, Error>>,
266}
267
268impl OnFDomainSignals {
269    /// Construct a new [`OnFDomainSignals`]. The next time one of the given
270    /// signals is asserted the future will return. The return value is all
271    /// asserted signals intersected with the input signals.
272    pub fn new(handle: &Handle, signals: fidl::Signals) -> Self {
273        let client = handle.client();
274        let handle = handle.proto();
275        let fut = client
276            .transaction(
277                ordinals::WAIT_FOR_SIGNALS,
278                proto::FDomainWaitForSignalsRequest { handle, signals: signals.bits() },
279                Responder::WaitForSignals,
280            )
281            .map(|f| f.map(|x| fidl::Signals::from_bits_retain(x.signals)));
282        OnFDomainSignals { fut: fut.boxed() }
283    }
284}
285
286impl Future for OnFDomainSignals {
287    type Output = Result<fidl::Signals, Error>;
288
289    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
290        self.fut.as_mut().poll(cx)
291    }
292}
293
294impl Handle {
295    /// Get a proto::HandleId with the ID of this handle.
296    pub(crate) fn proto(&self) -> proto::HandleId {
297        proto::HandleId { id: self.id }
298    }
299
300    /// Get a proto::HandleId with the ID of this handle, then destroy this object
301    /// without sending a request to close the handlel.
302    pub(crate) fn take_proto(mut self) -> proto::HandleId {
303        let ret = self.proto();
304        self.invalidate();
305        ret
306    }
307
308    /// Close this handle. Surfaces errors that dropping the handle will not.
309    pub fn close(self) -> impl Future<Output = Result<(), Error>> {
310        let client = self.client();
311        client.transaction(
312            ordinals::CLOSE,
313            proto::FDomainCloseRequest { handles: vec![self.take_proto()] },
314            Responder::Close,
315        )
316    }
317
318    /// Replace this handle with a new handle to the same object, with different
319    /// rights.
320    pub fn replace(self, rights: fidl::Rights) -> impl Future<Output = Result<Handle, Error>> {
321        let client = self.client();
322        let handle = self.take_proto();
323        {
324            let mut client = client.0.lock();
325            let _ = client.channel_read_states.remove(&handle);
326            let _ = client.socket_read_states.remove(&handle);
327        }
328        let new_handle = client.new_hid();
329
330        let id = new_handle.id;
331        let ret = Handle { id, client: Arc::downgrade(&client) };
332        let fut = client.transaction(
333            ordinals::REPLACE,
334            proto::FDomainReplaceRequest { handle, new_handle, rights },
335            Responder::Replace,
336        );
337
338        async move {
339            fut.await?;
340            Ok(ret)
341        }
342    }
343}
344
345impl Drop for Handle {
346    fn drop(&mut self) {
347        if let Some(client) = self.client.upgrade() {
348            let mut client = client.0.lock();
349            if client.waiting_to_close.is_empty() {
350                client.waiting_to_close_waker.wake_by_ref();
351            }
352            client.waiting_to_close.push(self.proto());
353        }
354    }
355}
356
357macro_rules! handle_type {
358    ($name:ident $objtype:ident) => {
359        impl From<$name> for Handle {
360            fn from(other: $name) -> Handle {
361                other.0
362            }
363        }
364
365        impl From<Handle> for $name {
366            fn from(other: Handle) -> $name {
367                $name(other)
368            }
369        }
370
371        impl $crate::AsHandleRef for $name {
372            fn as_handle_ref(&self) -> $crate::HandleRef<'_> {
373                self.0.as_handle_ref()
374            }
375
376            fn object_type(
377            ) -> fidl::ObjectType {
378                ::fidl::ObjectType::$objtype
379            }
380        }
381
382        impl $crate::HandleBased for $name {
383            fn invalidate(&mut self) {
384                self.0.invalidate();
385            }
386        }
387    };
388    ($name:ident $objtype:ident peered) => {
389        handle_type!($name $objtype);
390
391        impl $crate::Peered for $name {}
392    };
393}
394
395pub(crate) use handle_type;