Skip to main content

fuchsia_component_runtime/
lib.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// This library is only usable at API versions from which fuchsia.component.runtime.Capabilities is
6// available.
7
8#[cfg(fuchsia_api_level_at_least = "HEAD")]
9pub use everything::*;
10
11#[cfg(fuchsia_api_level_less_than = "HEAD")]
12mod everything {
13    use fidl as _;
14    use fidl_fuchsia_component_runtime as _;
15    use fidl_fuchsia_io as _;
16    use fuchsia_component_client as _;
17    use futures as _;
18    use zx as _;
19
20    #[cfg(test)]
21    mod tests {
22        use assert_matches as _;
23    }
24}
25
26#[cfg(fuchsia_api_level_at_least = "HEAD")]
27mod everything {
28    use fidl::endpoints::{ServerEnd, create_proxy, create_request_stream};
29    use fidl_fuchsia_component_runtime as fruntime;
30    use fidl_fuchsia_io as fio;
31    use fuchsia_component_client::connect_to_protocol;
32    use futures::future::BoxFuture;
33    use futures::{Future, Stream, StreamExt};
34    use std::pin::{Pin, pin};
35    use std::task::{Context, Poll};
36    use zx::HandleBased;
37
38    /// The value of a data capability. Can be stored in or retrieved from a [`Data`].
39    #[derive(Debug, PartialEq, Clone)]
40    pub enum DataValue {
41        Bytes(Vec<u8>),
42        String(String),
43        Int64(i64),
44        Uint64(u64),
45    }
46
47    impl From<Vec<u8>> for DataValue {
48        fn from(val: Vec<u8>) -> Self {
49            Self::Bytes(val)
50        }
51    }
52
53    impl From<String> for DataValue {
54        fn from(val: String) -> Self {
55            Self::String(val)
56        }
57    }
58
59    impl From<i64> for DataValue {
60        fn from(val: i64) -> Self {
61            Self::Int64(val)
62        }
63    }
64
65    impl From<u64> for DataValue {
66        fn from(val: u64) -> Self {
67            Self::Uint64(val)
68        }
69    }
70
71    impl TryFrom<fruntime::Data> for DataValue {
72        type Error = ();
73
74        fn try_from(val: fruntime::Data) -> Result<Self, Self::Error> {
75            match val {
76                fruntime::Data::Bytes(b) => Ok(Self::Bytes(b)),
77                fruntime::Data::String(b) => Ok(Self::String(b)),
78                fruntime::Data::Int64(b) => Ok(Self::Int64(b)),
79                fruntime::Data::Uint64(b) => Ok(Self::Uint64(b)),
80                _other_value => Err(()),
81            }
82        }
83    }
84
85    impl From<DataValue> for fruntime::Data {
86        fn from(val: DataValue) -> Self {
87            match val {
88                DataValue::Bytes(b) => Self::Bytes(b),
89                DataValue::String(b) => Self::String(b),
90                DataValue::Int64(b) => Self::Int64(b),
91                DataValue::Uint64(b) => Self::Uint64(b),
92            }
93        }
94    }
95
96    /// Receives new channels sent over a [`Connector`]
97    pub struct ConnectorReceiver {
98        pub stream: fruntime::ReceiverRequestStream,
99    }
100
101    impl From<fruntime::ReceiverRequestStream> for ConnectorReceiver {
102        fn from(stream: fruntime::ReceiverRequestStream) -> Self {
103            Self { stream }
104        }
105    }
106
107    impl Stream for ConnectorReceiver {
108        type Item = zx::Channel;
109
110        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
111            let pinned_stream = pin!(&mut self.stream);
112            match pinned_stream.poll_next(cx) {
113                Poll::Pending => Poll::Pending,
114                Poll::Ready(Some(Ok(fruntime::ReceiverRequest::Receive { channel, .. }))) => {
115                    Poll::Ready(Some(channel))
116                }
117                _ => Poll::Ready(None),
118            }
119        }
120    }
121
122    /// Receives new fuchsia.io open requests sent over a [`DirConnector`]
123    pub struct DirConnectorReceiver {
124        pub stream: fruntime::DirReceiverRequestStream,
125    }
126
127    impl From<fruntime::DirReceiverRequestStream> for DirConnectorReceiver {
128        fn from(stream: fruntime::DirReceiverRequestStream) -> Self {
129            Self { stream }
130        }
131    }
132
133    pub struct DirConnectorRequest {
134        pub channel: ServerEnd<fio::DirectoryMarker>,
135        pub path: String,
136        pub flags: fio::Flags,
137    }
138
139    impl Stream for DirConnectorReceiver {
140        type Item = DirConnectorRequest;
141
142        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
143            let pinned_stream = pin!(&mut self.stream);
144            match pinned_stream.poll_next(cx) {
145                Poll::Pending => Poll::Pending,
146                Poll::Ready(Some(Ok(fruntime::DirReceiverRequest::Receive {
147                    channel,
148                    path,
149                    rights,
150                    ..
151                }))) => Poll::Ready(Some(DirConnectorRequest { channel, path, flags: rights })),
152                _ => Poll::Ready(None),
153            }
154        }
155    }
156
157    /// A capability is a typed reference to an object owned by component manager. This reference which
158    /// may used to interact with the referenced object or this reference may be passed to another
159    /// component (or component manager itself).
160    #[derive(Debug, Clone)]
161    pub enum Capability {
162        Connector(Connector),
163        ConnectorRouter(ConnectorRouter),
164        Data(Data),
165        DataRouter(DataRouter),
166        Dictionary(Dictionary),
167        DictionaryRouter(DictionaryRouter),
168        DirConnector(DirConnector),
169        DirConnectorRouter(DirConnectorRouter),
170        InstanceToken(InstanceToken),
171    }
172
173    impl Capability {
174        pub fn from_raw_with_proxy(
175            capabilities_proxy: fruntime::CapabilitiesProxy,
176            handle: zx::EventPair,
177            type_: fruntime::CapabilityType,
178        ) -> Self {
179            match type_ {
180                fruntime::CapabilityType::Data => Self::Data(Data { handle, capabilities_proxy }),
181                fruntime::CapabilityType::Connector => {
182                    Self::Connector(Connector { handle, capabilities_proxy })
183                }
184                fruntime::CapabilityType::DirConnector => {
185                    Self::DirConnector(DirConnector { handle, capabilities_proxy })
186                }
187                fruntime::CapabilityType::Dictionary => {
188                    Self::Dictionary(Dictionary { handle, capabilities_proxy })
189                }
190                fruntime::CapabilityType::DataRouter => {
191                    Self::DataRouter(DataRouter { handle, capabilities_proxy })
192                }
193                fruntime::CapabilityType::ConnectorRouter => {
194                    Self::ConnectorRouter(ConnectorRouter { handle, capabilities_proxy })
195                }
196                fruntime::CapabilityType::DirConnectorRouter => {
197                    Self::DirConnectorRouter(DirConnectorRouter { handle, capabilities_proxy })
198                }
199                fruntime::CapabilityType::DictionaryRouter => {
200                    Self::DictionaryRouter(DictionaryRouter { handle, capabilities_proxy })
201                }
202                fruntime::CapabilityType::InstanceToken => {
203                    Self::InstanceToken(InstanceToken { handle })
204                }
205                other_type => panic!("unknown capability type: {other_type:?}"),
206            }
207        }
208
209        pub fn as_event_pair(&self) -> &zx::EventPair {
210            match self {
211                Self::Data(data) => &data.handle,
212                Self::Connector(connector) => &connector.handle,
213                Self::DirConnector(dir_connector) => &dir_connector.handle,
214                Self::Dictionary(dictionary) => &dictionary.handle,
215                Self::DataRouter(data_router) => &data_router.handle,
216                Self::ConnectorRouter(connector_router) => &connector_router.handle,
217                Self::DirConnectorRouter(dir_connector_router) => &dir_connector_router.handle,
218                Self::DictionaryRouter(dictionary_router) => &dictionary_router.handle,
219                Self::InstanceToken(instance_token) => &instance_token.handle,
220            }
221        }
222    }
223
224    impl From<Data> for Capability {
225        fn from(val: Data) -> Self {
226            Self::Data(val)
227        }
228    }
229
230    impl From<Connector> for Capability {
231        fn from(val: Connector) -> Self {
232            Self::Connector(val)
233        }
234    }
235
236    impl From<DirConnector> for Capability {
237        fn from(val: DirConnector) -> Self {
238            Self::DirConnector(val)
239        }
240    }
241
242    impl From<Dictionary> for Capability {
243        fn from(val: Dictionary) -> Self {
244            Self::Dictionary(val)
245        }
246    }
247
248    impl From<DataRouter> for Capability {
249        fn from(val: DataRouter) -> Self {
250            Self::DataRouter(val)
251        }
252    }
253
254    impl From<ConnectorRouter> for Capability {
255        fn from(val: ConnectorRouter) -> Self {
256            Self::ConnectorRouter(val)
257        }
258    }
259
260    impl From<DirConnectorRouter> for Capability {
261        fn from(val: DirConnectorRouter) -> Self {
262            Self::DirConnectorRouter(val)
263        }
264    }
265
266    impl From<DictionaryRouter> for Capability {
267        fn from(val: DictionaryRouter) -> Self {
268            Self::DictionaryRouter(val)
269        }
270    }
271
272    impl From<InstanceToken> for Capability {
273        fn from(val: InstanceToken) -> Self {
274            Self::InstanceToken(val)
275        }
276    }
277
278    impl TryFrom<Capability> for Data {
279        type Error = ();
280        fn try_from(val: Capability) -> Result<Self, Self::Error> {
281            match val {
282                Capability::Data(val) => Ok(val),
283                _ => Err(()),
284            }
285        }
286    }
287
288    impl TryFrom<Capability> for Connector {
289        type Error = ();
290        fn try_from(val: Capability) -> Result<Self, Self::Error> {
291            match val {
292                Capability::Connector(val) => Ok(val),
293                _ => Err(()),
294            }
295        }
296    }
297
298    impl TryFrom<Capability> for DirConnector {
299        type Error = ();
300        fn try_from(val: Capability) -> Result<Self, Self::Error> {
301            match val {
302                Capability::DirConnector(val) => Ok(val),
303                _ => Err(()),
304            }
305        }
306    }
307
308    impl TryFrom<Capability> for Dictionary {
309        type Error = ();
310        fn try_from(val: Capability) -> Result<Self, Self::Error> {
311            match val {
312                Capability::Dictionary(val) => Ok(val),
313                _ => Err(()),
314            }
315        }
316    }
317
318    impl TryFrom<Capability> for DataRouter {
319        type Error = ();
320        fn try_from(val: Capability) -> Result<Self, Self::Error> {
321            match val {
322                Capability::DataRouter(val) => Ok(val),
323                _ => Err(()),
324            }
325        }
326    }
327
328    impl TryFrom<Capability> for ConnectorRouter {
329        type Error = ();
330        fn try_from(val: Capability) -> Result<Self, Self::Error> {
331            match val {
332                Capability::ConnectorRouter(val) => Ok(val),
333                _ => Err(()),
334            }
335        }
336    }
337
338    impl TryFrom<Capability> for DirConnectorRouter {
339        type Error = ();
340        fn try_from(val: Capability) -> Result<Self, Self::Error> {
341            match val {
342                Capability::DirConnectorRouter(val) => Ok(val),
343                _ => Err(()),
344            }
345        }
346    }
347
348    impl TryFrom<Capability> for DictionaryRouter {
349        type Error = ();
350        fn try_from(val: Capability) -> Result<Self, Self::Error> {
351            match val {
352                Capability::DictionaryRouter(val) => Ok(val),
353                _ => Err(()),
354            }
355        }
356    }
357
358    impl TryFrom<Capability> for InstanceToken {
359        type Error = ();
360        fn try_from(val: Capability) -> Result<Self, Self::Error> {
361            match val {
362                Capability::InstanceToken(val) => Ok(val),
363                _ => Err(()),
364            }
365        }
366    }
367
368    /// A data capability holds a bit of static data which can be read back.
369    #[derive(Debug)]
370    pub struct Data {
371        /// The handle that references this capability
372        pub handle: zx::EventPair,
373
374        /// The proxy used to create this capability, and the proxy which will be used to perform
375        /// operations on this capability.
376        pub capabilities_proxy: fruntime::CapabilitiesProxy,
377    }
378
379    impl From<zx::EventPair> for Data {
380        fn from(handle: zx::EventPair) -> Self {
381            Self {
382                handle,
383                capabilities_proxy: connect_to_protocol::<fruntime::CapabilitiesMarker>()
384                    .expect("failed to connect to fuchsia.component.runtime.Capabilities"),
385            }
386        }
387    }
388
389    impl Data {
390        /// Creates a new [`Data`], connecting to `/svc/fuchsia.component.runtime.Capabilities` to do
391        /// so.
392        pub async fn new(value: DataValue) -> Self {
393            let proxy = connect_to_protocol::<fruntime::CapabilitiesMarker>()
394                .expect("failed to connect to fuchsia.component.runtime.Capabilities");
395            Self::new_with_proxy(proxy, value).await
396        }
397
398        /// Creates a new [`Data`] using the provided `capabilities_proxy`.
399        pub async fn new_with_proxy(
400            capabilities_proxy: fruntime::CapabilitiesProxy,
401            value: DataValue,
402        ) -> Self {
403            let (handle, handle_other_end) = zx::EventPair::create();
404            capabilities_proxy
405                .data_create(handle_other_end, &value.into())
406                .await
407                .expect("failed to use fuchsia.component.runtime.Capabilities")
408                .expect(
409                    "this should be impossible, we passed a valid handle with the correct rights",
410                );
411            Self { handle, capabilities_proxy }
412        }
413
414        /// Associates `other_handle` with the same object referenced by this capability, so that
415        /// whoever holds the other end of `other_handle` can refer to our capability.
416        pub async fn associate_with_handle(&self, other_handle: zx::EventPair) {
417            self.capabilities_proxy
418                .capability_associate_handle(
419                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
420                        "failed to duplicate handle, please only use handles with the duplicate right",
421                    ),
422                    other_handle,
423                )
424                .await
425                .expect("failed to use fuchsia.component.runtime.Capabilities")
426                .expect("failed to clone onto handle, does it have sufficient rights?");
427        }
428
429        pub async fn get_value(&self) -> DataValue {
430            self.capabilities_proxy
431                .data_get(self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
432                    "failed to duplicate handle, please only use handles with the duplicate right",
433                ))
434                .await
435                .expect("failed to use fuchsia.component.runtime.Capabilities")
436                .expect("failed to get data value")
437                .try_into()
438                .expect("we were sent an invalid data value")
439        }
440    }
441
442    impl Clone for Data {
443        fn clone(&self) -> Self {
444            Self {
445                handle: self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
446                    "failed to duplicate handle, please only use handles with the duplicate right",
447                ),
448                capabilities_proxy: self.capabilities_proxy.clone(),
449            }
450        }
451    }
452
453    /// A connector capability can be invoked to send a channel to the creator of the connector.
454    #[derive(Debug)]
455    pub struct Connector {
456        /// The handle that references this capability
457        pub handle: zx::EventPair,
458
459        /// The proxy used to create this capability, and the proxy which will be used to perform
460        /// operations on this capability.
461        pub capabilities_proxy: fruntime::CapabilitiesProxy,
462    }
463
464    impl From<zx::EventPair> for Connector {
465        fn from(handle: zx::EventPair) -> Self {
466            Self {
467                handle,
468                capabilities_proxy: connect_to_protocol::<fruntime::CapabilitiesMarker>()
469                    .expect("failed to connect to fuchsia.component.runtime.Capabilities"),
470            }
471        }
472    }
473
474    impl Connector {
475        /// Creates a new [`Connector`], connecting to `/svc/fuchsia.component.runtime.Capabilities` to
476        /// do so.
477        pub async fn new() -> (Self, ConnectorReceiver) {
478            let proxy = connect_to_protocol::<fruntime::CapabilitiesMarker>()
479                .expect("failed to connect to fuchsia.component.runtime.Capabilities");
480            Self::new_with_proxy(proxy).await
481        }
482
483        /// Creates a new [`Connector`] using the provided `capabilities_proxy`.
484        pub async fn new_with_proxy(
485            capabilities_proxy: fruntime::CapabilitiesProxy,
486        ) -> (Self, ConnectorReceiver) {
487            let (handle, handle_other_end) = zx::EventPair::create();
488            let (receiver_client_end, stream) = create_request_stream::<fruntime::ReceiverMarker>();
489            capabilities_proxy
490                .connector_create(handle_other_end, receiver_client_end)
491                .await
492                .expect("failed to use fuchsia.component.runtime.Capabilities")
493                .expect(
494                    "this should be impossible, we passed a valid handle with the correct rights",
495                );
496            let connector = Self { handle, capabilities_proxy };
497            let receiver = ConnectorReceiver { stream };
498            (connector, receiver)
499        }
500
501        /// Associates `other_handle` with the same object referenced by this capability, so that
502        /// whoever holds the other end of `other_handle` can refer to our capability.
503        pub async fn associate_with_handle(&self, other_handle: zx::EventPair) {
504            self.capabilities_proxy
505                .capability_associate_handle(
506                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
507                        "failed to duplicate handle, please only use handles with the duplicate right",
508                    ),
509                    other_handle,
510                )
511                .await
512                .expect("failed to use fuchsia.component.runtime.Capabilities")
513                .expect("failed to clone onto handle, does it have sufficient rights?");
514        }
515
516        pub async fn connect(
517            &self,
518            channel: zx::Channel,
519        ) -> Result<(), fruntime::CapabilitiesError> {
520            self.capabilities_proxy
521                .connector_open(
522                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
523                        "failed to duplicate handle, please only use handles with the duplicate right",
524                    ),
525                    channel,
526                )
527                .await
528                .expect("failed to use fuchsia.component.runtime.Capabilities")
529        }
530    }
531
532    impl Clone for Connector {
533        fn clone(&self) -> Self {
534            Self {
535                handle: self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
536                    "failed to duplicate handle, please only use handles with the duplicate right",
537                ),
538                capabilities_proxy: self.capabilities_proxy.clone(),
539            }
540        }
541    }
542
543    /// A dir connector can be invoked to send a fuchsia.io open request to the creator of the dir
544    /// connector.
545    #[derive(Debug)]
546    pub struct DirConnector {
547        /// The handle that references this capability
548        pub handle: zx::EventPair,
549
550        /// The proxy used to create this capability, and the proxy which will be used to perform
551        /// operations on this capability.
552        pub capabilities_proxy: fruntime::CapabilitiesProxy,
553    }
554
555    impl From<zx::EventPair> for DirConnector {
556        fn from(handle: zx::EventPair) -> Self {
557            Self {
558                handle,
559                capabilities_proxy: connect_to_protocol::<fruntime::CapabilitiesMarker>()
560                    .expect("failed to connect to fuchsia.component.runtime.Capabilities"),
561            }
562        }
563    }
564
565    impl DirConnector {
566        /// Creates a new [`DirConnector`], connecting to `/svc/fuchsia.component.runtime.Capabilities`
567        /// to do so.
568        pub async fn new() -> (Self, DirConnectorReceiver) {
569            let proxy = connect_to_protocol::<fruntime::CapabilitiesMarker>()
570                .expect("failed to connect to fuchsia.component.runtime.Capabilities");
571            Self::new_with_proxy(proxy).await
572        }
573
574        /// Creates a new [`DirConnector`] using the provided `capabilities_proxy`.
575        pub async fn new_with_proxy(
576            capabilities_proxy: fruntime::CapabilitiesProxy,
577        ) -> (Self, DirConnectorReceiver) {
578            let (handle, handle_other_end) = zx::EventPair::create();
579            let (receiver_client_end, stream) =
580                create_request_stream::<fruntime::DirReceiverMarker>();
581            capabilities_proxy
582                .dir_connector_create(handle_other_end, receiver_client_end)
583                .await
584                .expect("failed to use fuchsia.component.runtime.Capabilities")
585                .expect(
586                    "this should be impossible, we passed a valid handle with the correct rights",
587                );
588            let connector = Self { handle, capabilities_proxy };
589            let receiver = DirConnectorReceiver { stream };
590            (connector, receiver)
591        }
592
593        /// Associates `other_handle` with the same object referenced by this capability, so that
594        /// whoever holds the other end of `other_handle` can refer to our capability.
595        pub async fn associate_with_handle(&self, other_handle: zx::EventPair) {
596            self.capabilities_proxy
597                .capability_associate_handle(
598                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
599                        "failed to duplicate handle, please only use handles with the duplicate right",
600                    ),
601                    other_handle,
602                )
603                .await
604                .expect("failed to use fuchsia.component.runtime.Capabilities")
605                .expect("failed to clone onto handle, does it have sufficient rights?");
606        }
607
608        pub async fn connect(
609            &self,
610            server_end: ServerEnd<fio::DirectoryMarker>,
611            flags: Option<fio::Flags>,
612            path: Option<String>,
613        ) -> Result<(), fruntime::CapabilitiesError> {
614            self.capabilities_proxy
615                .dir_connector_open(fruntime::CapabilitiesDirConnectorOpenRequest {
616                    dir_connector: Some(self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
617                        "failed to duplicate handle, please only use handles with the duplicate right",
618                    )),
619                    channel: Some(server_end),
620                    flags,
621                    path,
622                    ..Default::default()
623                })
624                .await
625                .expect("failed to use fuchsia.component.runtime.Capabilities")
626        }
627    }
628
629    impl Clone for DirConnector {
630        fn clone(&self) -> Self {
631            Self {
632                handle: self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
633                    "failed to duplicate handle, please only use handles with the duplicate right",
634                ),
635                capabilities_proxy: self.capabilities_proxy.clone(),
636            }
637        }
638    }
639
640    /// A dictionary is a key-value mapping of names to other capabilities.
641    #[derive(Debug)]
642    pub struct Dictionary {
643        /// The handle that references this capability
644        pub handle: zx::EventPair,
645
646        /// The proxy used to create this capability, and the proxy which will be used to perform
647        /// operations on this capability.
648        pub capabilities_proxy: fruntime::CapabilitiesProxy,
649    }
650
651    impl From<zx::EventPair> for Dictionary {
652        fn from(handle: zx::EventPair) -> Self {
653            Self {
654                handle,
655                capabilities_proxy: connect_to_protocol::<fruntime::CapabilitiesMarker>()
656                    .expect("failed to connect to fuchsia.component.runtime.Capabilities"),
657            }
658        }
659    }
660
661    impl Dictionary {
662        /// Creates a new [`Dictionary`], connecting to `/svc/fuchsia.component.runtime.Capabilities`
663        /// to do so.
664        pub async fn new() -> Self {
665            let proxy = connect_to_protocol::<fruntime::CapabilitiesMarker>()
666                .expect("failed to connect to fuchsia.component.runtime.Capabilities");
667            Self::new_with_proxy(proxy).await
668        }
669
670        /// Creates a new [`Dictionary`] using the provided `capabilities_proxy`.
671        pub async fn new_with_proxy(capabilities_proxy: fruntime::CapabilitiesProxy) -> Self {
672            let (handle, handle_other_end) = zx::EventPair::create();
673            capabilities_proxy
674                .dictionary_create(handle_other_end)
675                .await
676                .expect("failed to use fuchsia.component.runtime.Capabilities")
677                .expect(
678                    "this should be impossible, we passed a valid handle with the correct rights",
679                );
680            Self { handle, capabilities_proxy }
681        }
682
683        /// Associates `other_handle` with the same object referenced by this capability, so that
684        /// whoever holds the other end of `other_handle` can refer to our capability.
685        pub async fn associate_with_handle(&self, other_handle: zx::EventPair) {
686            self.capabilities_proxy
687                .capability_associate_handle(
688                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
689                        "failed to duplicate handle, please only use handles with the duplicate right",
690                    ),
691                    other_handle,
692                )
693                .await
694                .expect("failed to use fuchsia.component.runtime.Capabilities")
695                .expect("failed to clone onto handle, does it have sufficient rights?");
696        }
697
698        pub async fn insert(&self, key: &str, value: impl Into<Capability>) {
699            let capability: Capability = value.into();
700            let dictionary = self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
701                "failed to duplicate handle, please only use handles with the duplicate right",
702            );
703            let handle =
704                capability.as_event_pair().duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
705                    "failed to duplicate handle, please only use handles with the duplicate right",
706                );
707            self.capabilities_proxy
708                .dictionary_insert(dictionary, key, handle)
709                .await
710                .expect("failed to use fuchsia.component.runtime.Capabilities")
711                .expect("failed to insert into dictionary")
712        }
713
714        pub async fn get(&self, key: &str) -> Option<Capability> {
715            let (handle, handle_other_end) = zx::EventPair::create();
716            let res = self
717                .capabilities_proxy
718                .dictionary_get(
719                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
720                        "failed to duplicate handle, please only use handles with the duplicate right",
721                    ),
722                    key,
723                    handle_other_end,
724                )
725                .await
726                .expect("failed to use fuchsia.component.runtime.Capabilities");
727            match res {
728                Ok(type_) => Some(Capability::from_raw_with_proxy(
729                    self.capabilities_proxy.clone(),
730                    handle,
731                    type_,
732                )),
733                Err(fruntime::CapabilitiesError::NoSuchCapability) => None,
734                Err(other_error) => panic!(
735                    "this arm should be impossible, we passed a valid handle with the correct rights: {other_error:?}"
736                ),
737            }
738        }
739
740        pub async fn remove(&self, key: &str) -> Option<Capability> {
741            let (handle, handle_other_end) = zx::EventPair::create();
742            let res = self
743                .capabilities_proxy
744                .dictionary_remove(fruntime::CapabilitiesDictionaryRemoveRequest {
745                    dictionary: Some(self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
746                        "failed to duplicate handle, please only use handles with the duplicate right",
747                    )),
748                    key: Some(key.to_string()),
749                    value: Some(handle_other_end),
750                    ..Default::default()
751                })
752                .await
753                .expect("failed to use fuchsia.component.runtime.Capabilities");
754            match res {
755                Ok(type_) => Some(Capability::from_raw_with_proxy(
756                    self.capabilities_proxy.clone(),
757                    handle,
758                    type_,
759                )),
760                Err(fruntime::CapabilitiesError::NoSuchCapability) => None,
761                Err(other_error) => panic!(
762                    "this arm should be impossible, we passed a valid handle with the correct rights: {other_error:?}"
763                ),
764            }
765        }
766
767        pub async fn keys(&self) -> DictionaryKeysStream {
768            let (key_iterator_proxy, key_iterator_server_end) =
769                create_proxy::<fruntime::DictionaryKeyIteratorMarker>();
770            self.capabilities_proxy
771                .dictionary_iterate_keys(
772                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
773                        "failed to duplicate handle, please only use handles with the duplicate right",
774                    ),
775                    key_iterator_server_end,
776                )
777                .await
778                .expect("failed to use fuchsia.component.runtime.Capabilities")
779                .expect("failed to iterate keys");
780            DictionaryKeysStream { key_iterator_proxy, key_cache: vec![], more_keys_fut: None }
781        }
782    }
783
784    impl Clone for Dictionary {
785        fn clone(&self) -> Self {
786            Self {
787                handle: self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
788                    "failed to duplicate handle, please only use handles with the duplicate right",
789                ),
790                capabilities_proxy: self.capabilities_proxy.clone(),
791            }
792        }
793    }
794
795    pub struct DictionaryKeysStream {
796        key_iterator_proxy: fruntime::DictionaryKeyIteratorProxy,
797        key_cache: Vec<String>,
798        more_keys_fut: Option<
799            fidl::client::QueryResponseFut<
800                Vec<String>,
801                fidl::encoding::DefaultFuchsiaResourceDialect,
802            >,
803        >,
804    }
805
806    impl Stream for DictionaryKeysStream {
807        type Item = String;
808
809        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
810            if let Some(key) = self.key_cache.pop() {
811                return Poll::Ready(Some(key));
812            }
813            if self.more_keys_fut.is_none() {
814                self.more_keys_fut = Some(self.key_iterator_proxy.get_next());
815            }
816
817            let fut = self.more_keys_fut.as_mut().expect("we just checked if this was None");
818            let fut = pin!(fut);
819            match fut.poll(cx) {
820                Poll::Ready(Ok(mut keys)) if !keys.is_empty() => {
821                    self.key_cache.append(&mut keys);
822                    self.key_cache.reverse();
823                    self.more_keys_fut = None;
824                    Poll::Ready(self.key_cache.pop())
825                }
826                Poll::Pending => Poll::Pending,
827                _ => Poll::Ready(None),
828            }
829        }
830    }
831
832    /// An instance token is an opaque identifier tied to a specific component instance. Component
833    /// manager relies on these internally to identify which component has initiated a given routing
834    /// operation.
835    #[derive(Debug)]
836    pub struct InstanceToken {
837        /// The handle that references this capability
838        pub handle: zx::EventPair,
839    }
840
841    impl From<zx::EventPair> for InstanceToken {
842        fn from(handle: zx::EventPair) -> Self {
843            Self { handle }
844        }
845    }
846
847    impl InstanceToken {
848        /// Creates a new [`InstanceToken`], connecting to
849        /// `/svc/fuchsia.component.runtime.Capabilities` to do so. This instance token will be tied to
850        /// the component that `fuchsia.component.runtime.Capabilities` is scoped to (which will
851        /// typically be the same component this code is running in).
852        pub async fn new() -> Self {
853            let proxy = connect_to_protocol::<fruntime::CapabilitiesMarker>()
854                .expect("failed to connect to fuchsia.component.runtime.Capabilities");
855            Self::new_with_proxy(proxy).await
856        }
857
858        /// Creates a new [`InstanceToken`] using the provided `capabilities_proxy`.
859        pub async fn new_with_proxy(capabilities_proxy: fruntime::CapabilitiesProxy) -> Self {
860            let (handle, handle_other_end) = zx::EventPair::create();
861            capabilities_proxy
862                .instance_token_create(handle_other_end)
863                .await
864                .expect("failed to use fuchsia.component.runtime.Capabilities")
865                .expect(
866                    "this should be impossible, we passed a valid handle with the correct rights",
867                );
868            Self { handle }
869        }
870    }
871
872    impl Clone for InstanceToken {
873        fn clone(&self) -> Self {
874            Self {
875                handle: self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
876                    "failed to duplicate handle, please only use handles with the duplicate right",
877                ),
878            }
879        }
880    }
881
882    /// A connector router may be used to request it produce a [`Connector`] capability. The router may
883    /// decide to do so, decline to do so, or return an error, and it may rely on the contents of the
884    /// `metadata` provided when `route` is called to do so. Routers may also delegate the request to
885    /// other routers, often mutating `metadata` when they do.
886    #[derive(Debug)]
887    pub struct ConnectorRouter {
888        /// The handle that references this capability
889        pub handle: zx::EventPair,
890
891        /// The proxy used to create this capability, and the proxy which will be used to perform
892        /// operations on this capability.
893        pub capabilities_proxy: fruntime::CapabilitiesProxy,
894    }
895
896    impl From<zx::EventPair> for ConnectorRouter {
897        fn from(handle: zx::EventPair) -> Self {
898            Self {
899                handle,
900                capabilities_proxy: connect_to_protocol::<fruntime::CapabilitiesMarker>()
901                    .expect("failed to connect to fuchsia.component.runtime.Capabilities"),
902            }
903        }
904    }
905
906    impl ConnectorRouter {
907        /// Creates a new [`ConnectorRouter`], connecting to
908        /// `/svc/fuchsia.component.runtime.Capabilities` to do so.
909        pub async fn new() -> (Self, ConnectorRouterReceiver) {
910            let proxy = connect_to_protocol::<fruntime::CapabilitiesMarker>()
911                .expect("failed to connect to fuchsia.component.runtime.Capabilities");
912            Self::new_with_proxy(proxy).await
913        }
914
915        /// Creates a new [`ConnectorRouter`] using the provided `capabilities_proxy`.
916        pub async fn new_with_proxy(
917            capabilities_proxy: fruntime::CapabilitiesProxy,
918        ) -> (Self, ConnectorRouterReceiver) {
919            let (handle, handle_other_end) = zx::EventPair::create();
920            let (client_end, stream) = create_request_stream::<fruntime::ConnectorRouterMarker>();
921            capabilities_proxy
922                .connector_router_create(handle_other_end, client_end)
923                .await
924                .expect("failed to use fuchsia.component.runtime.Capabilities")
925                .expect(
926                    "this should be impossible, we passed a valid handle with the correct rights",
927                );
928            let connector = Self { handle, capabilities_proxy };
929            let receiver = ConnectorRouterReceiver { stream };
930            (connector, receiver)
931        }
932
933        /// Associates `other_handle` with the same object referenced by this capability, so that
934        /// whoever holds the other end of `other_handle` can refer to our capability.
935        pub async fn associate_with_handle(&self, other_handle: zx::EventPair) {
936            self.capabilities_proxy
937                .capability_associate_handle(
938                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
939                        "failed to duplicate handle, please only use handles with the duplicate right",
940                    ),
941                    other_handle,
942                )
943                .await
944                .expect("failed to use fuchsia.component.runtime.Capabilities")
945                .expect("failed to clone onto handle, does it have sufficient rights?");
946        }
947
948        pub async fn route(
949            &self,
950            request: fruntime::RouteRequest,
951            instance_token: &InstanceToken,
952        ) -> Result<Option<Connector>, zx::Status> {
953            let (connector, connector_other_end) = zx::EventPair::create();
954            let res = self
955                .capabilities_proxy
956                .connector_router_route(
957                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
958                        "failed to duplicate handle, please only use handles with the duplicate right",
959                    ),
960                    &request,
961                    instance_token.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
962                        "failed to duplicate handle, please only use handles with the duplicate right",
963                    ),
964                    connector_other_end,
965                )
966                .await
967                .expect("failed to use fuchsia.component.runtime.Capabilities");
968            match res.map_err(|s| zx::Status::from_raw(s))? {
969                fruntime::RouterResponse::Success => Ok(Some(Connector {
970                    handle: connector,
971                    capabilities_proxy: self.capabilities_proxy.clone(),
972                })),
973                fruntime::RouterResponse::Unavailable => Ok(None),
974                _ => Err(zx::Status::INTERNAL),
975            }
976        }
977    }
978
979    impl Clone for ConnectorRouter {
980        fn clone(&self) -> Self {
981            Self {
982                handle: self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
983                    "failed to duplicate handle, please only use handles with the duplicate right",
984                ),
985                capabilities_proxy: self.capabilities_proxy.clone(),
986            }
987        }
988    }
989
990    /// A connector router receiver will receive requests for connector capabilities.
991    pub struct ConnectorRouterReceiver {
992        pub stream: fruntime::ConnectorRouterRequestStream,
993    }
994
995    impl From<fruntime::ConnectorRouterRequestStream> for ConnectorRouterReceiver {
996        fn from(stream: fruntime::ConnectorRouterRequestStream) -> Self {
997            Self { stream }
998        }
999    }
1000
1001    impl Stream for ConnectorRouterReceiver {
1002        type Item = (
1003            fruntime::RouteRequest,
1004            InstanceToken,
1005            zx::EventPair,
1006            fruntime::ConnectorRouterRouteResponder,
1007        );
1008
1009        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1010            let pinned_stream = pin!(&mut self.stream);
1011            match pinned_stream.poll_next(cx) {
1012                Poll::Pending => Poll::Pending,
1013                Poll::Ready(Some(Ok(fruntime::ConnectorRouterRequest::Route {
1014                    request,
1015                    instance_token,
1016                    handle,
1017                    responder,
1018                }))) => {
1019                    let instance_token = InstanceToken { handle: instance_token };
1020                    Poll::Ready(Some((request, instance_token, handle, responder)))
1021                }
1022                _ => Poll::Ready(None),
1023            }
1024        }
1025    }
1026
1027    impl ConnectorRouterReceiver {
1028        pub async fn handle_with<F>(mut self, f: F)
1029        where
1030            F: Fn(
1031                    fruntime::RouteRequest,
1032                    InstanceToken,
1033                ) -> BoxFuture<'static, Result<Option<Connector>, zx::Status>>
1034                + Sync
1035                + Send
1036                + 'static,
1037        {
1038            while let Some((request, instance_token, event_pair, responder)) = self.next().await {
1039                let res = match f(request, instance_token).await {
1040                    Ok(Some(connector)) => {
1041                        connector.associate_with_handle(event_pair).await;
1042                        Ok(fruntime::RouterResponse::Success)
1043                    }
1044                    Ok(None) => Ok(fruntime::RouterResponse::Unavailable),
1045                    Err(e) => Err(e.into_raw()),
1046                };
1047                let _ = responder.send(res);
1048            }
1049        }
1050    }
1051
1052    /// A dir connector router may be used to request it produce a [`DirConnector`] capability. The
1053    /// router may decide to do so, decline to do so, or return an error, and it may rely on the
1054    /// contents of the `metadata` provided when `route` is called to do so. Routers may also delegate
1055    /// the request to other routers, often mutating `metadata` when they do.
1056    #[derive(Debug)]
1057    pub struct DirConnectorRouter {
1058        /// The handle that references this capability
1059        pub handle: zx::EventPair,
1060
1061        /// The proxy used to create this capability, and the proxy which will be used to perform
1062        /// operations on this capability.
1063        pub capabilities_proxy: fruntime::CapabilitiesProxy,
1064    }
1065
1066    impl From<zx::EventPair> for DirConnectorRouter {
1067        fn from(handle: zx::EventPair) -> Self {
1068            Self {
1069                handle,
1070                capabilities_proxy: connect_to_protocol::<fruntime::CapabilitiesMarker>()
1071                    .expect("failed to connect to fuchsia.component.runtime.Capabilities"),
1072            }
1073        }
1074    }
1075
1076    impl DirConnectorRouter {
1077        /// Creates a new [`DirConnectorRouter`], connecting to
1078        /// `/svc/fuchsia.component.runtime.Capabilities` to do so.
1079        pub async fn new() -> (Self, DirConnectorRouterReceiver) {
1080            let proxy = connect_to_protocol::<fruntime::CapabilitiesMarker>()
1081                .expect("failed to connect to fuchsia.component.runtime.Capabilities");
1082            Self::new_with_proxy(proxy).await
1083        }
1084
1085        /// Creates a new [`DirConnectorRouter`] using the provided `capabilities_proxy`.
1086        pub async fn new_with_proxy(
1087            capabilities_proxy: fruntime::CapabilitiesProxy,
1088        ) -> (Self, DirConnectorRouterReceiver) {
1089            let (handle, handle_other_end) = zx::EventPair::create();
1090            let (client_end, stream) =
1091                create_request_stream::<fruntime::DirConnectorRouterMarker>();
1092            capabilities_proxy
1093                .dir_connector_router_create(handle_other_end, client_end)
1094                .await
1095                .expect("failed to use fuchsia.component.runtime.Capabilities")
1096                .expect(
1097                    "this should be impossible, we passed a valid handle with the correct rights",
1098                );
1099            let connector = Self { handle, capabilities_proxy };
1100            let receiver = DirConnectorRouterReceiver { stream };
1101            (connector, receiver)
1102        }
1103
1104        /// Associates `other_handle` with the same object referenced by this capability, so that
1105        /// whoever holds the other end of `other_handle` can refer to our capability.
1106        pub async fn associate_with_handle(&self, other_handle: zx::EventPair) {
1107            self.capabilities_proxy
1108                .capability_associate_handle(
1109                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1110                        "failed to duplicate handle, please only use handles with the duplicate right",
1111                    ),
1112                    other_handle,
1113                )
1114                .await
1115                .expect("failed to use fuchsia.component.runtime.Capabilities")
1116                .expect("failed to clone onto handle, does it have sufficient rights?");
1117        }
1118
1119        pub async fn route(
1120            &self,
1121            request: fruntime::RouteRequest,
1122            instance_token: &InstanceToken,
1123        ) -> Result<Option<DirConnector>, zx::Status> {
1124            let (connector, connector_other_end) = zx::EventPair::create();
1125            let res = self
1126                .capabilities_proxy
1127                .dir_connector_router_route(
1128                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1129                        "failed to duplicate handle, please only use handles with the duplicate right",
1130                    ),
1131                    &request,
1132                    instance_token.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1133                        "failed to duplicate handle, please only use handles with the duplicate right",
1134                    ),
1135                    connector_other_end,
1136                )
1137                .await
1138                .expect("failed to use fuchsia.component.runtime.Capabilities");
1139            match res.map_err(|s| zx::Status::from_raw(s))? {
1140                fruntime::RouterResponse::Success => Ok(Some(DirConnector {
1141                    handle: connector,
1142                    capabilities_proxy: self.capabilities_proxy.clone(),
1143                })),
1144                fruntime::RouterResponse::Unavailable => Ok(None),
1145                _ => Err(zx::Status::INTERNAL),
1146            }
1147        }
1148    }
1149
1150    impl Clone for DirConnectorRouter {
1151        fn clone(&self) -> Self {
1152            Self {
1153                handle: self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1154                    "failed to duplicate handle, please only use handles with the duplicate right",
1155                ),
1156                capabilities_proxy: self.capabilities_proxy.clone(),
1157            }
1158        }
1159    }
1160
1161    /// A dir connector router receiver will receive requests for dir connector capabilities.
1162    pub struct DirConnectorRouterReceiver {
1163        pub stream: fruntime::DirConnectorRouterRequestStream,
1164    }
1165
1166    impl From<fruntime::DirConnectorRouterRequestStream> for DirConnectorRouterReceiver {
1167        fn from(stream: fruntime::DirConnectorRouterRequestStream) -> Self {
1168            Self { stream }
1169        }
1170    }
1171
1172    impl Stream for DirConnectorRouterReceiver {
1173        type Item = (
1174            fruntime::RouteRequest,
1175            InstanceToken,
1176            zx::EventPair,
1177            fruntime::DirConnectorRouterRouteResponder,
1178        );
1179
1180        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1181            let pinned_stream = pin!(&mut self.stream);
1182            match pinned_stream.poll_next(cx) {
1183                Poll::Pending => Poll::Pending,
1184                Poll::Ready(Some(Ok(fruntime::DirConnectorRouterRequest::Route {
1185                    request,
1186                    instance_token,
1187                    handle,
1188                    responder,
1189                }))) => {
1190                    let instance_token = InstanceToken { handle: instance_token };
1191                    Poll::Ready(Some((request, instance_token, handle, responder)))
1192                }
1193                _ => Poll::Ready(None),
1194            }
1195        }
1196    }
1197
1198    impl DirConnectorRouterReceiver {
1199        pub async fn handle_with<F>(mut self, f: F)
1200        where
1201            F: Fn(
1202                    fruntime::RouteRequest,
1203                    InstanceToken,
1204                ) -> BoxFuture<'static, Result<Option<DirConnector>, zx::Status>>
1205                + Sync
1206                + Send
1207                + 'static,
1208        {
1209            while let Some((request, instance_token, event_pair, responder)) = self.next().await {
1210                let res = match f(request, instance_token).await {
1211                    Ok(Some(dictionary)) => {
1212                        dictionary.associate_with_handle(event_pair).await;
1213                        Ok(fruntime::RouterResponse::Success)
1214                    }
1215                    Ok(None) => Ok(fruntime::RouterResponse::Unavailable),
1216                    Err(e) => Err(e.into_raw()),
1217                };
1218                let _ = responder.send(res);
1219            }
1220        }
1221    }
1222
1223    /// A dictionary router may be used to request it produce a [`Dictionary`] capability. The router
1224    /// may decide to do so, decline to do so, or return an error, and it may rely on the contents of
1225    /// the `metadata` provided when `route` is called to do so. Routers may also delegate the request
1226    /// to other routers, often mutating `metadata` when they do.
1227    #[derive(Debug)]
1228    pub struct DictionaryRouter {
1229        /// The handle that references this capability
1230        pub handle: zx::EventPair,
1231
1232        /// The proxy used to create this capability, and the proxy which will be used to perform
1233        /// operations on this capability.
1234        pub capabilities_proxy: fruntime::CapabilitiesProxy,
1235    }
1236
1237    impl From<zx::EventPair> for DictionaryRouter {
1238        fn from(handle: zx::EventPair) -> Self {
1239            Self {
1240                handle,
1241                capabilities_proxy: connect_to_protocol::<fruntime::CapabilitiesMarker>()
1242                    .expect("failed to connect to fuchsia.component.runtime.Capabilities"),
1243            }
1244        }
1245    }
1246
1247    impl DictionaryRouter {
1248        /// Creates a new [`DictionaryRouter`], connecting to
1249        /// `/svc/fuchsia.component.runtime.Capabilities` to do so.
1250        pub async fn new() -> (Self, DictionaryRouterReceiver) {
1251            let proxy = connect_to_protocol::<fruntime::CapabilitiesMarker>()
1252                .expect("failed to connect to fuchsia.component.runtime.Capabilities");
1253            Self::new_with_proxy(proxy).await
1254        }
1255
1256        /// Creates a new [`DictionaryRouter`] using the provided `capabilities_proxy`.
1257        pub async fn new_with_proxy(
1258            capabilities_proxy: fruntime::CapabilitiesProxy,
1259        ) -> (Self, DictionaryRouterReceiver) {
1260            let (handle, handle_other_end) = zx::EventPair::create();
1261            let (client_end, stream) = create_request_stream::<fruntime::DictionaryRouterMarker>();
1262            capabilities_proxy
1263                .dictionary_router_create(handle_other_end, client_end)
1264                .await
1265                .expect("failed to use fuchsia.component.runtime.Capabilities")
1266                .expect(
1267                    "this should be impossible, we passed a valid handle with the correct rights",
1268                );
1269            let connector = Self { handle, capabilities_proxy };
1270            let receiver = DictionaryRouterReceiver { stream };
1271            (connector, receiver)
1272        }
1273
1274        /// Associates `other_handle` with the same object referenced by this capability, so that
1275        /// whoever holds the other end of `other_handle` can refer to our capability.
1276        pub async fn associate_with_handle(&self, other_handle: zx::EventPair) {
1277            self.capabilities_proxy
1278                .capability_associate_handle(
1279                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1280                        "failed to duplicate handle, please only use handles with the duplicate right",
1281                    ),
1282                    other_handle,
1283                )
1284                .await
1285                .expect("failed to use fuchsia.component.runtime.Capabilities")
1286                .expect("failed to clone onto handle, does it have sufficient rights?");
1287        }
1288
1289        pub async fn route(
1290            &self,
1291            request: fruntime::RouteRequest,
1292            instance_token: &InstanceToken,
1293        ) -> Result<Option<Dictionary>, zx::Status> {
1294            let (connector, connector_other_end) = zx::EventPair::create();
1295            let res = self
1296                .capabilities_proxy
1297                .dictionary_router_route(
1298                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1299                        "failed to duplicate handle, please only use handles with the duplicate right",
1300                    ),
1301                    &request,
1302                    instance_token.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1303                        "failed to duplicate handle, please only use handles with the duplicate right",
1304                    ),
1305                    connector_other_end,
1306                )
1307                .await
1308                .expect("failed to use fuchsia.component.runtime.Capabilities");
1309            match res.map_err(|s| zx::Status::from_raw(s))? {
1310                fruntime::RouterResponse::Success => Ok(Some(Dictionary {
1311                    handle: connector,
1312                    capabilities_proxy: self.capabilities_proxy.clone(),
1313                })),
1314                fruntime::RouterResponse::Unavailable => Ok(None),
1315                _ => Err(zx::Status::INTERNAL),
1316            }
1317        }
1318    }
1319
1320    impl Clone for DictionaryRouter {
1321        fn clone(&self) -> Self {
1322            Self {
1323                handle: self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1324                    "failed to duplicate handle, please only use handles with the duplicate right",
1325                ),
1326                capabilities_proxy: self.capabilities_proxy.clone(),
1327            }
1328        }
1329    }
1330
1331    /// A dictionary router receiver will receive requests for dictionary capabilities.
1332    pub struct DictionaryRouterReceiver {
1333        pub stream: fruntime::DictionaryRouterRequestStream,
1334    }
1335
1336    impl From<fruntime::DictionaryRouterRequestStream> for DictionaryRouterReceiver {
1337        fn from(stream: fruntime::DictionaryRouterRequestStream) -> Self {
1338            Self { stream }
1339        }
1340    }
1341
1342    impl Stream for DictionaryRouterReceiver {
1343        type Item = (
1344            fruntime::RouteRequest,
1345            InstanceToken,
1346            zx::EventPair,
1347            fruntime::DictionaryRouterRouteResponder,
1348        );
1349
1350        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1351            let pinned_stream = pin!(&mut self.stream);
1352            match pinned_stream.poll_next(cx) {
1353                Poll::Pending => Poll::Pending,
1354                Poll::Ready(Some(Ok(fruntime::DictionaryRouterRequest::Route {
1355                    request,
1356                    instance_token,
1357                    handle,
1358                    responder,
1359                }))) => {
1360                    let instance_token = InstanceToken { handle: instance_token };
1361                    Poll::Ready(Some((request, instance_token, handle, responder)))
1362                }
1363                _ => Poll::Ready(None),
1364            }
1365        }
1366    }
1367
1368    impl DictionaryRouterReceiver {
1369        pub async fn handle_with<F>(mut self, f: F)
1370        where
1371            F: Fn(
1372                    fruntime::RouteRequest,
1373                    InstanceToken,
1374                ) -> BoxFuture<'static, Result<Option<Dictionary>, zx::Status>>
1375                + Sync
1376                + Send
1377                + 'static,
1378        {
1379            while let Some((request, instance_token, event_pair, responder)) = self.next().await {
1380                let res = match f(request, instance_token).await {
1381                    Ok(Some(dictionary)) => {
1382                        dictionary.associate_with_handle(event_pair).await;
1383                        Ok(fruntime::RouterResponse::Success)
1384                    }
1385                    Ok(None) => Ok(fruntime::RouterResponse::Unavailable),
1386                    Err(e) => Err(e.into_raw()),
1387                };
1388                let _ = responder.send(res);
1389            }
1390        }
1391    }
1392
1393    /// A data router may be used to request it produce a [`Data`] capability. The router may decide to
1394    /// do so, decline to do so, or return an error, and it may rely on the contents of the `metadata`
1395    /// provided when `route` is called to do so. Routers may also delegate the request to other
1396    /// routers, often mutating `metadata` when they do.
1397    #[derive(Debug)]
1398    pub struct DataRouter {
1399        /// The handle that references this capability
1400        pub handle: zx::EventPair,
1401
1402        /// The proxy used to create this capability, and the proxy which will be used to perform
1403        /// operations on this capability.
1404        pub capabilities_proxy: fruntime::CapabilitiesProxy,
1405    }
1406
1407    impl From<zx::EventPair> for DataRouter {
1408        fn from(handle: zx::EventPair) -> Self {
1409            Self {
1410                handle,
1411                capabilities_proxy: connect_to_protocol::<fruntime::CapabilitiesMarker>()
1412                    .expect("failed to connect to fuchsia.component.runtime.Capabilities"),
1413            }
1414        }
1415    }
1416
1417    impl DataRouter {
1418        /// Creates a new [`DataRouter`], connecting to `/svc/fuchsia.component.runtime.Capabilities`
1419        /// to do so.
1420        pub async fn new() -> (Self, DataRouterReceiver) {
1421            let proxy = connect_to_protocol::<fruntime::CapabilitiesMarker>()
1422                .expect("failed to connect to fuchsia.component.runtime.Capabilities");
1423            Self::new_with_proxy(proxy).await
1424        }
1425
1426        /// Creates a new [`DataRouter`] using the provided `capabilities_proxy`.
1427        pub async fn new_with_proxy(
1428            capabilities_proxy: fruntime::CapabilitiesProxy,
1429        ) -> (Self, DataRouterReceiver) {
1430            let (handle, handle_other_end) = zx::EventPair::create();
1431            let (client_end, stream) = create_request_stream::<fruntime::DataRouterMarker>();
1432            capabilities_proxy
1433                .data_router_create(handle_other_end, client_end)
1434                .await
1435                .expect("failed to use fuchsia.component.runtime.Capabilities")
1436                .expect(
1437                    "this should be impossible, we passed a valid handle with the correct rights",
1438                );
1439            let connector = Self { handle, capabilities_proxy };
1440            let receiver = DataRouterReceiver { stream };
1441            (connector, receiver)
1442        }
1443
1444        /// Associates `other_handle` with the same object referenced by this capability, so that
1445        /// whoever holds the other end of `other_handle` can refer to our capability.
1446        pub async fn associate_with_handle(&self, other_handle: zx::EventPair) {
1447            self.capabilities_proxy
1448                .capability_associate_handle(
1449                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1450                        "failed to duplicate handle, please only use handles with the duplicate right",
1451                    ),
1452                    other_handle,
1453                )
1454                .await
1455                .expect("failed to use fuchsia.component.runtime.Capabilities")
1456                .expect("failed to clone onto handle, does it have sufficient rights?");
1457        }
1458
1459        pub async fn route(
1460            &self,
1461            request: fruntime::RouteRequest,
1462            instance_token: &InstanceToken,
1463        ) -> Result<Option<Data>, zx::Status> {
1464            let (connector, connector_other_end) = zx::EventPair::create();
1465            let res = self
1466                .capabilities_proxy
1467                .data_router_route(
1468                    self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1469                        "failed to duplicate handle, please only use handles with the duplicate right",
1470                    ),
1471                    &request,
1472                    instance_token.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1473                        "failed to duplicate handle, please only use handles with the duplicate right",
1474                    ),
1475                    connector_other_end,
1476                )
1477                .await
1478                .expect("failed to use fuchsia.component.runtime.Capabilities");
1479            match res.map_err(|s| zx::Status::from_raw(s))? {
1480                fruntime::RouterResponse::Success => Ok(Some(Data {
1481                    handle: connector,
1482                    capabilities_proxy: self.capabilities_proxy.clone(),
1483                })),
1484                fruntime::RouterResponse::Unavailable => Ok(None),
1485                _ => Err(zx::Status::INTERNAL),
1486            }
1487        }
1488    }
1489
1490    impl Clone for DataRouter {
1491        fn clone(&self) -> Self {
1492            Self {
1493                handle: self.handle.duplicate_handle(zx::Rights::SAME_RIGHTS).expect(
1494                    "failed to duplicate handle, please only use handles with the duplicate right",
1495                ),
1496                capabilities_proxy: self.capabilities_proxy.clone(),
1497            }
1498        }
1499    }
1500
1501    /// A data router receiver will receive requests for data capabilities.
1502    pub struct DataRouterReceiver {
1503        pub stream: fruntime::DataRouterRequestStream,
1504    }
1505
1506    impl From<fruntime::DataRouterRequestStream> for DataRouterReceiver {
1507        fn from(stream: fruntime::DataRouterRequestStream) -> Self {
1508            Self { stream }
1509        }
1510    }
1511
1512    impl Stream for DataRouterReceiver {
1513        type Item = (
1514            fruntime::RouteRequest,
1515            InstanceToken,
1516            zx::EventPair,
1517            fruntime::DataRouterRouteResponder,
1518        );
1519
1520        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1521            let pinned_stream = pin!(&mut self.stream);
1522            match pinned_stream.poll_next(cx) {
1523                Poll::Pending => Poll::Pending,
1524                Poll::Ready(Some(Ok(fruntime::DataRouterRequest::Route {
1525                    request,
1526                    instance_token,
1527                    handle,
1528                    responder,
1529                }))) => {
1530                    let instance_token = InstanceToken { handle: instance_token };
1531                    Poll::Ready(Some((request, instance_token, handle, responder)))
1532                }
1533                _ => Poll::Ready(None),
1534            }
1535        }
1536    }
1537
1538    impl DataRouterReceiver {
1539        pub async fn handle_with<F>(mut self, f: F)
1540        where
1541            F: Fn(
1542                    fruntime::RouteRequest,
1543                    InstanceToken,
1544                ) -> BoxFuture<'static, Result<Option<Data>, zx::Status>>
1545                + Sync
1546                + Send
1547                + 'static,
1548        {
1549            while let Some((request, instance_token, event_pair, responder)) = self.next().await {
1550                let res = match f(request, instance_token).await {
1551                    Ok(Some(data)) => {
1552                        data.associate_with_handle(event_pair).await;
1553                        Ok(fruntime::RouterResponse::Success)
1554                    }
1555                    Ok(None) => Ok(fruntime::RouterResponse::Unavailable),
1556                    Err(e) => Err(e.into_raw()),
1557                };
1558                let _ = responder.send(res);
1559            }
1560        }
1561    }
1562
1563    #[cfg(test)]
1564    mod tests {
1565        use super::*;
1566        use assert_matches::assert_matches;
1567        use futures::StreamExt;
1568        use std::collections::HashSet;
1569        use zx::AsHandleRef;
1570
1571        #[fuchsia::test]
1572        async fn connector_test() {
1573            let (connector, mut receiver) = Connector::new().await;
1574            let (c1, c2) = zx::Channel::create();
1575            connector.connect(c1).await.unwrap();
1576            let c1 = receiver.next().await.unwrap();
1577            assert_eq!(c1.basic_info().unwrap().koid, c2.basic_info().unwrap().related_koid);
1578        }
1579
1580        #[fuchsia::test]
1581        async fn dir_connector_test() {
1582            let (dir_connector, mut dir_receiver) = DirConnector::new().await;
1583            let (client_end, server_end) =
1584                fidl::endpoints::create_endpoints::<fio::DirectoryMarker>();
1585            dir_connector
1586                .connect(server_end, Some(fio::PERM_WRITABLE), Some("foo/bar".to_string()))
1587                .await
1588                .unwrap();
1589            let dir_request = dir_receiver.next().await.unwrap();
1590            assert_eq!(
1591                client_end.as_handle_ref().basic_info().unwrap().koid,
1592                dir_request.channel.as_handle_ref().basic_info().unwrap().related_koid
1593            );
1594            assert_eq!("foo/bar", dir_request.path);
1595            assert_eq!(fio::PERM_WRITABLE, dir_request.flags);
1596        }
1597
1598        #[fuchsia::test]
1599        async fn dictionary_test() {
1600            let dictionary = Dictionary::new().await;
1601            assert!(dictionary.get("foo").await.is_none());
1602            dictionary.insert("foo", Dictionary::new().await).await;
1603            assert_matches!(dictionary.get("foo").await, Some(Capability::Dictionary(_)));
1604            let mut keys_stream = dictionary.keys().await;
1605            assert_eq!(Some("foo".to_string()), keys_stream.next().await);
1606            assert_eq!(None, keys_stream.next().await);
1607
1608            assert_matches!(dictionary.remove("foo").await, Some(Capability::Dictionary(_)));
1609            assert_matches!(dictionary.remove("foo").await, None);
1610            assert!(dictionary.get("foo").await.is_none());
1611        }
1612
1613        #[fuchsia::test]
1614        async fn dictionary_key_iterator_many_keys_test() {
1615            let dictionary = Dictionary::new().await;
1616
1617            // We want to make more keys than will fit in a single FIDL message.
1618            let mut keys = HashSet::new();
1619            for i in 0..zx::sys::ZX_CHANNEL_MAX_MSG_BYTES / 50 {
1620                keys.insert(format!("{:0100}", i));
1621            }
1622            for key in keys.iter() {
1623                dictionary.insert(key.as_str(), Dictionary::new().await).await;
1624            }
1625
1626            let mut keys_stream = dictionary.keys().await;
1627            let mut returned_keys = HashSet::new();
1628            while let Some(key) = keys_stream.next().await {
1629                returned_keys.insert(key);
1630            }
1631            assert_eq!(keys, returned_keys);
1632        }
1633
1634        #[fuchsia::test]
1635        async fn all_capabilities_into_and_out_of_a_dictionary_test() {
1636            let dictionary = Dictionary::new().await;
1637            let (connector, _receiver) = Connector::new().await;
1638            dictionary.insert("connector", connector).await;
1639            let (dir_connector, _dir_receiver) = DirConnector::new().await;
1640            dictionary.insert("dir_connector", dir_connector).await;
1641            dictionary.insert("dictionary", Dictionary::new().await).await;
1642            dictionary.insert("data", Data::new(DataValue::Int64(1)).await).await;
1643            let (connector_router, _connector_router_receiver) = ConnectorRouter::new().await;
1644            dictionary.insert("connector_router", connector_router).await;
1645            let (dir_connector_router, _dir_connector_router_receiver) =
1646                DirConnectorRouter::new().await;
1647            dictionary.insert("dir_connector_router", dir_connector_router).await;
1648            let (dictionary_router, _dictionary_router_receiver) = DictionaryRouter::new().await;
1649            dictionary.insert("dictionary_router", dictionary_router).await;
1650            let (data_router, _data_router_receiver) = DataRouter::new().await;
1651            dictionary.insert("data_router", data_router).await;
1652            dictionary.insert("instance_token", InstanceToken::new().await).await;
1653
1654            assert_matches!(dictionary.get("connector").await, Some(Capability::Connector(_)));
1655            assert_matches!(
1656                dictionary.get("dir_connector").await,
1657                Some(Capability::DirConnector(_))
1658            );
1659            assert_matches!(dictionary.get("dictionary").await, Some(Capability::Dictionary(_)));
1660            assert_matches!(dictionary.get("data").await, Some(Capability::Data(_)));
1661            assert_matches!(
1662                dictionary.get("connector_router").await,
1663                Some(Capability::ConnectorRouter(_))
1664            );
1665            assert_matches!(
1666                dictionary.get("dir_connector_router").await,
1667                Some(Capability::DirConnectorRouter(_))
1668            );
1669            assert_matches!(
1670                dictionary.get("dictionary_router").await,
1671                Some(Capability::DictionaryRouter(_))
1672            );
1673            assert_matches!(dictionary.get("data_router").await, Some(Capability::DataRouter(_)));
1674            assert_matches!(
1675                dictionary.get("instance_token").await,
1676                Some(Capability::InstanceToken(_))
1677            );
1678        }
1679
1680        #[fuchsia::test]
1681        async fn data_test() {
1682            let data = Data::new(DataValue::Uint64(100)).await;
1683            assert_eq!(DataValue::Uint64(100), data.get_value().await);
1684        }
1685
1686        #[fuchsia::test]
1687        async fn connector_router_test() {
1688            let (connector_router, mut connector_router_receiver) = ConnectorRouter::new().await;
1689
1690            let result_fut = fuchsia_async::Task::spawn(async move {
1691                let instance_token = InstanceToken::new().await;
1692                connector_router.route(fruntime::RouteRequest::default(), &instance_token).await
1693            });
1694
1695            let (_route_request, _instance_token, handle, responder) =
1696                connector_router_receiver.next().await.unwrap();
1697            let (connector, mut receiver) = Connector::new().await;
1698            connector.associate_with_handle(handle).await;
1699            responder.send(Ok(fruntime::RouterResponse::Success)).unwrap();
1700
1701            let connector = match result_fut.await {
1702                Ok(Some(connector)) => connector,
1703                other_value => panic!("unexpected route result: {other_value:?}"),
1704            };
1705
1706            let (c1, c2) = zx::Channel::create();
1707            connector.connect(c1).await.unwrap();
1708            let c1 = receiver.next().await.unwrap();
1709            assert_eq!(c1.basic_info().unwrap().koid, c2.basic_info().unwrap().related_koid);
1710        }
1711
1712        #[fuchsia::test]
1713        async fn dir_connector_router_test() {
1714            let (dir_connector_router, mut dir_connector_router_receiver) =
1715                DirConnectorRouter::new().await;
1716
1717            let result_fut = fuchsia_async::Task::spawn(async move {
1718                let instance_token = InstanceToken::new().await;
1719                dir_connector_router.route(fruntime::RouteRequest::default(), &instance_token).await
1720            });
1721
1722            let (_route_request, _instance_token, handle, responder) =
1723                dir_connector_router_receiver.next().await.unwrap();
1724            let (dir_connector, mut dir_receiver) = DirConnector::new().await;
1725            dir_connector.associate_with_handle(handle).await;
1726            responder.send(Ok(fruntime::RouterResponse::Success)).unwrap();
1727
1728            let dir_connector = match result_fut.await {
1729                Ok(Some(dir_connector)) => dir_connector,
1730                other_value => panic!("unexpected route result: {other_value:?}"),
1731            };
1732
1733            let (client_end, server_end) =
1734                fidl::endpoints::create_endpoints::<fio::DirectoryMarker>();
1735            dir_connector
1736                .connect(server_end, Some(fio::PERM_WRITABLE), Some("foo/bar".to_string()))
1737                .await
1738                .unwrap();
1739            let dir_request = dir_receiver.next().await.unwrap();
1740            assert_eq!(
1741                client_end.as_handle_ref().basic_info().unwrap().koid,
1742                dir_request.channel.as_handle_ref().basic_info().unwrap().related_koid
1743            );
1744            assert_eq!("foo/bar", dir_request.path);
1745            assert_eq!(fio::PERM_WRITABLE, dir_request.flags);
1746        }
1747
1748        #[fuchsia::test]
1749        async fn dictionary_router_test() {
1750            let (dictionary_router, mut dictionary_router_receiver) = DictionaryRouter::new().await;
1751
1752            let result_fut = fuchsia_async::Task::spawn(async move {
1753                let instance_token = InstanceToken::new().await;
1754                dictionary_router.route(fruntime::RouteRequest::default(), &instance_token).await
1755            });
1756
1757            let (_route_request, _instance_token, handle, responder) =
1758                dictionary_router_receiver.next().await.unwrap();
1759            let dictionary = Dictionary::new().await;
1760            dictionary.insert("foo", Data::new(DataValue::String("bar".to_string())).await).await;
1761            dictionary.associate_with_handle(handle).await;
1762            responder.send(Ok(fruntime::RouterResponse::Success)).unwrap();
1763
1764            let dictionary = match result_fut.await {
1765                Ok(Some(dictionary)) => dictionary,
1766                other_value => panic!("unexpected route result: {other_value:?}"),
1767            };
1768
1769            let data = match dictionary.get("foo").await {
1770                Some(Capability::Data(data)) => data,
1771                other_value => panic!("unexpected dictionary contents: {other_value:?}"),
1772            };
1773            assert_eq!(data.get_value().await, DataValue::String("bar".to_string()));
1774        }
1775    }
1776}