Skip to main content

router_error/
lib.rs

1// Copyright 2024 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 fidl_fuchsia_component_runtime as fruntime;
6use fidl_fuchsia_component_sandbox as fsandbox;
7use moniker::Moniker;
8use std::fmt::{self, Debug, Display};
9use std::sync::Arc;
10use thiserror::Error;
11use zx_status as zx;
12
13/// The error type returned by bedrock operations.
14#[derive(Debug, Error, Clone)]
15pub enum RouterError {
16    #[error("{0}")]
17    NotFound(Arc<dyn Explain>),
18
19    #[error("not supported")]
20    NotSupported,
21
22    #[error("internal")]
23    Internal,
24
25    #[error("unknown")]
26    Unknown,
27
28    #[error("route continues outside of component manager at component {moniker}")]
29    RemotedAt { moniker: Moniker },
30}
31
32impl From<fruntime::RouterError> for RouterError {
33    fn from(router_error: fruntime::RouterError) -> Self {
34        match router_error {
35            fruntime::RouterError::NotFound => Self::NotFound(Arc::new(ExternalNotFoundError {})),
36            fruntime::RouterError::NotSupported => RouterError::NotSupported,
37            fruntime::RouterError::Internal => RouterError::Internal,
38            _ => RouterError::Unknown,
39        }
40    }
41}
42
43impl From<RouterError> for fruntime::RouterError {
44    fn from(router_error: RouterError) -> Self {
45        match router_error {
46            RouterError::NotFound(_) => fruntime::RouterError::NotFound,
47            RouterError::NotSupported => fruntime::RouterError::NotSupported,
48            RouterError::RemotedAt { .. } => fruntime::RouterError::NotSupported,
49            RouterError::Internal => fruntime::RouterError::Internal,
50            RouterError::Unknown => fruntime::RouterError::Unknown,
51        }
52    }
53}
54
55impl From<fsandbox::RouterError> for RouterError {
56    fn from(err: fsandbox::RouterError) -> Self {
57        match err {
58            fsandbox::RouterError::NotFound => Self::NotFound(Arc::new(ExternalNotFoundError {})),
59            fsandbox::RouterError::NotSupported => Self::NotSupported,
60            fsandbox::RouterError::Internal => Self::Internal,
61            fsandbox::RouterErrorUnknown!() => Self::Unknown,
62        }
63    }
64}
65
66impl From<RouterError> for fsandbox::RouterError {
67    fn from(err: RouterError) -> Self {
68        match err {
69            RouterError::NotFound(_) => Self::NotFound,
70            RouterError::NotSupported => Self::NotSupported,
71            RouterError::RemotedAt { .. } => Self::NotSupported,
72            RouterError::Internal => Self::Internal,
73            RouterError::Unknown => Self::unknown(),
74        }
75    }
76}
77
78#[derive(Debug, Error, Clone)]
79struct ExternalNotFoundError {}
80
81impl Explain for ExternalNotFoundError {
82    fn as_zx_status(&self) -> zx::Status {
83        zx::Status::NOT_FOUND
84    }
85}
86
87impl fmt::Display for ExternalNotFoundError {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        write!(f, "external not found error")
90    }
91}
92
93/// All detailed error objects must implement the [`Explain`] trait, since:
94///
95/// - Some operations are not yet refactored into bedrock.
96/// - Some operations fundamentally are not fit for bedrock.
97///
98/// The detailed errors are hidden, but users may get strings or codes for debugging.
99pub trait Explain: std::error::Error + Debug + Display + Send + Sync + sealed::AnyCast {
100    fn as_zx_status(&self) -> zx::Status;
101}
102
103impl Explain for RouterError {
104    fn as_zx_status(&self) -> zx::Status {
105        match self {
106            Self::NotFound(err) => err.as_zx_status(),
107            Self::RemotedAt { .. } => zx::Status::NOT_SUPPORTED,
108            Self::NotSupported => zx::Status::NOT_SUPPORTED,
109            Self::Internal => zx::Status::INTERNAL,
110            Self::Unknown => zx::Status::INTERNAL,
111        }
112    }
113}
114
115mod sealed {
116    use std::any::Any;
117
118    pub trait AnyCast: Any {
119        fn as_any(&self) -> &dyn Any;
120    }
121
122    impl<T: Any> AnyCast for T {
123        fn as_any(&self) -> &dyn Any {
124            self
125        }
126    }
127}