zx_status/
lib.rs

1// Copyright 2018 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//! Type-safe bindings for Zircon status.
6
7use std::ffi::NulError;
8use std::{error, fmt, io};
9use zx_types as sys;
10
11// Creates associated constants of TypeName of the form
12// `pub const NAME: TypeName = TypeName(path::to::value);`
13// and provides a private `assoc_const_name` method and a `Debug` implementation
14// for the type based on `$name`.
15// If multiple names match, the first will be used in `name` and `Debug`.
16#[macro_export]
17macro_rules! assoc_values {
18    ($typename:ident, [$($(#[$attr:meta])* $name:ident = $value:path;)*]) => {
19        #[allow(non_upper_case_globals)]
20        impl $typename {
21            $(
22                $(#[$attr])*
23                pub const $name: $typename = $typename($value);
24            )*
25
26            fn assoc_const_name(&self) -> Option<&'static str> {
27                match self.0 {
28                    $(
29                        $(#[$attr])*
30                        $value => Some(stringify!($name)),
31                    )*
32                    _ => None,
33                }
34            }
35        }
36
37        impl ::std::fmt::Debug for $typename {
38            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
39                f.write_str(concat!(stringify!($typename), "("))?;
40                match self.assoc_const_name() {
41                    Some(name) => f.write_str(&name)?,
42                    None => ::std::fmt::Debug::fmt(&self.0, f)?,
43                }
44                f.write_str(")")
45            }
46        }
47    }
48}
49
50/// Status type indicating the result of a Fuchsia syscall.
51///
52/// This type is generally used to indicate the reason for an error.
53/// While this type can contain `Status::OK` (`ZX_OK` in C land), elements of this type are
54/// generally constructed using the `ok` method, which checks for `ZX_OK` and returns a
55/// `Result<(), Status>` appropriately.
56#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
57#[repr(transparent)]
58pub struct Status(sys::zx_status_t);
59impl Status {
60    /// Returns `Ok(())` if the status was `OK`,
61    /// otherwise returns `Err(status)`.
62    pub fn ok(raw: sys::zx_status_t) -> Result<(), Status> {
63        if raw == Status::OK.0 {
64            Ok(())
65        } else {
66            Err(Status(raw))
67        }
68    }
69
70    pub fn from_raw(raw: sys::zx_status_t) -> Self {
71        Status(raw)
72    }
73
74    pub fn into_raw(self) -> sys::zx_status_t {
75        self.0
76    }
77}
78
79/// Convenience re-export of `Status::ok`.
80pub fn ok(raw: sys::zx_status_t) -> Result<(), Status> {
81    Status::ok(raw)
82}
83
84assoc_values!(Status, [
85    OK                     = sys::ZX_OK;
86    INTERNAL               = sys::ZX_ERR_INTERNAL;
87    NOT_SUPPORTED          = sys::ZX_ERR_NOT_SUPPORTED;
88    NO_RESOURCES           = sys::ZX_ERR_NO_RESOURCES;
89    NO_MEMORY              = sys::ZX_ERR_NO_MEMORY;
90    INTERRUPTED_RETRY      = sys::ZX_ERR_INTERRUPTED_RETRY;
91    INVALID_ARGS           = sys::ZX_ERR_INVALID_ARGS;
92    BAD_HANDLE             = sys::ZX_ERR_BAD_HANDLE;
93    WRONG_TYPE             = sys::ZX_ERR_WRONG_TYPE;
94    BAD_SYSCALL            = sys::ZX_ERR_BAD_SYSCALL;
95    OUT_OF_RANGE           = sys::ZX_ERR_OUT_OF_RANGE;
96    BUFFER_TOO_SMALL       = sys::ZX_ERR_BUFFER_TOO_SMALL;
97    BAD_STATE              = sys::ZX_ERR_BAD_STATE;
98    TIMED_OUT              = sys::ZX_ERR_TIMED_OUT;
99    SHOULD_WAIT            = sys::ZX_ERR_SHOULD_WAIT;
100    CANCELED               = sys::ZX_ERR_CANCELED;
101    PEER_CLOSED            = sys::ZX_ERR_PEER_CLOSED;
102    NOT_FOUND              = sys::ZX_ERR_NOT_FOUND;
103    ALREADY_EXISTS         = sys::ZX_ERR_ALREADY_EXISTS;
104    ALREADY_BOUND          = sys::ZX_ERR_ALREADY_BOUND;
105    UNAVAILABLE            = sys::ZX_ERR_UNAVAILABLE;
106    ACCESS_DENIED          = sys::ZX_ERR_ACCESS_DENIED;
107    IO                     = sys::ZX_ERR_IO;
108    IO_REFUSED             = sys::ZX_ERR_IO_REFUSED;
109    IO_DATA_INTEGRITY      = sys::ZX_ERR_IO_DATA_INTEGRITY;
110    IO_DATA_LOSS           = sys::ZX_ERR_IO_DATA_LOSS;
111    IO_NOT_PRESENT         = sys::ZX_ERR_IO_NOT_PRESENT;
112    IO_OVERRUN             = sys::ZX_ERR_IO_OVERRUN;
113    IO_MISSED_DEADLINE     = sys::ZX_ERR_IO_MISSED_DEADLINE;
114    IO_INVALID             = sys::ZX_ERR_IO_INVALID;
115    BAD_PATH               = sys::ZX_ERR_BAD_PATH;
116    NOT_DIR                = sys::ZX_ERR_NOT_DIR;
117    NOT_FILE               = sys::ZX_ERR_NOT_FILE;
118    FILE_BIG               = sys::ZX_ERR_FILE_BIG;
119    NO_SPACE               = sys::ZX_ERR_NO_SPACE;
120    NOT_EMPTY              = sys::ZX_ERR_NOT_EMPTY;
121    STOP                   = sys::ZX_ERR_STOP;
122    NEXT                   = sys::ZX_ERR_NEXT;
123    ASYNC                  = sys::ZX_ERR_ASYNC;
124    PROTOCOL_NOT_SUPPORTED = sys::ZX_ERR_PROTOCOL_NOT_SUPPORTED;
125    ADDRESS_UNREACHABLE    = sys::ZX_ERR_ADDRESS_UNREACHABLE;
126    ADDRESS_IN_USE         = sys::ZX_ERR_ADDRESS_IN_USE;
127    NOT_CONNECTED          = sys::ZX_ERR_NOT_CONNECTED;
128    CONNECTION_REFUSED     = sys::ZX_ERR_CONNECTION_REFUSED;
129    CONNECTION_RESET       = sys::ZX_ERR_CONNECTION_RESET;
130    CONNECTION_ABORTED     = sys::ZX_ERR_CONNECTION_ABORTED;
131]);
132
133impl Status {
134    pub fn into_io_error(self) -> io::Error {
135        self.into()
136    }
137
138    pub fn from_result(res: Result<(), Self>) -> Self {
139        res.into()
140    }
141}
142
143impl From<io::ErrorKind> for Status {
144    fn from(kind: io::ErrorKind) -> Self {
145        use std::io::ErrorKind::*;
146        match kind {
147            NotFound => Status::NOT_FOUND,
148            PermissionDenied => Status::ACCESS_DENIED,
149            ConnectionRefused => Status::IO_REFUSED,
150            ConnectionAborted => Status::PEER_CLOSED,
151            AddrInUse => Status::ALREADY_BOUND,
152            AddrNotAvailable => Status::UNAVAILABLE,
153            BrokenPipe => Status::PEER_CLOSED,
154            AlreadyExists => Status::ALREADY_EXISTS,
155            WouldBlock => Status::SHOULD_WAIT,
156            InvalidInput => Status::INVALID_ARGS,
157            TimedOut => Status::TIMED_OUT,
158            Interrupted => Status::INTERRUPTED_RETRY,
159            UnexpectedEof | WriteZero | ConnectionReset | NotConnected | Other | _ => Status::IO,
160        }
161    }
162}
163
164impl From<Status> for io::ErrorKind {
165    fn from(status: Status) -> io::ErrorKind {
166        use std::io::ErrorKind::*;
167        match status {
168            Status::INTERRUPTED_RETRY => Interrupted,
169            Status::BAD_HANDLE => BrokenPipe,
170            Status::TIMED_OUT => TimedOut,
171            Status::SHOULD_WAIT => WouldBlock,
172            Status::PEER_CLOSED => ConnectionAborted,
173            Status::NOT_FOUND => NotFound,
174            Status::ALREADY_EXISTS => AlreadyExists,
175            Status::ALREADY_BOUND => AlreadyExists,
176            Status::UNAVAILABLE => AddrNotAvailable,
177            Status::ACCESS_DENIED => PermissionDenied,
178            Status::IO_REFUSED => ConnectionRefused,
179            Status::IO_DATA_INTEGRITY => InvalidData,
180
181            Status::BAD_PATH | Status::INVALID_ARGS | Status::OUT_OF_RANGE | Status::WRONG_TYPE => {
182                InvalidInput
183            }
184
185            Status::OK
186            | Status::NEXT
187            | Status::STOP
188            | Status::NO_SPACE
189            | Status::FILE_BIG
190            | Status::NOT_FILE
191            | Status::NOT_DIR
192            | Status::IO_DATA_LOSS
193            | Status::IO
194            | Status::CANCELED
195            | Status::BAD_STATE
196            | Status::BUFFER_TOO_SMALL
197            | Status::BAD_SYSCALL
198            | Status::INTERNAL
199            | Status::NOT_SUPPORTED
200            | Status::NO_RESOURCES
201            | Status::NO_MEMORY
202            | _ => Other,
203        }
204    }
205}
206
207impl fmt::Display for Status {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        match self.assoc_const_name() {
210            Some(name) => name.fmt(f),
211            None => write!(f, "Unknown zircon status code: {}", self.0),
212        }
213    }
214}
215
216impl error::Error for Status {}
217
218impl From<io::Error> for Status {
219    fn from(err: io::Error) -> Status {
220        err.kind().into()
221    }
222}
223
224impl From<Status> for io::Error {
225    fn from(status: Status) -> io::Error {
226        io::Error::from(io::ErrorKind::from(status))
227    }
228}
229
230impl From<NulError> for Status {
231    fn from(_error: NulError) -> Status {
232        Status::INVALID_ARGS
233    }
234}
235
236impl From<Result<(), Status>> for Status {
237    fn from(res: Result<(), Status>) -> Status {
238        match res {
239            Ok(()) => Self::OK,
240            Err(status) => status,
241        }
242    }
243}
244
245impl From<Status> for Result<(), Status> {
246    fn from(src: Status) -> Result<(), Status> {
247        Status::ok(src.into_raw())
248    }
249}
250
251#[cfg(test)]
252mod test {
253    use super::Status;
254
255    #[test]
256    fn status_debug_format() {
257        let cases = [
258            ("Status(OK)", Status::OK),
259            ("Status(BAD_SYSCALL)", Status::BAD_SYSCALL),
260            ("Status(NEXT)", Status::NEXT),
261            ("Status(-5050)", Status(-5050)),
262        ];
263        for &(expected, value) in &cases {
264            assert_eq!(expected, format!("{:?}", value));
265        }
266    }
267
268    #[test]
269    fn status_into_result() {
270        let ok_result: Result<(), Status> = Status::OK.into();
271        assert_eq!(ok_result, Ok(()));
272
273        let err_result: Result<(), Status> = Status::BAD_SYSCALL.into();
274        assert_eq!(err_result, Err(Status::BAD_SYSCALL));
275    }
276}