1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! Error and Result types

use crate::compat::string::String;
use core::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize};

/// The type of errors returned by Ockam functions.
///
/// This type has two implementations that are switched depending on
/// whether the `"std"` Cargo feature is enabled.
///
/// # std
/// When the `"std"` feature is enabled and the Rust Standard Library is
/// available, the `Error` stores:
///
/// 1. __Error Code__: A `u32` representing the the presise error.
/// 2. __Error Domain__: An error domain string.
///
/// # no_std
/// When the `"std"` feature is not enabled we assume that the Rust Standard
/// Library is not available, the `Error` stores:
///
/// 1. __Error Code__: A `u32` representing the the presise error.
///
#[derive(Serialize, Deserialize, Debug)]
pub struct Error {
    code: u32,

    #[cfg(any(feature = "std", feature = "alloc"))]
    domain: String,
}

/// The type returned by Ockam functions.
pub type Result<T> = core::result::Result<T, Error>;

/// Produces Ok(false), which reads confusingly in auth code.
pub fn deny() -> Result<bool> {
    Ok(false)
}

/// Produces Ok(true), which reads confusingly in auth code.
pub fn allow() -> Result<bool> {
    Ok(true)
}

impl Error {
    /// Creates a new [`Error`].
    #[cfg(all(not(feature = "std"), not(feature = "alloc")))]
    pub fn new(code: u32) -> Self {
        Self { code }
    }

    /// Creates a new [`Error`].
    #[cfg(any(feature = "std", feature = "alloc"))]
    pub fn new<S: Into<String>>(code: u32, domain: S) -> Self {
        Self {
            code,
            domain: domain.into(),
        }
    }

    /// Returns an error's domain.
    #[cfg(any(feature = "std", feature = "alloc"))]
    #[inline]
    pub fn domain(&self) -> &String {
        &self.domain
    }

    /// Returns an error's code.
    #[inline]
    pub fn code(&self) -> u32 {
        self.code
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        #[cfg(any(feature = "std", feature = "alloc"))]
        {
            write!(
                f,
                "Error {{ code: {}, domain: \"{}\" }}",
                self.code, self.domain
            )
        }
        #[cfg(all(not(feature = "std"), not(feature = "alloc")))]
        {
            write!(f, "Error {{ code: {} }}", self.code)
        }
    }
}

impl crate::compat::error::Error for Error {}

#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg(test)]
mod std_test {
    use super::*;

    #[test]
    fn can_be_created() {
        let _error = Error::new(1000, "SOME_ERROR_DOMAIN");
    }

    #[test]
    fn code_returns_provided_code() {
        let error = Error::new(1000, "SOME_ERROR_DOMAIN");
        assert_eq!(error.code(), 1000);
        assert_eq!(error.code, 1000);
    }

    #[test]
    fn domain_returns_provided_domain() {
        let error = Error::new(1000, "SOME_ERROR_DOMAIN");
        assert_eq!(error.domain(), "SOME_ERROR_DOMAIN");
        assert_eq!(error.domain, "SOME_ERROR_DOMAIN");
    }

    #[test]
    fn can_be_displayed() {
        let error = Error::new(1000, "SOME_ERROR_DOMAIN");
        assert_eq!(
            format!("{}", error),
            "Error { code: 1000, domain: \"SOME_ERROR_DOMAIN\" }"
        );
    }

    #[test]
    fn can_be_debugged() {
        let error = Error::new(1000, "SOME_ERROR_DOMAIN");
        assert_eq!(
            format!("{:?}", error),
            "Error { code: 1000, domain: \"SOME_ERROR_DOMAIN\" }"
        );
    }
}

#[cfg(all(not(feature = "std"), not(feature = "alloc")))]
#[cfg(test)]
mod no_std_test {
    // These following tests are run for no_std targets without
    // support for heap allocation:
    //
    //     cargo test --no-default-features --features="no_std"
    use super::*;

    #[test]
    fn can_be_created_and_code_returns_provided_code() {
        let error = Error::new(1000);
        assert_eq!(error.code(), 1000);
        assert_eq!(error.code, 1000);
    }
}