Skip to main content

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