Skip to main content

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
7#![no_std]
8
9use core::fmt;
10use zx_types as sys;
11
12// Creates associated constants of TypeName of the form
13// `pub const NAME: TypeName = TypeName(path::to::value);`
14// and provides a private `assoc_const_name` method and a `Debug` implementation
15// for the type based on `$name`.
16// If multiple names match, the first will be used in `name` and `Debug`.
17#[macro_export]
18macro_rules! assoc_values {
19    ($typename:ident, [$($(#[$attr:meta])* $name:ident = $value:path;)*]) => {
20        #[allow(non_upper_case_globals)]
21        impl $typename {
22            $(
23                $(#[$attr])*
24                pub const $name: $typename = $typename($value);
25            )*
26
27            fn assoc_const_name(&self) -> Option<&'static str> {
28                match self.0 {
29                    $(
30                        $value => Some(stringify!($name)),
31                    )*
32                    _ => None,
33                }
34            }
35        }
36
37        impl ::core::fmt::Debug for $typename {
38            fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
39                f.write_str(concat!(stringify!($typename), "("))?;
40                match self.assoc_const_name() {
41                    Some(name) => f.write_str(&name)?,
42                    None => ::core::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 { Ok(()) } else { Err(Status(raw)) }
64    }
65
66    /// Returns the raw `zx_status_t` code corresponding to a `Result<(), Status>`.
67    ///
68    /// Returns `ZX_OK` (`0`) for `Ok(())`, and the underlying error code for `Err(status)`.
69    #[inline]
70    pub const fn result_into_raw(res: Result<(), Self>) -> sys::zx_status_t {
71        match res {
72            Ok(()) => sys::ZX_OK,
73            Err(status) => status.0,
74        }
75    }
76
77    /// Returns `Some(status)` if `raw` is not `ZX_OK`, otherwise returns `None`.
78    #[inline]
79    pub const fn try_from_raw(raw: sys::zx_status_t) -> Option<Self> {
80        if raw == sys::ZX_OK { None } else { Some(Status(raw)) }
81    }
82
83    /// Creates a `Status` from a raw `zx_status_t`.
84    ///
85    /// # Deprecated
86    ///
87    /// This function is deprecated because it does not verify whether `raw` is `0` (`ZX_OK`).
88    /// Prefer [`Status::ok`] or [`Status::try_from_raw`] instead.
89    #[inline]
90    #[doc(hidden)]
91    pub const fn from_raw(raw: sys::zx_status_t) -> Self {
92        Status(raw)
93    }
94
95    pub fn into_raw(self) -> sys::zx_status_t {
96        self.0
97    }
98}
99
100/// Convenience re-export of `Status::ok`.
101pub fn ok(raw: sys::zx_status_t) -> Result<(), Status> {
102    Status::ok(raw)
103}
104
105// LINT.IfChange(zx_status_t)
106assoc_values!(Status, [
107    #[doc = "Indicates an operation was successful."]
108    OK                     = sys::ZX_OK;
109    #[doc = "The system encountered an otherwise unspecified error while performing the"]
110    #[doc = "operation."]
111    INTERNAL               = sys::ZX_ERR_INTERNAL;
112    #[doc = "The operation is not implemented, supported, or enabled."]
113    NOT_SUPPORTED          = sys::ZX_ERR_NOT_SUPPORTED;
114    #[doc = "The system was not able to allocate some resource needed for the operation."]
115    NO_RESOURCES           = sys::ZX_ERR_NO_RESOURCES;
116    #[doc = "The system was not able to allocate memory needed for the operation."]
117    NO_MEMORY              = sys::ZX_ERR_NO_MEMORY;
118    #[doc = "The system call was interrupted, but should be retried. This should not be"]
119    #[doc = "seen outside of the VDSO."]
120    INTERRUPTED_RETRY      = sys::ZX_ERR_INTERRUPTED_RETRY;
121    #[doc = "An argument is invalid. For example, a null pointer when a null pointer is"]
122    #[doc = "not permitted."]
123    INVALID_ARGS           = sys::ZX_ERR_INVALID_ARGS;
124    #[doc = "A specified handle value does not refer to a handle."]
125    BAD_HANDLE             = sys::ZX_ERR_BAD_HANDLE;
126    #[doc = "The subject of the operation is the wrong type to perform the operation."]
127    #[doc = ""]
128    #[doc = "For example: Attempting a message_read on a thread handle."]
129    WRONG_TYPE             = sys::ZX_ERR_WRONG_TYPE;
130    #[doc = "The specified syscall number is invalid."]
131    BAD_SYSCALL            = sys::ZX_ERR_BAD_SYSCALL;
132    #[doc = "An argument is outside the valid range for this operation."]
133    OUT_OF_RANGE           = sys::ZX_ERR_OUT_OF_RANGE;
134    #[doc = "The caller-provided buffer is too small for this operation."]
135    BUFFER_TOO_SMALL       = sys::ZX_ERR_BUFFER_TOO_SMALL;
136    #[doc = "The operation failed because the current state of the object does not allow"]
137    #[doc = "it, or a precondition of the operation is not satisfied."]
138    BAD_STATE              = sys::ZX_ERR_BAD_STATE;
139    #[doc = "The time limit for the operation elapsed before the operation completed."]
140    TIMED_OUT              = sys::ZX_ERR_TIMED_OUT;
141    #[doc = "The operation cannot be performed currently but potentially could succeed if"]
142    #[doc = "the caller waits for a prerequisite to be satisfied, like waiting for a"]
143    #[doc = "handle to be readable or writable."]
144    #[doc = ""]
145    #[doc = "Example: Attempting to read from a channel that has no messages waiting but"]
146    #[doc = "has an open remote will return `ZX_ERR_SHOULD_WAIT`. In contrast, attempting"]
147    #[doc = "to read from a channel that has no messages waiting and has a closed remote"]
148    #[doc = "end will return `ZX_ERR_PEER_CLOSED`."]
149    SHOULD_WAIT            = sys::ZX_ERR_SHOULD_WAIT;
150    #[doc = "The in-progress operation, for example, a wait, has been canceled."]
151    CANCELED               = sys::ZX_ERR_CANCELED;
152    #[doc = "The operation failed because the remote end of the subject of the operation"]
153    #[doc = "was closed."]
154    PEER_CLOSED            = sys::ZX_ERR_PEER_CLOSED;
155    #[doc = "The requested entity is not found."]
156    NOT_FOUND              = sys::ZX_ERR_NOT_FOUND;
157    #[doc = "An object with the specified identifier already exists."]
158    #[doc = ""]
159    #[doc = "Example: Attempting to create a file when a file already exists with that"]
160    #[doc = "name."]
161    ALREADY_EXISTS         = sys::ZX_ERR_ALREADY_EXISTS;
162    #[doc = "The operation failed because the named entity is already owned or controlled"]
163    #[doc = "by another entity. The operation could succeed later if the current owner"]
164    #[doc = "releases the entity."]
165    ALREADY_BOUND          = sys::ZX_ERR_ALREADY_BOUND;
166    #[doc = "The subject of the operation is currently unable to perform the operation."]
167    #[doc = ""]
168    #[doc = "This is used when there's no direct way for the caller to observe when the"]
169    #[doc = "subject will be able to perform the operation and should thus retry."]
170    UNAVAILABLE            = sys::ZX_ERR_UNAVAILABLE;
171    #[doc = "The caller did not have permission to perform the specified operation."]
172    ACCESS_DENIED          = sys::ZX_ERR_ACCESS_DENIED;
173    #[doc = "Otherwise-unspecified error occurred during I/O."]
174    IO                     = sys::ZX_ERR_IO;
175    #[doc = "The entity the I/O operation is being performed on rejected the operation."]
176    #[doc = ""]
177    #[doc = "Example: an I2C device NAK'ing a transaction or a disk controller rejecting"]
178    #[doc = "an invalid command, or a stalled USB endpoint."]
179    IO_REFUSED             = sys::ZX_ERR_IO_REFUSED;
180    #[doc = "The data in the operation failed an integrity check and is possibly"]
181    #[doc = "corrupted."]
182    #[doc = ""]
183    #[doc = "Example: CRC or Parity error."]
184    IO_DATA_INTEGRITY      = sys::ZX_ERR_IO_DATA_INTEGRITY;
185    #[doc = "The data in the operation is currently unavailable and may be permanently"]
186    #[doc = "lost."]
187    #[doc = ""]
188    #[doc = "Example: A disk block is irrecoverably damaged."]
189    IO_DATA_LOSS           = sys::ZX_ERR_IO_DATA_LOSS;
190    #[doc = "The device is no longer available (has been unplugged from the system,"]
191    #[doc = "powered down, or the driver has been unloaded)."]
192    IO_NOT_PRESENT         = sys::ZX_ERR_IO_NOT_PRESENT;
193    #[doc = "More data was received from the device than expected."]
194    #[doc = ""]
195    #[doc = "Example: a USB \"babble\" error due to a device sending more data than the"]
196    #[doc = "host queued to receive."]
197    IO_OVERRUN             = sys::ZX_ERR_IO_OVERRUN;
198    #[doc = "An operation did not complete within the required timeframe."]
199    #[doc = ""]
200    #[doc = "Example: A USB isochronous transfer that failed to complete due to an"]
201    #[doc = "overrun or underrun."]
202    IO_MISSED_DEADLINE     = sys::ZX_ERR_IO_MISSED_DEADLINE;
203    #[doc = "The data in the operation is invalid parameter or is out of range."]
204    #[doc = ""]
205    #[doc = "Example: A USB transfer that failed to complete with TRB Error"]
206    IO_INVALID             = sys::ZX_ERR_IO_INVALID;
207    #[doc = "Path name is too long."]
208    BAD_PATH               = sys::ZX_ERR_BAD_PATH;
209    #[doc = "The object is not a directory or does not support directory operations."]
210    #[doc = ""]
211    #[doc = "Example: Attempted to open a file as a directory or attempted to do"]
212    #[doc = "directory operations on a file."]
213    NOT_DIR                = sys::ZX_ERR_NOT_DIR;
214    #[doc = "Object is not a regular file."]
215    NOT_FILE               = sys::ZX_ERR_NOT_FILE;
216    #[doc = "This operation would cause a file to exceed a filesystem-specific size"]
217    #[doc = "limit."]
218    FILE_BIG               = sys::ZX_ERR_FILE_BIG;
219    #[doc = "The filesystem or device space is exhausted."]
220    NO_SPACE               = sys::ZX_ERR_NO_SPACE;
221    #[doc = "The directory is not empty for an operation that requires it to be empty."]
222    #[doc = ""]
223    #[doc = "For example, non-recursively deleting a directory with files still in it."]
224    NOT_EMPTY              = sys::ZX_ERR_NOT_EMPTY;
225    #[doc = "An indicate to not call again."]
226    #[doc = ""]
227    #[doc = "The flow control values `ZX_ERR_STOP`, `ZX_ERR_NEXT`, and `ZX_ERR_ASYNC` are"]
228    #[doc = "not errors and will never be returned by a system call or public API. They"]
229    #[doc = "allow callbacks to request their caller perform some other operation."]
230    #[doc = ""]
231    #[doc = "For example, a callback might be called on every event until it returns"]
232    #[doc = "something other than `ZX_OK`. This status allows differentiation between"]
233    #[doc = "\"stop due to an error\" and \"stop because work is done.\""]
234    STOP                   = sys::ZX_ERR_STOP;
235    #[doc = "Advance to the next item."]
236    #[doc = ""]
237    #[doc = "The flow control values `ZX_ERR_STOP`, `ZX_ERR_NEXT`, and `ZX_ERR_ASYNC` are"]
238    #[doc = "not errors and will never be returned by a system call or public API. They"]
239    #[doc = "allow callbacks to request their caller perform some other operation."]
240    #[doc = ""]
241    #[doc = "For example, a callback could use this value to indicate it did not consume"]
242    #[doc = "an item passed to it, but by choice, not due to an error condition."]
243    NEXT                   = sys::ZX_ERR_NEXT;
244    #[doc = "Ownership of the item has moved to an asynchronous worker."]
245    #[doc = ""]
246    #[doc = "The flow control values `ZX_ERR_STOP`, `ZX_ERR_NEXT`, and `ZX_ERR_ASYNC` are"]
247    #[doc = "not errors and will never be returned by a system call or public API. They"]
248    #[doc = "allow callbacks to request their caller perform some other operation."]
249    #[doc = ""]
250    #[doc = "Unlike `ZX_ERR_STOP`, which implies that iteration on an object"]
251    #[doc = "should stop, and `ZX_ERR_NEXT`, which implies that iteration"]
252    #[doc = "should continue to the next item, `ZX_ERR_ASYNC` implies"]
253    #[doc = "that an asynchronous worker is responsible for continuing iteration."]
254    #[doc = ""]
255    #[doc = "For example, a callback will be called on every event, but one event needs"]
256    #[doc = "to handle some work asynchronously before it can continue. `ZX_ERR_ASYNC`"]
257    #[doc = "implies the worker is responsible for resuming iteration once its work has"]
258    #[doc = "completed."]
259    ASYNC                  = sys::ZX_ERR_ASYNC;
260    #[doc = "The specified protocol is not supported."]
261    PROTOCOL_NOT_SUPPORTED = sys::ZX_ERR_PROTOCOL_NOT_SUPPORTED;
262    #[doc = "The host is unreachable."]
263    ADDRESS_UNREACHABLE    = sys::ZX_ERR_ADDRESS_UNREACHABLE;
264    #[doc = "Address is being used by someone else."]
265    ADDRESS_IN_USE         = sys::ZX_ERR_ADDRESS_IN_USE;
266    #[doc = "The socket is not connected."]
267    NOT_CONNECTED          = sys::ZX_ERR_NOT_CONNECTED;
268    #[doc = "The remote peer rejected the connection."]
269    CONNECTION_REFUSED     = sys::ZX_ERR_CONNECTION_REFUSED;
270    #[doc = "The connection was reset."]
271    CONNECTION_RESET       = sys::ZX_ERR_CONNECTION_RESET;
272    #[doc = "The connection was aborted."]
273    CONNECTION_ABORTED     = sys::ZX_ERR_CONNECTION_ABORTED;
274]);
275// LINT.ThenChange(//zircon/vdso/errors.fidl)
276
277impl Status {
278    pub fn from_result(res: Result<(), Self>) -> Self {
279        res.into()
280    }
281}
282
283impl fmt::Display for Status {
284    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285        match self.assoc_const_name() {
286            Some(name) => name.fmt(f),
287            None => write!(f, "Unknown zircon status code: {}", self.0),
288        }
289    }
290}
291
292impl core::error::Error for Status {}
293
294impl From<Result<(), Status>> for Status {
295    fn from(res: Result<(), Status>) -> Status {
296        match res {
297            Ok(()) => Self::OK,
298            Err(status) => status,
299        }
300    }
301}
302
303impl From<Status> for Result<(), Status> {
304    fn from(src: Status) -> Result<(), Status> {
305        Status::ok(src.into_raw())
306    }
307}
308
309impl From<core::convert::Infallible> for Status {
310    fn from(x: core::convert::Infallible) -> Status {
311        match x {}
312    }
313}
314
315/// A non-zero Zircon status code representing an error.
316///
317/// Because this wraps a `NonZero<sys::zx_status_t>`, `Result<T, ErrorStatus>` has a niche at `0`
318/// (`ZX_OK`), guaranteeing that `Result<(), ErrorStatus>` has the exact same 4-byte memory layout
319/// and machine ABI as `sys::zx_status_t` (`Status`).
320#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
321#[repr(transparent)]
322pub struct ErrorStatus(core::num::NonZero<sys::zx_status_t>);
323
324impl ErrorStatus {
325    pub fn from_raw(raw: sys::zx_status_t) -> Option<Self> {
326        core::num::NonZero::new(raw).map(ErrorStatus)
327    }
328
329    pub fn into_raw(self) -> sys::zx_status_t {
330        self.0.get()
331    }
332
333    pub fn ok(raw: sys::zx_status_t) -> Result<(), Self> {
334        match core::num::NonZero::new(raw) {
335            Some(err) => Err(ErrorStatus(err)),
336            None => Ok(()),
337        }
338    }
339}
340
341impl From<Status> for ErrorStatus {
342    #[inline]
343    fn from(status: Status) -> Self {
344        ErrorStatus(
345            core::num::NonZero::new(status.into_raw())
346                .expect("Attempted to convert Status::OK into ErrorStatus"),
347        )
348    }
349}
350
351impl From<ErrorStatus> for Status {
352    #[inline]
353    fn from(err: ErrorStatus) -> Self {
354        Status::from_raw(err.0.get())
355    }
356}
357
358impl fmt::Debug for ErrorStatus {
359    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360        fmt::Debug::fmt(&Status::from_raw(self.0.get()), f)
361    }
362}
363
364impl fmt::Display for ErrorStatus {
365    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366        fmt::Display::fmt(&Status::from_raw(self.0.get()), f)
367    }
368}
369
370impl core::error::Error for ErrorStatus {}
371
372#[cfg(test)]
373mod test {
374    extern crate std;
375    use super::Status;
376
377    #[test]
378    fn status_debug_format() {
379        let cases = [
380            ("Status(OK)", Status::OK),
381            ("Status(BAD_SYSCALL)", Status::BAD_SYSCALL),
382            ("Status(NEXT)", Status::NEXT),
383            ("Status(-5050)", Status(-5050)),
384        ];
385        for &(expected, value) in &cases {
386            assert_eq!(expected, std::format!("{value:?}"));
387        }
388    }
389
390    #[test]
391    fn status_into_result() {
392        let ok_result: Result<(), Status> = Status::OK.into();
393        assert_eq!(ok_result, Ok(()));
394
395        let err_result: Result<(), Status> = Status::BAD_SYSCALL.into();
396        assert_eq!(err_result, Err(Status::BAD_SYSCALL));
397    }
398
399    #[test]
400    fn error_status_conversions() {
401        let err_res: Result<(), super::ErrorStatus> = Err(Status::BAD_SYSCALL.into());
402        assert_eq!(err_res, Err(Status::BAD_SYSCALL.into()));
403    }
404}