endpoint_sec_sys/
result_wrapping.rs

1//! Helpers that need to live here due to Rust's orphan rules.
2//!
3//! They are not intended to be long/complicated and they should not depend on anything but the std
4//! ideally.
5#[cfg(doc)]
6use super::*;
7#[cfg(feature = "macos_13_0_0")]
8use crate::es_mute_inverted_return_t;
9
10/// Helper macro to generate proper Rust wrapper for the error types
11macro_rules! result_types {
12    // - `enum_doc`: Documentation for the whole enum
13    // - `rust_name`: Name of the enum on the Rust side
14    // - `c_name`: Name of the enum on the C side (autogenerated bindings)
15    // - `success_c_variant`: Success variant of the enum on the C side
16    // - `variant_doc`: Documentation for the variant
17    // - `rust_variant`: Name of the variant, Rust
18    // - `c_variant`: Name of the variant, C
19    (
20        $(#[$enum_doc:meta])+
21        enum $rust_name:ident =
22        $c_name:ident with
23        $success_c_variant:ident;
24        $($(#[$variant_meta: meta])? $rust_variant:ident is $c_variant:ident),+ $(,)?
25    ) => {
26        // First generate the enum with the proper cast to the C
27        $(#[$enum_doc] )+
28        #[doc = ""]
29        // Link to the relevant .ok() method
30        #[doc = "Usually constructed using "]
31        #[doc = ::std::concat!("[`", ::std::stringify!($c_name), "::ok()`].")]
32        #[derive(::std::fmt::Debug, ::std::clone::Clone, ::std::marker::Copy, ::std::cmp::PartialEq, ::std::cmp::Eq, ::std::hash::Hash)]
33        pub enum $rust_name {
34            // Ensure the variants match their C counterpart in value
35            $(
36                #[doc = ::std::concat!(
37                    "See [`", ::std::stringify!($c_variant), "`]",
38                    "[", ::std::stringify!($c_name), "::", ::std::stringify!($c_variant), "]"
39                )]
40                $(#[$variant_meta])?
41                $rust_variant,
42            )+
43            /// Catches new variants in the C enum
44            Unknown($crate::$c_name),
45            /// Used to signal a call to an unavailable API, either because it was removed or
46            /// because it is only available in higher versions (eg 12.0+ when running on macOS
47            /// 11.0)
48            ApiUnavailable,
49        }
50
51        // Implement display by simply rendering the C variant name (which pretty much contains the type name
52        // so it will be clear)
53        impl ::std::fmt::Display for $crate::$rust_name {
54            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
55                match self {
56                    $( $(#[$variant_meta])? Self::$rust_variant => ::std::write!(f, ::std::stringify!($c_variant)), )+
57                    Self::Unknown(err) => ::std::write!(f, ::std::concat!(::std::stringify!($c_name), "({:#X})"), err.0),
58                    Self::ApiUnavailable => ::std::write!(f, "API is unavailable in this version of macOS"),
59                }
60            }
61        }
62
63        impl ::std::error::Error for $crate::$rust_name {}
64
65        // Implemented the .ok() method
66        impl $crate::$c_name {
67            #[doc = "Converts an instance of [`"]
68            #[doc = ::std::stringify!($c_name)]
69            #[doc = "`] to a [`Result`]`<(), `[`"]
70            #[doc = ::std::stringify!($rust_name)]
71            #[doc = "`]`>`"]
72            pub fn ok(self) -> ::std::result::Result<(), $crate::$rust_name> {
73                let err = match self {
74                    Self::$success_c_variant => return ::std::result::Result::Ok(()),
75                    $( $(#[$variant_meta])? Self::$c_variant => $crate::$rust_name::$rust_variant, )+
76                    err => $crate::$rust_name::Unknown(err),
77                };
78
79                ::std::result::Result::Err(err)
80            }
81        }
82    };
83}
84
85result_types!(
86    /// Basic error without additional informations.
87    #[doc(alias = "es_return_t")]
88    enum ReturnError = es_return_t with ES_RETURN_SUCCESS;
89    Error is ES_RETURN_ERROR,
90);
91
92result_types!(
93    /// Responding to a message failed.
94    #[doc(alias = "es_respond_result_t")]
95    enum RespondError = es_respond_result_t with ES_RESPOND_RESULT_SUCCESS;
96    InvalidArgument is ES_RESPOND_RESULT_ERR_INVALID_ARGUMENT,
97    Internal is ES_RESPOND_RESULT_ERR_INTERNAL,
98    MessageNotFound is ES_RESPOND_RESULT_NOT_FOUND,
99    DuplicateResponse is ES_RESPOND_RESULT_ERR_DUPLICATE_RESPONSE,
100    EventType is ES_RESPOND_RESULT_ERR_EVENT_TYPE,
101);
102
103result_types!(
104    /// Clearing authorisation caches failed.
105    #[doc(alias = "es_clear_cache_result_t")]
106    enum ClearCacheError = es_clear_cache_result_t with ES_CLEAR_CACHE_RESULT_SUCCESS;
107    Internal is ES_CLEAR_CACHE_RESULT_ERR_INTERNAL,
108    Throttle is ES_CLEAR_CACHE_RESULT_ERR_THROTTLE,
109);
110
111result_types!(
112    /// Creating a new client failed.
113    #[doc(alias = "es_new_client_result_t")]
114    enum NewClientError = es_new_client_result_t with ES_NEW_CLIENT_RESULT_SUCCESS;
115    InvalidArgument is ES_NEW_CLIENT_RESULT_ERR_INVALID_ARGUMENT,
116    Internal is ES_NEW_CLIENT_RESULT_ERR_INTERNAL,
117    NotEntitled is ES_NEW_CLIENT_RESULT_ERR_NOT_ENTITLED,
118    NotPermitted is ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED,
119    NotPrivileged is ES_NEW_CLIENT_RESULT_ERR_NOT_PRIVILEGED,
120    #[cfg(feature = "macos_10_15_1")]
121    TooManyClients is ES_NEW_CLIENT_RESULT_ERR_TOO_MANY_CLIENTS,
122);
123
124#[cfg(feature = "macos_13_0_0")]
125result_types!(
126    /// OpenSSH login failed.
127    #[doc(alias = "es_openssh_login_result_type_t")]
128    enum OpensshLoginError = es_openssh_login_result_type_t with ES_OPENSSH_AUTH_SUCCESS;
129    LoginExceedMaxTries is ES_OPENSSH_LOGIN_EXCEED_MAXTRIES,
130    LoginRootDenied is ES_OPENSSH_LOGIN_ROOT_DENIED,
131    AuthNone is ES_OPENSSH_AUTH_FAIL_NONE,
132    AuthPassword is ES_OPENSSH_AUTH_FAIL_PASSWD,
133    AuthKbdint is ES_OPENSSH_AUTH_FAIL_KBDINT,
134    AuthPubkey is ES_OPENSSH_AUTH_FAIL_PUBKEY,
135    AuthHostBased is ES_OPENSSH_AUTH_FAIL_HOSTBASED,
136    AuthGssapi is ES_OPENSSH_AUTH_FAIL_GSSAPI,
137    InvalidUser is ES_OPENSSH_INVALID_USER,
138);
139
140// There are several success variants for the enum below, fitting it into the helper macro would be
141// more work than it's worth as long as this pattern only appears once
142
143/// Type of muting for a specific [`es_mute_inversion_type_t`]
144///
145/// Usually constructed using [`es_mute_inverted_return_t::ok()`]
146#[doc(alias = "es_mute_inverted_return_t")]
147#[cfg(feature = "macos_13_0_0")]
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
149pub enum MuteInvertedType {
150    /// The type of muting queried was not inverted
151    ///
152    /// See [`es_mute_inverted_return_t::ES_MUTE_NOT_INVERTED`]
153    Normal,
154    /// The type of muting queried was inverted
155    ///
156    /// See [`es_mute_inverted_return_t::ES_MUTE_INVERTED`]
157    Inverted,
158}
159
160/// Getting the [mute type][MuteInvertedType] failed.
161///
162/// Usually constructed using [`es_mute_inverted_return_t::ok()`]
163#[doc(alias = "es_mute_inverted_return_t")]
164#[cfg(feature = "macos_13_0_0")]
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
166pub enum MuteTypeError {
167    /// See [`es_mute_inverted_return_t::ES_MUTE_INVERTED_ERROR`]
168    Error,
169    /// Catches new variants in the C enum
170    Unknown(es_mute_inverted_return_t),
171    /// Used to signal a call to an unavailable API, either because it was removed or
172    /// because it is only available in higher versions (eg 12.0+ when running on macOS
173    /// 11.0)
174    ApiUnavailable,
175}
176
177// Implement display by simply rendering the C variant name (which pretty much contains the type name
178// so it will be clear)
179#[cfg(feature = "macos_13_0_0")]
180impl ::std::fmt::Display for MuteTypeError {
181    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
182        match self {
183            Self::Error => ::std::write!(f, "ES_MUTE_INVERTED_ERROR"),
184            Self::Unknown(err) => ::std::write!(f, "es_mute_inverted_return_t({:#X})", err.0),
185            Self::ApiUnavailable => ::std::write!(f, "API is unavailable in this version of macOS"),
186        }
187    }
188}
189
190#[cfg(feature = "macos_13_0_0")]
191impl ::std::error::Error for MuteTypeError {}
192
193#[cfg(feature = "macos_13_0_0")]
194impl es_mute_inverted_return_t {
195    /// Converts an instance of [`es_mute_inverted_return_t`] to a
196    /// [`Result`]`<`[`MuteInvertedType`]`, `[`MuteTypeError`]`>`.
197    pub fn ok(self) -> Result<MuteInvertedType, MuteTypeError> {
198        match self {
199            Self::ES_MUTE_INVERTED => Ok(MuteInvertedType::Inverted),
200            Self::ES_MUTE_NOT_INVERTED => Ok(MuteInvertedType::Normal),
201            Self::ES_MUTE_INVERTED_ERROR => Err(MuteTypeError::Error),
202            err => Err(MuteTypeError::Unknown(err)),
203        }
204    }
205}