Skip to main content

runtime_capabilities/
connector.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{CapabilityBound, Receiver};
6use futures::channel::mpsc;
7use std::fmt::Debug;
8use std::sync::Arc;
9
10/// Types that implement [`Connectable`] let the holder send channels
11/// to them.
12pub trait Connectable: Send + Sync + Debug {
13    fn send(&self, channel: fidl::Channel) -> Result<(), ()>;
14}
15
16impl Connectable for mpsc::UnboundedSender<fidl::Channel> {
17    fn send(&self, channel: fidl::Channel) -> Result<(), ()> {
18        self.unbounded_send(channel).map_err(|_| ())
19    }
20}
21
22/// A capability that transfers another capability to a [Receiver].
23#[derive(Debug, Clone)]
24pub struct Connector {
25    inner: Arc<dyn Connectable>,
26}
27
28impl CapabilityBound for Connector {
29    fn debug_typename() -> &'static str {
30        "Connector"
31    }
32}
33
34impl Connector {
35    pub fn new() -> (Receiver, Self) {
36        let (sender, receiver) = mpsc::unbounded();
37        let receiver = Receiver::new(receiver);
38        let this = Self::new_sendable(sender);
39        (receiver, this)
40    }
41
42    pub fn new_sendable(connector: impl Connectable + 'static) -> Self {
43        Self { inner: Arc::new(connector) }
44    }
45
46    pub fn send(&self, channel: fidl::Channel) -> Result<(), ()> {
47        self.inner.send(channel)
48    }
49}
50
51impl Connectable for Connector {
52    fn send(&self, channel: fidl::Channel) -> Result<(), ()> {
53        self.send(channel)
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use fidl::handle::{Channel, HandleBased, Rights};
61    use fidl_fuchsia_component_sandbox as fsandbox;
62
63    // NOTE: sending-and-receiving tests are written in `receiver.rs`.
64
65    /// Tests that a Connector can be cloned by cloning its FIDL token.
66    /// and capabilities sent to the original and clone arrive at the same Receiver.
67    #[fuchsia::test]
68    async fn fidl_clone() {
69        let (receiver, sender) = Connector::new();
70
71        // Send a channel through the Connector.
72        let (ch1, _ch2) = Channel::create();
73        sender.send(ch1).unwrap();
74
75        // Convert the Sender to a FIDL token.
76        let connector: fsandbox::Connector = sender.into();
77
78        // Clone the Sender by cloning the token.
79        let token_clone = fsandbox::Connector {
80            token: connector.token.duplicate_handle(Rights::SAME_RIGHTS).unwrap(),
81        };
82        let connector_clone = match crate::Capability::try_from(fsandbox::Capability::Connector(
83            token_clone,
84        ))
85        .unwrap()
86        {
87            crate::Capability::Connector(connector) => connector,
88            capability @ _ => panic!("wrong type {capability:?}"),
89        };
90
91        // Send a channel through the cloned Sender.
92        let (ch1, _ch2) = Channel::create();
93        connector_clone.send(ch1).unwrap();
94
95        // The Receiver should receive two channels, one from each connector.
96        for _ in 0..2 {
97            let _ch = receiver.receive().await.unwrap();
98        }
99    }
100}