codemp/src/ffi/lua/ext/callback.rs

119 lines
2.7 KiB
Rust
Raw Normal View History

2024-10-03 03:41:28 +02:00
use crate::api::change::Delta;
use crate::buffer::controller::BufferAck;
2024-10-03 04:10:52 +02:00
use crate::ext::IgnorableError;
use crate::prelude::*;
2024-10-01 00:42:57 +02:00
use mlua::prelude::*;
use mlua_codemp_patch as mlua;
2024-09-17 23:00:30 +02:00
pub(crate) fn callback() -> &'static CallbackChannel<LuaCallback> {
static CHANNEL: std::sync::OnceLock<CallbackChannel<LuaCallback>> = std::sync::OnceLock::new();
CHANNEL.get_or_init(CallbackChannel::default)
2024-09-17 23:00:30 +02:00
}
pub(crate) struct CallbackChannel<T> {
tx: std::sync::Arc<tokio::sync::mpsc::UnboundedSender<T>>,
2024-10-01 00:42:57 +02:00
rx: std::sync::Mutex<tokio::sync::mpsc::UnboundedReceiver<T>>,
2024-09-17 23:00:30 +02:00
}
impl Default for CallbackChannel<LuaCallback> {
2024-09-17 23:00:30 +02:00
fn default() -> Self {
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
let rx = std::sync::Mutex::new(rx);
Self {
tx: std::sync::Arc::new(tx),
rx,
}
}
}
impl CallbackChannel<LuaCallback> {
pub(crate) fn invoke(&self, cb: LuaFunction, arg: impl Into<CallbackArg>) {
2024-10-01 00:42:57 +02:00
self.tx
.send(LuaCallback::Invoke(cb, arg.into()))
2024-09-17 23:00:30 +02:00
.unwrap_or_warn("error scheduling callback")
}
pub(crate) fn failure(&self, err: impl std::error::Error) {
2024-10-01 00:42:57 +02:00
self.tx
.send(LuaCallback::Fail(format!(
"promise failed with error: {err:?}"
)))
.unwrap_or_warn("error scheduling callback failure")
}
pub(crate) fn recv(&self) -> Option<LuaCallback> {
2024-09-17 23:00:30 +02:00
match self.rx.try_lock() {
Err(e) => {
tracing::debug!("backing off from callback mutex: {e}");
2024-09-17 23:00:30 +02:00
None
2024-10-01 00:42:57 +02:00
}
2024-09-17 23:00:30 +02:00
Ok(mut lock) => match lock.try_recv() {
Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => {
tracing::error!("callback channel closed");
None
2024-10-01 00:42:57 +02:00
}
Err(tokio::sync::mpsc::error::TryRecvError::Empty) => None,
Ok(cb) => Some(cb),
2024-09-17 23:00:30 +02:00
},
}
}
}
pub(crate) enum LuaCallback {
Fail(String),
Invoke(LuaFunction, CallbackArg),
}
2024-10-03 03:40:55 +02:00
macro_rules! callback_args {
($($name:ident : $t:ty ,)*) => {
pub(crate) enum CallbackArg {
Nil,
$(
$name($t),
)*
}
2024-09-17 23:00:30 +02:00
2024-10-03 03:40:55 +02:00
impl IntoLua for CallbackArg {
fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
match self {
Self::Nil => Ok(LuaValue::Nil),
$(
Self::$name(x) => x.into_lua(lua),
)*
}
}
2024-09-17 23:00:30 +02:00
}
2024-10-03 03:40:55 +02:00
impl From<()> for CallbackArg {
fn from(_value: ()) -> Self {
Self::Nil
}
}
$(
impl From<$t> for CallbackArg {
fn from(value: $t) -> Self {
Self::$name(value)
}
}
)*
};
2024-09-17 23:00:30 +02:00
}
2024-10-03 03:40:55 +02:00
callback_args! {
Str: String,
VecStr: Vec<String>,
Client: CodempClient,
CursorController: CodempCursorController,
BufferController: CodempBufferController,
Workspace: CodempWorkspace,
Event: CodempEvent,
MaybeEvent: Option<CodempEvent>,
Cursor: CodempCursor,
MaybeCursor: Option<CodempCursor>,
TextChange: CodempTextChange,
MaybeTextChange: Option<CodempTextChange>,
2024-10-03 03:41:28 +02:00
Delta: Delta<BufferAck>,
MaybeDelta: Option<Delta<BufferAck>>,
2024-10-03 03:40:55 +02:00
}