Rust bindings

Rust supports extending with dynamic libraries. A demo project can be found at https://github.com/calcit-lang/dylib-workflow

Currently two APIs are supported, based on Cirru EDN data.

First one is a synchronous Edn API with type signature:


#![allow(unused)]
fn main() {
#[no_mangle]
pub fn demo(args: Vec<Edn>) -> Result<Edn, String> {
}
}

The other one is an asynchorous API, it can be called multiple times, which relies on Arc type(not sure if we can find a better solution yet),


#![allow(unused)]
fn main() {
#[no_mangle]
pub fn demo(
  args: Vec<Edn>,
  handler: Arc<dyn Fn(Vec<Edn>) -> Result<Edn, String> + Send + Sync + 'static>,
  finish: Box<dyn FnOnce() + Send + Sync + 'static>,
) -> Result<Edn, String> {
}
}

in this snippet, the function handler is used as the callback, which could be called multiple times.

The function finish is used for indicating that the task has finished. It can be called once, or not being called. Internally Calcit tracks with a counter to see if all asynchorous tasks are finished. Process need to keep running when there are tasks running.

Asynchronous tasks are based on threads, which is currently decoupled from core features of Calcit. We may need techniques like tokio for better performance in the future, but current solution is quite naive yet.

Also to declare the ABI version, we need another function with specific name so that Calcit could check before actually calling it,


#![allow(unused)]
fn main() {
#[no_mangle]
pub fn abi_version() -> String {
  String::from("0.0.1")
}
}

(This feature is not stable enough yet.)

Call in Calcit

Rust code is compiled into dylibs, and then Calcit could call with:

&call-dylib-edn (get-dylib-path "\"/dylibs/libcalcit_std") "\"read_file" name

first argument is the file path to that dylib. And multiple arguments are supported:

&call-dylib-edn (get-dylib-path "\"/dylibs/libcalcit_std") "\"add_duration" (nth date 1) n k

calling a function is special, we need another function, with last argument being the callback function:

&call-dylib-edn-fn (get-dylib-path "\"/dylibs/libcalcit_std") "\"set_timeout" t cb

Extensions

Currently there are some early extensions: