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