Documentation Index
Fetch the complete documentation index at: https://mintlify.com/cactus-compute/cactus/llms.txt
Use this file to discover all available pages before exploring further.
Rust SDK
Raw FFI bindings to the Cactus C API. Auto-generated via bindgen.
Installation
Add to your Cargo.toml:
[dependencies]
cactus-sys = { path = "rust/cactus-sys" }
Build requirements:
- CMake
- C++20 compiler
- On macOS: Xcode command line tools
- On Linux:
build-essential, libcurl4-openssl-dev, libclang-dev
Usage
All functions mirror the C API. The Rust bindings provide direct FFI access to all Cactus Engine functionality.
Basic Example
use cactus_sys::*;
use std::ffi::{CString, CStr};
use std::ptr;
unsafe {
// Initialize model
let model_path = CString::new("/path/to/model").unwrap();
let model = cactus_init(model_path.as_ptr(), ptr::null(), false);
if model.is_null() {
let error = cactus_get_last_error();
if !error.is_null() {
eprintln!("Error: {}", CStr::from_ptr(error).to_str().unwrap());
}
return;
}
// Prepare messages
let messages = CString::new(
r#"[{"role":"user","content":"What is 2+2?"}]"#
).unwrap();
// Complete
let result = cactus_complete(
model,
messages.as_ptr(),
ptr::null(), // options
ptr::null(), // tools
None, // callback
);
if !result.is_null() {
let response = CStr::from_ptr(result).to_str().unwrap();
println!("Response: {}", response);
}
// Cleanup
cactus_destroy(model);
}
Transcription Example
use cactus_sys::*;
use std::ffi::{CString, CStr};
use std::ptr;
unsafe {
let model_path = CString::new("/path/to/whisper-model").unwrap();
let model = cactus_init(model_path.as_ptr(), ptr::null(), false);
let audio_path = CString::new("/path/to/audio.wav").unwrap();
let result = cactus_transcribe(
model,
audio_path.as_ptr(),
ptr::null(), // prompt
ptr::null(), // options
None, // callback
ptr::null(), // pcm_data
0, // pcm_len
);
if !result.is_null() {
let transcription = CStr::from_ptr(result).to_str().unwrap();
println!("Transcription: {}", transcription);
}
cactus_destroy(model);
}
Embeddings Example
use cactus_sys::*;
use std::ffi::CString;
use std::ptr;
use std::slice;
unsafe {
let model_path = CString::new("/path/to/model").unwrap();
let model = cactus_init(model_path.as_ptr(), ptr::null(), false);
let text = CString::new("Hello, world!").unwrap();
let mut embedding_len: usize = 0;
let embedding_ptr = cactus_embed(
model,
text.as_ptr(),
true, // normalize
&mut embedding_len as *mut usize,
);
if !embedding_ptr.is_null() {
let embedding = slice::from_raw_parts(embedding_ptr, embedding_len);
println!("Embedding dimension: {}", embedding_len);
println!("First few values: {:?}", &embedding[..5]);
}
cactus_destroy(model);
}
Vector Index Example
use cactus_sys::*;
use std::ffi::{CString, CStr};
use std::ptr;
unsafe {
let index_dir = CString::new("/path/to/index").unwrap();
let index = cactus_index_init(index_dir.as_ptr(), 384);
if index.is_null() {
eprintln!("Failed to initialize index");
return;
}
// Add documents
let ids = vec![1i32, 2i32];
let doc1 = CString::new("First document").unwrap();
let doc2 = CString::new("Second document").unwrap();
let docs = vec![doc1.as_ptr(), doc2.as_ptr()];
let embedding1 = vec![0.1f32; 384];
let embedding2 = vec![0.2f32; 384];
let embeddings = vec![embedding1.as_ptr(), embedding2.as_ptr()];
cactus_index_add(
index,
ids.as_ptr(),
docs.as_ptr(),
embeddings.as_ptr(),
ptr::null(), // metadatas
2, // count
);
// Query
let query_embedding = vec![0.15f32; 384];
let results = cactus_index_query(
index,
query_embedding.as_ptr(),
ptr::null(), // options
);
if !results.is_null() {
let results_json = CStr::from_ptr(results).to_str().unwrap();
println!("Results: {}", results_json);
}
cactus_index_destroy(index);
}
API Reference
All functions mirror the C API documented in the C API Reference. Key functions include:
Init / Lifecycle
pub fn cactus_init(model_path: *const c_char, corpus_dir: *const c_char, cache_index: bool) -> *mut c_void;
pub fn cactus_destroy(model: *mut c_void);
pub fn cactus_reset(model: *mut c_void);
pub fn cactus_stop(model: *mut c_void);
pub fn cactus_get_last_error() -> *const c_char;
Completion
pub fn cactus_complete(
model: *mut c_void,
messages_json: *const c_char,
options_json: *const c_char,
tools_json: *const c_char,
callback: Option<unsafe extern "C" fn(*const c_char, u32, *mut c_void)>,
) -> *const c_char;
Transcription
pub fn cactus_transcribe(
model: *mut c_void,
audio_path: *const c_char,
prompt: *const c_char,
options_json: *const c_char,
callback: Option<unsafe extern "C" fn(*const c_char, u32, *mut c_void)>,
pcm_data: *const u8,
pcm_len: usize,
) -> *const c_char;
Embeddings
pub fn cactus_embed(model: *mut c_void, text: *const c_char, normalize: bool, out_len: *mut usize) -> *const f32;
pub fn cactus_image_embed(model: *mut c_void, image_path: *const c_char, out_len: *mut usize) -> *const f32;
pub fn cactus_audio_embed(model: *mut c_void, audio_path: *const c_char, out_len: *mut usize) -> *const f32;
Vector Index
pub fn cactus_index_init(index_dir: *const c_char, embedding_dim: i32) -> *mut c_void;
pub fn cactus_index_destroy(index: *mut c_void);
pub fn cactus_index_add(
index: *mut c_void,
ids: *const i32,
documents: *const *const c_char,
embeddings: *const *const f32,
metadatas: *const *const c_char,
count: usize,
) -> i32;
pub fn cactus_index_query(
index: *mut c_void,
embedding: *const f32,
options_json: *const c_char,
) -> *const c_char;
Testing
export CACTUS_MODEL_PATH=/path/to/model
export CACTUS_STT_MODEL_PATH=/path/to/whisper-model
cargo test --manifest-path rust/Cargo.toml -- --nocapture
Safety Considerations
All functions are marked as unsafe because they interact with C FFI. When using this crate:
- Always check returned pointers for null before dereferencing
- Ensure strings are valid UTF-8 and null-terminated
- Handle memory management carefully (initialize and destroy models)
- Use proper error checking with
cactus_get_last_error()
See Also
C API Reference
Full C API reference that the Rust bindings wrap
Python SDK
Python bindings with higher-level wrappers
Swift SDK
Swift bindings for Apple platforms
Kotlin SDK
Kotlin bindings for Android