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