use std::cell::UnsafeCell;
use std::ffi::CString;
use std::marker::PhantomData;
use std::os::raw::c_void;
use std::ptr::NonNull;
use std::time::Duration;
use crate::tlua::{self as tlua, AsLua};
#[cfg(not(all(target_arch = "aarch64", target_os = "macos")))]
use ::va_list::{VaList, VaPrimitive};
#[cfg(all(target_arch = "aarch64", target_os = "macos"))]
use crate::va_list::{VaList, VaPrimitive};
use crate::c_ptr;
use crate::error::TarantoolError;
use crate::ffi::{tarantool as ffi, lua};
use crate::Result;
pub mod channel;
pub use channel::{
Channel, SendTimeout, RecvTimeout, SendError, RecvError, TrySendError, TryRecvError,
};
pub mod mutex;
pub use mutex::Mutex;
macro_rules! impl_debug_stub {
($t:ident $($p:tt)*) => {
impl $($p)* ::std::fmt::Debug for $t $($p)* {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
f.debug_struct(::std::stringify!($t))
.finish_non_exhaustive()
}
}
}
}
macro_rules! impl_eq_hash {
($t:ident $($p:tt)*) => {
impl $($p)* ::std::cmp::PartialEq for $t $($p)* {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl $($p)* ::std::cmp::Eq for $t $($p)* {}
impl $($p)* ::std::hash::Hash for $t $($p)* {
fn hash<H>(&self, state: &mut H)
where
H: ::std::hash::Hasher,
{
self.inner.hash(state)
}
}
}
}
pub struct Fiber<'a, T: 'a> {
inner: *mut ffi::Fiber,
callback: *mut c_void,
phantom: PhantomData<&'a T>,
}
impl_debug_stub!{Fiber<'a, T>}
impl<'a, T> Fiber<'a, T> {
pub fn new<F>(name: &str, callback: &mut F) -> Self
where
F: FnMut(Box<T>) -> i32,
{
let (callback_ptr, trampoline) = unsafe { unpack_callback(callback) };
Self {
inner: unsafe { ffi::fiber_new(CString::new(name).unwrap().into_raw(), trampoline) },
callback: callback_ptr,
phantom: PhantomData,
}
}
pub fn new_with_attr<F>(name: &str, attr: &FiberAttr, callback: &mut F) -> Self
where
F: FnMut(Box<T>) -> i32,
{
let (callback_ptr, trampoline) = unsafe { unpack_callback(callback) };
Self {
inner: unsafe {
ffi::fiber_new_ex(
CString::new(name).unwrap().into_raw(),
attr.inner,
trampoline,
)
},
callback: callback_ptr,
phantom: PhantomData,
}
}
pub fn start(&mut self, arg: T) {
unsafe {
let boxed_arg = Box::into_raw(Box::<T>::new(arg));
ffi::fiber_start(self.inner, self.callback, boxed_arg);
}
}
pub fn wakeup(&self) {
unsafe { ffi::fiber_wakeup(self.inner) }
}
pub fn join(&self) -> i32 {
unsafe { ffi::fiber_join(self.inner) }
}
pub fn set_joinable(&mut self, is_joinable: bool) {
unsafe { ffi::fiber_set_joinable(self.inner, is_joinable) }
}
pub fn cancel(&mut self) {
unsafe { ffi::fiber_cancel(self.inner) }
}
}
pub struct Builder<F> {
name: Option<String>,
attr: Option<FiberAttr>,
f: F,
}
impl_debug_stub!{Builder<F>}
impl Builder<NoFunc> {
pub fn new() -> Self {
Builder {
name: None,
attr: None,
f: NoFunc,
}
}
pub fn func<'f, F, T>(self, f: F) -> Builder<FiberFunc<'f, F, T>>
where
F: FnOnce() -> T,
F: 'f,
{
Builder {
name: self.name,
attr: self.attr,
f: FiberFunc {
f: Box::new(f),
result: Default::default(),
marker: PhantomData,
},
}
}
pub fn proc<'f, F>(self, f: F) -> Builder<FiberProc<'f, F>>
where
F: FnOnce(),
F: 'f,
{
Builder {
name: self.name,
attr: self.attr,
f: FiberProc {
f: Box::new(f),
marker: PhantomData,
},
}
}
}
impl Default for Builder<NoFunc> {
fn default() -> Self {
Self::new()
}
}
impl<F> Builder<F> {
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn stack_size(mut self, stack_size: usize) -> Result<Self> {
let mut attr = FiberAttr::new();
attr.set_stack_size(stack_size)?;
self.attr = Some(attr);
Ok(self)
}
}
macro_rules! inner_spawn {
($self:expr, $invocation:tt) => {
{
let Self { name, attr, f } = $self;
let name = name.unwrap_or_else(|| "<rust>".into());
Ok(Fyber::$invocation(name, f, attr.as_ref())?.spawn())
}
};
}
impl<C> Builder<C>
where
C: Callee,
{
pub fn start(self) -> Result<C::JoinHandle> {
inner_spawn!(self, immediate)
}
#[cfg(feature = "defer")]
pub fn defer(self) -> Result<C::JoinHandle> {
inner_spawn!(self, deferred)
}
}
pub struct Fyber<C, I> {
inner: NonNull<ffi::Fiber>,
callee: C,
_invocation: PhantomData<I>,
}
impl_debug_stub!{Fyber<C, I>}
impl<C, I> Fyber<C, I>
where
C: Callee,
I: Invocation,
{
fn new(name: String, callee: C, attr: Option<&FiberAttr>) -> Result<Self> {
let cname = CString::new(name)
.expect("fiber name may not contain interior null bytes");
let inner_raw = unsafe {
if let Some(attr) = attr {
ffi::fiber_new_ex(
cname.as_ptr(), attr.inner, Some(Self::trampoline)
)
} else {
ffi::fiber_new(cname.as_ptr(), Some(Self::trampoline))
}
};
if let Some(inner) = NonNull::new(inner_raw) {
Ok(Self {
inner,
callee,
_invocation: PhantomData,
})
} else {
Err(TarantoolError::last().into())
}
}
pub fn spawn(self) -> C::JoinHandle {
unsafe {
ffi::fiber_set_joinable(self.inner.as_ptr(), true);
let jh = self.callee.start_fiber(self.inner);
I::after_start(self.inner);
jh
}
}
unsafe extern "C" fn trampoline(args: VaList) -> i32 {
let a = C::parse_args(args);
I::before_callee();
C::invoke(a);
0
}
}
impl<C> Fyber<C, Immediate>
where
C: Callee,
{
pub fn immediate(
name: String,
callee: C,
attr: Option<&FiberAttr>,
) -> Result<Self> {
Self::new(name, callee, attr)
}
}
impl<C> Fyber<C, Deferred>
where
C: Callee,
{
pub fn deferred(
name: String,
callee: C,
attr: Option<&FiberAttr>,
) -> Result<Self> {
Self::new(name, callee, attr)
}
}
pub struct LuaFiber<C> {
callee: C,
}
impl_debug_stub!{LuaFiber<C>}
impl<C> LuaFiber<C>
where
C: LuaCallee,
{
pub fn new(callee: C) -> Self {
Self { callee }
}
pub fn spawn(self) -> Result<C::JoinHandle> {
let Self { callee } = self;
let fiber_ref = unsafe {
let l = ffi::luaT_state();
lua::lua_getglobal(l, c_ptr!("require"));
lua::lua_pushstring(l, c_ptr!("fiber"));
impl_details::guarded_pcall(l, 1, 1)?;
lua::lua_getfield(l, -1, c_ptr!("new"));
impl_details::push_userdata(l, callee.into_inner());
lua::lua_pushcclosure(l, Self::trampoline, 1);
impl_details::guarded_pcall(l, 1, 1)
.map_err(|e| {
lua::lua_pop(l, 1);
e
})?;
lua::lua_getfield(l, -1, c_ptr!("set_joinable"));
lua::lua_pushvalue(l, -2);
lua::lua_pushboolean(l, true as i32);
impl_details::guarded_pcall(l, 2, 0)
.map_err(|e| panic!("{}", e))
.unwrap();
let fiber_ref = lua::luaL_ref(l, lua::LUA_REGISTRYINDEX);
lua::lua_pop(l, 1);
fiber_ref
};
Ok(C::join_handle(fiber_ref))
}
unsafe extern "C" fn trampoline(l: *mut lua::lua_State) -> i32 {
let ud_ptr = lua::lua_touserdata(l, lua::lua_upvalueindex(1));
let f = (ud_ptr as *mut Option<C::Function>).as_mut()
.unwrap_or_else(||
tlua::error!(l, "failed to extract upvalue")
)
.take()
.unwrap_or_else(||
tlua::error!(l, "rust FnOnce callback was called more than once")
);
let res = f();
C::save_result(l, res)
}
}
#[derive(PartialEq, Eq, Hash)]
pub struct LuaJoinHandle<'f, T> {
fiber_ref: Option<i32>,
marker: PhantomData<(&'f (), T)>,
}
impl_debug_stub!{LuaJoinHandle<'f, T>}
impl<'f, T> LuaJoinHandle<'f, T> {
fn new(fiber_ref: i32) -> Self {
Self { fiber_ref: Some(fiber_ref), marker: PhantomData }
}
pub fn join(mut self) -> T {
let fiber_ref = self.fiber_ref.take().unwrap();
unsafe {
let guard = impl_details::lua_fiber_join(fiber_ref)
.map_err(|e| panic!("Unrecoverable lua failure: {}", e))
.unwrap();
let ud_ptr = lua::lua_touserdata(guard.as_lua(), -1);
let res = (ud_ptr as *mut Option<T>).as_mut()
.expect("fiber:join must return correct userdata")
.take()
.expect("data can only be taken once from the UDBox");
res
}
}
}
impl<'f, T> Drop for LuaJoinHandle<'f, T> {
fn drop(&mut self) {
if self.fiber_ref.is_some() {
panic!("LuaJoinHandle dropped before being joined")
}
}
}
#[derive(PartialEq, Eq, Hash)]
pub struct LuaUnitJoinHandle<'f> {
fiber_ref: Option<i32>,
marker: PhantomData<&'f ()>,
}
impl_debug_stub!{LuaUnitJoinHandle<'f>}
impl<'f> LuaUnitJoinHandle<'f> {
fn new(fiber_ref: i32) -> Self {
Self {
fiber_ref: Some(fiber_ref),
marker: PhantomData,
}
}
pub fn join(mut self) {
let fiber_ref = self.fiber_ref.take().unwrap();
match unsafe { impl_details::lua_fiber_join(fiber_ref) } {
Ok(_pushguard) => (),
Err(e) => panic!("Unrecoverable lua failure: {}", e),
}
}
}
impl<'f> Drop for LuaUnitJoinHandle<'f> {
fn drop(&mut self) {
if self.fiber_ref.is_some() {
panic!("LuaUnitJoinHandle dropped before being joined")
}
}
}
mod impl_details {
use super::*;
use crate::tlua::{AsLua, StaticLua, LuaError, PushGuard};
pub(super) unsafe fn lua_error_from_top(l: *mut lua::lua_State) -> LuaError {
let mut len = std::mem::MaybeUninit::uninit();
let data = lua::lua_tolstring(l, -1, len.as_mut_ptr());
assert!(!data.is_null());
let msg_bytes = std::slice::from_raw_parts(
data as *mut u8, len.assume_init()
);
let msg = String::from_utf8_lossy(msg_bytes);
tlua::LuaError::ExecutionError(msg)
}
pub(super) unsafe fn guarded_pcall(
lptr: *mut lua::lua_State, nargs: i32, nresults: i32
) -> Result<()>
{
match lua::lua_pcall(lptr, nargs, nresults, 0) {
lua::LUA_OK => Ok(()),
lua::LUA_ERRRUN => {
let err = lua_error_from_top(lptr).into();
lua::lua_pop(lptr, 1);
Err(err)
}
code => panic!("lua_pcall: Unrecoverable failure code: {}", code)
}
}
pub(super) unsafe fn lua_fiber_join(f_ref: i32) -> Result<PushGuard<StaticLua>> {
let l = crate::global_lua();
let lptr = l.as_lua();
lua::lua_rawgeti(lptr, lua::LUA_REGISTRYINDEX, f_ref);
lua::lua_getfield(lptr, -1, c_ptr!("join"));
lua::lua_pushvalue(lptr, -2);
lua::luaL_unref(lptr, lua::LUA_REGISTRYINDEX, f_ref);
guarded_pcall(lptr, 1, 2)
.map_err(|e| {
lua::lua_pop(lptr, 1);
e
})?;
let guard = PushGuard::new(l, 3);
assert_ne!(lua::lua_toboolean(lptr, -2), 0);
Ok(guard)
}
pub(super) unsafe fn push_userdata<T>(lua: tlua::LuaState, value: T) {
use tlua::ffi;
type UDBox<T> = Option<T>;
let ud_ptr = ffi::lua_newuserdata(lua, std::mem::size_of::<UDBox<T>>());
std::ptr::write(ud_ptr.cast::<UDBox<T>>(), Some(value));
if std::mem::needs_drop::<T>() {
ffi::lua_newtable(lua);
ffi::lua_pushstring(lua, c_ptr!("__gc"));
ffi::lua_pushcfunction(lua, wrap_gc::<T>);
ffi::lua_settable(lua, -3);
ffi::lua_setmetatable(lua, -2);
}
unsafe extern "C" fn wrap_gc<T>(lua: *mut ffi::lua_State) -> i32 {
let ud_ptr = ffi::lua_touserdata(lua, 1);
let ud = ud_ptr.cast::<UDBox<T>>()
.as_mut()
.expect("__gc called with userdata pointing to NULL");
drop(ud.take());
0
}
}
}
pub trait LuaCallee {
type Function: FnOnce() -> Self::Output;
type Output;
type JoinHandle;
fn into_inner(self) -> Self::Function;
fn join_handle(fiber_ref: i32) -> Self::JoinHandle;
unsafe fn save_result(l: *mut lua::lua_State, res: Self::Output) -> i32;
}
pub struct LuaFiberFunc<'f, F> {
f: F,
marker: PhantomData<&'f ()>,
}
impl<'f, F> LuaFiberFunc<'f, F> {
pub fn new(f: F) -> Self {
Self {
f,
marker: PhantomData,
}
}
}
impl<'f, F, T> LuaCallee for LuaFiberFunc<'f, F>
where
F: FnOnce() -> T,
F: 'f,
T: 'f,
{
type Function = F;
type Output = T;
type JoinHandle = LuaJoinHandle<'f, T>;
fn into_inner(self) -> F {
self.f
}
fn join_handle(fiber_ref: i32) -> Self::JoinHandle {
LuaJoinHandle::new(fiber_ref)
}
unsafe fn save_result(l: *mut lua::lua_State, res: T) -> i32 {
impl_details::push_userdata(l, res);
1
}
}
pub struct LuaFiberProc<'f, F> {
f: F,
marker: PhantomData<&'f ()>,
}
impl<'f, F> LuaFiberProc<'f, F> {
pub fn new(f: F) -> Self {
Self {
f,
marker: PhantomData,
}
}
}
impl<'f, F> LuaCallee for LuaFiberProc<'f, F>
where
F: FnOnce(),
F: 'f,
{
type Function = F;
type Output = ();
type JoinHandle = LuaUnitJoinHandle<'f>;
fn join_handle(fiber_ref: i32) -> Self::JoinHandle {
LuaUnitJoinHandle::new(fiber_ref)
}
fn into_inner(self) -> F {
self.f
}
unsafe fn save_result(_: *mut lua::lua_State, _: ()) -> i32 {
0
}
}
pub trait Callee {
type Args;
type JoinHandle;
unsafe fn start_fiber(self, inner: NonNull<ffi::Fiber>) -> Self::JoinHandle;
unsafe fn parse_args(args: VaList) -> Self::Args;
unsafe fn invoke(a: Self::Args);
}
pub struct NoFunc;
pub struct FiberFunc<'f, F, T>
where
F: FnOnce() -> T,
F: 'f,
{
f: Box<F>,
result: Box<UnsafeCell<Option<T>>>,
marker: PhantomData<&'f ()>,
}
impl<'f, F, T> Callee for FiberFunc<'f, F, T>
where
F: FnOnce() -> T,
F: 'f,
T: 'f,
{
type JoinHandle = JoinHandle<'f, T>;
type Args = (Box<F>, *mut Option<T>);
unsafe fn start_fiber(self, inner: NonNull<ffi::Fiber>) -> Self::JoinHandle {
let (f, result): Self::Args = (self.f, self.result.get());
ffi::fiber_start(inner.as_ptr(), Box::into_raw(f), result);
JoinHandle::new(inner, self.result)
}
unsafe fn parse_args(mut args: VaList) -> Self::Args {
let f = args.get_boxed::<F>();
let result = args.get_ptr::<Option<T>>();
(f, result)
}
unsafe fn invoke((f, result): Self::Args) {
std::ptr::write(result, Some(f()))
}
}
pub struct FiberProc<'f, F>
where
F: FnOnce(),
{
f: Box<F>,
marker: PhantomData<&'f ()>,
}
impl<'f, F> Callee for FiberProc<'f, F>
where
F: FnOnce(),
F: 'f,
{
type JoinHandle = UnitJoinHandle<'f>;
type Args = Box<F>;
unsafe fn start_fiber(self, inner: NonNull<ffi::Fiber>) -> Self::JoinHandle {
let f: Self::Args = self.f;
ffi::fiber_start(inner.as_ptr(), Box::into_raw(f));
UnitJoinHandle::new(inner)
}
unsafe fn parse_args(mut args: VaList) -> Self::Args {
args.get_boxed::<F>()
}
unsafe fn invoke(f: Self::Args) {
f()
}
}
pub trait Invocation {
unsafe fn before_callee();
unsafe fn after_start(f: NonNull<ffi::Fiber>);
}
pub struct Immediate;
impl Invocation for Immediate {
unsafe fn before_callee() {}
unsafe fn after_start(_: NonNull<ffi::Fiber>) {}
}
pub struct Deferred;
impl Invocation for Deferred {
unsafe fn before_callee() {
ffi::fiber_yield()
}
unsafe fn after_start(f: NonNull<ffi::Fiber>) {
ffi::fiber_wakeup(f.as_ptr())
}
}
pub struct JoinHandle<'f, T> {
inner: Option<NonNull<ffi::Fiber>>,
result: Box<UnsafeCell<Option<T>>>,
marker: PhantomData<&'f ()>,
}
impl_debug_stub!{JoinHandle<'f, T>}
impl_eq_hash!{JoinHandle<'f, T>}
impl<'f, T> JoinHandle<'f, T> {
fn new(inner: NonNull<ffi::Fiber>, result: Box<UnsafeCell<Option<T>>>) -> Self {
Self {
inner: Some(inner),
result,
marker: PhantomData,
}
}
pub fn join(mut self) -> T {
let inner_raw = self.inner.take().unwrap().as_ptr();
let _code = unsafe { ffi::fiber_join(inner_raw) };
self.result.get_mut().take().unwrap()
}
}
impl<'f, T> Drop for JoinHandle<'f, T> {
fn drop(&mut self) {
if self.inner.is_some() {
panic!("JoinHandle dropped before being joined")
}
}
}
pub struct UnitJoinHandle<'f> {
inner: Option<NonNull<ffi::Fiber>>,
marker: PhantomData<&'f ()>,
}
impl_debug_stub!{UnitJoinHandle<'f>}
impl_eq_hash!{UnitJoinHandle<'f>}
impl<'f> UnitJoinHandle<'f> {
fn new(inner: NonNull<ffi::Fiber>) -> Self {
Self {
inner: Some(inner),
marker: PhantomData,
}
}
pub fn join(mut self) {
let inner_raw = self.inner.take().unwrap().as_ptr();
let _code = unsafe { ffi::fiber_join(inner_raw) };
}
}
impl<'f> Drop for UnitJoinHandle<'f> {
fn drop(&mut self) {
if self.inner.is_some() {
panic!("UnitJoinHandle dropped before being joined")
}
}
}
trait TrampolineArgs {
unsafe fn get<T>(&mut self) -> T
where
T: VaPrimitive;
unsafe fn get_boxed<T>(&mut self) -> Box<T> {
Box::from_raw(self.get::<*const c_void>() as *mut T)
}
unsafe fn get_ptr<T>(&mut self) -> *mut T {
self.get::<*const c_void>() as *mut T
}
unsafe fn get_str(&mut self) -> String {
let buf = self.get::<*const u8>() as *mut u8;
let length = self.get::<usize>();
let capacity = self.get::<usize>();
String::from_raw_parts(buf, length, capacity)
}
}
impl TrampolineArgs for VaList {
unsafe fn get<T>(&mut self) -> T
where
T: VaPrimitive,
{
self.get::<T>()
}
}
pub fn start<'f, F, T>(f: F) -> JoinHandle<'f, T>
where
F: FnOnce() -> T,
F: 'f,
T: 'f,
{
Builder::new().func(f).start().unwrap()
}
pub fn start_proc<'f, F>(f: F) -> UnitJoinHandle<'f>
where
F: FnOnce(),
F: 'f,
{
Builder::new().proc(f).start().unwrap()
}
pub fn defer<'f, F, T>(f: F) -> LuaJoinHandle<'f, T>
where
F: FnOnce() -> T,
F: 'f,
T: 'f,
{
LuaFiber::new(LuaFiberFunc::new(f)).spawn().unwrap()
}
pub fn defer_proc<'f, F>(f: F) -> LuaUnitJoinHandle<'f>
where
F: FnOnce(),
F: 'f,
{
LuaFiber::new(LuaFiberProc::new(f)).spawn().unwrap()
}
pub fn set_cancellable(is_cancellable: bool) -> bool {
unsafe { ffi::fiber_set_cancellable(is_cancellable) }
}
pub fn is_cancelled() -> bool {
unsafe { ffi::fiber_is_cancelled() }
}
pub fn sleep(time: Duration) {
unsafe { ffi::fiber_sleep(time.as_secs_f64()) }
}
pub fn time() -> f64 {
unsafe { ffi::fiber_time() }
}
pub fn time64() -> u64 {
unsafe { ffi::fiber_time64() }
}
pub fn clock() -> f64 {
unsafe { ffi::fiber_clock() }
}
pub fn clock64() -> u64 {
unsafe { ffi::fiber_clock64() }
}
pub fn fiber_yield() {
unsafe { ffi::fiber_yield() }
}
pub fn reschedule() {
unsafe { ffi::fiber_reschedule() }
}
#[derive(Debug)]
pub struct FiberAttr {
inner: *mut ffi::FiberAttr,
}
impl FiberAttr {
pub fn new() -> Self {
FiberAttr {
inner: unsafe { ffi::fiber_attr_new() },
}
}
pub fn stack_size(&self) -> usize {
unsafe { ffi::fiber_attr_getstacksize(self.inner) }
}
pub fn set_stack_size(&mut self, stack_size: usize) -> Result<()> {
if unsafe { ffi::fiber_attr_setstacksize(self.inner, stack_size) } < 0 {
Err(TarantoolError::last().into())
} else {
Ok(())
}
}
}
impl Default for FiberAttr {
fn default() -> Self {
Self::new()
}
}
impl Drop for FiberAttr {
fn drop(&mut self) {
unsafe { ffi::fiber_attr_delete(self.inner) }
}
}
#[derive(Debug)]
pub struct Cond {
inner: *mut ffi::FiberCond,
}
impl Cond {
pub fn new() -> Self {
Cond {
inner: unsafe { ffi::fiber_cond_new() },
}
}
pub fn signal(&self) {
unsafe { ffi::fiber_cond_signal(self.inner) }
}
pub fn broadcast(&self) {
unsafe { ffi::fiber_cond_broadcast(self.inner) }
}
pub fn wait_timeout(&self, timeout: Duration) -> bool {
unsafe {
ffi::fiber_cond_wait_timeout(self.inner, timeout.as_secs_f64()) >= 0
}
}
pub fn wait(&self) -> bool {
unsafe { ffi::fiber_cond_wait(self.inner) >= 0 }
}
}
impl Default for Cond {
fn default() -> Self {
Self::new()
}
}
impl Drop for Cond {
fn drop(&mut self) {
unsafe { ffi::fiber_cond_delete(self.inner) }
}
}
#[derive(Debug)]
pub struct Latch {
inner: *mut ffi::Latch,
}
impl Latch {
pub fn new() -> Self {
Latch {
inner: unsafe { ffi::box_latch_new() },
}
}
pub fn lock(&self) -> LatchGuard {
unsafe { ffi::box_latch_lock(self.inner) };
LatchGuard {
latch_inner: self.inner,
}
}
pub fn try_lock(&self) -> Option<LatchGuard> {
if unsafe { ffi::box_latch_trylock(self.inner) } == 0 {
Some(LatchGuard {
latch_inner: self.inner,
})
} else {
None
}
}
}
impl Default for Latch {
fn default() -> Self {
Self::new()
}
}
impl Drop for Latch {
fn drop(&mut self) {
unsafe { ffi::box_latch_delete(self.inner) }
}
}
#[derive(Debug)]
pub struct LatchGuard {
latch_inner: *mut ffi::Latch,
}
impl Drop for LatchGuard {
fn drop(&mut self) {
unsafe { ffi::box_latch_unlock(self.latch_inner) }
}
}
pub(crate) unsafe fn unpack_callback<F, T>(callback: &mut F) -> (*mut c_void, ffi::FiberFunc)
where
F: FnMut(Box<T>) -> i32,
{
unsafe extern "C" fn trampoline<F, T>(mut args: VaList) -> i32
where
F: FnMut(Box<T>) -> i32,
{
let closure: &mut F = &mut *(args.get::<*const c_void>() as *mut F);
let boxed_arg = Box::from_raw(args.get::<*const c_void>() as *mut T);
(*closure)(boxed_arg)
}
(callback as *mut F as *mut c_void, Some(trampoline::<F, T>))
}