Rust offers a powerful type system with generics, similar to C++ templates. However, structs and functions with generics cannot be used in C via FFI without monomorphization (i.e. picking a single instance of the generic type or function). This crate defines a macro for the red black tree in sokoban that facilitates such monomorphization, exposing a simple C-compatible interface for tree initialization, insertion, removal, and retrieval.
This helper macro is defined in sokoban-bindings, and an example of its use is provided in sokoban-bindings-example.
The sokoban-bindgen crate defines the monomorphization helper macro. You must use this macro in your own rust library via
red_black_tree_bindings!(key_type, value_type, capacity);This will define C-compatible types and functions that use the monomorphized sokoban types and methods.
You will need
lib-sokoban- The
cbindgencrate to generate the C headers, with nightly since the expand feature requres it. (Thesokoban-bindgenmacro must be expanded before cbindgen can parse and generate headers) - The
concat-identscrate. This is re-exported withinsokoban-bindgen, so you can get it viause sokoban_bindgen::*.
This crate shows how to generate the staticlib and use the bindgen macro and cbindgen to generate a C header for sokoban. In particular, you should note:
- The
build.rswithin the crate - The
staticliboption specified within the[lib]section of the Cargo.toml - The use of
use sokoban_bindgen::*, which imports theconcat_identsmacro with a particular name
To use the example in C or Zig:
- To build the static library and header via cargo, use
cargo +nightly build --release -p sokoban-bindings-example. Nightly is required for macro expansion. The header will be written toexamples/c/sokoban.h.
To build and run the C example: The makefile provided will do the same thing as step 1 when make is invoked, in addition to building the C example. The executable will be written to examples/c/sokoban.out.
To run the Zig Example: After building the static library and header via step 1 or via make, navigate to examples/zig and zig build run.
-
Option<T>is used by sokoban to communicate insertion and retrieval success and failure, but it is not FFI safe. Two valuesSUCCESS = 0andFAILURE = u32::MAXwere introduced to deal with this1. In lieu of anOption, these values communicates to the C or Zig application that an attempt to insert or retrieve a value failed or succeeded. As an example, for the red black tree:- Instead of
insertreturning anOption<u32>node address which isNonewhen insertion fails, the function returnsFAILUREif it failed to insert or the node address (also au32) if it succeeded. - Instead of
getreturning anOption<&V>, orremovereturning anOption<V>, the function accepts a pointer to which the value will be copied if successful, along withSUCCESS = 0. If the retrieval fails,FAILURE = u32::MAXis returned and the pointer remains untouched (and perhaps uninitialized!).
- Instead of
Footnotes
-
This limits the capacity of the node allocator to one less than its max value. ↩