endpoint-sec-sys 0.6.0

Raw Rust wrappers around the Endpoint Security Framework
Documentation
//! Helpers that need to live here due to Rust's orphan rules.
//!
//! They are not intended to be long/complicated and they should not depend on anything but the std
//! ideally.
#[cfg(doc)]
use super::*;
#[cfg(feature = "macos_13_0_0")]
use crate::es_mute_inverted_return_t;

/// Helper macro to generate proper Rust wrapper for the error types
macro_rules! result_types {
    // - `enum_doc`: Documentation for the whole enum
    // - `rust_name`: Name of the enum on the Rust side
    // - `c_name`: Name of the enum on the C side (autogenerated bindings)
    // - `success_c_variant`: Success variant of the enum on the C side
    // - `variant_doc`: Documentation for the variant
    // - `rust_variant`: Name of the variant, Rust
    // - `c_variant`: Name of the variant, C
    (
        $(#[$enum_doc:meta])+
        enum $rust_name:ident =
        $c_name:ident with
        $success_c_variant:ident;
        $($(#[$variant_meta: meta])? $rust_variant:ident is $c_variant:ident),+ $(,)?
    ) => {
        // First generate the enum with the proper cast to the C
        $(#[$enum_doc] )+
        #[doc = ""]
        // Link to the relevant .ok() method
        #[doc = "Usually constructed using "]
        #[doc = ::std::concat!("[`", ::std::stringify!($c_name), "::ok()`].")]
        #[derive(::std::fmt::Debug, ::std::clone::Clone, ::std::marker::Copy, ::std::cmp::PartialEq, ::std::cmp::Eq, ::std::hash::Hash)]
        pub enum $rust_name {
            // Ensure the variants match their C counterpart in value
            $(
                #[doc = ::std::concat!(
                    "See [`", ::std::stringify!($c_variant), "`]",
                    "[", ::std::stringify!($c_name), "::", ::std::stringify!($c_variant), "]"
                )]
                $(#[$variant_meta])?
                $rust_variant,
            )+
            /// Catches new variants in the C enum
            Unknown($crate::$c_name),
            /// Used to signal a call to an unavailable API, either because it was removed or
            /// because it is only available in higher versions (eg 12.0+ when running on macOS
            /// 11.0)
            ApiUnavailable,
        }

        // Implement display by simply rendering the C variant name (which pretty much contains the type name
        // so it will be clear)
        impl ::std::fmt::Display for $crate::$rust_name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
                match self {
                    $( $(#[$variant_meta])? Self::$rust_variant => ::std::write!(f, ::std::stringify!($c_variant)), )+
                    Self::Unknown(err) => ::std::write!(f, ::std::concat!(::std::stringify!($c_name), "({:#X})"), err.0),
                    Self::ApiUnavailable => ::std::write!(f, "API is unavailable in this version of macOS"),
                }
            }
        }

        impl ::std::error::Error for $crate::$rust_name {}

        // Implemented the .ok() method
        impl $crate::$c_name {
            #[doc = "Converts an instance of [`"]
            #[doc = ::std::stringify!($c_name)]
            #[doc = "`] to a [`Result`]`<(), `[`"]
            #[doc = ::std::stringify!($rust_name)]
            #[doc = "`]`>`"]
            pub fn ok(self) -> ::std::result::Result<(), $crate::$rust_name> {
                let err = match self {
                    Self::$success_c_variant => return ::std::result::Result::Ok(()),
                    $( $(#[$variant_meta])? Self::$c_variant => $crate::$rust_name::$rust_variant, )+
                    err => $crate::$rust_name::Unknown(err),
                };

                ::std::result::Result::Err(err)
            }
        }
    };
}

result_types!(
    /// Basic error without additional informations.
    #[doc(alias = "es_return_t")]
    enum ReturnError = es_return_t with ES_RETURN_SUCCESS;
    Error is ES_RETURN_ERROR,
);

result_types!(
    /// Responding to a message failed.
    #[doc(alias = "es_respond_result_t")]
    enum RespondError = es_respond_result_t with ES_RESPOND_RESULT_SUCCESS;
    InvalidArgument is ES_RESPOND_RESULT_ERR_INVALID_ARGUMENT,
    Internal is ES_RESPOND_RESULT_ERR_INTERNAL,
    MessageNotFound is ES_RESPOND_RESULT_NOT_FOUND,
    DuplicateResponse is ES_RESPOND_RESULT_ERR_DUPLICATE_RESPONSE,
    EventType is ES_RESPOND_RESULT_ERR_EVENT_TYPE,
);

result_types!(
    /// Clearing authorisation caches failed.
    #[doc(alias = "es_clear_cache_result_t")]
    enum ClearCacheError = es_clear_cache_result_t with ES_CLEAR_CACHE_RESULT_SUCCESS;
    Internal is ES_CLEAR_CACHE_RESULT_ERR_INTERNAL,
    Throttle is ES_CLEAR_CACHE_RESULT_ERR_THROTTLE,
);

result_types!(
    /// Creating a new client failed.
    #[doc(alias = "es_new_client_result_t")]
    enum NewClientError = es_new_client_result_t with ES_NEW_CLIENT_RESULT_SUCCESS;
    InvalidArgument is ES_NEW_CLIENT_RESULT_ERR_INVALID_ARGUMENT,
    Internal is ES_NEW_CLIENT_RESULT_ERR_INTERNAL,
    NotEntitled is ES_NEW_CLIENT_RESULT_ERR_NOT_ENTITLED,
    NotPermitted is ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED,
    NotPrivileged is ES_NEW_CLIENT_RESULT_ERR_NOT_PRIVILEGED,
    #[cfg(feature = "macos_10_15_1")]
    TooManyClients is ES_NEW_CLIENT_RESULT_ERR_TOO_MANY_CLIENTS,
);

#[cfg(feature = "macos_13_0_0")]
result_types!(
    /// OpenSSH login failed.
    #[doc(alias = "es_openssh_login_result_type_t")]
    enum OpensshLoginError = es_openssh_login_result_type_t with ES_OPENSSH_AUTH_SUCCESS;
    LoginExceedMaxTries is ES_OPENSSH_LOGIN_EXCEED_MAXTRIES,
    LoginRootDenied is ES_OPENSSH_LOGIN_ROOT_DENIED,
    AuthNone is ES_OPENSSH_AUTH_FAIL_NONE,
    AuthPassword is ES_OPENSSH_AUTH_FAIL_PASSWD,
    AuthKbdint is ES_OPENSSH_AUTH_FAIL_KBDINT,
    AuthPubkey is ES_OPENSSH_AUTH_FAIL_PUBKEY,
    AuthHostBased is ES_OPENSSH_AUTH_FAIL_HOSTBASED,
    AuthGssapi is ES_OPENSSH_AUTH_FAIL_GSSAPI,
    InvalidUser is ES_OPENSSH_INVALID_USER,
);

// There are several success variants for the enum below, fitting it into the helper macro would be
// more work than it's worth as long as this pattern only appears once

/// Type of muting for a specific [`es_mute_inversion_type_t`]
///
/// Usually constructed using [`es_mute_inverted_return_t::ok()`]
#[doc(alias = "es_mute_inverted_return_t")]
#[cfg(feature = "macos_13_0_0")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MuteInvertedType {
    /// The type of muting queried was not inverted
    ///
    /// See [`es_mute_inverted_return_t::ES_MUTE_NOT_INVERTED`]
    Normal,
    /// The type of muting queried was inverted
    ///
    /// See [`es_mute_inverted_return_t::ES_MUTE_INVERTED`]
    Inverted,
}

/// Getting the [mute type][MuteInvertedType] failed.
///
/// Usually constructed using [`es_mute_inverted_return_t::ok()`]
#[doc(alias = "es_mute_inverted_return_t")]
#[cfg(feature = "macos_13_0_0")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MuteTypeError {
    /// See [`es_mute_inverted_return_t::ES_MUTE_INVERTED_ERROR`]
    Error,
    /// Catches new variants in the C enum
    Unknown(es_mute_inverted_return_t),
    /// Used to signal a call to an unavailable API, either because it was removed or
    /// because it is only available in higher versions (eg 12.0+ when running on macOS
    /// 11.0)
    ApiUnavailable,
}

// Implement display by simply rendering the C variant name (which pretty much contains the type name
// so it will be clear)
#[cfg(feature = "macos_13_0_0")]
impl ::std::fmt::Display for MuteTypeError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        match self {
            Self::Error => ::std::write!(f, "ES_MUTE_INVERTED_ERROR"),
            Self::Unknown(err) => ::std::write!(f, "es_mute_inverted_return_t({:#X})", err.0),
            Self::ApiUnavailable => ::std::write!(f, "API is unavailable in this version of macOS"),
        }
    }
}

#[cfg(feature = "macos_13_0_0")]
impl ::std::error::Error for MuteTypeError {}

#[cfg(feature = "macos_13_0_0")]
impl es_mute_inverted_return_t {
    /// Converts an instance of [`es_mute_inverted_return_t`] to a
    /// [`Result`]`<`[`MuteInvertedType`]`, `[`MuteTypeError`]`>`.
    pub fn ok(self) -> Result<MuteInvertedType, MuteTypeError> {
        match self {
            Self::ES_MUTE_INVERTED => Ok(MuteInvertedType::Inverted),
            Self::ES_MUTE_NOT_INVERTED => Ok(MuteInvertedType::Normal),
            Self::ES_MUTE_INVERTED_ERROR => Err(MuteTypeError::Error),
            err => Err(MuteTypeError::Unknown(err)),
        }
    }
}