Skip to content
This repository has been archived by the owner on May 9, 2022. It is now read-only.

TY-1759 move serialized bytes allocation from dart to rust #52

Merged
merged 6 commits into from
Apr 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions bindings/dart/lib/src/reranker/ai.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,19 @@ class XaynAi {
XaynAi(String vocab, String model, [Uint8List? serialized]) {
final vocabPtr = vocab.toNativeUtf8().cast<Int8>();
final modelPtr = model.toNativeUtf8().cast<Int8>();
final bytes = Bytes.fromList(serialized ?? Uint8List(0));
Bytes? bytes;
final error = XaynAiError();

_ai = ffi.xaynai_new(vocabPtr, modelPtr, bytes.ptr, error.ptr);
try {
bytes = Bytes.fromList(serialized ?? Uint8List(0));
_ai = ffi.xaynai_new(vocabPtr, modelPtr, bytes.ptr, error.ptr);
if (error.isError()) {
throw error.toException();
}
} finally {
malloc.free(vocabPtr);
malloc.free(modelPtr);
bytes.free();
bytes?.free();
error.free();
}
}
Expand Down
50 changes: 22 additions & 28 deletions bindings/dart/lib/src/reranker/bytes.dart
Original file line number Diff line number Diff line change
@@ -1,44 +1,45 @@
import 'dart:ffi'
show AllocatorAlloc, nullptr, Pointer, StructPointer, Uint8, Uint8Pointer;
import 'dart:ffi' show nullptr, Pointer, StructPointer, Uint8Pointer;
import 'dart:typed_data' show Uint8List;

import 'package:ffi/ffi.dart' show malloc;

import 'package:xayn_ai_ffi_dart/src/ffi/genesis.dart' show CBytes;
import 'package:xayn_ai_ffi_dart/src/ffi/library.dart' show ffi;
import 'package:xayn_ai_ffi_dart/src/result/error.dart' show XaynAiError;

/// A bytes buffer.
class Bytes {
late Pointer<CBytes> _bytes;
final bool _owned;

/// Creates the borrowed bytes buffer.
/// Creates the bytes buffer from a pointer.
///
/// This constructor never throws an exception.
Bytes(this._bytes) : _owned = false;
Bytes(this._bytes);

/// Creates the owned bytes buffer.
/// Creates the bytes buffer from a list.
///
/// This constructor never throws an exception.
Bytes.fromList(Uint8List bytes) : _owned = true {
_bytes = malloc.call<CBytes>();
_bytes.ref.len = bytes.length;
if (bytes.isEmpty) {
_bytes.ref.data = nullptr;
} else {
_bytes.ref.data = malloc.call<Uint8>(_bytes.ref.len);
bytes.asMap().forEach((i, byte) {
_bytes.ref.data[i] = byte;
});
/// This constructor can throw an exception.
Bytes.fromList(Uint8List bytes) {
final error = XaynAiError();

_bytes = ffi.bytes_new(bytes.length, error.ptr);
try {
if (error.isError()) {
throw error.toException();
}
} finally {
error.free();
}

bytes.asMap().forEach((i, byte) {
_bytes.ref.data[i] = byte;
});
}

/// Gets the pointer.
Pointer<CBytes> get ptr => _bytes;

/// Converts the buffer to a list.
Uint8List toList() {
if (_bytes == nullptr) {
if (_bytes == nullptr || _bytes.ref.data == nullptr) {
return Uint8List(0);
} else {
final bytes = Uint8List(_bytes.ref.len);
Expand All @@ -52,14 +53,7 @@ class Bytes {
/// Frees the memory.
void free() {
if (_bytes != nullptr) {
if (_owned) {
if (_bytes.ref.data != nullptr) {
malloc.free(_bytes.ref.data);
}
malloc.free(_bytes);
} else {
ffi.bytes_drop(_bytes);
}
ffi.bytes_drop(_bytes);
_bytes = nullptr;
}
}
Expand Down
67 changes: 25 additions & 42 deletions bindings/dart/test/reranker/bytes_test.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,18 @@
import 'dart:ffi'
show
AllocatorAlloc,
nullptr,
StructPointer,
Uint8,
// ignore: unused_shown_name
Uint8Pointer;
import 'dart:ffi' show nullptr, StructPointer;
import 'dart:typed_data' show Uint8List;

import 'package:ffi/ffi.dart' show malloc;
import 'package:flutter_test/flutter_test.dart'
show equals, expect, group, isEmpty, isNot, test;

import 'package:xayn_ai_ffi_dart/src/ffi/genesis.dart' show CBytes;
import 'package:xayn_ai_ffi_dart/src/reranker/bytes.dart' show Bytes;

void main() {
group('Bytes', () {
test('to list', () {
final bytes = Uint8List.fromList(List.generate(10, (i) => i));
final borrowed = malloc.call<CBytes>();
borrowed.ref.data = malloc.call<Uint8>(bytes.length);
borrowed.ref.len = bytes.length;
bytes.asMap().forEach((i, byte) => borrowed.ref.data[i] = byte);
expect(Bytes(borrowed).toList(), equals(bytes));
malloc.free(borrowed.ref.data);
malloc.free(borrowed);
test('list', () {
final list = Uint8List.fromList(List.generate(10, (i) => i));
final bytes = Bytes.fromList(list);
expect(bytes.toList(), equals(list));
bytes.free();
});

test('null', () {
Expand All @@ -34,36 +21,32 @@ void main() {
});

test('empty', () {
final borrowed = malloc.call<CBytes>();
borrowed.ref.data = nullptr;
borrowed.ref.len = 0;
expect(Bytes(borrowed).toList(), isEmpty);
malloc.free(borrowed.ref.data);
malloc.free(borrowed);
final bytes = Bytes.fromList(Uint8List(0));
expect(bytes.toList(), isEmpty);
bytes.free();
});
});

group('Bytes owned', () {
test('to list', () {
final bytes = Uint8List.fromList(List.generate(10, (i) => i));
final owned = Bytes.fromList(bytes);
expect(owned.toList(), equals(bytes));
owned.free();
test('invalid data', () {
final len = 10;
final bytes = Bytes.fromList(Uint8List(len));
bytes.ptr.ref.len = 0;
expect(bytes.toList(), isEmpty);
bytes.ptr.ref.len = len;
bytes.free();
});

test('empty', () {
final bytes = Uint8List(0);
final owned = Bytes.fromList(bytes);
expect(owned.toList(), isEmpty);
owned.free();
test('invalid len', () {
final bytes = Bytes.fromList(Uint8List(0));
bytes.ptr.ref.len = 10;
expect(bytes.toList(), isEmpty);
});

test('free', () {
final bytes = Uint8List.fromList(List.generate(10, (i) => i));
final owned = Bytes.fromList(bytes);
expect(owned.ptr, isNot(equals(nullptr)));
owned.free();
expect(owned.ptr, equals(nullptr));
final bytes =
Bytes.fromList(Uint8List.fromList(List.generate(10, (i) => i)));
expect(bytes.ptr, isNot(equals(nullptr)));
bytes.free();
expect(bytes.ptr, equals(nullptr));
});
});
}
8 changes: 8 additions & 0 deletions xayn-ai-ffi-c/src/data/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
//! I/O types for reranking.

pub(crate) mod document;
pub(crate) mod history;
pub(crate) mod rank;

pub use self::{
document::{CDocument, CDocuments},
history::{CFeedback, CHistories, CHistory, CRelevance},
rank::{ranks_drop, CRanks},
};
34 changes: 4 additions & 30 deletions xayn-ai-ffi-c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,10 @@
#![cfg_attr(doc, forbid(broken_intra_doc_links, private_intra_doc_links))]
#![allow(unused_unsafe)]

mod data;
mod reranker;
mod result;
mod utils;

pub use crate::{
data::{
document::{CDocument, CDocuments},
history::{CFeedback, CHistories, CHistory, CRelevance},
rank::{ranks_drop, CRanks},
},
reranker::{
ai::{
xaynai_analytics,
xaynai_drop,
xaynai_faults,
xaynai_new,
xaynai_rerank,
xaynai_serialize,
CXaynAi,
},
analytics::{analytics_drop, CAnalytics},
bytes::{bytes_drop, CBytes},
},
result::{
error::{error_message_drop, CCode},
fault::{faults_drop, CFaults},
},
utils::dummy_function,
};
pub mod data;
pub mod reranker;
pub mod result;
pub mod utils;

#[cfg(test)]
pub(crate) mod tests {
Expand Down
Loading