Skip to main content

runtime_capabilities/
capability.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::Router;
6use from_enum::FromEnum;
7use router_error::Explain;
8use std::fmt::Debug;
9use std::sync::Arc;
10use thiserror::Error;
11use zx_status;
12
13#[derive(Error, Debug, Clone)]
14pub enum ConversionError {
15    #[error("invalid `fuchsia.io` node name: name `{0}` is too long")]
16    ParseNameErrorTooLong(String),
17
18    #[error("invalid `fuchsia.io` node name: name cannot be empty")]
19    ParseNameErrorEmpty,
20
21    #[error("invalid `fuchsia.io` node name: name cannot be `.`")]
22    ParseNameErrorDot,
23
24    #[error("invalid `fuchsia.io` node name: name cannot be `..`")]
25    ParseNameErrorDotDot,
26
27    #[error("invalid `fuchsia.io` node name: name cannot contain `/`")]
28    ParseNameErrorSlash,
29
30    #[error("invalid `fuchsia.io` node name: name cannot contain embedded NUL")]
31    ParseNameErrorEmbeddedNul,
32
33    #[error("conversion to type is not supported")]
34    NotSupported,
35
36    #[error("conversion failed because a capability could not be cloned")]
37    NotCloneable,
38
39    #[error("value at `{key}` could not be converted: {err}")]
40    Nested {
41        key: String,
42        #[source]
43        err: Box<ConversionError>,
44    },
45}
46
47#[cfg(target_os = "fuchsia")]
48impl From<vfs::name::ParseNameError> for ConversionError {
49    fn from(parse_name_error: vfs::name::ParseNameError) -> Self {
50        match parse_name_error {
51            vfs::name::ParseNameError::TooLong(s) => ConversionError::ParseNameErrorTooLong(s),
52            vfs::name::ParseNameError::Empty => ConversionError::ParseNameErrorEmpty,
53            vfs::name::ParseNameError::Dot => ConversionError::ParseNameErrorDot,
54            vfs::name::ParseNameError::DotDot => ConversionError::ParseNameErrorDotDot,
55            vfs::name::ParseNameError::Slash => ConversionError::ParseNameErrorSlash,
56            vfs::name::ParseNameError::EmbeddedNul => ConversionError::ParseNameErrorEmbeddedNul,
57        }
58    }
59}
60
61/// Errors arising from conversion between Rust and FIDL types.
62#[derive(Error, Debug)]
63pub enum RemoteError {
64    #[error("unknown FIDL variant")]
65    UnknownVariant,
66
67    #[error("unregistered capability; only capabilities created by sandbox are allowed")]
68    Unregistered,
69
70    #[error("registered capability had the wrong type")]
71    BadCapability,
72}
73
74impl Explain for RemoteError {
75    fn as_zx_status(&self) -> zx_status::Status {
76        match self {
77            RemoteError::UnknownVariant => zx_status::Status::NOT_SUPPORTED,
78            RemoteError::Unregistered => zx_status::Status::INVALID_ARGS,
79            RemoteError::BadCapability => zx_status::Status::INVALID_ARGS,
80        }
81    }
82}
83
84#[derive(FromEnum, Debug, Clone)]
85pub enum Capability {
86    Connector(Arc<crate::Connector>),
87    DirConnector(Arc<crate::DirConnector>),
88    Dictionary(Arc<crate::Dictionary>),
89    Data(Arc<crate::Data>),
90    Handle(Arc<crate::Handle>),
91    ConnectorRouter(Arc<crate::Router<crate::Connector>>),
92    DictionaryRouter(Arc<crate::Router<crate::Dictionary>>),
93    DirConnectorRouter(Arc<crate::Router<crate::DirConnector>>),
94    DataRouter(Arc<crate::Router<crate::Data>>),
95    Instance(Arc<crate::WeakInstanceToken>),
96}
97
98impl Capability {
99    pub fn to_dictionary(self) -> Option<Arc<crate::Dictionary>> {
100        match self {
101            Self::Dictionary(d) => Some(d),
102            _ => None,
103        }
104    }
105
106    pub fn debug_typename(&self) -> &'static str {
107        match self {
108            Self::Connector(_) => crate::Connector::debug_typename(),
109            Self::DirConnector(_) => crate::DirConnector::debug_typename(),
110            Self::ConnectorRouter(_) => crate::Router::<crate::Connector>::debug_typename(),
111            Self::DictionaryRouter(_) => crate::Router::<crate::Dictionary>::debug_typename(),
112            Self::DirConnectorRouter(_) => crate::Router::<crate::DirConnector>::debug_typename(),
113            Self::DataRouter(_) => crate::Router::<crate::Data>::debug_typename(),
114            Self::Dictionary(_) => crate::Dictionary::debug_typename(),
115            Self::Data(_) => crate::Data::debug_typename(),
116            Self::Handle(_) => crate::Handle::debug_typename(),
117            Self::Instance(_) => "Instance",
118        }
119    }
120}
121
122impl TryFrom<Capability> for Arc<crate::Connector> {
123    type Error = ();
124
125    fn try_from(c: Capability) -> Result<Self, Self::Error> {
126        match c {
127            Capability::Connector(c) => Ok(c),
128            _ => Err(()),
129        }
130    }
131}
132
133impl TryFrom<Capability> for Arc<crate::DirConnector> {
134    type Error = ();
135
136    fn try_from(c: Capability) -> Result<Self, Self::Error> {
137        match c {
138            Capability::DirConnector(c) => Ok(c),
139            _ => Err(()),
140        }
141    }
142}
143
144impl TryFrom<Capability> for Arc<crate::Dictionary> {
145    type Error = ();
146
147    fn try_from(c: Capability) -> Result<Self, Self::Error> {
148        match c {
149            Capability::Dictionary(c) => Ok(c),
150            _ => Err(()),
151        }
152    }
153}
154
155impl TryFrom<Capability> for Arc<crate::Data> {
156    type Error = ();
157
158    fn try_from(c: Capability) -> Result<Self, Self::Error> {
159        match c {
160            Capability::Data(c) => Ok(c),
161            _ => Err(()),
162        }
163    }
164}
165
166impl TryFrom<Capability> for Arc<Router<crate::Dictionary>> {
167    type Error = ();
168
169    fn try_from(c: Capability) -> Result<Self, Self::Error> {
170        match c {
171            Capability::DictionaryRouter(c) => Ok(c),
172            _ => Err(()),
173        }
174    }
175}
176
177impl TryFrom<Capability> for Arc<Router<crate::DirConnector>> {
178    type Error = ();
179
180    fn try_from(c: Capability) -> Result<Self, Self::Error> {
181        match c {
182            Capability::DirConnectorRouter(c) => Ok(c),
183            _ => Err(()),
184        }
185    }
186}
187
188impl TryFrom<Capability> for Arc<Router<crate::Connector>> {
189    type Error = ();
190
191    fn try_from(c: Capability) -> Result<Self, Self::Error> {
192        match c {
193            Capability::ConnectorRouter(c) => Ok(c),
194            _ => Err(()),
195        }
196    }
197}
198
199impl TryFrom<Capability> for Arc<Router<crate::Data>> {
200    type Error = ();
201
202    fn try_from(c: Capability) -> Result<Self, Self::Error> {
203        match c {
204            Capability::DataRouter(c) => Ok(c),
205            _ => Err(()),
206        }
207    }
208}
209
210impl TryFrom<Capability> for Arc<crate::WeakInstanceToken> {
211    type Error = ();
212
213    fn try_from(c: Capability) -> Result<Self, Self::Error> {
214        match c {
215            Capability::Instance(i) => Ok(i),
216            _ => Err(()),
217        }
218    }
219}
220
221/// Parent trait implemented by all capability types. Useful for defining interfaces that
222/// generic over a capability type.
223pub trait CapabilityBound: Send + Sync + 'static {
224    fn debug_typename() -> &'static str;
225
226    /// Converts this capability into a directory entry.
227    ///
228    /// This is on the "main" capability trait because this is something supported by (almost)
229    /// every capability type, and all capability types are expected to either support this or be
230    /// able to report that they cannot (i.e. return an error when this is called).
231    #[cfg(target_os = "fuchsia")]
232    fn try_into_directory_entry(
233        self: Arc<Self>,
234        _scope: vfs::execution_scope::ExecutionScope,
235        _token: Arc<crate::WeakInstanceToken>,
236    ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
237        Err(ConversionError::NotSupported)
238    }
239}