use std::{mem, ops::Deref}; use futures::{FutureExt, future::BoxFuture}; use mlua::{UserData, UserDataMethods}; use tokio::sync::SemaphorePermit; pub type PermitRef = mlua::UserDataRef; pub struct Permit { inner: Option>, destruct: Option>, } impl Deref for Permit { type Target = Option>; fn deref(&self) -> &Self::Target { &self.inner } } impl Permit { pub fn new(inner: SemaphorePermit<'static>, f: F) -> Self where F: Future + 'static + Send, { Self { inner: Some(inner), destruct: Some(f.boxed()) } } fn dropping(&mut self) -> impl Future + 'static { let inner = self.inner.take(); let destruct = self.destruct.take(); async move { if let Some(f) = destruct { f.await; } if let Some(p) = inner { mem::drop(p); } } } } impl Drop for Permit { fn drop(&mut self) { tokio::spawn(self.dropping()); } } impl UserData for Permit { fn add_methods>(methods: &mut M) { methods.add_async_method_mut("drop", |_, mut me, ()| async move { Ok(me.dropping().await) }); } }