Fix known leaks and memory safety issues in both swift and android SDKs (#745)

This commit is contained in:
Thom 2018-06-25 12:10:11 -07:00 committed by GitHub
parent 605c3d938c
commit f335253d4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 1711 additions and 1325 deletions

2
.gitignore vendored
View file

@ -81,7 +81,7 @@ build.xcarchive
## Obj-C/Swift specific
*.hmap
*.ipa
/sdks/swift/Mentat/External-Dependencies
# Android & IntelliJ
**/*.iml

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@ pub mod strings {
};
pub fn c_char_to_string(cchar: *const c_char) -> &'static str {
assert!(!cchar.is_null());
let c_str = unsafe { CStr::from_ptr(cchar) };
c_str.to_str().unwrap_or("")
}
@ -61,3 +62,96 @@ pub mod log {
unsafe { android::__android_log_write(android::LogLevel::Debug as i32, tag, message) };
}
}
pub mod error {
use super::strings::string_to_c_char;
use std::os::raw::c_char;
use std::boxed::Box;
use std::fmt::Display;
use std::ptr;
/// Represents an error that occurred on the mentat side. Many mentat FFI functions take a
/// `*mut ExternError` as the last argument. This is an out parameter that indicates an
/// error that occurred during that function's execution (if any).
///
/// For functions that use this pattern, if the ExternError's message property is null, then no
/// error occurred. If the message is non-null then it contains a string description of the
/// error that occurred.
///
/// Important: This message is allocated on the heap and it is the consumer's responsibility to
/// free it using `destroy_mentat_string`!
///
/// While this pattern is not ergonomic in Rust, it offers two main benefits:
///
/// 1. It avoids defining a large number of `Result`-shaped types in the FFI consumer, as would
/// be required with something like an `struct ExternResult<T> { ok: *mut T, err:... }`
/// 2. It offers additional type safety over `struct ExternResult { ok: *mut c_void, err:... }`,
/// which helps avoid memory safety errors.
#[repr(C)]
#[derive(Debug)]
pub struct ExternError {
pub message: *mut c_char,
// TODO: Include an error code here.
}
impl Default for ExternError {
fn default() -> ExternError {
ExternError { message: ptr::null_mut() }
}
}
/// Translate Result<T, E>, into something C can understand, when T is not `#[repr(C)]`
///
/// - If `result` is `Ok(v)`, moves `v` to the heap and returns a pointer to it, and sets
/// `error` to a state indicating that no error occurred (`message` is null).
/// - If `result` is `Err(e)`, returns a null pointer and stores a string representing the error
/// message (which was allocated on the heap and should eventually be freed) into
/// `error.message`
pub unsafe fn translate_result<T, E>(result: Result<T, E>, error: *mut ExternError) -> *mut T
where E: Display {
// TODO: can't unwind across FFI...
assert!(!error.is_null(), "Error output parameter is not optional");
let error = &mut *error;
error.message = ptr::null_mut();
match result {
Ok(val) => Box::into_raw(Box::new(val)),
Err(e) => {
error.message = string_to_c_char(e.to_string());
ptr::null_mut()
}
}
}
/// Translate Result<Option<T>, E> into something C can understand, when T is not `#[repr(C)]`.
///
/// - If `result` is `Ok(Some(v))`, moves `v` to the heap and returns a pointer to it, and
/// sets `error` to a state indicating that no error occurred (`message` is null).
/// - If `result` is `Ok(None)` returns a null pointer, but sets `error` to a state indicating
/// that no error occurred (`message` is null).
/// - If `result` is `Err(e)`, returns a null pointer and stores a string representing the error
/// message (which was allocated on the heap and should eventually be freed) into
/// `error.message`
pub unsafe fn translate_opt_result<T, E>(result: Result<Option<T>, E>, error: *mut ExternError) -> *mut T
where E: Display {
assert!(!error.is_null(), "Error output parameter is not optional");
let error = &mut *error;
error.message = ptr::null_mut();
match result {
Ok(Some(val)) => Box::into_raw(Box::new(val)),
Ok(None) => ptr::null_mut(),
Err(e) => {
error.message = string_to_c_char(e.to_string());
ptr::null_mut()
}
}
}
/// Identical to `translate_result`, but with additional type checking for the case that we have
/// a `Result<(), E>` (which we're about to drop on the floor).
pub unsafe fn translate_void_result<E>(result: Result<(), E>, error: *mut ExternError) where E: Display {
// Note that Box<T> guarantees that if T is zero sized, it's not heap allocated. So not
// only do we never need to free the return value of this, it would be a problem if someone did.
translate_result(result, error);
}
}

View file

@ -1,4 +1,5 @@
cd ffi
cargo lipo --release
cd ..
mkdir -p sdks/swift/Mentat/External-Dependencies/
cp target/universal/release/libmentat_ffi.a sdks/swift/Mentat/External-Dependencies/

View file

@ -10,7 +10,7 @@ buildscript {
ext.build = [
compileSdkVersion: 27,
targetSdkVersion: 27,
minSdkVersion: 16
minSdkVersion: 19
]
repositories {

View file

@ -1016,10 +1016,11 @@ public class FFIIntegrationTest {
builder.addRef(bEntid, ":foo/ref", longEntid);
InProgressTransactionResult result = builder.transact();
assertNotNull(result);
assertNotNull(result.getInProgress());
InProgress inProgress = result.getInProgress();
assertNotNull(inProgress);
assertNotNull(result.getReport());
result.getInProgress().transact("[[:db/add "+ aEntid +" :foo/long 22]]");
result.getInProgress().commit();
inProgress.transact("[[:db/add "+ aEntid +" :foo/long 22]]");
inProgress.commit();
// test that the values are as expected
String query = "[:find [?b ?i ?u ?l ?d ?s ?k ?r]\n" +
@ -1081,10 +1082,11 @@ public class FFIIntegrationTest {
builder.addRef(":foo/ref", longEntid);
InProgressTransactionResult result = builder.transact();
assertNotNull(result);
assertNotNull(result.getInProgress());
InProgress inProgress = result.getInProgress();
assertNotNull(inProgress);
assertNotNull(result.getReport());
result.getInProgress().transact("[[:db/add "+ aEntid +" :foo/long 22]]");
result.getInProgress().commit();
inProgress.transact("[[:db/add "+ aEntid +" :foo/long 22]]");
inProgress.commit();
// test that the values are as expected
String query = "[:find [?b ?i ?u ?l ?d ?s ?k ?r]\n" +

View file

@ -1,48 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* Copyright 2018 Mozilla
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. */
package org.mozilla.mentat;
import com.sun.jna.Structure;
import com.sun.jna.ptr.IntByReference;
import java.io.Closeable;
import java.util.Arrays;
import java.util.List;
/**
* Represents a C struct of a list of Strings containing attributes in the format
* `:namespace/name`.
*/
public class AttributeList extends Structure implements Closeable {
public static class ByReference extends AttributeList implements Structure.ByReference {
}
public static class ByValue extends AttributeList implements Structure.ByValue {
}
public IntByReference attributes;
public int numberOfItems;
// Used by the Swift counterpart, JNA does this for us automagically.
// But we still need it here so that the number of fields and their order is correct
public int len;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("attributes", "numberOfItems", "len");
}
@Override
public void close() {
if (this.getPointer() != null) {
JNA.INSTANCE.destroy(this.getPointer());
}
}
}

View file

@ -12,43 +12,27 @@ package org.mozilla.mentat;
import com.sun.jna.Pointer;
import java.util.Iterator;
/**
* Iterator for a {@link CollResult}
*/
public class ColResultIterator extends RustObject implements Iterator {
public class ColResultIterator extends RustIterator<JNA.TypedValueListIter, JNA.TypedValue, TypedValue> {
Pointer nextPointer;
ColResultIterator(Pointer iterator) {
this.rawPointer = iterator;
}
private Pointer getNextPointer() {
return JNA.INSTANCE.typed_value_list_iter_next(this.rawPointer);
ColResultIterator(JNA.TypedValueListIter iterator) {
super(iterator);
}
@Override
public boolean hasNext() {
this.nextPointer = getNextPointer();
return this.nextPointer != null;
protected JNA.TypedValue advanceIterator() {
return JNA.INSTANCE.typed_value_list_iter_next(this.validPointer());
}
@Override
public TypedValue next() {
Pointer next = this.nextPointer == null ? getNextPointer() : this.nextPointer;
if (next == null) {
return null;
}
return new TypedValue(next);
protected TypedValue constructItem(JNA.TypedValue p) {
return new TypedValue(p);
}
@Override
public void close() {
if (this.rawPointer != null) {
JNA.INSTANCE.typed_value_list_iter_destroy(this.rawPointer);
}
protected void destroyPointer(JNA.TypedValueListIter p) {
JNA.INSTANCE.typed_value_list_iter_destroy(p);
}
}

View file

@ -37,21 +37,13 @@ import java.util.UUID;
*/
public class CollResult extends TupleResult implements Iterable<TypedValue> {
public CollResult(Pointer pointer) {
public CollResult(JNA.TypedValueList pointer) {
super(pointer);
}
@Override
public void close() {
if (this.rawPointer != null) {
JNA.INSTANCE.destroy(this.rawPointer);
}
}
@Override
public ColResultIterator iterator() {
Pointer iterPointer = JNA.INSTANCE.typed_value_list_into_iter(this.rawPointer);
this.rawPointer = null;
JNA.TypedValueListIter iterPointer = JNA.INSTANCE.typed_value_list_into_iter(this.consumePointer());
if (iterPointer == null) {
return null;
}

View file

@ -14,7 +14,6 @@ import android.util.Log;
import com.sun.jna.Pointer;
import java.io.IOException;
import java.util.Date;
import java.util.UUID;
@ -54,10 +53,10 @@ import java.util.UUID;
* builder.commit();
* }</pre>
*/
public class EntityBuilder extends RustObject {
public class EntityBuilder extends RustObject<JNA.EntityBuilder> {
public EntityBuilder(Pointer pointer) {
this.rawPointer = pointer;
public EntityBuilder(JNA.EntityBuilder pointer) {
super(pointer);
}
/**
@ -66,11 +65,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(String keyword, long value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_add_long(this.rawPointer, keyword, value);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_add_long(this.validPointer(), keyword, value, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -80,11 +77,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be asserted
*/
public void addRef(String keyword, long value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_add_ref(this.rawPointer, keyword, value);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_add_ref(this.validPointer(), keyword, value, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -94,11 +89,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be asserted
*/
public void addKeyword(String keyword, String value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_add_keyword(this.rawPointer, keyword, value);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_add_keyword(this.validPointer(), keyword, value, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -108,11 +101,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(String keyword, boolean value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_add_boolean(this.rawPointer, keyword, value ? 1 : 0);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_add_boolean(this.validPointer(), keyword, value ? 1 : 0, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -122,11 +113,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(String keyword, double value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_add_double(this.rawPointer, keyword, value);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_add_double(this.validPointer(), keyword, value, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -136,11 +125,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(String keyword, Date value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_add_timestamp(this.rawPointer, keyword, value.getTime() * 1_000);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_add_timestamp(this.validPointer(), keyword, value.getTime() * 1_000, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -150,11 +137,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(String keyword, String value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_add_string(this.rawPointer, keyword, value);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_add_string(this.validPointer(), keyword, value, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -164,12 +149,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(String keyword, UUID value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_add_uuid(this.rawPointer, keyword, getPointerForUUID(value));
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_add_uuid(this.validPointer(), keyword, getPointerForUUID(value), err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -181,11 +163,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(String keyword, long value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_retract_long(this.rawPointer, keyword, value);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_retract_long(this.validPointer(), keyword, value, err);
err.logAndConsumeError("EntityBuilder");
}
@ -198,11 +178,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retractRef(String keyword, long value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_retract_ref(this.rawPointer, keyword, value);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_retract_ref(this.validPointer(), keyword, value, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -214,11 +192,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retractKeyword(String keyword, String value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_retract_keyword(this.rawPointer, keyword, value);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_retract_keyword(this.validPointer(), keyword, value, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -230,11 +206,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(String keyword, boolean value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_retract_boolean(this.rawPointer, keyword, value ? 1 : 0);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_retract_boolean(this.validPointer(), keyword, value ? 1 : 0, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -246,11 +220,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(String keyword, double value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_retract_double(this.rawPointer, keyword, value);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_retract_double(this.validPointer(), keyword, value, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -262,11 +234,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(String keyword, Date value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_retract_timestamp(this.rawPointer, keyword, value.getTime() * 1_000);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_retract_timestamp(this.validPointer(), keyword, value.getTime() * 1_000, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -278,11 +248,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(String keyword, String value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_retract_string(this.rawPointer, keyword, value);
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_retract_string(this.validPointer(), keyword, value, err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -294,11 +262,9 @@ public class EntityBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(String keyword, UUID value) {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_retract_uuid(this.rawPointer, keyword, this.getPointerForUUID(value));
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.entity_builder_retract_uuid(this.validPointer(), keyword, getPointerForUUID(value), err);
err.logAndConsumeError("EntityBuilder");
}
/**
@ -316,10 +282,7 @@ public class EntityBuilder extends RustObject {
* the {@link TxReport} generated by the transact.
*/
public InProgressTransactionResult transact() {
this.validate();
InProgressTransactionResult result = JNA.INSTANCE.entity_builder_transact(this.rawPointer);
this.rawPointer = null;
return result;
return JNA.INSTANCE.entity_builder_transact(this.consumePointer());
}
/**
@ -335,21 +298,17 @@ public class EntityBuilder extends RustObject {
* @return The {@link TxReport} generated by the commit.
*/
public TxReport commit() {
this.validate();
RustResult result = JNA.INSTANCE.entity_builder_commit(this.rawPointer);
this.rawPointer = null;
if (result.isFailure()) {
Log.e("EntityBuilder", result.err);
RustError.ByReference err = new RustError.ByReference();
JNA.TxReport report = JNA.INSTANCE.entity_builder_commit(this.consumePointer(), err);
if (err.isFailure()) {
Log.e("EntityBuilder", err.consumeErrorMessage());
return null;
}
return new TxReport(result.ok);
return new TxReport(report);
}
@Override
public void close() throws IOException {
if (this.rawPointer != null) {
JNA.INSTANCE.entity_builder_destroy(this.rawPointer);
}
protected void destroyPointer(JNA.EntityBuilder p) {
JNA.INSTANCE.entity_builder_destroy(p);
}
}

View file

@ -14,8 +14,6 @@ import android.util.Log;
import com.sun.jna.Pointer;
import java.io.IOException;
/**
* This class wraps a raw pointer that points to a Rust {@link InProgress} object.
* </p>
@ -77,10 +75,10 @@ import java.io.IOException;
* inProgress.commit();
* }</pre>
*/
public class InProgress extends RustObject {
public class InProgress extends RustObject<JNA.InProgress> {
public InProgress(Pointer pointer) {
this.rawPointer = pointer;
public InProgress(JNA.InProgress pointer) {
super(pointer);
}
/**
@ -89,10 +87,7 @@ public class InProgress extends RustObject {
* @return an {@link InProgressBuilder} for this {@link InProgress}
*/
public InProgressBuilder builder() {
this.validate();
InProgressBuilder builder = new InProgressBuilder(JNA.INSTANCE.in_progress_builder(this.rawPointer));
this.rawPointer = null;
return builder;
return new InProgressBuilder(JNA.INSTANCE.in_progress_builder(this.consumePointer()));
}
/**
@ -102,11 +97,8 @@ public class InProgress extends RustObject {
* @param entid The `Entid` for this entity.
* @return an `EntityBuilder` for this `InProgress`
*/
public EntityBuilder builderForEntid(long entid){
this.validate();
EntityBuilder builder = new EntityBuilder(JNA.INSTANCE.in_progress_entity_builder_from_entid(this.rawPointer, entid));
this.rawPointer = null;
return builder;
public EntityBuilder builderForEntid(long entid) {
return new EntityBuilder(JNA.INSTANCE.in_progress_entity_builder_from_entid(this.consumePointer(), entid));
}
/**
@ -117,10 +109,7 @@ public class InProgress extends RustObject {
* @return an `EntityBuilder` for this `InProgress`
*/
public EntityBuilder builderForTempid(String tempid){
this.validate();
EntityBuilder builder = new EntityBuilder(JNA.INSTANCE.in_progress_entity_builder_from_temp_id(this.rawPointer, tempid));
this.rawPointer = null;
return builder;
return new EntityBuilder(JNA.INSTANCE.in_progress_entity_builder_from_temp_id(this.consumePointer(), tempid));
}
/**
@ -146,13 +135,13 @@ public class InProgress extends RustObject {
* @return The `TxReport` generated by the transact.
*/
public TxReport transact(String transaction) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_transact(this.rawPointer, transaction);
if (result.isFailure()) {
Log.e("InProgress", result.err);
RustError.ByReference err = new RustError.ByReference();
JNA.TxReport txr = JNA.INSTANCE.in_progress_transact(this.validPointer(), transaction, err);
if (err.isFailure()) {
Log.e("InProgress", err.consumeErrorMessage());
return null;
}
return new TxReport(result.ok);
return new TxReport(txr);
}
/**
@ -163,12 +152,9 @@ public class InProgress extends RustObject {
* TODO throw exception if error occurs
*/
public void commit() {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_commit(this.rawPointer);
this.rawPointer = null;
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.in_progress_commit(this.consumePointer(), err);
err.logAndConsumeError("InProgress");
}
/**
@ -178,18 +164,13 @@ public class InProgress extends RustObject {
* TODO throw exception if error occurs
*/
public void rollback() {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_rollback(this.rawPointer);
this.rawPointer = null;
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference err = new RustError.ByReference();
JNA.INSTANCE.in_progress_rollback(this.consumePointer(), err);
err.logAndConsumeError("InProgress");
}
@Override
public void close() throws IOException {
if (this.rawPointer != null) {
JNA.INSTANCE.in_progress_destroy(this.rawPointer);
}
protected void destroyPointer(JNA.InProgress p) {
JNA.INSTANCE.in_progress_destroy(p);
}
}

View file

@ -14,7 +14,6 @@ import android.util.Log;
import com.sun.jna.Pointer;
import java.io.IOException;
import java.util.Date;
import java.util.UUID;
@ -56,10 +55,10 @@ import java.util.UUID;
* builder.commit();
* }</pre>
*/
public class InProgressBuilder extends RustObject {
public class InProgressBuilder extends RustObject<JNA.InProgressBuilder> {
public InProgressBuilder(Pointer pointer) {
this.rawPointer = pointer;
public InProgressBuilder(JNA.InProgressBuilder pointer) {
super(pointer);
}
/**
* Asserts the value of attribute `keyword` to be the provided `value`.
@ -71,11 +70,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(long entid, String keyword, long value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_add_long(this.rawPointer, entid, keyword, value);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_add_long(this.validPointer(), entid, keyword, value, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -87,11 +84,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be asserted
*/
public void addRef(long entid, String keyword, long value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_add_ref(this.rawPointer, entid, keyword, value);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_add_ref(this.validPointer(), entid, keyword, value, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -103,11 +98,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be asserted
*/
public void addKeyword(long entid, String keyword, String value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_add_keyword(this.rawPointer, entid, keyword, value);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_add_keyword(this.validPointer(), entid, keyword, value, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -119,11 +112,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(long entid, String keyword, boolean value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_add_boolean(this.rawPointer, entid, keyword, value ? 1 : 0);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_add_boolean(this.validPointer(), entid, keyword, value ? 1 : 0, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -135,11 +126,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(long entid, String keyword, double value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_add_double(this.rawPointer, entid, keyword, value);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_add_double(this.validPointer(), entid, keyword, value, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -151,11 +140,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(long entid, String keyword, Date value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_add_timestamp(this.rawPointer, entid, keyword, value.getTime() * 1_000);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_add_timestamp(this.validPointer(), entid, keyword, value.getTime() * 1_000, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -167,11 +154,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(long entid, String keyword, String value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_add_string(this.rawPointer, entid, keyword, value);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_add_string(this.validPointer(), entid, keyword, value, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -183,12 +168,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be asserted
*/
public void add(long entid, String keyword, UUID value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_add_uuid(this.rawPointer, entid, keyword, getPointerForUUID(value));
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_add_uuid(this.validPointer(), entid, keyword, getPointerForUUID(value), error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -201,11 +183,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(long entid, String keyword, long value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_retract_long(this.rawPointer, entid, keyword, value);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_retract_long(this.validPointer(), entid, keyword, value, error);
error.logAndConsumeError("InProgressBuilder");
}
@ -219,11 +199,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retractRef(long entid, String keyword, long value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_retract_ref(this.rawPointer, entid, keyword, value);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_retract_ref(this.validPointer(), entid, keyword, value, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -236,11 +214,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retractKeyword(long entid, String keyword, String value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_retract_keyword(this.rawPointer, entid, keyword, value);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_retract_keyword(this.validPointer(), entid, keyword, value, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -253,11 +229,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(long entid, String keyword, boolean value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_retract_boolean(this.rawPointer, entid, keyword, value ? 1 : 0);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_retract_boolean(this.validPointer(), entid, keyword, value ? 1 : 0, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -270,11 +244,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(long entid, String keyword, double value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_retract_double(this.rawPointer, entid, keyword, value);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_retract_double(this.validPointer(), entid, keyword, value, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -287,11 +259,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(long entid, String keyword, Date value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_retract_timestamp(this.rawPointer, entid, keyword, value.getTime() * 1_000);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_retract_timestamp(this.validPointer(), entid, keyword, value.getTime() * 1_000, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -304,11 +274,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(long entid, String keyword, String value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_retract_string(this.rawPointer, entid, keyword, value);
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_retract_string(this.validPointer(), entid, keyword, value, error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -321,11 +289,9 @@ public class InProgressBuilder extends RustObject {
* @param value The value to be retracted
*/
public void retract(long entid, String keyword, UUID value) {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_retract_uuid(this.rawPointer, entid, keyword, this.getPointerForUUID(value));
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
}
RustError.ByReference error = new RustError.ByReference();
JNA.INSTANCE.in_progress_builder_retract_uuid(this.validPointer(), entid, keyword, this.getPointerForUUID(value), error);
error.logAndConsumeError("InProgressBuilder");
}
/**
@ -343,9 +309,7 @@ public class InProgressBuilder extends RustObject {
* the {@link TxReport} generated by the transact.
*/
public InProgressTransactionResult transact() {
this.validate();
InProgressTransactionResult result = JNA.INSTANCE.in_progress_builder_transact(this.rawPointer);
this.rawPointer = null;
InProgressTransactionResult result = JNA.INSTANCE.in_progress_builder_transact(this.consumePointer());
return result;
}
@ -362,21 +326,17 @@ public class InProgressBuilder extends RustObject {
* @return The {@link TxReport} generated by the commit.
*/
public TxReport commit() {
this.validate();
RustResult result = JNA.INSTANCE.in_progress_builder_commit(this.rawPointer);
this.rawPointer = null;
if (result.isFailure()) {
Log.e("InProgressBuilder", result.err);
RustError.ByReference error = new RustError.ByReference();
JNA.TxReport result = JNA.INSTANCE.in_progress_builder_commit(this.consumePointer(), error);
if (error.isFailure()) {
Log.e("InProgressBuilder", error.consumeErrorMessage());
return null;
}
return new TxReport(result.ok);
return new TxReport(result);
}
@Override
public void close() throws IOException {
if (this.rawPointer != null) {
JNA.INSTANCE.in_progress_builder_destroy(this.rawPointer);
}
protected void destroyPointer(JNA.InProgressBuilder p) {
JNA.INSTANCE.in_progress_builder_destroy(p);
}
}

View file

@ -15,43 +15,57 @@ import android.util.Log;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class InProgressTransactionResult extends Structure implements Closeable {
public class InProgressTransactionResult extends Structure {
public static class ByReference extends InProgressTransactionResult implements Structure.ByReference {
}
public static class ByValue extends InProgressTransactionResult implements Structure.ByValue {
}
public Pointer inProgress;
public RustResult.ByReference result;
public JNA.InProgress inProgress;
public JNA.TxReport txReport;
public RustError error;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("inProgress", "result");
return Arrays.asList("inProgress", "txReport", "error");
}
public InProgress getInProgress() {
return new InProgress(this.inProgress);
if (this.inProgress == null) {
throw new NullPointerException("Already consumed InProgress");
}
InProgress ip = new InProgress(this.inProgress);
this.inProgress = null;
return ip;
}
public TxReport getReport() {
if (this.result.isFailure()) {
Log.e("InProgressTransactRes", this.result.err);
if (this.error.isFailure()) {
Log.e("InProgressTransactRes", this.error.consumeErrorMessage());
return null;
}
return new TxReport(this.result.ok);
if (this.txReport == null) {
throw new NullPointerException("Already consumed TxReport");
}
JNA.TxReport report = this.txReport;
this.txReport = null;
return new TxReport(report);
}
@Override
public void close() throws IOException {
if (this.getPointer() != null) {
JNA.INSTANCE.destroy(this.getPointer());
protected void finalize() {
if (this.txReport != null) {
JNA.INSTANCE.tx_report_destroy(this.txReport);
this.txReport = null;
}
if (this.inProgress != null) {
JNA.INSTANCE.in_progress_destroy(this.inProgress);
this.inProgress = null;
}
}
}

View file

@ -14,6 +14,9 @@ import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import java.lang.reflect.Type;
/**
* JNA interface for FFI to Mentat's Rust library
@ -26,136 +29,148 @@ public interface JNA extends Library {
JNA INSTANCE = (JNA) Native.loadLibrary(JNA_LIBRARY_NAME, JNA.class);
Pointer store_open(String dbPath);
class Store extends PointerType {}
class QueryBuilder extends PointerType {}
class TypedValue extends PointerType {}
class TypedValueList extends PointerType {}
class TypedValueListIter extends PointerType {}
class RelResult extends PointerType {}
class RelResultIter extends PointerType {}
class TxReport extends PointerType {}
class InProgress extends PointerType {}
class InProgressBuilder extends PointerType {}
class EntityBuilder extends PointerType {}
Store store_open(String dbPath);
void destroy(Pointer obj);
void query_builder_destroy(Pointer obj);
void store_destroy(Pointer obj);
void typed_value_destroy(Pointer obj);
void typed_value_list_destroy(Pointer obj);
void typed_value_list_iter_destroy(Pointer obj);
void typed_value_result_set_destroy(Pointer obj);
void typed_value_result_set_iter_destroy(Pointer obj);
void tx_report_destroy(Pointer obj);
void in_progress_destroy(Pointer obj);
void in_progress_builder_destroy(Pointer obj);
void entity_builder_destroy(Pointer obj);
void uuid_destroy(Pointer obj);
void query_builder_destroy(QueryBuilder obj);
void store_destroy(Store obj);
void typed_value_destroy(TypedValue obj);
void typed_value_list_destroy(TypedValueList obj);
void typed_value_list_iter_destroy(TypedValueListIter obj);
void typed_value_result_set_destroy(RelResult obj);
void typed_value_result_set_iter_destroy(RelResultIter obj);
void tx_report_destroy(TxReport obj);
void in_progress_destroy(InProgress obj);
void in_progress_builder_destroy(InProgressBuilder obj);
void entity_builder_destroy(EntityBuilder obj);
void rust_c_string_destroy(Pointer str);
// caching
RustResult store_cache_attribute_forward(Pointer store, String attribute);
RustResult store_cache_attribute_reverse(Pointer store, String attribute);
RustResult store_cache_attribute_bi_directional(Pointer store, String attribute);
void store_cache_attribute_forward(Store store, String attribute, RustError.ByReference err);
void store_cache_attribute_reverse(Store store, String attribute, RustError.ByReference err);
void store_cache_attribute_bi_directional(Store store, String attribute, RustError.ByReference err);
// transact
RustResult store_transact(Pointer store, String transaction);
Pointer tx_report_entity_for_temp_id(Pointer report, String tempid);
long tx_report_get_entid(Pointer report);
long tx_report_get_tx_instant(Pointer report);
RustResult store_begin_transaction(Pointer store);
TxReport store_transact(Store store, String transaction, RustError.ByReference err);
Pointer tx_report_entity_for_temp_id(TxReport report, String tempid); // returns a pointer to a 64 bit int on the heap
long tx_report_get_entid(TxReport report);
long tx_report_get_tx_instant(TxReport report);
InProgress store_begin_transaction(Store store, RustError.ByReference error);
// in progress
RustResult in_progress_transact(Pointer in_progress, String transaction);
RustResult in_progress_commit(Pointer in_progress);
RustResult in_progress_rollback(Pointer in_progress);
Pointer in_progress_builder(Pointer in_progress);
Pointer in_progress_entity_builder_from_temp_id(Pointer in_progress, String temp_id);
Pointer in_progress_entity_builder_from_entid(Pointer in_progress, long entid);
TxReport in_progress_transact(InProgress in_progress, String transaction, RustError.ByReference err);
void in_progress_commit(InProgress in_progress, RustError.ByReference err);
void in_progress_rollback(InProgress in_progress, RustError.ByReference err);
InProgressBuilder in_progress_builder(InProgress in_progress);
EntityBuilder in_progress_entity_builder_from_temp_id(InProgress in_progress, String temp_id);
EntityBuilder in_progress_entity_builder_from_entid(InProgress in_progress, long entid);
// in_progress entity building
RustResult store_in_progress_builder(Pointer store);
RustResult in_progress_builder_add_string(Pointer builder, long entid, String kw, String value);
RustResult in_progress_builder_add_long(Pointer builder, long entid, String kw, long value);
RustResult in_progress_builder_add_ref(Pointer builder, long entid, String kw, long value);
RustResult in_progress_builder_add_keyword(Pointer builder, long entid, String kw, String value);
RustResult in_progress_builder_add_timestamp(Pointer builder, long entid, String kw, long value);
RustResult in_progress_builder_add_boolean(Pointer builder, long entid, String kw, int value);
RustResult in_progress_builder_add_double(Pointer builder, long entid, String kw, double value);
RustResult in_progress_builder_add_uuid(Pointer builder, long entid, String kw, Pointer value);
RustResult in_progress_builder_retract_string(Pointer builder, long entid, String kw, String value);
RustResult in_progress_builder_retract_long(Pointer builder, long entid, String kw, long value);
RustResult in_progress_builder_retract_ref(Pointer builder, long entid, String kw, long value);
RustResult in_progress_builder_retract_keyword(Pointer builder, long entid, String kw, String value);
RustResult in_progress_builder_retract_timestamp(Pointer builder, long entid, String kw, long value);
RustResult in_progress_builder_retract_boolean(Pointer builder, long entid, String kw, int value);
RustResult in_progress_builder_retract_double(Pointer builder, long entid, String kw, double value);
RustResult in_progress_builder_retract_uuid(Pointer builder, long entid, String kw, Pointer value);
InProgressTransactionResult in_progress_builder_transact(Pointer builder);
RustResult in_progress_builder_commit(Pointer builder);
InProgressBuilder store_in_progress_builder(Store store, RustError.ByReference err);
void in_progress_builder_add_string(InProgressBuilder builder, long entid, String kw, String value, RustError.ByReference err);
void in_progress_builder_add_long(InProgressBuilder builder, long entid, String kw, long value, RustError.ByReference err);
void in_progress_builder_add_ref(InProgressBuilder builder, long entid, String kw, long value, RustError.ByReference err);
void in_progress_builder_add_keyword(InProgressBuilder builder, long entid, String kw, String value, RustError.ByReference err);
void in_progress_builder_add_timestamp(InProgressBuilder builder, long entid, String kw, long value, RustError.ByReference err);
void in_progress_builder_add_boolean(InProgressBuilder builder, long entid, String kw, int value, RustError.ByReference err);
void in_progress_builder_add_double(InProgressBuilder builder, long entid, String kw, double value, RustError.ByReference err);
void in_progress_builder_add_uuid(InProgressBuilder builder, long entid, String kw, Pointer value, RustError.ByReference err);
void in_progress_builder_retract_string(InProgressBuilder builder, long entid, String kw, String value, RustError.ByReference err);
void in_progress_builder_retract_long(InProgressBuilder builder, long entid, String kw, long value, RustError.ByReference err);
void in_progress_builder_retract_ref(InProgressBuilder builder, long entid, String kw, long value, RustError.ByReference err);
void in_progress_builder_retract_keyword(InProgressBuilder builder, long entid, String kw, String value, RustError.ByReference err);
void in_progress_builder_retract_timestamp(InProgressBuilder builder, long entid, String kw, long value, RustError.ByReference err);
void in_progress_builder_retract_boolean(InProgressBuilder builder, long entid, String kw, int value, RustError.ByReference err);
void in_progress_builder_retract_double(InProgressBuilder builder, long entid, String kw, double value, RustError.ByReference err);
void in_progress_builder_retract_uuid(InProgressBuilder builder, long entid, String kw, Pointer value, RustError.ByReference err);
InProgressTransactionResult.ByValue in_progress_builder_transact(InProgressBuilder builder);
TxReport in_progress_builder_commit(InProgressBuilder builder, RustError.ByReference err);
// entity building
RustResult store_entity_builder_from_temp_id(Pointer store, String temp_id);
RustResult store_entity_builder_from_entid(Pointer store, long entid);
RustResult entity_builder_add_string(Pointer builder, String kw, String value);
RustResult entity_builder_add_long(Pointer builder, String kw, long value);
RustResult entity_builder_add_ref(Pointer builder, String kw, long value);
RustResult entity_builder_add_keyword(Pointer builder, String kw, String value);
RustResult entity_builder_add_boolean(Pointer builder, String kw, int value);
RustResult entity_builder_add_double(Pointer builder, String kw, double value);
RustResult entity_builder_add_timestamp(Pointer builder, String kw, long value);
RustResult entity_builder_add_uuid(Pointer builder, String kw, Pointer value);
RustResult entity_builder_retract_string(Pointer builder, String kw, String value);
RustResult entity_builder_retract_long(Pointer builder, String kw, long value);
RustResult entity_builder_retract_ref(Pointer builder, String kw, long value);
RustResult entity_builder_retract_keyword(Pointer builder, String kw, String value);
RustResult entity_builder_retract_boolean(Pointer builder, String kw, int value);
RustResult entity_builder_retract_double(Pointer builder, String kw, double value);
RustResult entity_builder_retract_timestamp(Pointer builder, String kw, long value);
RustResult entity_builder_retract_uuid(Pointer builder, String kw, Pointer value);
InProgressTransactionResult entity_builder_transact(Pointer builder);
RustResult entity_builder_commit(Pointer builder);
// sync
RustResult store_sync(Pointer store, String userUuid, String serverUri);
EntityBuilder store_entity_builder_from_temp_id(Store store, String temp_id, RustError.ByReference err);
EntityBuilder store_entity_builder_from_entid(Store store, long entid, RustError.ByReference err);
void entity_builder_add_string(EntityBuilder builder, String kw, String value, RustError.ByReference err);
void entity_builder_add_long(EntityBuilder builder, String kw, long value, RustError.ByReference err);
void entity_builder_add_ref(EntityBuilder builder, String kw, long value, RustError.ByReference err);
void entity_builder_add_keyword(EntityBuilder builder, String kw, String value, RustError.ByReference err);
void entity_builder_add_boolean(EntityBuilder builder, String kw, int value, RustError.ByReference err);
void entity_builder_add_double(EntityBuilder builder, String kw, double value, RustError.ByReference err);
void entity_builder_add_timestamp(EntityBuilder builder, String kw, long value, RustError.ByReference err);
void entity_builder_add_uuid(EntityBuilder builder, String kw, Pointer value, RustError.ByReference err);
void entity_builder_retract_string(EntityBuilder builder, String kw, String value, RustError.ByReference err);
void entity_builder_retract_long(EntityBuilder builder, String kw, long value, RustError.ByReference err);
void entity_builder_retract_ref(EntityBuilder builder, String kw, long value, RustError.ByReference err);
void entity_builder_retract_keyword(EntityBuilder builder, String kw, String value, RustError.ByReference err);
void entity_builder_retract_boolean(EntityBuilder builder, String kw, int value, RustError.ByReference err);
void entity_builder_retract_double(EntityBuilder builder, String kw, double value, RustError.ByReference err);
void entity_builder_retract_timestamp(EntityBuilder builder, String kw, long value, RustError.ByReference err);
void entity_builder_retract_uuid(EntityBuilder builder, String kw, Pointer value, RustError.ByReference err);
InProgressTransactionResult.ByValue entity_builder_transact(EntityBuilder builder);
TxReport entity_builder_commit(EntityBuilder builder, RustError.ByReference err);
// observers
void store_register_observer(Pointer store, String key, Pointer attributes, int len, TxObserverCallback callback);
void store_unregister_observer(Pointer store, String key);
long store_entid_for_attribute(Pointer store, String attr);
void store_register_observer(Store store, String key, Pointer attributes, int len, TxObserverCallback callback);
void store_unregister_observer(Store store, String key);
long store_entid_for_attribute(Store store, String attr);
// Query Building
Pointer store_query(Pointer store, String query);
RustResult store_value_for_attribute(Pointer store, long entid, String attribute);
void query_builder_bind_long(Pointer query, String var, long value);
void query_builder_bind_ref(Pointer query, String var, long value);
void query_builder_bind_ref_kw(Pointer query, String var, String value);
void query_builder_bind_kw(Pointer query, String var, String value);
void query_builder_bind_boolean(Pointer query, String var, int value);
void query_builder_bind_double(Pointer query, String var, double value);
void query_builder_bind_timestamp(Pointer query, String var, long value);
void query_builder_bind_string(Pointer query, String var, String value);
void query_builder_bind_uuid(Pointer query, String var, Pointer value);
QueryBuilder store_query(Store store, String query);
TypedValue store_value_for_attribute(Store store, long entid, String attribute, RustError.ByReference err);
void query_builder_bind_long(QueryBuilder query, String var, long value);
void query_builder_bind_ref(QueryBuilder query, String var, long value);
void query_builder_bind_ref_kw(QueryBuilder query, String var, String value);
void query_builder_bind_kw(QueryBuilder query, String var, String value);
void query_builder_bind_boolean(QueryBuilder query, String var, int value);
void query_builder_bind_double(QueryBuilder query, String var, double value);
void query_builder_bind_timestamp(QueryBuilder query, String var, long value);
void query_builder_bind_string(QueryBuilder query, String var, String value);
void query_builder_bind_uuid(QueryBuilder query, String var, Pointer value);
// Query Execution
RustResult query_builder_execute(Pointer query);
RustResult query_builder_execute_scalar(Pointer query);
RustResult query_builder_execute_coll(Pointer query);
RustResult query_builder_execute_tuple(Pointer query);
RelResult query_builder_execute(QueryBuilder query, RustError.ByReference err);
TypedValue query_builder_execute_scalar(QueryBuilder query, RustError.ByReference err);
TypedValueList query_builder_execute_coll(QueryBuilder query, RustError.ByReference err);
TypedValueList query_builder_execute_tuple(QueryBuilder query, RustError.ByReference err);
// Query Result Processing
long typed_value_into_long(Pointer value);
long typed_value_into_entid(Pointer value);
String typed_value_into_kw(Pointer value);
String typed_value_into_string(Pointer value);
Pointer typed_value_into_uuid(Pointer value);
int typed_value_into_boolean(Pointer value);
double typed_value_into_double(Pointer value);
long typed_value_into_timestamp(Pointer value);
Pointer typed_value_value_type(Pointer value);
long typed_value_into_long(TypedValue value);
long typed_value_into_entid(TypedValue value);
Pointer typed_value_into_kw(TypedValue value);
Pointer typed_value_into_string(TypedValue value);
Pointer typed_value_into_uuid(TypedValue value);
int typed_value_into_boolean(TypedValue value);
double typed_value_into_double(TypedValue value);
long typed_value_into_timestamp(TypedValue value);
int typed_value_value_type(TypedValue value);
Pointer row_at_index(Pointer rows, int index);
Pointer typed_value_result_set_into_iter(Pointer rows);
Pointer typed_value_result_set_iter_next(Pointer iter);
TypedValueList row_at_index(RelResult rows, int index);
RelResultIter typed_value_result_set_into_iter(RelResult rows);
TypedValueList typed_value_result_set_iter_next(RelResultIter iter);
Pointer typed_value_list_into_iter(Pointer rows);
Pointer typed_value_list_iter_next(Pointer iter);
TypedValueListIter typed_value_list_into_iter(TypedValueList rows);
TypedValue typed_value_list_iter_next(TypedValueListIter iter);
Pointer value_at_index(Pointer rows, int index);
long value_at_index_into_long(Pointer rows, int index);
long value_at_index_into_entid(Pointer rows, int index);
String value_at_index_into_kw(Pointer rows, int index);
String value_at_index_into_string(Pointer rows, int index);
Pointer value_at_index_into_uuid(Pointer rows, int index);
int value_at_index_into_boolean(Pointer rows, int index);
double value_at_index_into_double(Pointer rows, int index);
long value_at_index_into_timestamp(Pointer rows, int index);
TypedValue value_at_index(TypedValueList rows, int index);
long value_at_index_into_long(TypedValueList rows, int index);
long value_at_index_into_entid(TypedValueList rows, int index);
Pointer value_at_index_into_kw(TypedValueList rows, int index);
Pointer value_at_index_into_string(TypedValueList rows, int index);
Pointer value_at_index_into_uuid(TypedValueList rows, int index);
int value_at_index_into_boolean(TypedValueList rows, int index);
double value_at_index_into_double(TypedValueList rows, int index);
long value_at_index_into_timestamp(TypedValueList rows, int index);
}

View file

@ -20,7 +20,7 @@ import com.sun.jna.Pointer;
* This class provides all of the basic API that can be found in Mentat's Store struct.<br/>
* The raw pointer it holds is a pointer to a Store.
*/
public class Mentat extends RustObject {
public class Mentat extends RustObject<JNA.Store> {
static {
System.loadLibrary("mentat_ffi");
@ -32,21 +32,21 @@ public class Mentat extends RustObject {
* @param dbPath The URI as a String of the store to open.
*/
public Mentat(String dbPath) {
this.rawPointer = JNA.INSTANCE.store_open(dbPath);
this(JNA.INSTANCE.store_open(dbPath));
}
/**
* Open a connection to an in-memory Store.
*/
public Mentat() {
this.rawPointer = JNA.INSTANCE.store_open("");
this(JNA.INSTANCE.store_open(""));
}
/**
* Create a new Mentat with the provided pointer to a Mentat Store
* @param rawPointer A pointer to a Mentat Store.
*/
public Mentat(Pointer rawPointer) { this.rawPointer = rawPointer; }
public Mentat(JNA.Store rawPointer) { super(rawPointer); }
/**
* Add an attribute to the cache. The {@link CacheDirection} determines how that attribute can be
@ -63,18 +63,19 @@ public class Mentat extends RustObject {
* BOTH adds an attribute such that it is cached in both directions.
*/
public void cache(String attribute, CacheDirection direction) {
RustResult result = null;
RustError.ByReference err = new RustError.ByReference();
switch (direction) {
case FORWARD:
result = JNA.INSTANCE.store_cache_attribute_forward(this.rawPointer, attribute);
JNA.INSTANCE.store_cache_attribute_forward(this.validPointer(), attribute, err);
break;
case REVERSE:
result = JNA.INSTANCE.store_cache_attribute_reverse(this.rawPointer, attribute);
JNA.INSTANCE.store_cache_attribute_reverse(this.validPointer(), attribute, err);
break;
case BOTH:
result = JNA.INSTANCE.store_cache_attribute_bi_directional(this.rawPointer, attribute);
}
if (result.isFailure()) {
Log.e("Mentat", result.err);
JNA.INSTANCE.store_cache_attribute_bi_directional(this.validPointer(), attribute, err);
break;
}
err.logAndConsumeError("Mentat");
}
/**
@ -84,15 +85,12 @@ public class Mentat extends RustObject {
* @return The {@link TxReport} of the completed transaction
*/
public TxReport transact(String transaction) {
RustResult result = JNA.INSTANCE.store_transact(this.rawPointer, transaction);
if (result.isFailure()) {
Log.e("Mentat", result.err);
return null;
}
if (result.isSuccess()) {
return new TxReport(result.ok);
RustError.ByReference err = new RustError.ByReference();
JNA.TxReport report = JNA.INSTANCE.store_transact(this.validPointer(), transaction, err);
if (err.isSuccess()) {
return new TxReport(report);
} else {
err.logAndConsumeError("Mentat");
return null;
}
}
@ -103,7 +101,7 @@ public class Mentat extends RustObject {
* @return The `Entid` associated with the attribute.
*/
public long entIdForAttribute(String attribute) {
return JNA.INSTANCE.store_entid_for_attribute(this.rawPointer, attribute);
return JNA.INSTANCE.store_entid_for_attribute(this.validPointer(), attribute);
}
/**
@ -112,7 +110,7 @@ public class Mentat extends RustObject {
* @return The {@link Query} representing the query that can be executed.
*/
public Query query(String query) {
return new Query(JNA.INSTANCE.store_query(this.rawPointer, query));
return new Query(JNA.INSTANCE.store_query(this.validPointer(), query));
}
/**
@ -123,16 +121,14 @@ public class Mentat extends RustObject {
* @return The {@link TypedValue} containing the value of the attribute for the entity.
*/
public TypedValue valueForAttributeOfEntity(String attribute, long entid) {
RustResult result = JNA.INSTANCE.store_value_for_attribute(this.rawPointer, entid, attribute);
RustError.ByReference err = new RustError.ByReference();
JNA.TypedValue typedVal = JNA.INSTANCE.store_value_for_attribute(this.validPointer(), entid, attribute, err);
if (result.isSuccess()) {
return new TypedValue(result.ok);
}
if (result.isFailure()) {
Log.e("Mentat", result.err);
if (err.isSuccess()) {
return new TypedValue(typedVal);
}
err.logAndConsumeError("Mentat");
return null;
}
@ -149,11 +145,11 @@ public class Mentat extends RustObject {
// turn string array into int array
long[] attrEntids = new long[attributes.length];
for(int i = 0; i < attributes.length; i++) {
attrEntids[i] = JNA.INSTANCE.store_entid_for_attribute(this.rawPointer, attributes[i]);
attrEntids[i] = JNA.INSTANCE.store_entid_for_attribute(this.validPointer(), attributes[i]);
}
final Pointer entidsNativeArray = new Memory(8 * attrEntids.length);
entidsNativeArray.write(0, attrEntids, 0, attrEntids.length);
JNA.INSTANCE.store_register_observer(rawPointer, key, entidsNativeArray, attrEntids.length, callback);
JNA.INSTANCE.store_register_observer(validPointer(), key, entidsNativeArray, attrEntids.length, callback);
}
/**
@ -164,10 +160,9 @@ public class Mentat extends RustObject {
* @param key String representing an identifier for the observer.
*/
public void unregisterObserver(String key) {
JNA.INSTANCE.store_unregister_observer(rawPointer, key);
JNA.INSTANCE.store_unregister_observer(validPointer(), key);
}
/**
* Start a new transaction
*
@ -176,15 +171,12 @@ public class Mentat extends RustObject {
* @return The {@link InProgress} used to manage the transaction
*/
public InProgress beginTransaction() {
RustResult result = JNA.INSTANCE.store_begin_transaction(this.rawPointer);
if (result.isSuccess()) {
return new InProgress(result.ok);
RustError.ByReference err = new RustError.ByReference();
JNA.InProgress inProg = JNA.INSTANCE.store_begin_transaction(this.validPointer(), err);
if (err.isSuccess()) {
return new InProgress(inProg);
}
if (result.isFailure()) {
Log.i("Mentat", result.err);
}
err.logAndConsumeError("Mentat");
return null;
}
@ -197,15 +189,12 @@ public class Mentat extends RustObject {
* @return an {@link InProgressBuilder} for a new transaction.
*/
public InProgressBuilder entityBuilder() {
RustResult result = JNA.INSTANCE.store_in_progress_builder(this.rawPointer);
if (result.isSuccess()) {
return new InProgressBuilder(result.ok);
RustError.ByReference err = new RustError.ByReference();
JNA.InProgressBuilder builder = JNA.INSTANCE.store_in_progress_builder(this.validPointer(), err);
if (err.isSuccess()) {
return new InProgressBuilder(builder);
}
if (result.isFailure()) {
Log.i("Mentat", result.err);
}
err.logAndConsumeError("Mentat");
return null;
}
@ -219,15 +208,12 @@ public class Mentat extends RustObject {
* @return an {@link EntityBuilder} for a new transaction.
*/
public EntityBuilder entityBuilder(long entid) {
RustResult result = JNA.INSTANCE.store_entity_builder_from_entid(this.rawPointer, entid);
if (result.isSuccess()) {
return new EntityBuilder(result.ok);
RustError.ByReference err = new RustError.ByReference();
JNA.EntityBuilder builder = JNA.INSTANCE.store_entity_builder_from_entid(this.validPointer(), entid, err);
if (err.isSuccess()) {
return new EntityBuilder(builder);
}
if (result.isFailure()) {
Log.i("Mentat", result.err);
}
err.logAndConsumeError("Mentat");
return null;
}
@ -241,22 +227,17 @@ public class Mentat extends RustObject {
* @return an {@link EntityBuilder} for a new transaction.
*/
public EntityBuilder entityBuilder(String tempId) {
RustResult result = JNA.INSTANCE.store_entity_builder_from_temp_id(this.rawPointer, tempId);
if (result.isSuccess()) {
return new EntityBuilder(result.ok);
RustError.ByReference err = new RustError.ByReference();
JNA.EntityBuilder builder = JNA.INSTANCE.store_entity_builder_from_temp_id(this.validPointer(), tempId, err);
if (err.isSuccess()) {
return new EntityBuilder(builder);
}
if (result.isFailure()) {
Log.i("Mentat", result.err);
}
err.logAndConsumeError("Mentat");
return null;
}
@Override
public void close() {
if (this.rawPointer != null) {
JNA.INSTANCE.store_destroy(this.rawPointer);
}
protected void destroyPointer(JNA.Store p) {
JNA.INSTANCE.store_destroy(p);
}
}

View file

@ -12,8 +12,6 @@ package org.mozilla.mentat;
import android.util.Log;
import com.sun.jna.Pointer;
import java.util.Date;
import java.util.UUID;
@ -106,10 +104,10 @@ import java.util.UUID;
* });
*</pre>
*/
public class Query extends RustObject {
public class Query extends RustObject<JNA.QueryBuilder> {
public Query(Pointer pointer) {
this.rawPointer = pointer;
public Query(JNA.QueryBuilder pointer) {
super(pointer);
}
/**
@ -119,9 +117,9 @@ public class Query extends RustObject {
* @param value The value to be bound
* @return This {@link Query} such that further function can be called.
*/
Query bind(String varName, long value) {
this.validate();
JNA.INSTANCE.query_builder_bind_long(this.rawPointer, varName, value);
public Query bind(String varName, long value) {
this.assertValidPointer();
JNA.INSTANCE.query_builder_bind_long(this.validPointer(), varName, value);
return this;
}
@ -132,9 +130,8 @@ public class Query extends RustObject {
* @param value The value to be bound
* @return This {@link Query} such that further function can be called.
*/
Query bindEntidReference(String varName, long value) {
this.validate();
JNA.INSTANCE.query_builder_bind_ref(this.rawPointer, varName, value);
public Query bindEntidReference(String varName, long value) {
JNA.INSTANCE.query_builder_bind_ref(this.validPointer(), varName, value);
return this;
}
@ -145,9 +142,8 @@ public class Query extends RustObject {
* @param value The value to be bound
* @return This {@link Query} such that further function can be called.
*/
Query bindKeywordReference(String varName, String value) {
this.validate();
JNA.INSTANCE.query_builder_bind_ref_kw(this.rawPointer, varName, value);
public Query bindKeywordReference(String varName, String value) {
JNA.INSTANCE.query_builder_bind_ref_kw(this.validPointer(), varName, value);
return this;
}
@ -158,9 +154,8 @@ public class Query extends RustObject {
* @param value The value to be bound
* @return This {@link Query} such that further function can be called.
*/
Query bindKeyword(String varName, String value) {
this.validate();
JNA.INSTANCE.query_builder_bind_kw(this.rawPointer, varName, value);
public Query bindKeyword(String varName, String value) {
JNA.INSTANCE.query_builder_bind_kw(this.validPointer(), varName, value);
return this;
}
@ -171,9 +166,8 @@ public class Query extends RustObject {
* @param value The value to be bound
* @return This {@link Query} such that further function can be called.
*/
Query bind(String varName, boolean value) {
this.validate();
JNA.INSTANCE.query_builder_bind_boolean(this.rawPointer, varName, value ? 1 : 0);
public Query bind(String varName, boolean value) {
JNA.INSTANCE.query_builder_bind_boolean(this.validPointer(), varName, value ? 1 : 0);
return this;
}
@ -184,9 +178,8 @@ public class Query extends RustObject {
* @param value The value to be bound
* @return This {@link Query} such that further function can be called.
*/
Query bind(String varName, double value) {
this.validate();
JNA.INSTANCE.query_builder_bind_double(this.rawPointer, varName, value);
public Query bind(String varName, double value) {
JNA.INSTANCE.query_builder_bind_double(this.validPointer(), varName, value);
return this;
}
@ -197,10 +190,9 @@ public class Query extends RustObject {
* @param value The value to be bound
* @return This {@link Query} such that further function can be called.
*/
Query bind(String varName, Date value) {
this.validate();
public Query bind(String varName, Date value) {
long timestamp = value.getTime() * 1000;
JNA.INSTANCE.query_builder_bind_timestamp(this.rawPointer, varName, timestamp);
JNA.INSTANCE.query_builder_bind_timestamp(this.validPointer(), varName, timestamp);
return this;
}
@ -211,9 +203,8 @@ public class Query extends RustObject {
* @param value The value to be bound
* @return This {@link Query} such that further function can be called.
*/
Query bind(String varName, String value) {
this.validate();
JNA.INSTANCE.query_builder_bind_string(this.rawPointer, varName, value);
public Query bind(String varName, String value) {
JNA.INSTANCE.query_builder_bind_string(this.validPointer(), varName, value);
return this;
}
@ -224,9 +215,8 @@ public class Query extends RustObject {
* @param value The value to be bound
* @return This {@link Query} such that further function can be called.
*/
Query bind(String varName, UUID value) {
this.validate();
JNA.INSTANCE.query_builder_bind_uuid(this.rawPointer, varName, getPointerForUUID(value));
public Query bind(String varName, UUID value) {
JNA.INSTANCE.query_builder_bind_uuid(this.validPointer(), varName, getPointerForUUID(value));
return this;
}
@ -236,16 +226,14 @@ public class Query extends RustObject {
* TODO: Throw an exception if the query raw pointer has been consumed or the query fails to execute
* @param handler the handler to call with the results of this query
*/
void run(final RelResultHandler handler) {
this.validate();
RustResult result = JNA.INSTANCE.query_builder_execute(rawPointer);
rawPointer = null;
if (result.isFailure()) {
Log.e("Query", result.err);
public void run(final RelResultHandler handler) {
RustError.ByReference error = new RustError.ByReference();
JNA.RelResult relResult = JNA.INSTANCE.query_builder_execute(this.consumePointer(), error);
if (error.isFailure()) {
Log.e("Query", error.consumeErrorMessage());
return;
}
handler.handleRows(new RelResult(result.ok));
handler.handleRows(new RelResult(relResult));
}
/**
@ -254,18 +242,17 @@ public class Query extends RustObject {
* TODO: Throw an exception if the query raw pointer has been consumed or the query fails to execute
* @param handler the handler to call with the results of this query
*/
void run(final ScalarResultHandler handler) {
this.validate();
RustResult result = JNA.INSTANCE.query_builder_execute_scalar(rawPointer);
rawPointer = null;
public void run(final ScalarResultHandler handler) {
RustError.ByReference error = new RustError.ByReference();
JNA.TypedValue valOrNull = JNA.INSTANCE.query_builder_execute_scalar(consumePointer(), error);
if (result.isFailure()) {
Log.e("Query", result.err);
if (error.isFailure()) {
Log.e("Query", error.consumeErrorMessage());
return;
}
if (result.isSuccess()) {
handler.handleValue(new TypedValue(result.ok));
if (valOrNull != null) {
handler.handleValue(new TypedValue(valOrNull));
} else {
handler.handleValue(null);
}
@ -277,16 +264,15 @@ public class Query extends RustObject {
* TODO: Throw an exception if the query raw pointer has been consumed or the query fails to execute
* @param handler the handler to call with the results of this query
*/
void run(final CollResultHandler handler) {
this.validate();
RustResult result = JNA.INSTANCE.query_builder_execute_coll(rawPointer);
rawPointer = null;
public void run(final CollResultHandler handler) {
RustError.ByReference error = new RustError.ByReference();
JNA.TypedValueList collResult = JNA.INSTANCE.query_builder_execute_coll(this.consumePointer(), error);
if (result.isFailure()) {
Log.e("Query", result.err);
if (error.isFailure()) {
Log.e("Query", error.consumeErrorMessage());
return;
}
handler.handleList(new CollResult(result.ok));
handler.handleList(new CollResult(collResult));
}
/**
@ -295,28 +281,24 @@ public class Query extends RustObject {
* TODO: Throw an exception if the query raw pointer has been consumed or the query fails to execute
* @param handler the handler to call with the results of this query
*/
void run(final TupleResultHandler handler) {
this.validate();
RustResult result = JNA.INSTANCE.query_builder_execute_tuple(rawPointer);
rawPointer = null;
public void run(final TupleResultHandler handler) {
RustError.ByReference error = new RustError.ByReference();
JNA.TypedValueList tuple = JNA.INSTANCE.query_builder_execute_tuple(this.consumePointer(), error);
if (result.isFailure()) {
Log.e("Query", result.err);
if (error.isFailure()) {
Log.e("Query", error.consumeErrorMessage());
return;
}
if (result.isSuccess()) {
handler.handleRow(new TupleResult(result.ok));
if (tuple != null) {
handler.handleRow(new TupleResult(tuple));
} else {
handler.handleRow(null);
}
}
@Override
public void close() {
if (this.rawPointer == null) {
return;
}
JNA.INSTANCE.query_builder_destroy(this.rawPointer);
protected void destroyPointer(JNA.QueryBuilder p) {
JNA.INSTANCE.query_builder_destroy(p);
}
}

View file

@ -10,8 +10,6 @@
package org.mozilla.mentat;
import com.sun.jna.Pointer;
/**
* Wraps a `Rel` result from a Mentat query.
* A `Rel` result is a list of rows of `TypedValues`.
@ -44,10 +42,10 @@ import com.sun.jna.Pointer;
* </p>
* Note that iteration is consuming and can only be done once.
*/
public class RelResult extends RustObject implements Iterable<TupleResult> {
public class RelResult extends RustObject<JNA.RelResult> implements Iterable<TupleResult> {
public RelResult(Pointer pointer) {
this.rawPointer = pointer;
public RelResult(JNA.RelResult pointer) {
super(pointer);
}
/**
@ -57,8 +55,8 @@ public class RelResult extends RustObject implements Iterable<TupleResult> {
* @return The row at the requested index as a `TupleResult`, if present, or nil if there is no row at that index.
*/
public TupleResult rowAtIndex(int index) {
this.validate();
Pointer pointer = JNA.INSTANCE.row_at_index(this.rawPointer, index);
this.assertValidPointer();
JNA.TypedValueList pointer = JNA.INSTANCE.row_at_index(this.validPointer(), index);
if (pointer == null) {
return null;
}
@ -68,19 +66,12 @@ public class RelResult extends RustObject implements Iterable<TupleResult> {
@Override
public RelResultIterator iterator() {
this.validate();
Pointer iterPointer = JNA.INSTANCE.typed_value_result_set_into_iter(this.rawPointer);
this.rawPointer = null;
if (iterPointer == null) {
return null;
}
JNA.RelResultIter iterPointer = JNA.INSTANCE.typed_value_result_set_into_iter(this.consumePointer());
return new RelResultIterator(iterPointer);
}
@Override
public void close() {
if (this.rawPointer != null) {
JNA.INSTANCE.typed_value_result_set_destroy(this.rawPointer);
}
protected void destroyPointer(JNA.RelResult p) {
JNA.INSTANCE.typed_value_result_set_destroy(p);
}
}

View file

@ -12,43 +12,27 @@ package org.mozilla.mentat;
import com.sun.jna.Pointer;
import java.util.Iterator;
/**
* Iterator for a {@link RelResult}
*/
public class RelResultIterator extends RustObject implements Iterator {
public class RelResultIterator extends RustIterator<JNA.RelResultIter, JNA.TypedValueList, TupleResult> {
Pointer nextPointer;
RelResultIterator(Pointer iterator) {
this.rawPointer = iterator;
}
private Pointer getNextPointer() {
return JNA.INSTANCE.typed_value_result_set_iter_next(this.rawPointer);
RelResultIterator(JNA.RelResultIter iterator) {
super(iterator);
}
@Override
public boolean hasNext() {
this.nextPointer = getNextPointer();
return this.nextPointer != null;
protected JNA.TypedValueList advanceIterator() {
return JNA.INSTANCE.typed_value_result_set_iter_next(this.validPointer());
}
@Override
public TupleResult next() {
Pointer next = this.nextPointer == null ? getNextPointer() : this.nextPointer;
if (next == null) {
return null;
}
return new TupleResult(next);
protected TupleResult constructItem(JNA.TypedValueList p) {
return new TupleResult(p);
}
@Override
public void close() {
if (this.rawPointer != null) {
JNA.INSTANCE.typed_value_result_set_iter_destroy(this.rawPointer);
}
protected void destroyPointer(JNA.RelResultIter p) {
JNA.INSTANCE.typed_value_result_set_iter_destroy(p);
}
}

View file

@ -0,0 +1,86 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* Copyright 2018 Mozilla
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. */
package org.mozilla.mentat;
import android.util.Log;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
/**
* Represents a C struct containing a {@link Pointer}s and String that map to a Rust Result.
* A RustResult will contain either an ok value, OR an err value, or neither - never both.
*/
public class RustError extends Structure {
public static class ByReference extends RustError implements Structure.ByReference {
}
public static class ByValue extends RustError implements Structure.ByValue {
}
// It's probably a mistake to touch this, but it needs to be public for JNA
public Pointer message;
/**
* Does this represent success?
*/
public boolean isSuccess() {
return this.message == null;
}
/**
* Does this represent failure?
*/
public boolean isFailure() {
return this.message != null;
}
/**
* Get and consume the error message, or null if there is none.
*/
public String consumeErrorMessage() {
String result = this.getErrorMessage();
if (this.message != null) {
JNA.INSTANCE.rust_c_string_destroy(this.message);
this.message = null;
}
return result;
}
/**
* Get the error message or null if there is none.
*/
public String getErrorMessage() {
return this.message == null ? null : this.message.getString(0, "utf8");
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("message");
}
@Override
protected void finalize() {
if (this.message != null) {
JNA.INSTANCE.rust_c_string_destroy(this.message);
this.message = null;
}
}
/* package-local */
void logAndConsumeError(String tag) {
if (this.isFailure()) {
Log.e(tag, this.consumeErrorMessage());
}
}
}

View file

@ -0,0 +1,70 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* Copyright 2018 Mozilla
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. */
package org.mozilla.mentat;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import java.util.Iterator;
import java.util.NoSuchElementException;
// Common factored-out code shared by both RelResultIterator and CollResultIterator (and possibly
// others in the future). This code is a bit error-prone so it's worth avoiding the duplication.
abstract class RustIterator<T extends PointerType, ItemPtr extends PointerType, E extends RustObject<ItemPtr>> extends RustObject<T> implements Iterator<E> {
// We own this if it is not null!
private ItemPtr nextPointer;
RustIterator(T pointer) {
super(pointer);
}
/** Implement by calling `JNA.INSTANCE.whatever_iter_next(this.validPointer());` */
abstract protected ItemPtr advanceIterator();
// Generally should be implemented as `new E(p)`.
abstract protected E constructItem(ItemPtr p);
private ItemPtr consumeNextPointer() {
if (this.nextPointer == null) {
throw new NullPointerException(this.getClass() + " nextPointer already consumed");
}
ItemPtr p = this.nextPointer;
this.nextPointer = null;
return p;
}
@Override
public boolean hasNext() {
if (this.nextPointer != null) {
return true;
}
this.nextPointer = advanceIterator();
return this.nextPointer != null;
}
@Override
public E next() {
ItemPtr next = this.nextPointer == null ? advanceIterator() : this.consumeNextPointer();
if (next == null) {
throw new NoSuchElementException();
}
return this.constructItem(next);
}
@Override
public void close() {
if (this.nextPointer != null) {
// Clean up the next pointer by delegating to the iterated item -- this simplifies
// iterator implementations, and keeps the cleanup code in one place.
this.constructItem(this.consumeNextPointer());
}
super.close();
}
}

View file

@ -10,32 +10,58 @@
package org.mozilla.mentat;
import android.util.Log;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import java.io.Closeable;
import java.nio.ByteBuffer;
import java.util.UUID;
/**
* Base class that wraps an non-optional {@link Pointer} representing a pointer to a Rust object.
* This class implements {@link Closeable} but does not provide an implementation, forcing all
* This class implements {@link AutoCloseable} but does not provide an implementation, forcing all
* subclasses to implement it. This ensures that all classes that inherit from RustObject
* will have their {@link Pointer} destroyed when the Java wrapper is destroyed.
*/
abstract class RustObject implements Closeable {
Pointer rawPointer;
abstract class RustObject<T extends PointerType> implements AutoCloseable {
// This should probably be private to let us better prevent usage mistakes (which lead to
// memory-unsafety).
private T rawPointer;
RustObject(T p) {
rawPointer = p;
}
/**
* Throws a {@link NullPointerException} if the underlying {@link Pointer} is null.
*/
void validate() {
if (this.rawPointer == null) {
void assertValidPointer() {
if (this.isConsumed()) {
throw new NullPointerException(this.getClass() + " consumed");
}
}
public Pointer getPointerForUUID(UUID uuid) {
T validPointer() {
this.assertValidPointer();
return this.rawPointer;
}
boolean isConsumed() {
return this.rawPointer == null;
}
/* package-local */
T consumePointer() {
this.assertValidPointer();
T p = this.rawPointer;
this.rawPointer = null;
return p;
}
/* package-local */
static Pointer getPointerForUUID(UUID uuid) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
@ -45,11 +71,46 @@ abstract class RustObject implements Closeable {
return bytesNativeArray;
}
public UUID getUUIDFromPointer(Pointer uuidPtr) {
byte[] bytes = uuidPtr.getByteArray(0, 16);
ByteBuffer bb = ByteBuffer.wrap(bytes);
long high = bb.getLong();
long low = bb.getLong();
return new UUID(high, low);
/* package-local */
static UUID getAndConsumeUUIDPointer(Pointer uuidPtr) {
try {
byte[] bytes = uuidPtr.getByteArray(0, 16);
ByteBuffer bb = ByteBuffer.wrap(bytes);
long high = bb.getLong();
long low = bb.getLong();
return new UUID(high, low);
} finally {
JNA.INSTANCE.uuid_destroy(uuidPtr);
}
}
/* package-local */
static String getAndConsumeMentatString(Pointer stringPtr) {
if (stringPtr == null) {
return null;
}
try {
return stringPtr.getString(0, "utf8");
} finally {
JNA.INSTANCE.rust_c_string_destroy(stringPtr);
}
}
abstract protected void destroyPointer(T p);
@Override
public void close() {
if (this.rawPointer != null) {
this.destroyPointer(this.consumePointer());
}
}
@Override
protected void finalize() {
try {
this.close();
} catch (Exception e) {
Log.e("RustObject", e.toString());
}
}
}

View file

@ -1,62 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* Copyright 2018 Mozilla
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. */
package org.mozilla.mentat;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* Represents a C struct containing a {@link Pointer}s and String that map to a Rust Result.
* A RustResult will contain either an ok value, OR an err value, or neither - never both.
*/
public class RustResult extends Structure implements Closeable {
public static class ByReference extends RustResult implements Structure.ByReference {
}
public static class ByValue extends RustResult implements Structure.ByValue {
}
public Pointer ok;
public String err;
/**
* Is there an value attached to this result
* @return true if a value is present, false otherwise
*/
public boolean isSuccess() {
return this.ok != null;
}
/**
* Is there an error attached to this result?
* @return true is an error is present, false otherwise
*/
public boolean isFailure() {
return this.err != null;
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("ok", "err");
}
@Override
public void close() throws IOException {
if (this.getPointer() != null) {
JNA.INSTANCE.destroy(this.getPointer());
}
}
}

View file

@ -35,10 +35,10 @@ import java.util.UUID;
* <p>
* To iterate over the result set use standard iteration flows.
*/
public class TupleResult extends RustObject {
public class TupleResult extends RustObject<JNA.TypedValueList> {
public TupleResult(Pointer pointer) {
this.rawPointer = pointer;
public TupleResult(JNA.TypedValueList pointer) {
super(pointer);
}
/**
@ -48,8 +48,7 @@ public class TupleResult extends RustObject {
* @return The {@link TypedValue} at that index.
*/
public TypedValue get(Integer index) {
this.validate();
Pointer pointer = JNA.INSTANCE.value_at_index(this.rawPointer, index);
JNA.TypedValue pointer = JNA.INSTANCE.value_at_index(this.validPointer(), index);
if (pointer == null) {
return null;
}
@ -64,8 +63,7 @@ public class TupleResult extends RustObject {
* @return The {@link Long} at that index.
*/
public Long asLong(Integer index) {
this.validate();
return JNA.INSTANCE.value_at_index_into_long(this.rawPointer, index);
return JNA.INSTANCE.value_at_index_into_long(this.validPointer(), index);
}
/**
@ -76,8 +74,7 @@ public class TupleResult extends RustObject {
* @return The Entid at that index.
*/
public Long asEntid(Integer index) {
this.validate();
return JNA.INSTANCE.value_at_index_into_entid(this.rawPointer, index);
return JNA.INSTANCE.value_at_index_into_entid(this.validPointer(), index);
}
/**
@ -88,8 +85,7 @@ public class TupleResult extends RustObject {
* @return The keyword at that index.
*/
public String asKeyword(Integer index) {
this.validate();
return JNA.INSTANCE.value_at_index_into_kw(this.rawPointer, index);
return getAndConsumeMentatString(JNA.INSTANCE.value_at_index_into_kw(this.validPointer(), index));
}
/**
@ -100,8 +96,7 @@ public class TupleResult extends RustObject {
* @return The {@link Boolean} at that index.
*/
public Boolean asBool(Integer index) {
this.validate();
return JNA.INSTANCE.value_at_index_into_boolean(this.rawPointer, index) == 0 ? false : true;
return JNA.INSTANCE.value_at_index_into_boolean(this.validPointer(), index) == 0 ? false : true;
}
/**
@ -112,8 +107,7 @@ public class TupleResult extends RustObject {
* @return The {@link Double} at that index.
*/
public Double asDouble(Integer index) {
this.validate();
return JNA.INSTANCE.value_at_index_into_double(this.rawPointer, index);
return JNA.INSTANCE.value_at_index_into_double(this.validPointer(), index);
}
/**
@ -124,8 +118,7 @@ public class TupleResult extends RustObject {
* @return The {@link Date} at that index.
*/
public Date asDate(Integer index) {
this.validate();
return new Date(JNA.INSTANCE.value_at_index_into_timestamp(this.rawPointer, index) * 1_000);
return new Date(JNA.INSTANCE.value_at_index_into_timestamp(this.validPointer(), index) * 1_000);
}
/**
@ -136,8 +129,8 @@ public class TupleResult extends RustObject {
* @return The {@link String} at that index.
*/
public String asString(Integer index) {
this.validate();
return JNA.INSTANCE.value_at_index_into_string(this.rawPointer, index);
return getAndConsumeMentatString(
JNA.INSTANCE.value_at_index_into_string(this.validPointer(), index));
}
/**
@ -148,14 +141,12 @@ public class TupleResult extends RustObject {
* @return The {@link UUID} at that index.
*/
public UUID asUUID(Integer index) {
this.validate();
return getUUIDFromPointer(JNA.INSTANCE.value_at_index_into_uuid(this.rawPointer, index));
return getAndConsumeUUIDPointer(
JNA.INSTANCE.value_at_index_into_uuid(this.validPointer(), index));
}
@Override
public void close() {
if (this.rawPointer != null) {
JNA.INSTANCE.typed_value_list_destroy(this.rawPointer);
}
protected void destroyPointer(JNA.TypedValueList p) {
JNA.INSTANCE.typed_value_list_destroy(p);
}
}

View file

@ -13,7 +13,6 @@ package org.mozilla.mentat;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import java.io.Closeable;
import java.util.Arrays;
import java.util.List;
@ -22,27 +21,24 @@ import java.util.List;
* These changes contain the transaction identifier, a {@link Pointer} to a list of affected attribute
* Entids and the number of items that the list contains.
*/
public class TxChange extends Structure implements Closeable {
public class TxChange extends Structure {
public static class ByReference extends TxChange implements Structure.ByReference {
}
public static class ByValue extends TxChange implements Structure.ByValue {
}
public int txid;
public long txid;
public Pointer changes;
public int numberOfItems;
// Used by the Swift counterpart, JNA does this for us automagically.
// But we still need it here so that the number of fields and their order is correct
public int changes_len;
public long changes_len;
/**
* Get the affected attributes for this transaction
* @return The changes as a list of Entids of affected attributes
*/
public List<Long> getChanges() {
final long[] array = (long[]) changes.getLongArray(0, numberOfItems);
Long[] longArray = new Long[numberOfItems];
final long[] array = (long[]) changes.getLongArray(0, (int)changes_len);
Long[] longArray = new Long[(int)changes_len];
int idx = 0;
for (long change: array) {
longArray[idx++] = change;
@ -52,13 +48,8 @@ public class TxChange extends Structure implements Closeable {
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("txid", "changes", "changes_len", "numberOfItems");
return Arrays.asList("txid", "changes", "changes_len");
}
@Override
public void close() {
if (this.getPointer() != null) {
JNA.INSTANCE.destroy(this.getPointer());
}
}
// Note: Rust has ownership of this data.
}

View file

@ -12,14 +12,13 @@ package org.mozilla.mentat;
import com.sun.jna.Structure;
import java.io.Closeable;
import java.util.Arrays;
import java.util.List;
/**
* Represents a C struct containing a list of {@link TxChange}s that occured.
*/
public class TxChangeList extends Structure implements Closeable {
public class TxChangeList extends Structure {
public static class ByReference extends TxChangeList implements Structure.ByReference {
}
@ -27,30 +26,21 @@ public class TxChangeList extends Structure implements Closeable {
}
public TxChange.ByReference reports;
public int numberOfItems;
// Used by the Swift counterpart, JNA does this for us automagically.
// // But we still need it here so that the number of fields and their order is correct
public int len;
public long len;
/**
* Get the changes that occured
* @return a list of {@link TxChange}s for the notification
*/
public List<TxChange> getReports() {
final TxChange[] array = (TxChange[]) reports.toArray(numberOfItems);
final TxChange[] array = (TxChange[]) reports.toArray((int)len);
return Arrays.asList(array);
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("reports", "numberOfItems", "len");
return Arrays.asList("reports", "len");
}
@Override
public void close() {
final TxChange[] nativeReports = (TxChange[]) reports.toArray(numberOfItems);
for (TxChange nativeReport : nativeReports) {
nativeReport.close();
}
}
// Note: Rust has ownership of this data.
}

View file

@ -33,14 +33,14 @@ import java.util.Date;
* long aEntid = report.getEntidForTempId("a");
*}</pre>
*/
public class TxReport extends RustObject {
public class TxReport extends RustObject<JNA.TxReport> {
private Long txId;
private Date txInstant;
public TxReport(Pointer pointer) {
this.rawPointer = pointer;
public TxReport(JNA.TxReport pointer) {
super(pointer);
}
/**
@ -49,7 +49,7 @@ public class TxReport extends RustObject {
*/
public Long getTxId() {
if (this.txId == null) {
this.txId = JNA.INSTANCE.tx_report_get_entid(this.rawPointer);
this.txId = JNA.INSTANCE.tx_report_get_entid(this.validPointer());
}
return this.txId;
@ -61,7 +61,7 @@ public class TxReport extends RustObject {
*/
public Date getTxInstant() {
if (this.txInstant == null) {
this.txInstant = new Date(JNA.INSTANCE.tx_report_get_tx_instant(this.rawPointer));
this.txInstant = new Date(JNA.INSTANCE.tx_report_get_tx_instant(this.validPointer()));
}
return this.txInstant;
}
@ -72,18 +72,19 @@ public class TxReport extends RustObject {
* @return The `Entid` for the temporary identifier, if present, otherwise `null`.
*/
public Long getEntidForTempId(String tempId) {
Pointer longPointer = JNA.INSTANCE.tx_report_entity_for_temp_id(this.rawPointer, tempId);
Pointer longPointer = JNA.INSTANCE.tx_report_entity_for_temp_id(this.validPointer(), tempId);
if (longPointer == null) {
return null;
}
return longPointer.getLong(0);
try {
return longPointer.getLong(0);
} finally {
JNA.INSTANCE.destroy(longPointer);
}
}
@Override
public void close() {
if (this.rawPointer != null) {
JNA.INSTANCE.tx_report_destroy(this.rawPointer);
}
protected void destroyPointer(JNA.TxReport p) {
JNA.INSTANCE.tx_report_destroy(p);
}
}

View file

@ -25,16 +25,12 @@ import java.util.UUID;
* Also, due to the consuming nature of the FFI layer, this class also manages it's raw pointer, nilling it after calling the
* FFI conversion function so that the underlying base class can manage cleanup.
*/
public class TypedValue extends RustObject {
public class TypedValue extends RustObject<JNA.TypedValue> {
private Object value;
private boolean isConsumed() {
return this.rawPointer == null;
}
public TypedValue(Pointer pointer) {
this.rawPointer = pointer;
public TypedValue(JNA.TypedValue pointer) {
super(pointer);
}
/**
@ -44,8 +40,7 @@ public class TypedValue extends RustObject {
*/
public Long asLong() {
if (!this.isConsumed()) {
this.value = JNA.INSTANCE.typed_value_into_long(this.rawPointer);
this.rawPointer = null;
this.value = JNA.INSTANCE.typed_value_into_long(this.consumePointer());
}
return (Long)value;
}
@ -57,8 +52,7 @@ public class TypedValue extends RustObject {
*/
public Long asEntid() {
if (!this.isConsumed()) {
this.value = JNA.INSTANCE.typed_value_into_entid(this.rawPointer);
this.rawPointer = null;
this.value = JNA.INSTANCE.typed_value_into_entid(this.consumePointer());
}
return (Long)value;
}
@ -70,8 +64,7 @@ public class TypedValue extends RustObject {
*/
public String asKeyword() {
if (!this.isConsumed()) {
this.value = JNA.INSTANCE.typed_value_into_kw(this.rawPointer);
this.rawPointer = null;
this.value = getAndConsumeMentatString(JNA.INSTANCE.typed_value_into_kw(this.consumePointer()));
}
return (String)value;
}
@ -83,9 +76,8 @@ public class TypedValue extends RustObject {
*/
public Boolean asBoolean() {
if (!this.isConsumed()) {
long value = JNA.INSTANCE.typed_value_into_boolean(this.rawPointer);
long value = JNA.INSTANCE.typed_value_into_boolean(this.consumePointer());
this.value = value == 0 ? false : true;
this.rawPointer = null;
}
return (Boolean) this.value;
}
@ -97,8 +89,7 @@ public class TypedValue extends RustObject {
*/
public Double asDouble() {
if (!this.isConsumed()) {
this.value = JNA.INSTANCE.typed_value_into_double(this.rawPointer);
this.rawPointer = null;
this.value = JNA.INSTANCE.typed_value_into_double(this.consumePointer());
}
return (Double)value;
}
@ -110,8 +101,7 @@ public class TypedValue extends RustObject {
*/
public Date asDate() {
if (!this.isConsumed()) {
this.value = new Date(JNA.INSTANCE.typed_value_into_timestamp(this.rawPointer) * 1_000);
this.rawPointer = null;
this.value = new Date(JNA.INSTANCE.typed_value_into_timestamp(this.consumePointer()) * 1_000);
}
return (Date)this.value;
}
@ -123,8 +113,8 @@ public class TypedValue extends RustObject {
*/
public String asString() {
if (!this.isConsumed()) {
this.value = JNA.INSTANCE.typed_value_into_string(this.rawPointer);
this.rawPointer = null;
this.value = getAndConsumeMentatString(
JNA.INSTANCE.typed_value_into_string(this.consumePointer()));
}
return (String)value;
}
@ -136,16 +126,13 @@ public class TypedValue extends RustObject {
*/
public UUID asUUID() {
if (!this.isConsumed()) {
this.value = getUUIDFromPointer(JNA.INSTANCE.typed_value_into_uuid(this.rawPointer));
this.rawPointer = null;
this.value = getAndConsumeUUIDPointer(JNA.INSTANCE.typed_value_into_uuid(this.consumePointer()));
}
return (UUID)this.value;
}
@Override
public void close() {
if (this.rawPointer != null) {
JNA.INSTANCE.typed_value_destroy(this.rawPointer);
}
protected void destroyPointer(JNA.TypedValue p) {
JNA.INSTANCE.typed_value_destroy(p);
}
}

View file

@ -11,7 +11,7 @@
7B64E44D209094520063909F /* InProgressBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B64E44A209094510063909F /* InProgressBuilder.swift */; };
7B64E44E209094520063909F /* EntityBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B64E44B209094510063909F /* EntityBuilder.swift */; };
7B64E44F209094520063909F /* InProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B64E44C209094520063909F /* InProgress.swift */; };
7B74483D208DF667006CFFB0 /* Result+Unwrap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B74483C208DF667006CFFB0 /* Result+Unwrap.swift */; };
7B74483D208DF667006CFFB0 /* RustError+Unwrap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B74483C208DF667006CFFB0 /* RustError+Unwrap.swift */; };
7BAE75A42089022B00895D37 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BAE75A32089022B00895D37 /* libsqlite3.tbd */; };
7BDB96942077C299009D0651 /* Mentat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BDB968A2077C299009D0651 /* Mentat.framework */; };
7BDB96992077C299009D0651 /* MentatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB96982077C299009D0651 /* MentatTests.swift */; };
@ -29,6 +29,8 @@
7BDB96C9207B735A009D0651 /* fixtures in Resources */ = {isa = PBXBuildFile; fileRef = 7BDB96C8207B735A009D0651 /* fixtures */; };
7BDB96CC207B7684009D0651 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB96CB207B7684009D0651 /* Errors.swift */; };
7BEB7D2C207D03DA000369AD /* TxReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEB7D2B207D03DA000369AD /* TxReport.swift */; };
D53A75B820D2DD3D00BAD7EA /* String+Destroying.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53A75B720D2DD3D00BAD7EA /* String+Destroying.swift */; };
D574353420DC26C7007C92EB /* UUID+Destroying.swift in Sources */ = {isa = PBXBuildFile; fileRef = D574353320DC26C7007C92EB /* UUID+Destroying.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -58,7 +60,7 @@
7B64E44A209094510063909F /* InProgressBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InProgressBuilder.swift; sourceTree = "<group>"; };
7B64E44B209094510063909F /* EntityBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntityBuilder.swift; sourceTree = "<group>"; };
7B64E44C209094520063909F /* InProgress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InProgress.swift; sourceTree = "<group>"; };
7B74483C208DF667006CFFB0 /* Result+Unwrap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Result+Unwrap.swift"; path = "Mentat/Extensions/Result+Unwrap.swift"; sourceTree = SOURCE_ROOT; };
7B74483C208DF667006CFFB0 /* RustError+Unwrap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "RustError+Unwrap.swift"; path = "Mentat/Extensions/RustError+Unwrap.swift"; sourceTree = SOURCE_ROOT; };
7BAE75A32089022B00895D37 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
7BDB968A2077C299009D0651 /* Mentat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Mentat.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7BDB968D2077C299009D0651 /* Mentat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Mentat.h; sourceTree = "<group>"; };
@ -81,6 +83,8 @@
7BDB96CB207B7684009D0651 /* Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = "<group>"; };
7BEB7D23207BE2AF000369AD /* libmentat_ffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmentat_ffi.a; path = ../../../target/universal/release/libmentat_ffi.a; sourceTree = "<group>"; };
7BEB7D2B207D03DA000369AD /* TxReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TxReport.swift; sourceTree = "<group>"; };
D53A75B720D2DD3D00BAD7EA /* String+Destroying.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Destroying.swift"; sourceTree = "<group>"; };
D574353320DC26C7007C92EB /* UUID+Destroying.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UUID+Destroying.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -193,8 +197,10 @@
7BDB96C42077D346009D0651 /* Extensions */ = {
isa = PBXGroup;
children = (
7B74483C208DF667006CFFB0 /* Result+Unwrap.swift */,
7B74483C208DF667006CFFB0 /* RustError+Unwrap.swift */,
D574353320DC26C7007C92EB /* UUID+Destroying.swift */,
7BDB96C52077D346009D0651 /* Date+Int64.swift */,
D53A75B720D2DD3D00BAD7EA /* String+Destroying.swift */,
);
path = Extensions;
sourceTree = "<group>";
@ -331,6 +337,7 @@
buildActionMask = 2147483647;
files = (
7BDB96B32077C38E009D0651 /* RustObject.swift in Sources */,
D53A75B820D2DD3D00BAD7EA /* String+Destroying.swift in Sources */,
7BDB96C62077D347009D0651 /* Date+Int64.swift in Sources */,
7BEB7D2C207D03DA000369AD /* TxReport.swift in Sources */,
7BDB96B42077C38E009D0651 /* OptionalRustObject.swift in Sources */,
@ -339,10 +346,11 @@
7BDB96CC207B7684009D0651 /* Errors.swift in Sources */,
7BDB96B02077C38E009D0651 /* Mentat.swift in Sources */,
7BDB96B72077C38E009D0651 /* TypedValue.swift in Sources */,
D574353420DC26C7007C92EB /* UUID+Destroying.swift in Sources */,
7B64E44E209094520063909F /* EntityBuilder.swift in Sources */,
7B64E44D209094520063909F /* InProgressBuilder.swift in Sources */,
7BDB96B52077C38E009D0651 /* TupleResult.swift in Sources */,
7B74483D208DF667006CFFB0 /* Result+Unwrap.swift in Sources */,
7B74483D208DF667006CFFB0 /* RustError+Unwrap.swift in Sources */,
7B64E44F209094520063909F /* InProgress.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View file

@ -82,7 +82,7 @@ open class TypedValue: OptionalRustObject {
}
if !self.isConsumed() {
self.value = String(cString: typed_value_into_kw(self.raw!))
self.value = String(destroyingRustString: typed_value_into_kw(self.raw!))
}
return self.value as! String
}
@ -152,7 +152,7 @@ open class TypedValue: OptionalRustObject {
}
if !self.isConsumed() {
self.value = String(cString: typed_value_into_string(self.raw!))
self.value = String(destroyingRustString: typed_value_into_string(self.raw!));
}
return self.value as! String
}
@ -169,8 +169,8 @@ open class TypedValue: OptionalRustObject {
}
if !self.isConsumed() {
let bytes = typed_value_into_uuid(self.raw!).pointee
self.value = UUID(uuid: bytes)
let bytes = typed_value_into_uuid(self.raw!);
self.value = UUID(destroyingRustUUID: bytes);
}
return self.value as! UUID?
}

View file

@ -1,50 +0,0 @@
/* Copyright 2018 Mozilla
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. */
import Foundation
import MentatStore
public extension Result {
/**
Force unwraps a result.
Expects there to be a value attached and throws an error is there is not.
- Throws: `ResultError.error` if the result contains an error
- Throws: `ResultError.empty` if the result contains no error but also no result.
- Returns: The pointer to the successful result value.
*/
@discardableResult public func unwrap() throws -> UnsafeMutableRawPointer {
guard let success = self.ok else {
if let error = self.err {
throw ResultError.error(message: String(cString: error))
}
throw ResultError.empty
}
return success
}
/**
Unwraps an optional result, yielding either a successful value or a nil.
- Throws: `ResultError.error` if the result contains an error
- Returns: The pointer to the successful result value, or nil if no value is present.
*/
@discardableResult public func tryUnwrap() throws -> UnsafeMutableRawPointer? {
guard let success = self.ok else {
if let error = self.err {
throw ResultError.error(message: String(cString: error))
}
return nil
}
return success
}
}

View file

@ -0,0 +1,48 @@
/* Copyright 2018 Mozilla
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. */
import Foundation
import MentatStore
extension RustError {
@discardableResult
public static func unwrap(_ callback: (UnsafeMutablePointer<RustError>) throws -> OpaquePointer?) throws -> OpaquePointer {
var err = RustError(message: nil)
guard let result = try callback(&err) else {
if let message = err.message {
throw ResultError.error(message: String(destroyingRustString: message))
}
throw ResultError.empty
}
return result;
}
@discardableResult
public static func tryUnwrap(_ callback: (UnsafeMutablePointer<RustError>) throws -> OpaquePointer?) throws -> OpaquePointer? {
var err = RustError(message: nil)
guard let result = try callback(&err) else {
if let message = err.message {
throw ResultError.error(message: String(destroyingRustString: message))
}
return nil
}
return result;
}
public static func withErrorCheck(_ callback: (UnsafeMutablePointer<RustError>) throws -> Void) throws {
var err = RustError(message: nil)
try callback(&err);
if let message = err.message {
throw ResultError.error(message: String(destroyingRustString: message))
}
}
}

View file

@ -0,0 +1,21 @@
/* Copyright 2018 Mozilla
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. */
import Foundation
import MentatStore
public extension String {
/** Helper to construct a String from a Rust string without leaking it. */
public init(destroyingRustString rustCString: UnsafeMutablePointer<CChar>) {
defer { rust_c_string_destroy(rustCString); }
self.init(cString: rustCString)
}
}

View file

@ -0,0 +1,21 @@
/* Copyright 2018 Mozilla
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. */
import Foundation
import MentatStore
public extension UUID {
/** Helper to construct a UUID from a Rust [u8; 16] without leaking it. */
public init(destroyingRustUUID rawUUID: UnsafeMutablePointer<uuid_t>) {
defer { uuid_destroy(rawUUID); }
self.init(uuid: rawUUID.pointee)
}
}

View file

@ -77,14 +77,16 @@ open class Mentat: RustObject {
- Throws: `ResultError.error` if an error occured while trying to cache the attribute.
*/
open func cache(attribute: String, direction: CacheDirection) throws {
switch direction {
case .forward:
try store_cache_attribute_forward(self.raw, attribute).pointee.tryUnwrap()
case .reverse:
try store_cache_attribute_reverse(self.raw, attribute).pointee.tryUnwrap()
case .both:
try store_cache_attribute_bi_directional(self.raw, attribute).pointee.tryUnwrap()
}
try RustError.withErrorCheck({err in
switch direction {
case .forward:
store_cache_attribute_forward(self.raw, attribute, err)
case .reverse:
store_cache_attribute_reverse(self.raw, attribute, err)
case .both:
store_cache_attribute_bi_directional(self.raw, attribute, err)
}
});
}
/**
@ -96,8 +98,7 @@ open class Mentat: RustObject {
- Returns: The `TxReport` of the completed transaction
*/
open func transact(transaction: String) throws -> TxReport {
let result = store_transact(self.raw, transaction).pointee
return TxReport(raw: try result.unwrap())
return TxReport(raw: try RustError.unwrap({err in store_transact(self.raw, transaction, err) }))
}
/**
@ -109,8 +110,7 @@ open class Mentat: RustObject {
- Returns: The `InProgress` used to manage the transaction
*/
open func beginTransaction() throws -> InProgress {
let result = store_begin_transaction(self.raw).pointee;
return InProgress(raw: try result.unwrap())
return InProgress(raw: try RustError.unwrap({err in store_begin_transaction(self.raw, err) }));
}
/**
@ -122,8 +122,7 @@ open class Mentat: RustObject {
- Returns: an `InProgressBuilder` for this `InProgress`
*/
open func entityBuilder() throws -> InProgressBuilder {
let result = store_in_progress_builder(self.raw).pointee
return InProgressBuilder(raw: try result.unwrap())
return InProgressBuilder(raw: try RustError.unwrap({err in store_in_progress_builder(self.raw, err) }))
}
/**
@ -138,8 +137,8 @@ open class Mentat: RustObject {
- Returns: an `EntityBuilder` for this `InProgress`
*/
open func entityBuilder(forEntid entid: Entid) throws -> EntityBuilder {
let result = store_entity_builder_from_entid(self.raw, entid).pointee
return EntityBuilder(raw: try result.unwrap())
return EntityBuilder(raw: try RustError.unwrap({err in
store_entity_builder_from_entid(self.raw, entid, err) }))
}
/**
@ -154,8 +153,9 @@ open class Mentat: RustObject {
- Returns: an `EntityBuilder` for this `InProgress`
*/
open func entityBuilder(forTempId tempId: String) throws -> EntityBuilder {
let result = store_entity_builder_from_temp_id(self.raw, tempId).pointee
return EntityBuilder(raw: try result.unwrap())
return EntityBuilder(raw: try RustError.unwrap({err in
store_entity_builder_from_temp_id(self.raw, tempId, err)
}))
}
/**
@ -189,8 +189,9 @@ open class Mentat: RustObject {
- Returns: The `TypedValue` containing the value of the attribute for the entity.
*/
open func value(forAttribute attribute: String, ofEntity entid: Entid) throws -> TypedValue? {
let result = store_value_for_attribute(self.raw, entid, attribute).pointee
return TypedValue(raw: try result.unwrap())
return TypedValue(raw: try RustError.unwrap({err in
store_value_for_attribute(self.raw, entid, attribute, err)
}));
}
// Destroys the pointer by passing it back into Rust to be cleaned up

View file

@ -245,14 +245,15 @@ open class Query: OptionalRustObject {
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the query has previously been executed.
*/
open func run(callback: @escaping (RelResult?) -> Void) throws {
let result = query_builder_execute(try! self.validPointer())
var error = RustError(message: nil)
let result = query_builder_execute(try! self.validPointer(), &error);
self.raw = nil
if let err = result.pointee.err {
let message = String(cString: err)
if let err = error.message {
let message = String(destroyingRustString: err)
throw QueryError.executionFailed(message: message)
}
guard let results = result.pointee.ok else {
guard let results = result else {
callback(nil)
return
}
@ -269,18 +270,19 @@ open class Query: OptionalRustObject {
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the query has previously been executed.
*/
open func runScalar(callback: @escaping (TypedValue?) -> Void) throws {
let result = query_builder_execute_scalar(try! self.validPointer())
var error = RustError(message: nil)
let result = query_builder_execute_scalar(try! self.validPointer(), &error)
self.raw = nil
if let err = result.pointee.err {
let message = String(cString: err)
if let err = error.message {
let message = String(destroyingRustString: err)
throw QueryError.executionFailed(message: message)
}
guard let results = result.pointee.ok else {
guard let results = result else {
callback(nil)
return
}
callback(TypedValue(raw: OpaquePointer(results)))
callback(TypedValue(raw: results))
}
/**
@ -293,14 +295,15 @@ open class Query: OptionalRustObject {
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the query has previously been executed.
*/
open func runColl(callback: @escaping (ColResult?) -> Void) throws {
let result = query_builder_execute_coll(try! self.validPointer())
var error = RustError(message: nil)
let result = query_builder_execute_coll(try! self.validPointer(), &error)
self.raw = nil
if let err = result.pointee.err {
let message = String(cString: err)
throw QueryError.executionFailed(message: message)
if let err = error.message {
let message = String(destroyingRustString: err)
throw QueryError.executionFailed(message: message)
}
guard let results = result.pointee.ok else {
guard let results = result else {
callback(nil)
return
}
@ -317,18 +320,19 @@ open class Query: OptionalRustObject {
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the query has previously been executed.
*/
open func runTuple(callback: @escaping (TupleResult?) -> Void) throws {
let result = query_builder_execute_tuple(try! self.validPointer())
var error = RustError(message: nil)
let result = query_builder_execute_tuple(try! self.validPointer(), &error)
self.raw = nil
if let err = result.pointee.err {
let message = String(cString: err)
if let err = error.message {
let message = String(destroyingRustString: err)
throw QueryError.executionFailed(message: message)
}
guard let results = result.pointee.ok else {
guard let results = result else {
callback(nil)
return
}
callback(TupleResult(raw: OpaquePointer(results)))
callback(TupleResult(raw: results))
}
override open func cleanup(pointer: OpaquePointer) {

View file

@ -55,7 +55,7 @@ open class RelResult: OptionalRustObject {
}
override open func cleanup(pointer: OpaquePointer) {
destroy(UnsafeMutableRawPointer(pointer))
typed_value_result_set_destroy(pointer)
}
}

View file

@ -77,7 +77,8 @@ open class TupleResult: OptionalRustObject {
- Returns: The keyword `String` at that index.
*/
open func asKeyword(index: Int) -> String {
return String(cString: value_at_index_into_kw(self.raw!, Int32(index)))
let str = value_at_index_into_kw(self.raw!, Int32(index));
return String(destroyingRustString: str);
}
/**
@ -129,7 +130,8 @@ open class TupleResult: OptionalRustObject {
- Returns: The `String` at that index.
*/
open func asString(index: Int) -> String {
return String(cString: value_at_index_into_string(self.raw!, Int32(index)))
let str = value_at_index_into_string(self.raw!, Int32(index));
return String(destroyingRustString: str)
}
/**
@ -142,7 +144,8 @@ open class TupleResult: OptionalRustObject {
- Returns: The `UUID` at that index.
*/
open func asUUID(index: Int) -> UUID? {
return UUID(uuid: value_at_index_into_uuid(self.raw!, Int32(index)).pointee)
let uuid = value_at_index_into_uuid(self.raw!, Int32(index));
return UUID(destroyingRustUUID: uuid)
}
override open func cleanup(pointer: OpaquePointer) {

View file

@ -38,7 +38,7 @@ open class RustObject: Destroyable {
}
self.raw = r
}
public func getRaw() -> OpaquePointer {
return self.raw
}
@ -46,7 +46,7 @@ open class RustObject: Destroyable {
deinit {
self.cleanup(pointer: self.raw)
}
open func cleanup(pointer: OpaquePointer) {
fatalError("\(cleanup) is not implemented.")
}

View file

@ -69,7 +69,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/long`.
*/
open func add(keyword: String, long value: Int64) throws {
try entity_builder_add_long(try self.validPointer(), keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_add_long(try self.validPointer(), keyword, value, err)
})
}
/**
@ -84,7 +86,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/ref`.
*/
open func add(keyword: String, reference value: Int64) throws {
try entity_builder_add_ref(try self.validPointer(), keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_add_ref(try self.validPointer(), keyword, value, err)
})
}
/**
@ -99,7 +103,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/keyword`.
*/
open func add(keyword: String, keyword value: String) throws {
try entity_builder_add_keyword(try self.validPointer(), keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_add_keyword(try self.validPointer(), keyword, value, err)
})
}
/**
@ -114,7 +120,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/boolean`.
*/
open func add(keyword: String, boolean value: Bool) throws {
try entity_builder_add_boolean(try self.validPointer(), keyword, value ? 1 : 0).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_add_boolean(try self.validPointer(), keyword, value ? 1 : 0, err)
})
}
/**
@ -129,7 +137,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/double`.
*/
open func add(keyword: String, double value: Double) throws {
try entity_builder_add_double(try self.validPointer(), keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_add_double(try self.validPointer(), keyword, value, err)
})
}
/**
@ -145,7 +155,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/instant`.
*/
open func add(keyword: String, date value: Date) throws {
try entity_builder_add_timestamp(try self.validPointer(), keyword, value.toMicroseconds()).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_add_timestamp(try self.validPointer(), keyword, value.toMicroseconds(), err)
})
}
/**
@ -160,7 +172,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/string`.
*/
open func add(keyword: String, string value: String) throws {
try entity_builder_add_string(try self.validPointer(), keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_add_string(try self.validPointer(), keyword, value, err)
})
}
/**
@ -177,7 +191,9 @@ open class EntityBuilder: OptionalRustObject {
open func add(keyword: String, uuid value: UUID) throws {
var rawUuid = value.uuid
let _ = try withUnsafePointer(to: &rawUuid) { uuidPtr in
try entity_builder_add_uuid(try self.validPointer(), keyword, uuidPtr).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_add_uuid(try self.validPointer(), keyword, uuidPtr, err)
})
}
}
@ -193,7 +209,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/long`.
*/
open func retract(keyword: String, long value: Int64) throws {
try entity_builder_retract_long(try self.validPointer(), keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_retract_long(try self.validPointer(), keyword, value, err)
})
}
/**
@ -208,7 +226,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/ref`.
*/
open func retract(keyword: String, reference value: Int64) throws {
try entity_builder_retract_ref(try self.validPointer(), keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_retract_ref(try self.validPointer(), keyword, value, err)
})
}
/**
@ -223,7 +243,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/keyword`.
*/
open func retract(keyword: String, keyword value: String) throws {
try entity_builder_retract_keyword(try self.validPointer(), keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_retract_keyword(try self.validPointer(), keyword, value, err)
})
}
/**
@ -238,7 +260,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/boolean`.
*/
open func retract(keyword: String, boolean value: Bool) throws {
try entity_builder_retract_boolean(try self.validPointer(), keyword, value ? 1 : 0).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_retract_boolean(try self.validPointer(), keyword, value ? 1 : 0, err)
})
}
/**
@ -253,7 +277,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/double`.
*/
open func retract(keyword: String, double value: Double) throws {
try entity_builder_retract_double(try self.validPointer(), keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_retract_double(try self.validPointer(), keyword, value, err)
})
}
/**
@ -268,7 +294,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/instant`.
*/
open func retract(keyword: String, date value: Date) throws {
try entity_builder_retract_timestamp(try self.validPointer(), keyword, value.toMicroseconds()).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_retract_timestamp(try self.validPointer(), keyword, value.toMicroseconds(), err)
})
}
/**
@ -283,7 +311,9 @@ open class EntityBuilder: OptionalRustObject {
is not `:db.type/string`.
*/
open func retract(keyword: String, string value: String) throws {
try entity_builder_retract_string(try self.validPointer(), keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_retract_string(try self.validPointer(), keyword, value, err)
})
}
@ -301,7 +331,9 @@ open class EntityBuilder: OptionalRustObject {
open func retract(keyword: String, uuid value: UUID) throws {
var rawUuid = value.uuid
let _ = try withUnsafePointer(to: &rawUuid) { uuidPtr in
try entity_builder_retract_uuid(try self.validPointer(), keyword, uuidPtr).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
entity_builder_retract_uuid(try self.validPointer(), keyword, uuidPtr, err)
})
}
}
@ -323,9 +355,12 @@ open class EntityBuilder: OptionalRustObject {
defer {
self.raw = nil
}
let result = entity_builder_transact(try self.validPointer()).pointee
let result = entity_builder_transact(try self.validPointer());
let inProgress = InProgress(raw: result.inProgress)
guard let report = try result.result.pointee.tryUnwrap() else {
if let errorMessage = result.error.message {
throw ResultError.error(message: String(destroyingRustString: errorMessage))
}
guard let report = result.txReport else {
return (inProgress, nil)
}
return (inProgress, TxReport(raw: report))
@ -346,9 +381,11 @@ open class EntityBuilder: OptionalRustObject {
defer {
self.raw = nil
}
return TxReport(raw: try entity_builder_commit(try self.validPointer()).pointee.unwrap())
return TxReport(raw: try RustError.unwrap({ err in
entity_builder_commit(try self.validPointer(), err)
}))
}
override open func cleanup(pointer: OpaquePointer) {
entity_builder_destroy(pointer)
}

View file

@ -126,7 +126,10 @@ open class InProgress: OptionalRustObject {
defer {
self.raw = nil
}
return EntityBuilder(raw: in_progress_entity_builder_from_temp_id(try self.validPointer(), tempId))
let builder = try RustError.unwrap({ err in
in_progress_entity_builder_from_temp_id(try self.validPointer(), tempId, err)
})
return EntityBuilder(raw: builder)
}
/**
@ -144,8 +147,10 @@ open class InProgress: OptionalRustObject {
- Returns: The `TxReport` generated by the transact.
*/
open func transact(transaction: String) throws -> TxReport {
let result = in_progress_transact(try self.validPointer(), transaction).pointee
return TxReport(raw: try result.unwrap())
let report = try RustError.unwrap({ err in
in_progress_transact(try self.validPointer(), transaction, err)
})
return TxReport(raw: report)
}
/**
@ -160,7 +165,9 @@ open class InProgress: OptionalRustObject {
defer {
self.raw = nil
}
try in_progress_commit(try self.validPointer()).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_commit(try self.validPointer(), err)
})
}
/**
@ -175,7 +182,9 @@ open class InProgress: OptionalRustObject {
defer {
self.raw = nil
}
try in_progress_rollback(try self.validPointer()).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_rollback(try self.validPointer(), err)
})
}
override open func cleanup(pointer: OpaquePointer) {

View file

@ -73,7 +73,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/long`.
*/
open func add(entid: Entid, keyword: String, long value: Int64) throws {
try in_progress_builder_add_long(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_add_long(try self.validPointer(), entid, keyword, value, err)
})
}
/**
@ -89,7 +91,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/ref`.
*/
open func add(entid: Entid, keyword: String, reference value: Entid) throws {
try in_progress_builder_add_ref(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_add_ref(try self.validPointer(), entid, keyword, value, err)
})
}
/**
@ -105,7 +109,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/keyword`.
*/
open func add(entid: Entid, keyword: String, keyword value: String) throws {
try in_progress_builder_add_keyword(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_add_keyword(try self.validPointer(), entid, keyword, value, err)
})
}
/**
@ -121,7 +127,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/boolean`.
*/
open func add(entid: Entid, keyword: String, boolean value: Bool) throws {
try in_progress_builder_add_boolean(try self.validPointer(), entid, keyword, value ? 1 : 0).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_add_boolean(try self.validPointer(), entid, keyword, value ? 1 : 0, err)
})
}
/**
@ -137,7 +145,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/double`.
*/
open func add(entid: Entid, keyword: String, double value: Double) throws {
try in_progress_builder_add_double(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_add_double(try self.validPointer(), entid, keyword, value, err)
})
}
/**
@ -153,7 +163,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/instant`.
*/
open func add(entid: Entid, keyword: String, date value: Date) throws {
try in_progress_builder_add_timestamp(try self.validPointer(), entid, keyword, value.toMicroseconds()).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_add_timestamp(try self.validPointer(), entid, keyword, value.toMicroseconds(), err)
})
}
/**
@ -169,7 +181,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/string`.
*/
open func add(entid: Entid, keyword: String, string value: String) throws {
try in_progress_builder_add_string(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_add_string(try self.validPointer(), entid, keyword, value, err)
})
}
/**
@ -187,7 +201,9 @@ open class InProgressBuilder: OptionalRustObject {
open func add(entid: Entid, keyword: String, uuid value: UUID) throws {
var rawUuid = value.uuid
let _ = try withUnsafePointer(to: &rawUuid) { uuidPtr in
try in_progress_builder_add_uuid(try self.validPointer(), entid, keyword, uuidPtr).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_add_uuid(try self.validPointer(), entid, keyword, uuidPtr, err)
})
}
}
@ -204,7 +220,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/long`.
*/
open func retract(entid: Entid, keyword: String, long value: Int64) throws {
try in_progress_builder_retract_long(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_retract_long(try self.validPointer(), entid, keyword, value, err)
})
}
/**
@ -220,7 +238,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/ref`.
*/
open func retract(entid: Entid, keyword: String, reference value: Entid) throws {
try in_progress_builder_retract_ref(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_retract_ref(try self.validPointer(), entid, keyword, value, err)
})
}
/**
@ -236,7 +256,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/keyword`.
*/
open func retract(entid: Entid, keyword: String, keyword value: String) throws {
try in_progress_builder_retract_keyword(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_retract_keyword(try self.validPointer(), entid, keyword, value, err)
})
}
/**
@ -252,7 +274,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/boolean`.
*/
open func retract(entid: Entid, keyword: String, boolean value: Bool) throws {
try in_progress_builder_retract_boolean(try self.validPointer(), entid, keyword, value ? 1 : 0).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_retract_boolean(try self.validPointer(), entid, keyword, value ? 1 : 0, err)
})
}
/**
@ -268,7 +292,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/double`.
*/
open func retract(entid: Entid, keyword: String, double value: Double) throws {
try in_progress_builder_retract_double(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_retract_double(try self.validPointer(), entid, keyword, value, err)
})
}
/**
@ -284,7 +310,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/instant`.
*/
open func retract(entid: Entid, keyword: String, date value: Date) throws {
try in_progress_builder_retract_timestamp(try self.validPointer(), entid, keyword, value.toMicroseconds()).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_retract_timestamp(try self.validPointer(), entid, keyword, value.toMicroseconds(), err)
})
}
/**
@ -300,7 +328,9 @@ open class InProgressBuilder: OptionalRustObject {
is not `:db.type/string`.
*/
open func retract(entid: Entid, keyword: String, string value: String) throws {
try in_progress_builder_retract_string(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_retract_string(try self.validPointer(), entid, keyword, value, err)
})
}
/**
@ -318,7 +348,9 @@ open class InProgressBuilder: OptionalRustObject {
open func retract(entid: Entid, keyword: String, uuid value: UUID) throws {
var rawUuid = value.uuid
let _ = try withUnsafePointer(to: &rawUuid) { uuidPtr in
try in_progress_builder_retract_uuid(try self.validPointer(), entid, keyword, uuidPtr).pointee.tryUnwrap()
try RustError.withErrorCheck({ err in
in_progress_builder_retract_uuid(try self.validPointer(), entid, keyword, uuidPtr, err)
})
}
}
@ -340,9 +372,12 @@ open class InProgressBuilder: OptionalRustObject {
defer {
self.raw = nil
}
let result = in_progress_builder_transact(try self.validPointer()).pointee
let inProgress = InProgress(raw: result.inProgress)
guard let report = try result.result.pointee.tryUnwrap() else {
let result = in_progress_builder_transact(try self.validPointer())
if let errorMessage = result.error.message {
throw ResultError.error(message: String(destroyingRustString: errorMessage))
}
let inProgress = InProgress(raw: result.inProgress);
guard let report = result.txReport else {
return (inProgress, nil)
}
return (inProgress, TxReport(raw: report))
@ -363,7 +398,9 @@ open class InProgressBuilder: OptionalRustObject {
defer {
self.raw = nil
}
return TxReport(raw: try in_progress_builder_commit(try self.validPointer()).pointee.unwrap())
return TxReport(raw: try RustError.unwrap({err in
in_progress_builder_commit(try self.validPointer(), err)
}));
}
override open func cleanup(pointer: OpaquePointer) {

View file

@ -52,7 +52,9 @@ open class TxReport: RustObject {
guard let entidPtr = tx_report_entity_for_temp_id(self.raw, tempId) else {
return nil
}
return entidPtr.pointee
let entid = entidPtr.pointee;
destroy(entidPtr);
return entid
}
override open func cleanup(pointer: OpaquePointer) {

View file

@ -21,52 +21,69 @@
* macros and flags that will not be recognised by other C based languages.
*/
// Opaque Structs mapping to Rust types that are passed over the FFI boundary. In cases where the
// struct's name differs from the name used for the Rust type, it's noted in a comment.
struct EntityBuilder; // Note: a `mentat::EntityBuilder<mentat::InProgressBuilder<'a, 'c>>`
struct InProgress;
struct InProgressBuilder;
struct Query; // Note: a `mentat::QueryBuilder`
struct QueryResultRow; // Note: a `Vec<mentat::Binding>`
struct QueryResultRows; // Note: a `mentat::RelResult<Binding>`
struct QueryRowsIterator; // Note: a `mentat::BindingListIterator`
struct QueryRowIterator; // Note: a `mentat::BindingIterator`
struct Store;
struct TxReport;
struct TypedValue; // Note: a `mentat::Binding`
/*
A mapping of the TxChange repr(C) Rust object.
The memory for this is managed by Swift.
A mapping of the TransactionChange repr(C) Rust object.
The memory for this is managed by Rust.
*/
struct TxChange {
int64_t txid;
int64_t*_Nonnull* _Nonnull changes;
const int64_t* _Nonnull changes;
uint64_t len;
};
/*
A mapping of the TxChangeList repr(C) Rust object.
The memory for this is managed by Swift.
The memory for this is managed by Rust.
*/
struct TxChangeList {
struct TxChange*_Nonnull* _Nonnull reports;
const struct TxChange* _Nonnull reports;
uint64_t len;
};
typedef struct TxChangeList TxChangeList;
/*
A mapping of the ExternResult repr(C) Rust object.
The memory for this is managed by Swift.
*/
struct Result {
void* _Nullable ok;
char* _Nullable err;
/* Representation of the `ExternError` Rust type.
If `message` is not null, an error occur occurred (and we're responsible for freeing `message`,
using `rust_c_string_destroy`).
*/
struct RustError {
char *message;
};
typedef struct Result Result;
/*
A mapping of the ExternOption repr(C) Rust object.
The memory for this is managed by Swift.
A mapping of the ExternResult<()> repr(C) Rust object.
These are not allocated on the heap, but the memory for `ok` and `err`
is managed by Swift.
*/
struct Option {
void* _Nullable value;
};
typedef struct Option Option;
struct VoidResult { void* _Nullable ok; char* _Nullable err; };
#define DEFINE_RESULT(Name, Type) struct Name { struct Type *_Nullable ok; char *_Nullable err; }
/*
A mapping of the InProgressTransactResult repr(C) Rust object.
The memory for this is managed by Swift.
These are not allocated on the heap, but the memory for `inProgress`,
`txReport`, and `result.message` (if pressent)
as well as `result.ok` and `result.err`, are managed by Swift.
*/
struct InProgressTransactResult {
struct InProgress*_Nonnull inProgress;
struct Result*_Nonnull result;
struct InProgress *_Nonnull inProgress;
struct TxReport *_Nullable txReport;
struct RustError error;
};
typedef struct InProgressTransactResult InProgressTransactResult;
@ -84,24 +101,12 @@ typedef NS_ENUM(NSInteger, ValueType) {
ValueTypeUuid
};
// Opaque Structs mapping to Rust types that are passed over the FFI boundary
struct EntityBuilder;
struct InProgress;
struct InProgressBuilder;
struct Query;
struct QueryResultRow;
struct QueryResultRows;
struct QueryRowsIterator;
struct QueryRowIterator;
struct Store;
struct TxReport;
struct TypedValue;
// Store
struct Store*_Nonnull store_open(const char*_Nonnull uri);
// Destructors.
void destroy(void* _Nullable obj);
void uuid_destroy(uuid_t* _Nullable obj);
void query_builder_destroy(struct Query* _Nullable obj);
void store_destroy(struct Store* _Nonnull obj);
void tx_report_destroy(struct TxReport* _Nonnull obj);
@ -113,72 +118,73 @@ void typed_value_result_set_iter_destroy(struct QueryRowsIterator* _Nullable obj
void in_progress_destroy(struct InProgress* _Nullable obj);
void in_progress_builder_destroy(struct InProgressBuilder* _Nullable obj);
void entity_builder_destroy(struct EntityBuilder* _Nullable obj);
void rust_c_string_destroy(char *_Nullable s);
// caching
struct Result*_Nonnull store_cache_attribute_forward(struct Store*_Nonnull store, const char* _Nonnull attribute);
struct Result*_Nonnull store_cache_attribute_reverse(struct Store*_Nonnull store, const char* _Nonnull attribute);
struct Result*_Nonnull store_cache_attribute_bi_directional(struct Store*_Nonnull store, const char* _Nonnull attribute);
void store_cache_attribute_forward(struct Store*_Nonnull store, const char* _Nonnull attribute, struct RustError* _Nonnull error);
void store_cache_attribute_reverse(struct Store*_Nonnull store, const char* _Nonnull attribute, struct RustError* _Nonnull error);
void store_cache_attribute_bi_directional(struct Store*_Nonnull store, const char* _Nonnull attribute, struct RustError* _Nonnull error);
// transact
struct Result*_Nonnull store_transact(struct Store*_Nonnull store, const char* _Nonnull transaction);
const int64_t* _Nullable tx_report_entity_for_temp_id(const struct TxReport* _Nonnull report, const char* _Nonnull tempid);
int64_t tx_report_get_entid(const struct TxReport* _Nonnull report);
struct TxReport*_Nullable store_transact(struct Store*_Nonnull store, const char* _Nonnull transaction, struct RustError* _Nonnull error);
int64_t* _Nullable tx_report_entity_for_temp_id(const struct TxReport* _Nonnull report, const char* _Nonnull tempid);
int64_t tx_report_get_entid(const struct TxReport* _Nonnull report);
int64_t tx_report_get_tx_instant(const struct TxReport* _Nonnull report);
struct Result*_Nonnull store_begin_transaction(struct Store*_Nonnull store);
struct InProgress *_Nullable store_begin_transaction(struct Store*_Nonnull store, struct RustError* _Nonnull error);
// in progress
struct Result*_Nonnull in_progress_transact(struct InProgress*_Nonnull in_progress, const char* _Nonnull transaction);
struct Result*_Nonnull in_progress_commit(struct InProgress*_Nonnull in_progress);
struct Result*_Nonnull in_progress_rollback(struct InProgress*_Nonnull in_progress);
struct TxReport*_Nullable in_progress_transact(struct InProgress*_Nonnull in_progress, const char* _Nonnull transaction, struct RustError*_Nonnull err);
void in_progress_commit(struct InProgress*_Nonnull in_progress, struct RustError* _Nonnull error);
void in_progress_rollback(struct InProgress*_Nonnull in_progress, struct RustError* _Nonnull error);
// in_progress entity building
struct Result*_Nonnull store_in_progress_builder(struct Store*_Nonnull store);
struct InProgressBuilder*_Nullable store_in_progress_builder(struct Store*_Nonnull store, struct RustError* _Nonnull error);
struct InProgressBuilder*_Nonnull in_progress_builder(struct InProgress*_Nonnull in_progress);
struct EntityBuilder*_Nonnull in_progress_entity_builder_from_temp_id(struct InProgress*_Nonnull in_progress, const char*_Nonnull temp_id);
struct EntityBuilder*_Nonnull in_progress_entity_builder_from_temp_id(struct InProgress*_Nonnull in_progress, const char*_Nonnull temp_id, struct RustError* _Nonnull error);
struct EntityBuilder*_Nonnull in_progress_entity_builder_from_entid(struct InProgress*_Nonnull in_progress, const int64_t entid);
struct Result*_Nonnull in_progress_builder_add_string(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value);
struct Result*_Nonnull in_progress_builder_add_long(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull in_progress_builder_add_ref(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull in_progress_builder_add_keyword(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value);
struct Result*_Nonnull in_progress_builder_add_timestamp(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull in_progress_builder_add_boolean(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int32_t value);
struct Result*_Nonnull in_progress_builder_add_double(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const double value);
struct Result*_Nonnull in_progress_builder_add_uuid(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const uuid_t* _Nonnull value);
struct Result*_Nonnull in_progress_builder_retract_string(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value);
struct Result*_Nonnull in_progress_builder_retract_long(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull in_progress_builder_retract_ref(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull in_progress_builder_retract_keyword(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value);
struct Result*_Nonnull in_progress_builder_retract_timestamp(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull in_progress_builder_retract_boolean(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int32_t value);
struct Result*_Nonnull in_progress_builder_retract_double(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const double value);
struct Result*_Nonnull in_progress_builder_retract_uuid(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const uuid_t* _Nonnull value);
struct InProgressTransactResult*_Nonnull in_progress_builder_transact(struct InProgressBuilder*_Nonnull builder);
struct Result*_Nonnull in_progress_builder_commit(struct InProgressBuilder*_Nonnull builder);
void in_progress_builder_add_string(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value, struct RustError* _Nonnull error);
void in_progress_builder_add_long(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void in_progress_builder_add_ref(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void in_progress_builder_add_keyword(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value, struct RustError* _Nonnull error);
void in_progress_builder_add_timestamp(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void in_progress_builder_add_boolean(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int32_t value, struct RustError* _Nonnull error);
void in_progress_builder_add_double(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const double value, struct RustError* _Nonnull error);
void in_progress_builder_add_uuid(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const uuid_t* _Nonnull value, struct RustError* _Nonnull error);
void in_progress_builder_retract_string(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value, struct RustError* _Nonnull error);
void in_progress_builder_retract_long(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void in_progress_builder_retract_ref(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void in_progress_builder_retract_keyword(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value, struct RustError* _Nonnull error);
void in_progress_builder_retract_timestamp(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void in_progress_builder_retract_boolean(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int32_t value, struct RustError* _Nonnull error);
void in_progress_builder_retract_double(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const double value, struct RustError* _Nonnull error);
void in_progress_builder_retract_uuid(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const uuid_t* _Nonnull value, struct RustError* _Nonnull error);
struct InProgressTransactResult in_progress_builder_transact(struct InProgressBuilder*_Nonnull builder);
struct TxReport*_Nullable in_progress_builder_commit(struct InProgressBuilder*_Nonnull builder, struct RustError* _Nonnull error);
// entity building
struct Result*_Nonnull store_entity_builder_from_temp_id(struct Store*_Nonnull store, const char*_Nonnull temp_id);
struct Result*_Nonnull store_entity_builder_from_entid(struct Store*_Nonnull store, const int64_t entid);
struct Result*_Nonnull entity_builder_add_string(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value);
struct Result*_Nonnull entity_builder_add_long(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull entity_builder_add_ref(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull entity_builder_add_keyword(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value);
struct Result*_Nonnull entity_builder_add_boolean(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int32_t value);
struct Result*_Nonnull entity_builder_add_double(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const double value);
struct Result*_Nonnull entity_builder_add_timestamp(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull entity_builder_add_uuid(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const uuid_t* _Nonnull value);
struct Result*_Nonnull entity_builder_retract_string(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value);
struct Result*_Nonnull entity_builder_retract_long(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull entity_builder_retract_ref(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull entity_builder_retract_keyword(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value);
struct Result*_Nonnull entity_builder_retract_boolean(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int32_t value);
struct Result*_Nonnull entity_builder_retract_double(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const double value);
struct Result*_Nonnull entity_builder_retract_timestamp(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
struct Result*_Nonnull entity_builder_retract_uuid(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const uuid_t* _Nonnull value);
struct InProgressTransactResult*_Nonnull entity_builder_transact(struct InProgressBuilder*_Nonnull builder);
struct Result*_Nonnull entity_builder_commit(struct EntityBuilder*_Nonnull builder);
struct EntityBuilder*_Nullable store_entity_builder_from_temp_id(struct Store*_Nonnull store, const char*_Nonnull temp_id, struct RustError* _Nonnull error);
struct EntityBuilder*_Nullable store_entity_builder_from_entid(struct Store*_Nonnull store, const int64_t entid, struct RustError* _Nonnull error) ;
void entity_builder_add_string(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value, struct RustError* _Nonnull error);
void entity_builder_add_long(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void entity_builder_add_ref(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void entity_builder_add_keyword(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value, struct RustError* _Nonnull error);
void entity_builder_add_boolean(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int32_t value, struct RustError* _Nonnull error);
void entity_builder_add_double(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const double value, struct RustError* _Nonnull error);
void entity_builder_add_timestamp(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void entity_builder_add_uuid(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const uuid_t* _Nonnull value, struct RustError* _Nonnull error);
// Sync
struct Result*_Nonnull store_sync(struct Store*_Nonnull store, const char* _Nonnull user_uuid, const char* _Nonnull server_uri);
void entity_builder_retract_string(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value, struct RustError* _Nonnull error);
void entity_builder_retract_long(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void entity_builder_retract_ref(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void entity_builder_retract_keyword(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value, struct RustError* _Nonnull error);
void entity_builder_retract_boolean(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int32_t value, struct RustError* _Nonnull error);
void entity_builder_retract_double(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const double value, struct RustError* _Nonnull error);
void entity_builder_retract_timestamp(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value, struct RustError* _Nonnull error);
void entity_builder_retract_uuid(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const uuid_t* _Nonnull value, struct RustError* _Nonnull error);
struct InProgressTransactResult entity_builder_transact(struct EntityBuilder*_Nonnull builder);
struct TxReport*_Nullable entity_builder_commit(struct EntityBuilder*_Nonnull builder, struct RustError* _Nonnull error);
// Observers
void store_register_observer(struct Store*_Nonnull store, const char* _Nonnull key, const int64_t* _Nonnull attributes, const int64_t len, void (*_Nonnull callback_fn)(const char* _Nonnull key, const struct TxChangeList* _Nonnull reports));
@ -188,7 +194,7 @@ int64_t changelist_entry_at(const struct TxChange* _Nonnull report, size_t index
// Query
struct Query*_Nonnull store_query(struct Store*_Nonnull store, const char* _Nonnull query);
struct Result*_Nonnull store_value_for_attribute(struct Store*_Nonnull store, const int64_t entid, const char* _Nonnull attribute);
struct TypedValue*_Nullable store_value_for_attribute(struct Store*_Nonnull store, const int64_t entid, const char* _Nonnull attribute, struct RustError* _Nonnull error);
// Query Variable Binding
void query_builder_bind_long(struct Query*_Nonnull query, const char* _Nonnull var, const int64_t value);
@ -202,20 +208,20 @@ void query_builder_bind_string(struct Query*_Nonnull query, const char* _Nonnull
void query_builder_bind_uuid(struct Query*_Nonnull query, const char* _Nonnull var, const uuid_t* _Nonnull value);
// Query execution
struct Result*_Nonnull query_builder_execute(struct Query*_Nonnull query);
struct Result*_Nonnull query_builder_execute_scalar(struct Query*_Nonnull query);
struct Result*_Nonnull query_builder_execute_coll(struct Query*_Nonnull query);
struct Result*_Nonnull query_builder_execute_tuple(struct Query*_Nonnull query);
struct QueryResultRows* _Nullable query_builder_execute(struct Query*_Nonnull query, struct RustError* _Nonnull error);
struct TypedValue* _Nullable query_builder_execute_scalar(struct Query*_Nonnull query, struct RustError* _Nonnull error);
struct QueryResultRow* _Nullable query_builder_execute_coll(struct Query*_Nonnull query, struct RustError* _Nonnull error);
struct QueryResultRow* _Nullable query_builder_execute_tuple(struct Query*_Nonnull query, struct RustError* _Nonnull error);
// Query Result Processing
int64_t typed_value_into_long(struct TypedValue*_Nonnull value);
int64_t typed_value_into_entid(struct TypedValue*_Nonnull value);
const char* _Nonnull typed_value_into_kw(struct TypedValue*_Nonnull value);
char* _Nonnull typed_value_into_kw(struct TypedValue*_Nonnull value);
int32_t typed_value_into_boolean(struct TypedValue*_Nonnull value);
double typed_value_into_double(struct TypedValue*_Nonnull value);
int64_t typed_value_into_timestamp(struct TypedValue*_Nonnull value);
const char* _Nonnull typed_value_into_string(struct TypedValue*_Nonnull value);
const uuid_t* _Nonnull typed_value_into_uuid(struct TypedValue*_Nonnull value);
char* _Nonnull typed_value_into_string(struct TypedValue*_Nonnull value);
uuid_t* _Nonnull typed_value_into_uuid(struct TypedValue*_Nonnull value);
enum ValueType typed_value_value_type(struct TypedValue*_Nonnull value);
struct QueryResultRow* _Nullable row_at_index(struct QueryResultRows* _Nonnull rows, const int32_t index);
@ -227,14 +233,15 @@ struct TypedValue* _Nullable typed_value_list_iter_next(struct QueryRowIterator*
struct TypedValue* _Nonnull value_at_index(struct QueryResultRow* _Nonnull row, const int32_t index);
int64_t value_at_index_into_long(struct QueryResultRow* _Nonnull row, const int32_t index);
int64_t value_at_index_into_entid(struct QueryResultRow* _Nonnull row, const int32_t index);
const char* _Nonnull value_at_index_into_kw(struct QueryResultRow* _Nonnull row, const int32_t index);
char* _Nonnull value_at_index_into_kw(struct QueryResultRow* _Nonnull row, const int32_t index);
int32_t value_at_index_into_boolean(struct QueryResultRow* _Nonnull row, const int32_t index);
double value_at_index_into_double(struct QueryResultRow* _Nonnull row, const int32_t index);
int64_t value_at_index_into_timestamp(struct QueryResultRow* _Nonnull row, const int32_t index);
const char* _Nonnull value_at_index_into_string(struct QueryResultRow* _Nonnull row, const int32_t index);
const uuid_t* _Nonnull value_at_index_into_uuid(struct QueryResultRow* _Nonnull row, const int32_t index);
char* _Nonnull value_at_index_into_string(struct QueryResultRow* _Nonnull row, const int32_t index);
uuid_t* _Nonnull value_at_index_into_uuid(struct QueryResultRow* _Nonnull row, const int32_t index);
// Transaction change lists
const struct TxChange* _Nullable tx_change_list_entry_at(const struct TxChangeList* _Nonnull list, size_t index);
const struct TxChange* _Nonnull tx_change_list_entry_at(const struct TxChangeList* _Nonnull list, size_t index);
#endif /* store_h */