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