pw_status/pw_status.rs
1// Copyright 2023 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15//! # pw_status
16//!
17//! Rust error types using error codes compatible with Pigweed's
18//! [pw_status](https://pigweed.dev/pw_status). In order to keep the interface
19//! idiomatic for Rust, `PW_STATUS_OK` is omitted from the Error enum and a
20//! `StatusCode` trait is provided to turn a `Result` into a canonical
21//! status code.
22//!
23//! For an in depth explanation of the values of the `Error` enum, see
24//! the [Pigweed status codes documentation](https://pigweed.dev/pw_status/#status-codes).
25//!
26//! # Example
27//!
28//! ```
29//! use pw_status::{Error, Result};
30//!
31//! fn div(numerator: u32, denominator: u32) -> Result<u32> {
32//! if denominator == 0 {
33//! Err(Error::FailedPrecondition)
34//! } else {
35//! Ok(numerator / denominator)
36//! }
37//! }
38//!
39//! assert_eq!(div(4, 2), Ok(2));
40//! assert_eq!(div(4, 0), Err(Error::FailedPrecondition));
41//! ```
42#![no_std]
43
44/// Status code for no error.
45pub const OK: u32 = 0;
46
47/// Error type compatible with Pigweed's [pw_status](https://pigweed.dev/pw_status).
48///
49/// For an in depth explanation of the values of the `Error` enum, see
50/// the [Pigweed status codes documentation](https://pigweed.dev/pw_status/#status-codes).
51#[derive(Clone, Copy, Debug, Eq, PartialEq)]
52#[repr(u32)]
53pub enum Error {
54 Cancelled = 1,
55 Unknown = 2,
56 InvalidArgument = 3,
57 DeadlineExceeded = 4,
58 NotFound = 5,
59 AlreadyExists = 6,
60 PermissionDenied = 7,
61 ResourceExhausted = 8,
62 FailedPrecondition = 9,
63 Aborted = 10,
64 OutOfRange = 11,
65 Unimplemented = 12,
66 Internal = 13,
67 Unavailable = 14,
68 DataLoss = 15,
69 Unauthenticated = 16,
70}
71
72pub type Result<T> = core::result::Result<T, Error>;
73
74/// Convert a Result into an status code.
75pub trait StatusCode {
76 /// Return a pigweed compatible status code.
77 fn status_code(self) -> u32;
78}
79
80impl<T> StatusCode for Result<T> {
81 fn status_code(self) -> u32 {
82 match self {
83 Ok(_) => OK,
84 Err(e) => e as u32,
85 }
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 #[test]
93 fn test_status_code() {
94 assert_eq!(Result::Ok(()).status_code(), 0);
95 assert_eq!(Result::<()>::Err(Error::Cancelled).status_code(), 1);
96 assert_eq!(Result::<()>::Err(Error::Unknown).status_code(), 2);
97 assert_eq!(Result::<()>::Err(Error::InvalidArgument).status_code(), 3);
98 assert_eq!(Result::<()>::Err(Error::DeadlineExceeded).status_code(), 4);
99 assert_eq!(Result::<()>::Err(Error::NotFound).status_code(), 5);
100 assert_eq!(Result::<()>::Err(Error::AlreadyExists).status_code(), 6);
101 assert_eq!(Result::<()>::Err(Error::PermissionDenied).status_code(), 7);
102 assert_eq!(Result::<()>::Err(Error::ResourceExhausted).status_code(), 8);
103 assert_eq!(
104 Result::<()>::Err(Error::FailedPrecondition).status_code(),
105 9
106 );
107 assert_eq!(Result::<()>::Err(Error::Aborted).status_code(), 10);
108 assert_eq!(Result::<()>::Err(Error::OutOfRange).status_code(), 11);
109 assert_eq!(Result::<()>::Err(Error::Unimplemented).status_code(), 12);
110 assert_eq!(Result::<()>::Err(Error::Internal).status_code(), 13);
111 assert_eq!(Result::<()>::Err(Error::Unavailable).status_code(), 14);
112 assert_eq!(Result::<()>::Err(Error::DataLoss).status_code(), 15);
113 assert_eq!(Result::<()>::Err(Error::Unauthenticated).status_code(), 16);
114 }
115}