#[macro_use]
pub mod macros;

pub mod prelude;

use ffi_sdk::ffi_utils::{repr_c, Blocking, ReprC};
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())
}

#[allow(clippy::type_complexity)]
pub(crate) fn make_continuation<T>() -> (
    repr_c::Box<dyn Send + FnMut(T, Blocking)>,
    oneshot::Receiver<T>,
)
where
    T: ReprC + Send + 'static,
{
    let (tx, rx) = 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 tx = Some(tx);
    let continuation = move |result, _| {
        tx.take()
            .expect("This callback has been called twice, but it is morally an `FnOnce`")
            .send(result)
            // Do not sweat a send failure: it just means the receiver was dropped, so there is
            // nobody to witness the lack of send.
            .ok();
    };

    (Box::new(continuation).into(), rx)
}
