Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Read.getObjectType #11

Merged
merged 1 commit into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/src/main/java/org/automerge/AutomergeSys.java
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,8 @@ public static native long lookupCursorIndexInDoc(DocPointer doc, ObjectId obj, C

public static native long lookupCursorIndexInTx(TransactionPointer tx, ObjectId obj, Cursor cursor,
Optional<ChangeHash[]> heads);

public static native Optional<ObjectType> getObjectTypeInDoc(DocPointer doc, ObjectId obj);

public static native Optional<ObjectType> getObjectTypeInTx(TransactionPointer tx, ObjectId obj);
}
9 changes: 9 additions & 0 deletions lib/src/main/java/org/automerge/Document.java
Original file line number Diff line number Diff line change
Expand Up @@ -714,4 +714,13 @@ public synchronized long lookupCursorIndex(ObjectId obj, Cursor cursor, ChangeHa
return AutomergeSys.lookupCursorIndexInDoc(this.pointer.get(), obj, cursor, Optional.of(heads));
}
}

@Override
public synchronized Optional<ObjectType> getObjectType(ObjectId obj) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.getObjectTypeInTx(this.transactionPtr.get(), obj);
} else {
return AutomergeSys.getObjectTypeInDoc(this.pointer.get(), obj);
}
}
}
11 changes: 11 additions & 0 deletions lib/src/main/java/org/automerge/Read.java
Original file line number Diff line number Diff line change
Expand Up @@ -408,4 +408,15 @@ public interface Read {
* object
*/
public long lookupCursorIndex(ObjectId obj, Cursor cursor, ChangeHash[] heads);

/**
* Get the object type of the object given by obj
*
* @param obj
* - The ID of the object to get the type of
*
* @return The type of the object or Optional.empty if the object does not exist
* in this document
*/
public Optional<ObjectType> getObjectType(ObjectId obj);
}
5 changes: 5 additions & 0 deletions lib/src/main/java/org/automerge/TransactionImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -378,4 +378,9 @@ public synchronized long lookupCursorIndex(ObjectId obj, Cursor cursor, ChangeHa
return AutomergeSys.lookupCursorIndexInTx(this.pointer.get(), obj, cursor, Optional.of(heads));
}

@Override
public synchronized Optional<ObjectType> getObjectType(ObjectId obj) {
return AutomergeSys.getObjectTypeInTx(this.pointer.get(), obj);
}

}
44 changes: 44 additions & 0 deletions lib/src/test/java/org/automerge/TestGetObjType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.automerge;

import java.util.Optional;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class TestGetObjType {

@Test
public void testGetObjType() {
Document doc = new Document();
ObjectId map;
ObjectId list;
ObjectId text;
try (Transaction tx = doc.startTransaction()) {
map = tx.set(ObjectId.ROOT, "map", ObjectType.MAP);
list = tx.set(ObjectId.ROOT, "list", ObjectType.LIST);
text = tx.set(ObjectId.ROOT, "text", ObjectType.TEXT);
tx.commit();
}

// make an object ID from a different document
Document otherDoc = new Document();
ObjectId missingObj;
try (Transaction tx = otherDoc.startTransaction()) {
missingObj = tx.set(ObjectId.ROOT, "other", ObjectType.MAP);
tx.commit();
}

Assertions.assertEquals(Optional.of(ObjectType.MAP), doc.getObjectType(map));
Assertions.assertEquals(Optional.of(ObjectType.LIST), doc.getObjectType(list));
Assertions.assertEquals(Optional.of(ObjectType.TEXT), doc.getObjectType(text));
Assertions.assertEquals(Optional.empty(), doc.getObjectType(missingObj));

// now the same tests but in a transaction
try (Transaction tx = doc.startTransaction()) {
Assertions.assertEquals(Optional.of(ObjectType.MAP), tx.getObjectType(map));
Assertions.assertEquals(Optional.of(ObjectType.LIST), tx.getObjectType(list));
Assertions.assertEquals(Optional.of(ObjectType.TEXT), tx.getObjectType(text));
Assertions.assertEquals(Optional.empty(), tx.getObjectType(missingObj));
}
}

}
3 changes: 1 addition & 2 deletions rust/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ impl Cursor {
.map_err(errors::FromRaw::GetByteArray)?;
let bytes =
std::slice::from_raw_parts(arr.as_ptr() as *const u8, arr.size().unwrap() as usize);
let cursor: automerge::Cursor =
bytes.try_into().map_err(errors::FromRaw::Invalid)?;
let cursor: automerge::Cursor = bytes.try_into().map_err(errors::FromRaw::Invalid)?;
Ok(Self(cursor))
}
}
Expand Down
20 changes: 20 additions & 0 deletions rust/src/obj_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@ pub(crate) enum JavaObjType {
Text,
}

pub(crate) const CLASSNAME: &str = am_classname!("ObjectType");

// The ordinal of the various types in the `org.automerge.jni.ObjectType` enum
const MAP_ORDINAL: i32 = 0;
const LIST_ORDINAL: i32 = 1;
const TEXT_ORDINAL: i32 = 2;

const MAP_FIELD_NAME: &str = "MAP";
const LIST_FIELD_NAME: &str = "LIST";
const TEXT_FIELD_NAME: &str = "TEXT";

impl JavaObjType {
/// Convert a `jobject` referring to an instance of org.automerge.jni.ObjectType to a
/// `JavaObjType`
Expand Down Expand Up @@ -42,6 +48,20 @@ impl JavaObjType {
other => Err(FromJavaError::UnknownOrdinal(other)),
}
}

/// Convert a `JavaObjType` to a `JOBject`
pub(crate) unsafe fn to_java_enum<'a>(
&'_ self,
env: jni::JNIEnv<'a>,
) -> Result<JObject<'a>, jni::errors::Error> {
let field_name = match self {
Self::Map => MAP_FIELD_NAME,
Self::List => LIST_FIELD_NAME,
Self::Text => TEXT_FIELD_NAME,
};
let field = env.get_static_field(CLASSNAME, field_name, format!("L{};", CLASSNAME))?;
field.l()
}
}

impl From<JavaObjType> for am::ObjType {
Expand Down
20 changes: 19 additions & 1 deletion rust/src/read_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::interop::{changehash_to_jobject, heads_from_jobject, CHANGEHASH_CLASS
use crate::java_option::{make_empty_option, make_optional};
use crate::mark::mark_to_java;
use crate::obj_id::JavaObjId;
use crate::obj_type::JavaObjType;
use crate::prop::JProp;
use crate::AUTOMERGE_EXCEPTION;
use crate::{interop::AsPointerObj, read_ops::ReadOps};
Expand All @@ -22,14 +23,14 @@ mod cursor;
mod get;
mod get_all;
mod get_at;
mod get_object_type;
mod heads;
mod keys;
mod length;
mod list_items;
mod map_entries;
mod marks;
mod text;

macro_rules! catch {
($env:ident, $e:expr) => {
match $e {
Expand Down Expand Up @@ -436,6 +437,23 @@ impl SomeReadPointer {
};
index as i64
}

unsafe fn get_object_type(self, env: jni::JNIEnv<'_>, obj_pointer: jobject) -> jobject {
let obj = JavaObjId::from_raw(&env, obj_pointer).unwrap();
let read = SomeRead::from_pointer(env, self);
let obj_type = match read.object_type(obj) {
Ok(o) => o,
Err(automerge::AutomergeError::InvalidObjId(_)) => {
return make_empty_option(&env).unwrap().into_raw();
}
Err(e) => {
env.throw_new(AUTOMERGE_EXCEPTION, e.to_string()).unwrap();
return JObject::null().into_raw();
}
};
let val = JavaObjType::from(obj_type).to_java_enum(env).unwrap();
return make_optional(&env, val.into()).unwrap().into_raw();
}
}

unsafe fn maybe_heads(
Expand Down
26 changes: 26 additions & 0 deletions rust/src/read_methods/get_object_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use automerge_jni_macros::jni_fn;
use jni::sys::jobject;

use super::SomeReadPointer;

#[no_mangle]
#[jni_fn]
pub unsafe extern "C" fn getObjectTypeInDoc(
env: jni::JNIEnv,
_class: jni::objects::JClass,
doc_pointer: jni::sys::jobject,
obj_pointer: jni::sys::jobject,
) -> jobject {
SomeReadPointer::doc(doc_pointer).get_object_type(env, obj_pointer)
}

#[no_mangle]
#[jni_fn]
pub unsafe extern "C" fn getObjectTypeInTx(
env: jni::JNIEnv,
_class: jni::objects::JClass,
tx_pointer: jni::sys::jobject,
obj_pointer: jni::sys::jobject,
) -> jobject {
SomeReadPointer::tx(tx_pointer).get_object_type(env, obj_pointer)
}
Loading