-
Notifications
You must be signed in to change notification settings - Fork 0
C API
include/qql.h is committed, so C consumers need no Rust toolchain.
#include <stdio.h>
#include <qql.h>
int main(void) {
qql_context_t *ctx = qql_context_create("./sources");
if (!ctx) return 1;
char *result = qql_context_execute(ctx, "Q:2:1-5,255;Q:1;");
printf("%s\n", result);
qql_free_string(result);
qql_context_destroy(ctx);
return 0;
}cargo build --release
cc example.c -Iinclude target/release/libqql.a -lpthread -ldl -lm -o example # static
cc example.c -Iinclude -Ltarget/release -lqql -o example # sharedThe static link needs -lpthread -ldl -lm because libqql.a does not carry
Rust's runtime dependencies. The shared library already records them.
const char *qql_version(void);
qql_context_t *qql_context_create(const char *data_directory);
char *qql_context_execute(qql_context_t *ctx, const char *query);
void qql_context_destroy(qql_context_t *ctx);
char *qql_execute(const char *query);
void qql_free_string(char *ptr);That is the whole ABI. qql_context_t is opaque — only the pointer crosses.
qql_context_execute() allocates the returned buffer
qql_free_string() frees it
- Returned strings are NUL-terminated UTF-8, and the caller owns them.
- Release them with
qql_free_string()— neverfree(), never a host language's allocator. -
qql_version()is the one exception: a static string that must not be freed. - Results stay valid after
qql_context_destroy— they are independently owned.
-
qql_context_executenever returns null and never returns malformed JSON. A null context, a null query and invalid UTF-8 all come back as{"ok":false,…}. -
Panics never cross the boundary. Every entry point catches unwinds and
returns
QQL_INTERNAL_ERRORinstead. - Invalid UTF-8 reports the byte offset where it went wrong rather than being lossily replaced.
-
qql_context_destroy(NULL)andqql_free_string(NULL)are no-ops.
One qql_context_t must not be used from two threads at once. In Rust the
compiler enforces this; across the ABI it cannot, so it is your
responsibility. Separate contexts on separate threads are fine.
qql_execute() uses a process-wide default context behind a mutex, reading
$QQL_DATA (default ./sources). Thread-safe but serialized — prefer an
explicit context for anything concurrent.
scripts/c-smoke.sh compiles a C client against include/qql.h under
-Wall -Wextra -Werror and links it to the real library, so a signature that
drifts from src/ffi.rs fails there rather than at a user's link step.
./scripts/c-smoke.sh
./scripts/c-smoke.sh 'q:1:"الحمد"'Careful: that script runs
cargo build --releasewithout features, so it overwrites the library with one that has no search engines. Rebuild with--features vector,fulltextafterwards if you need them.
All unsafe in the crate lives in src/ffi.rs — about 230 lines with no
query logic. The rest is #![deny(unsafe_code)]. The FFI tests run under Miri
and cover the abuse cases: null pointers, freeing null, invalid UTF-8, and
strings outliving their context.
Using QQL
Interfaces
Extending