dcrypt_api/error/
traits.rs1use super::registry::ERROR_REGISTRY;
4use super::types::{Error, Result};
5use subtle::{Choice, ConditionallySelectable};
6
7pub trait ResultExt<T, E>: Sized {
9    fn wrap_err<F, E2>(self, f: F) -> core::result::Result<T, E2>
11    where
12        F: FnOnce() -> E2;
13
14    fn with_context(self, context: &'static str) -> Result<T>
16    where
17        E: Into<Error>;
18
19    #[cfg(feature = "std")]
20    fn with_message(self, message: impl Into<String>) -> Result<T>
22    where
23        E: Into<Error>;
24}
25
26impl<T, E> ResultExt<T, E> for core::result::Result<T, E> {
27    fn wrap_err<F, E2>(self, f: F) -> core::result::Result<T, E2>
28    where
29        F: FnOnce() -> E2,
30    {
31        self.map_err(|_| f())
32    }
33
34    fn with_context(self, context: &'static str) -> Result<T>
35    where
36        E: Into<Error>,
37    {
38        self.map_err(|e| {
39            let err = e.into();
40            err.with_context(context)
41        })
42    }
43
44    #[cfg(feature = "std")]
45    fn with_message(self, message: impl Into<String>) -> Result<T>
46    where
47        E: Into<Error>,
48    {
49        self.map_err(|e| {
50            let err = e.into();
51            err.with_message(message)
52        })
53    }
54}
55
56pub trait SecureErrorHandling<T, E>: Sized {
58    fn secure_unwrap<F>(self, default: T, on_error: F) -> T
60    where
61        F: FnOnce() -> E;
62}
63
64impl<T, E> SecureErrorHandling<T, E> for core::result::Result<T, E> {
65    fn secure_unwrap<F>(self, default: T, on_error: F) -> T
66    where
67        F: FnOnce() -> E,
68    {
69        match self {
70            Ok(value) => value,
71            Err(_) => {
72                let error = on_error();
74                ERROR_REGISTRY.store(error);
75                default
76            }
77        }
78    }
79}
80
81pub trait ConstantTimeResult<T, E> {
83    fn ct_is_ok(&self) -> bool;
85
86    fn ct_is_err(&self) -> bool;
88
89    fn ct_map<U, F, G>(self, ok_fn: F, err_fn: G) -> U
92    where
93        F: FnOnce(T) -> U,
94        G: FnOnce(E) -> U,
95        U: ConditionallySelectable;
96}
97
98impl<T, E> ConstantTimeResult<T, E> for core::result::Result<T, E> {
99    fn ct_is_ok(&self) -> bool {
100        let is_ok_choice = match self {
102            Ok(_) => Choice::from(1u8),
103            Err(_) => Choice::from(0u8),
104        };
105
106        let mut result = false;
109        result.conditional_assign(&true, is_ok_choice);
110        result
111    }
112
113    fn ct_is_err(&self) -> bool {
114        let is_ok = self.ct_is_ok();
116
117        let is_ok_choice = Choice::from(is_ok as u8);
119
120        let mut result = true;
122        result.conditional_assign(&false, is_ok_choice);
123        result
124    }
125
126    fn ct_map<U, F, G>(self, ok_fn: F, err_fn: G) -> U
127    where
128        F: FnOnce(T) -> U,
129        G: FnOnce(E) -> U,
130        U: ConditionallySelectable,
131    {
132        match self {
135            Ok(t) => {
136                ok_fn(t)
141            }
142            Err(e) => {
143                err_fn(e)
146            }
147        }
148        }
154}
155
156trait ConditionalAssign {
158    fn conditional_assign(&mut self, other: &Self, choice: Choice);
159}
160
161impl ConditionalAssign for bool {
162    fn conditional_assign(&mut self, other: &bool, choice: Choice) {
163        let self_as_u8 = *self as u8;
165        let other_as_u8 = *other as u8;
166
167        let result = u8::conditional_select(&self_as_u8, &other_as_u8, choice);
169
170        *self = result != 0;
172    }
173}