#[macro_use]
pub mod macros;

pub mod prelude;

use ffi_sdk::ffi_utils::ReprC;
use safer_ffi::closure::BoxDynFnMut1;
pub(crate) use set_arc::SetArc;
use tokio::sync::oneshot;
mod set_arc;

pub(crate) mod zstr;

pub(crate) mod extension_traits;
pub type Str = ::std::borrow::Cow<'static, str>;

#[derive(Default)]
pub struct InvariantLifetimeMarker<'lifetime>(
    ::core::marker::PhantomData<&'lifetime mut &'lifetime ()>,
);

pub fn base64_encode_unpadded(bytes: &[u8]) -> String {
    ::base64::Engine::encode(&::base64::engine::general_purpose::URL_SAFE_NO_PAD, bytes)
}

pub fn base64_decode_unpadded(str: &str) -> Result<Box<[u8]>, ::base64::DecodeError> {
    let v = ::base64::Engine::decode(&::base64::engine::general_purpose::URL_SAFE_NO_PAD, str)?;
    Ok(v.into_boxed_slice())
}

pub(crate) fn make_continuation<T>() -> (BoxDynFnMut1<(), T>, oneshot::Receiver<T>)
where
    T: ReprC + Send + 'static,
{
    let (send, recv) = oneshot::channel();

    // `move` forces the closure to take ownership of `send`, which we make into an `Option<Sender>`
    // Then, in the callback, since it can only implement `FnMut`, we can use `Option::take` to get
    // ownership of the sender even though we only have a `&mut Option`. If the option is none,
    // that means that we've already run the function once
    let mut send = Some(send);
    let continuation = BoxDynFnMut1::new(Box::new(move |result| {
        let Some(send) = send.take() else {
            panic!("This callback has been called twice, but it is morally a `BoxDynFnOnce1`")
        };

        // no .unwrap() to avoid `T: Debug` bound
        if send.send(result).is_err() {
            panic!("failed to send in BoxDynFnMut1");
        }
    }));

    (continuation, recv)
}
