use crate::error::ErrorStack;
use crate::lib_ctx::LibCtxRef;
use crate::{cvt, cvt_p};
use foreign_types::{ForeignType, ForeignTypeRef};
use openssl_macros::corresponds;
use std::ffi::CString;
use std::ptr;
foreign_type_and_impl_send_sync! {
    type CType = ffi::OSSL_PROVIDER;
    fn drop = ossl_provider_free;
    pub struct Provider;
        pub struct ProviderRef;
}
#[inline]
unsafe fn ossl_provider_free(p: *mut ffi::OSSL_PROVIDER) {
    ffi::OSSL_PROVIDER_unload(p);
}
impl Provider {
                #[corresponds(OSSL_provider_load)]
    pub fn load(ctx: Option<&LibCtxRef>, name: &str) -> Result<Self, ErrorStack> {
        let name = CString::new(name).unwrap();
        unsafe {
            let p = cvt_p(ffi::OSSL_PROVIDER_load(
                ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
                name.as_ptr(),
            ))?;
            Ok(Provider::from_ptr(p))
        }
    }
                    #[corresponds(OSSL_provider_try_load)]
    pub fn try_load(
        ctx: Option<&LibCtxRef>,
        name: &str,
        retain_fallbacks: bool,
    ) -> Result<Self, ErrorStack> {
        let name = CString::new(name).unwrap();
        unsafe {
            let p = cvt_p(ffi::OSSL_PROVIDER_try_load(
                ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
                name.as_ptr(),
                retain_fallbacks as _,
            ))?;
            Ok(Provider::from_ptr(p))
        }
    }
                    #[corresponds(OSSL_PROVIDER_set_default_search_path)]
    pub fn set_default_search_path(ctx: Option<&LibCtxRef>, path: &str) -> Result<(), ErrorStack> {
        let path = CString::new(path).unwrap();
        unsafe {
            cvt(ffi::OSSL_PROVIDER_set_default_search_path(
                ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
                path.as_ptr(),
            ))
            .map(|_| ())
        }
    }
}