Skip to main content

fuchsia_component_runtime/
lib.rs

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