-
Notifications
You must be signed in to change notification settings - Fork 0
Dart Binding
A plain dart:ffi wrapper over the C API. Not a Flutter plugin — the
same file works in a console app and in Flutter.
cargo build --release
cd bindings/dart
dart pub get
dart testimport 'qql.dart';
final qql = Qql.open('sources', libraryPath: 'target/release/libqql.so');
try {
for (final record in qql.execute('Q:2:1-5,255')) {
print(record['ar']);
}
} on QqlException catch (e) {
print('${e.code}: ${e.message}');
} finally {
qql.dispose();
}| Member | Does |
|---|---|
Qql.open(dataDir, {libraryPath}) |
opens a context |
execute(query) |
List<Map<String, dynamic>>, throws QqlException
|
executeJson(query) |
the raw JSON string; never throws for a bad query |
version |
library version |
dispose() |
releases the native context; idempotent |
libraryPath defaults to the platform's usual name — libqql.so,
qql.dll, libqql.dylib.
Searching is part of the query string, so there is no extra API:
qql.execute('q:1:"الحمد"'); // Arabic, exact
qql.execute('q:2:"prayer"'); // English, exact
qql.execute("q:1:'الحمد'"); // either quote delimits a term
qql.execute('q:1:?"mercy"'); // ranked full text (fulltext feature)
qql.execute('q:1:*"worship"'); // ranked similarity (vector feature)Ranked hits carry score and ranked: true, ordered by score.
This is the one thing that catches people. The feature set lives in
libqql.so, not in Dart. A library built without them answers ?"…" and
*"…" with QqlException('QQL_UNSUPPORTED').
cargo build --release --features vector,fulltext
cargo run --features fulltext --bin qql-index # tantivy indexesA plain cargo build --release — including the one inside
scripts/c-smoke.sh — overwrites the library with a featureless one.
The binding owns two kinds of native memory and releases both:
| Allocation | Freed by |
|---|---|
Query strings (toNativeUtf8) |
calloc.free — Dart allocated them |
| Result strings from Rust |
qql_free_string — never calloc.free
|
| The context | Qql.dispose() |
Crossing those wires corrupts the heap. Dart's GC knows nothing about the Rust
allocation, so dispose() is not optional — there is no finalizer.
One Qql instance must not be used from two isolates at once. Give each its
own; contexts are independent and the cache is per-context.
| Platform | Artifact | Notes |
|---|---|---|
| Android |
libqql.so per ABI |
cargo ndk -t arm64-v8a -t armeabi-v7a build --release |
| iOS | libqql.a |
static — the App Store discourages loose dynamic libraries |
| Linux / Windows / macOS |
libqql.so / qql.dll / libqql.dylib
|
All fall out of the crate-type list in Cargo.toml.
The data must ship too. On Android and iOS copy sources/ into app
storage at first launch and pass that path to Qql.open. Budget for it:
| Size | |
|---|---|
| Text (Quran + hadith + Hisnul Muslim) | see Sources |
sources/vectors/ |
~28 MB, only with vector
|
sources/fulltext/ |
~22 MB, only with fulltext
|
Thirteen tests covering what the Rust suite cannot see from this side: Arabic
arriving byte-identical to the data file, query order and dedup surviving the
boundary, grouping and sticky sources and B::N numbering crossing intact,
search in both languages, ranked hits in descending score order, errors
becoming QqlException with code and position, and 200 consecutive executions
leaving the context healthy.
Using QQL
Interfaces
Extending