sandbox/
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 thiserror::Error;
10use zx_status;
11
12#[derive(Error, Debug, Clone)]
13pub enum ConversionError {
14    #[error("invalid `fuchsia.io` node name: name `{0}` is too long")]
15    ParseNameErrorTooLong(String),
16
17    #[error("invalid `fuchsia.io` node name: name cannot be empty")]
18    ParseNameErrorEmpty,
19
20    #[error("invalid `fuchsia.io` node name: name cannot be `.`")]
21    ParseNameErrorDot,
22
23    #[error("invalid `fuchsia.io` node name: name cannot be `..`")]
24    ParseNameErrorDotDot,
25
26    #[error("invalid `fuchsia.io` node name: name cannot contain `/`")]
27    ParseNameErrorSlash,
28
29    #[error("invalid `fuchsia.io` node name: name cannot contain embedded NUL")]
30    ParseNameErrorEmbeddedNul,
31
32    #[error("conversion to type is not supported")]
33    NotSupported,
34
35    #[error("conversion failed because a capability could not be cloned")]
36    NotCloneable,
37
38    #[error("value at `{key}` could not be converted: {err}")]
39    Nested {
40        key: String,
41        #[source]
42        err: Box<ConversionError>,
43    },
44}
45
46#[cfg(target_os = "fuchsia")]
47impl From<vfs::name::ParseNameError> for ConversionError {
48    fn from(parse_name_error: vfs::name::ParseNameError) -> Self {
49        match parse_name_error {
50            vfs::name::ParseNameError::TooLong(s) => ConversionError::ParseNameErrorTooLong(s),
51            vfs::name::ParseNameError::Empty => ConversionError::ParseNameErrorEmpty,
52            vfs::name::ParseNameError::Dot => ConversionError::ParseNameErrorDot,
53            vfs::name::ParseNameError::DotDot => ConversionError::ParseNameErrorDotDot,
54            vfs::name::ParseNameError::Slash => ConversionError::ParseNameErrorSlash,
55            vfs::name::ParseNameError::EmbeddedNul => ConversionError::ParseNameErrorEmbeddedNul,
56        }
57    }
58}
59
60/// Errors arising from conversion between Rust and FIDL types.
61#[derive(Error, Debug)]
62pub enum RemoteError {
63    #[error("unknown FIDL variant")]
64    UnknownVariant,
65
66    #[error("unregistered capability; only capabilities created by sandbox are allowed")]
67    Unregistered,
68
69    #[error("registered capability had the wrong type")]
70    BadCapability,
71}
72
73impl Explain for RemoteError {
74    fn as_zx_status(&self) -> zx_status::Status {
75        match self {
76            RemoteError::UnknownVariant => zx_status::Status::NOT_SUPPORTED,
77            RemoteError::Unregistered => zx_status::Status::INVALID_ARGS,
78            RemoteError::BadCapability => zx_status::Status::INVALID_ARGS,
79        }
80    }
81}
82
83#[derive(FromEnum, Debug)]
84pub enum Capability {
85    Unit(crate::Unit),
86    Connector(crate::Connector),
87    DirConnector(crate::DirConnector),
88    Dictionary(crate::Dict),
89    Data(crate::Data),
90    Directory(crate::Directory),
91    Handle(crate::Handle),
92    ConnectorRouter(crate::Router<crate::Connector>),
93    DictionaryRouter(crate::Router<crate::Dict>),
94    DirEntryRouter(crate::Router<crate::DirEntry>),
95    DirConnectorRouter(crate::Router<crate::DirConnector>),
96    DataRouter(crate::Router<crate::Data>),
97    Instance(crate::WeakInstanceToken),
98    DirEntry(crate::DirEntry),
99}
100
101impl Capability {
102    pub fn to_dictionary(self) -> Option<crate::Dict> {
103        match self {
104            Self::Dictionary(d) => Some(d),
105            _ => None,
106        }
107    }
108
109    pub fn try_clone(&self) -> Result<Self, ()> {
110        match self {
111            Self::Connector(s) => Ok(Self::Connector(s.clone())),
112            Self::DirConnector(s) => Ok(Self::DirConnector(s.clone())),
113            Self::ConnectorRouter(s) => Ok(Self::ConnectorRouter(s.clone())),
114            Self::DictionaryRouter(s) => Ok(Self::DictionaryRouter(s.clone())),
115            Self::DirEntryRouter(s) => Ok(Self::DirEntryRouter(s.clone())),
116            Self::DirConnectorRouter(s) => Ok(Self::DirConnectorRouter(s.clone())),
117            Self::DataRouter(s) => Ok(Self::DataRouter(s.clone())),
118            Self::Dictionary(s) => Ok(Self::Dictionary(s.clone())),
119            Self::Data(s) => Ok(Self::Data(s.clone())),
120            Self::Unit(s) => Ok(Self::Unit(s.clone())),
121            Self::Directory(_) => {
122                // Not supported.
123                Err(())
124            }
125            Self::Handle(s) => Ok(Self::Handle(s.try_clone()?)),
126            Self::Instance(s) => Ok(Self::Instance(s.clone())),
127            Self::DirEntry(s) => Ok(Self::DirEntry(s.clone())),
128        }
129    }
130
131    pub fn debug_typename(&self) -> &'static str {
132        match self {
133            Self::Connector(_) => crate::Connector::debug_typename(),
134            Self::DirConnector(_) => crate::DirConnector::debug_typename(),
135            Self::ConnectorRouter(_) => crate::Router::<crate::Connector>::debug_typename(),
136            Self::DictionaryRouter(_) => crate::Router::<crate::Dict>::debug_typename(),
137            Self::DirEntryRouter(_) => crate::Router::<crate::DirEntry>::debug_typename(),
138            Self::DirConnectorRouter(_) => crate::Router::<crate::DirConnector>::debug_typename(),
139            Self::DataRouter(_) => crate::Router::<crate::Data>::debug_typename(),
140            Self::Dictionary(_) => crate::Dict::debug_typename(),
141            Self::Data(_) => crate::Data::debug_typename(),
142            Self::Unit(_) => crate::Unit::debug_typename(),
143            Self::Directory(_) => crate::Directory::debug_typename(),
144            Self::Handle(_) => crate::Handle::debug_typename(),
145            Self::Instance(_) => "Instance",
146            Self::DirEntry(_) => crate::DirEntry::debug_typename(),
147        }
148    }
149}
150
151impl TryFrom<Capability> for crate::Connector {
152    type Error = ();
153
154    fn try_from(c: Capability) -> Result<Self, Self::Error> {
155        match c {
156            Capability::Connector(c) => Ok(c),
157            _ => Err(()),
158        }
159    }
160}
161
162impl TryFrom<Capability> for crate::DirConnector {
163    type Error = ();
164
165    fn try_from(c: Capability) -> Result<Self, Self::Error> {
166        match c {
167            Capability::DirConnector(c) => Ok(c),
168            _ => Err(()),
169        }
170    }
171}
172
173impl TryFrom<Capability> for crate::Dict {
174    type Error = ();
175
176    fn try_from(c: Capability) -> Result<Self, Self::Error> {
177        match c {
178            Capability::Dictionary(c) => Ok(c),
179            _ => Err(()),
180        }
181    }
182}
183
184impl TryFrom<Capability> for crate::Directory {
185    type Error = ();
186
187    fn try_from(c: Capability) -> Result<Self, Self::Error> {
188        match c {
189            Capability::Directory(c) => Ok(c),
190            _ => Err(()),
191        }
192    }
193}
194
195impl TryFrom<Capability> for crate::DirEntry {
196    type Error = ();
197
198    fn try_from(c: Capability) -> Result<Self, Self::Error> {
199        match c {
200            Capability::DirEntry(c) => Ok(c),
201            _ => Err(()),
202        }
203    }
204}
205
206impl TryFrom<Capability> for crate::Data {
207    type Error = ();
208
209    fn try_from(c: Capability) -> Result<Self, Self::Error> {
210        match c {
211            Capability::Data(c) => Ok(c),
212            _ => Err(()),
213        }
214    }
215}
216
217impl TryFrom<Capability> for crate::Handle {
218    type Error = ();
219
220    fn try_from(c: Capability) -> Result<Self, Self::Error> {
221        match c {
222            Capability::Handle(r) => Ok(r),
223            _ => Err(()),
224        }
225    }
226}
227
228impl TryFrom<Capability> for crate::Unit {
229    type Error = ();
230
231    fn try_from(c: Capability) -> Result<Self, Self::Error> {
232        match c {
233            Capability::Unit(r) => Ok(r),
234            _ => Err(()),
235        }
236    }
237}
238
239impl TryFrom<Capability> for Router<crate::Dict> {
240    type Error = ();
241
242    fn try_from(c: Capability) -> Result<Self, Self::Error> {
243        match c {
244            Capability::DictionaryRouter(c) => Ok(c),
245            _ => Err(()),
246        }
247    }
248}
249
250impl TryFrom<Capability> for Router<crate::DirConnector> {
251    type Error = ();
252
253    fn try_from(c: Capability) -> Result<Self, Self::Error> {
254        match c {
255            Capability::DirConnectorRouter(c) => Ok(c),
256            _ => Err(()),
257        }
258    }
259}
260
261impl TryFrom<Capability> for Router<crate::DirEntry> {
262    type Error = ();
263
264    fn try_from(c: Capability) -> Result<Self, Self::Error> {
265        match c {
266            Capability::DirEntryRouter(c) => Ok(c),
267            _ => Err(()),
268        }
269    }
270}
271
272impl TryFrom<Capability> for Router<crate::Connector> {
273    type Error = ();
274
275    fn try_from(c: Capability) -> Result<Self, Self::Error> {
276        match c {
277            Capability::ConnectorRouter(c) => Ok(c),
278            _ => Err(()),
279        }
280    }
281}
282
283impl TryFrom<Capability> for Router<crate::Data> {
284    type Error = ();
285
286    fn try_from(c: Capability) -> Result<Self, Self::Error> {
287        match c {
288            Capability::DataRouter(c) => Ok(c),
289            _ => Err(()),
290        }
291    }
292}
293
294/// Parent trait implemented by all capability types. Useful for defining interfaces that
295/// generic over a capability type.
296pub trait CapabilityBound: Into<Capability> + TryFrom<Capability> + Send + Sync + 'static {
297    fn debug_typename() -> &'static str;
298}