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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
//! Convenient Error Handling and Accumulation
//!
//! This module provides a simple, opaque error type (`Res`) designed to prevent
//! side-channel attacks through timing or error messages. It allows for
//! accumulation of error states without revealing specific error details.
use core::ffi::c_int;
use crate::error::Unspecified;

/// An opaque result type for error handling without exposing error details.
///
/// This type is designed to prevent side-channel attacks by not revealing
/// specific error information. It only indicates success or failure.
#[must_use = "You must handle the potential error"]
#[repr(transparent)]
pub struct Res(bool);

impl Default for Res {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl Res {
    /// Represents a successful result.
    pub const OK: Self = Self(true);
    /// Represents an error result.
    pub const ERR: Self = Self(false);

    /// Creates a new `Res` instance initialized to `OK`.
    ///
    /// # Returns
    ///
    /// A new `Res` instance representing success.
    pub const fn new() -> Self {
        Self::OK
    }

    /// Checks if the result is OK (successful).
    ///
    /// # Returns
    ///
    /// `true` if the result is OK, `false` otherwise.
    #[inline]
    pub const fn is_ok(&self) -> bool {
        self.0
    }


    /// Checks if the result is an error.
    ///
    /// # Returns
    ///
    /// `true` if the result is an error, `false` otherwise.
    #[inline]
    pub const fn is_err(&self) -> bool {
        !self.0
    }

    /// Updates the result based on a boolean condition.
    ///
    /// If `res` is `false`, this method will set the `Res` to an error state.
    ///
    /// # Arguments
    ///
    /// * `res` - A boolean representing a condition to check.
    #[inline]
    pub fn check(&mut self, res: bool) {
        self.0 &= res;
    }


    /// Ensures that a C integer result is equal to 1.
    ///
    /// Sets the `Res` to an error state if the input is not 1.
    ///
    /// # Arguments
    ///
    /// * `res` - A C integer to check.
    #[inline]
    pub fn ensure_1(&mut self, res: c_int) {
        self.0 &= (res as u8) == 1u8;
    }

    /// Ensures that a C integer result is equal to 0.
    ///
    /// Sets the `Res` to an error state if the input is not 0.
    ///
    /// # Arguments
    ///
    /// * `res` - A C integer to check.
    #[inline]
    pub fn ensure_0(&mut self, res: c_int) {
        self.0 &= (res as u8) == 0u8;
    }

    /// Ensures that a C integer result is positive.
    ///
    /// Sets the `Res` to an error state if the input is not positive.
    ///
    /// # Arguments
    ///
    /// * `res` - A C integer to check.
    #[inline]
    pub fn ensure_pos(&mut self, res: c_int) {
        const R_SHR: c_int = (core::mem::size_of::<c_int>() * 8 - 1) as c_int;
        self.0 &= (!(res >> R_SHR) as u8) & 1 == 1;
    }

    /// Combines this `Res` with another `Res`.
    ///
    /// The result will be OK only if both `Res` instances are OK.
    ///
    /// # Arguments
    ///
    /// * `res` - Another `Res` instance to combine with this one.
    #[inline]
    pub fn ensure(&mut self, res: Self) {
        self.0 &= res.0;
    }

    /// Converts the `Res` into a `Result<OK, Unspecified>`.
    ///
    /// # Warning
    ///
    /// This method is not constant time and should be used carefully in
    /// security-sensitive contexts.
    ///
    /// # Arguments
    ///
    /// * `ok` - The value to return in the `Ok` variant if the `Res` is OK.
    ///
    /// # Returns
    ///
    /// `Ok(ok)` if the `Res` is OK, `Err(Unspecified)` otherwise.
    #[allow(clippy::missing_errors_doc)]
    #[inline(always)]
    pub fn unit_err<OK>(self, ok: OK) -> Result<OK, Unspecified> {
        if self.is_ok() {
            Ok(ok)
        } else {
            Err(Unspecified)
        }
    }

    /// Converts the `Res` into a `Result<OK, Unspecified>`, with a closure for the OK case.
    ///
    /// # Warning
    ///
    /// This method is not constant time and should be used carefully in
    /// security-sensitive contexts.
    ///
    /// # When to Use
    ///
    /// Use this method when the creation of the `OK` value depends on the result
    /// being OK for safety reasons. The closure is only called if the `Res` is OK,
    /// ensuring that any preconditions for the OK value's creation are met.
    ///
    /// # Arguments
    ///
    /// * `ok` - A closure that returns the value for the `Ok` variant if the `Res` is OK.
    ///
    /// # Returns
    ///
    /// `Ok(ok())` if the `Res` is OK, `Err(Unspecified)` otherwise.
    #[inline(always)]
    #[allow(clippy::missing_errors_doc)]
    pub fn unit_err_with<F, OK>(self, ok: F) -> Result<OK, Unspecified>
        where F: FnOnce() -> OK
    {
        if self.is_ok() {
            Ok(ok())
        } else {
            Err(Unspecified)
        }
    }

    /// Unwraps the `Res`, panicking if it's an error.
    ///
    /// # Panics
    ///
    /// Panics if the `Res` is an error.
    ///
    /// # Warning
    ///
    /// This method should generally be avoided in production code, as it can lead
    /// to program termination. It's primarily useful for testing or in situations
    /// where an error truly represents an unrecoverable state.
    #[inline]
    #[track_caller]
    pub fn unwrap(self) {
        self.unit_err(()).unwrap();
    }
}