codemp/src/ffi/java/buffer.rs

113 lines
3.4 KiB
Rust
Raw Normal View History

use jni::{objects::JObject, JNIEnv};
use jni_toolbox::jni;
2024-10-01 00:42:57 +02:00
use crate::{
2024-10-03 04:05:58 +02:00
api::{
controller::{AsyncReceiver, AsyncSender},
2024-10-10 12:46:56 +02:00
BufferUpdate, TextChange,
2024-10-03 04:05:58 +02:00
},
2024-10-01 00:42:57 +02:00
errors::ControllerError,
};
use super::null_check;
2024-10-01 00:42:57 +02:00
/// Get the name of the buffer.
2024-09-23 18:12:13 +02:00
#[jni(package = "mp.code", class = "BufferController")]
fn get_name(controller: &mut crate::buffer::Controller) -> String {
controller.path().to_string() //TODO: &str is built into the newer version
}
/// Get the contents of the buffers.
2024-09-23 18:12:13 +02:00
#[jni(package = "mp.code", class = "BufferController")]
fn get_content(controller: &mut crate::buffer::Controller) -> Result<String, ControllerError> {
super::tokio().block_on(controller.content())
}
/// Try to fetch a [TextChange], or return null if there's nothing.
2024-09-23 18:12:13 +02:00
#[jni(package = "mp.code", class = "BufferController")]
2024-10-10 12:46:56 +02:00
fn try_recv(
controller: &mut crate::buffer::Controller,
) -> Result<Option<BufferUpdate>, ControllerError> {
super::tokio().block_on(controller.try_recv())
}
/// Block until it receives a [TextChange].
2024-09-23 18:12:13 +02:00
#[jni(package = "mp.code", class = "BufferController")]
fn recv(controller: &mut crate::buffer::Controller) -> Result<BufferUpdate, ControllerError> {
super::tokio().block_on(controller.recv())
}
/// Send a [TextChange] to the server.
#[jni(package = "mp.code", class = "BufferController")]
2024-10-01 00:42:57 +02:00
fn send(
controller: &mut crate::buffer::Controller,
change: TextChange,
) -> Result<(), ControllerError> {
2024-10-03 03:17:30 +02:00
controller.send(change)
}
/// Register a callback for buffer changes.
#[jni(package = "mp.code", class = "BufferController")]
2024-10-01 00:42:57 +02:00
fn callback<'local>(
env: &mut JNIEnv<'local>,
controller: &mut crate::buffer::Controller,
cb: JObject<'local>,
) {
null_check!(env, cb, {});
let Ok(cb_ref) = env.new_global_ref(cb) else {
2024-10-01 00:42:57 +02:00
env.throw_new(
"mp/code/exceptions/JNIException",
"Failed to pin callback reference!",
)
.expect("Failed to throw exception!");
return;
};
controller.callback(move |controller: crate::buffer::Controller| {
let jvm = super::jvm();
2024-10-01 00:42:57 +02:00
let mut env = jvm
.attach_current_thread_permanently()
.expect("failed attaching to main JVM thread");
if let Err(e) = env.with_local_frame(5, |env| {
use jni_toolbox::IntoJavaObject;
2024-09-23 18:12:13 +02:00
let jcontroller = controller.into_java_object(env)?;
if let Err(e) = env.call_method(
&cb_ref,
"accept",
"(Ljava/lang/Object;)V",
2024-10-01 00:42:57 +02:00
&[jni::objects::JValueGen::Object(&jcontroller)],
) {
tracing::error!("error invoking callback: {e:?}");
};
Ok::<(), jni::errors::Error>(())
}) {
tracing::error!("error invoking callback: {e}");
let _ = env.exception_describe();
}
});
}
/// Clear the callback for buffer changes.
#[jni(package = "mp.code", class = "BufferController")]
fn clear_callback(controller: &mut crate::buffer::Controller) {
controller.clear_callback()
}
/// Block until there is a new value available.
#[jni(package = "mp.code", class = "BufferController")]
fn poll(controller: &mut crate::buffer::Controller) -> Result<(), ControllerError> {
super::tokio().block_on(controller.poll())
}
/// Acknowledge that a change has been correctly applied.
#[jni(package = "mp.code", class = "BufferController")]
fn ack(controller: &mut crate::buffer::Controller, version: Vec<i64>) {
controller.ack(version)
}
/// Called by the Java GC to drop a [crate::buffer::Controller].
#[jni(package = "mp.code", class = "BufferController")]
fn free(input: jni::sys::jlong) {
let _ = unsafe { Box::from_raw(input as *mut crate::buffer::Controller) };
}