mirror of
https://github.com/hexedtech/codemp.git
synced 2024-11-22 15:24:48 +01:00
feat(java): expose hash function, use OptionalLong in TextChange
This commit is contained in:
parent
8b704fa668
commit
0d3af40eb0
5 changed files with 42 additions and 62 deletions
10
dist/java/src/mp/code/Utils.java
vendored
Normal file
10
dist/java/src/mp/code/Utils.java
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package mp.code;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
/**
|
||||||
|
* Hashes the given {@link String} using CodeMP's hashing algorithm (xxh3).
|
||||||
|
* @param input the string to hash
|
||||||
|
* @return the hash
|
||||||
|
*/
|
||||||
|
public static native long hash(String input);
|
||||||
|
}
|
12
dist/java/src/mp/code/data/TextChange.java
vendored
12
dist/java/src/mp/code/data/TextChange.java
vendored
|
@ -1,21 +1,17 @@
|
||||||
package mp.code.data;
|
package mp.code.data;
|
||||||
|
|
||||||
|
import java.util.OptionalLong;
|
||||||
|
|
||||||
public class TextChange {
|
public class TextChange {
|
||||||
public final long start;
|
public final long start;
|
||||||
public final long end;
|
public final long end;
|
||||||
public final String content;
|
public final String content;
|
||||||
private final long hash; // xxh3 hash
|
public final OptionalLong hash; // xxh3 hash
|
||||||
|
|
||||||
public TextChange(long start, long end, String content, long hash) {
|
public TextChange(long start, long end, String content, OptionalLong hash) {
|
||||||
this.start = start;
|
this.start = start;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
this.hash = hash;
|
this.hash = hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native long hash(String content);
|
|
||||||
public boolean hashMatches(String content) {
|
|
||||||
// 0 is Rust default value and a very unlikely hash
|
|
||||||
return hash == 0L || this.hash == hash(content);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,71 +63,27 @@ fn recv_jni(env: &mut JNIEnv, change: Option<crate::api::TextChange>) -> jobject
|
||||||
None => JObject::default(),
|
None => JObject::default(),
|
||||||
Some(event) => {
|
Some(event) => {
|
||||||
let content = env.new_string(event.content).jexcept(env);
|
let content = env.new_string(event.content).jexcept(env);
|
||||||
|
|
||||||
|
let hash = env.find_class("java/util/OptionalLong").and_then(|class| {
|
||||||
|
if let Some(h) = event.hash {
|
||||||
|
env.call_static_method(class, "of", "(J)Ljava/util/OptionalLong;", &[JValueGen::Long(h)])
|
||||||
|
} else {
|
||||||
|
env.call_static_method(class, "empty", "()Ljava/util/OptionalLong;", &[])
|
||||||
|
}
|
||||||
|
}).and_then(|o| o.l()).jexcept(env);
|
||||||
env.find_class("mp/code/data/TextChange")
|
env.find_class("mp/code/data/TextChange")
|
||||||
.and_then(|class| {
|
.and_then(|class| {
|
||||||
env.new_object(
|
env.new_object(
|
||||||
class,
|
class,
|
||||||
"(JJLjava/lang/String;J)V",
|
"(JJLjava/lang/String;Ljava/util/OptionalLong;)V",
|
||||||
&[
|
&[
|
||||||
JValueGen::Long(jlong::from(event.start)),
|
JValueGen::Long(jlong::from(event.start)),
|
||||||
JValueGen::Long(jlong::from(event.end)),
|
JValueGen::Long(jlong::from(event.end)),
|
||||||
JValueGen::Object(&content),
|
JValueGen::Object(&content),
|
||||||
JValueGen::Long(event.hash.unwrap_or_default())
|
JValueGen::Object(&hash)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}).jexcept(env)
|
}).jexcept(env)
|
||||||
}
|
}
|
||||||
}.as_raw()
|
}.as_raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receives from Java, converts and sends a [crate::api::TextChange].
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "system" fn Java_mp_code_BufferController_send<'local>(
|
|
||||||
mut env: JNIEnv,
|
|
||||||
_class: JClass<'local>,
|
|
||||||
self_ptr: jlong,
|
|
||||||
input: JObject<'local>
|
|
||||||
) {
|
|
||||||
let start = env.get_field(&input, "start", "J").and_then(|s| s.j()).jexcept(&mut env);
|
|
||||||
let end = env.get_field(&input, "end", "J").and_then(|e| e.j()).jexcept(&mut env);
|
|
||||||
let content = env.get_field(&input, "content", "Ljava/lang/String;")
|
|
||||||
.and_then(|c| c.l())
|
|
||||||
.map(|c| c.into())
|
|
||||||
.jexcept(&mut env);
|
|
||||||
let content = unsafe { env.get_string_unchecked(&content) }
|
|
||||||
.map(|c| c.to_string_lossy().to_string())
|
|
||||||
.jexcept(&mut env);
|
|
||||||
|
|
||||||
let controller = unsafe { Box::leak(Box::from_raw(self_ptr as *mut crate::buffer::Controller)) };
|
|
||||||
RT.block_on(controller.send(crate::api::TextChange {
|
|
||||||
start: start as u32,
|
|
||||||
end: end as u32,
|
|
||||||
content,
|
|
||||||
hash: None
|
|
||||||
})).jexcept(&mut env);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called by the Java GC to drop a [crate::buffer::Controller].
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "system" fn Java_mp_code_BufferController_free(
|
|
||||||
_env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
self_ptr: jlong,
|
|
||||||
) {
|
|
||||||
let _ = unsafe { Box::from_raw(self_ptr as *mut crate::cursor::Controller) };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Calculates the XXH3 hash for a given String.
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "system" fn Java_mp_code_data_TextChange_hash<'local>(
|
|
||||||
mut env: JNIEnv,
|
|
||||||
_class: JClass<'local>,
|
|
||||||
content: JString<'local>,
|
|
||||||
) -> jlong {
|
|
||||||
let content: String = env.get_string(&content)
|
|
||||||
.map(|s| s.into())
|
|
||||||
.jexcept(&mut env);
|
|
||||||
let hash = crate::ext::hash(content.as_bytes());
|
|
||||||
i64::from_ne_bytes(hash.to_ne_bytes())
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ pub mod client;
|
||||||
pub mod workspace;
|
pub mod workspace;
|
||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
pub mod buffer;
|
pub mod buffer;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
pub(crate) static ref RT: tokio::runtime::Runtime = tokio::runtime::Runtime::new().expect("could not create tokio runtime");
|
pub(crate) static ref RT: tokio::runtime::Runtime = tokio::runtime::Runtime::new().expect("could not create tokio runtime");
|
||||||
|
|
17
src/ffi/java/utils.rs
Normal file
17
src/ffi/java/utils.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
use jni::{objects::{JClass, JString}, sys::jlong, JNIEnv};
|
||||||
|
|
||||||
|
use super::JExceptable;
|
||||||
|
|
||||||
|
/// Calculates the XXH3 hash for a given String.
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_mp_code_Utils_hash<'local>(
|
||||||
|
mut env: JNIEnv,
|
||||||
|
_class: JClass<'local>,
|
||||||
|
content: JString<'local>,
|
||||||
|
) -> jlong {
|
||||||
|
let content: String = env.get_string(&content)
|
||||||
|
.map(|s| s.into())
|
||||||
|
.jexcept(&mut env);
|
||||||
|
let hash = crate::ext::hash(content.as_bytes());
|
||||||
|
i64::from_ne_bytes(hash.to_ne_bytes())
|
||||||
|
}
|
Loading…
Reference in a new issue