Expand description
Tarantool C API bindings for Rust. This library contains the following Tarantool API’s:
- Box: spaces, indexes, sequences
- Fibers: fiber attributes, conditional variables, latches
- CoIO
- Transactions
- Schema management
- Protocol implementation (
net.box
): CRUD, stored procedure call, triggers - Tuple utils
- Decimal numbers
- Logging (see https://docs.rs/log/)
- Error handling
- Stored procedures
Caution! The library is currently under development. API may be unstable until version 1.0 is released.
Features
net_box
- Enables protocol implementation (enabled by default)schema
- Enables schema manipulation utils (WIP as for now)
Prerequisites
- rustc 1.59 or newer
- tarantool 2.2
Stored procedures
There are several ways Tarantool can call Rust code. It can use either a plugin, a Lua FFI module, or a stored procedure. In this file we only cover the third option, namely Rust stored procedures. Even though Tarantool always treats Rust routines just as “C functions”, we keep on using the “stored procedure” term as an agreed convention and also for historical reasons.
This tutorial contains the following simple steps:
examples/easy
- prints “hello world”;examples/harder
- decodes a passed parameter value;examples/hardest
- uses this library to do a DBMS insert;examples/read
- uses this library to do a DBMS select;examples/write
- uses this library to do a DBMS replace.
Our examples are a good starting point for users who want to confidently start writing their own stored procedures.
Example
After getting the prerequisites installed, follow these steps:
Create a Cargo project:
$ cargo init --lib
Add the following lines to Cargo.toml
:
[package]
name = "easy"
version = "0.1.0"
edition = "2018"
# author, license, etc
[dependencies]
tarantool = "0.6.0" # (1)
serde = "1.0" # (2)
[lib]
crate-type = ["cdylib"] # (3)
- Add the
tarantool
library to the dependencies; - Optionally add Serde to the dependencies. This is only required if you want to use Rust structures as tuple values (see this example);
- Compile the dynamic library.
Requests will be done using Tarantool as a client. Start Tarantool, and enter the following requests:
box.cfg{listen=3306}
box.schema.space.create('capi_test')
box.space.capi_test:create_index('primary')
net_box = require('net.box')
capi_connection = net_box:new(3306)
Note: create a space named capi_test
and establish the connection named capi_connection
to the same instance.
Leave the client running. It will be used to enter more requests later.
Edit the lib.rs
file and add the following lines:
#[tarantool::proc]
fn easy() {
println!("hello world");
}
#[tarantool::proc]
fn easy2() {
println!("hello world -- easy2");
}
Compile the program:
$ cargo build
Start another shell. Change directory (cd
) so that it is the same as the directory that the client is running in.
Copy the compiled library from target/debug
to the current directory and rename it to easy.so
Now go back to the client and execute these requests:
box.schema.func.create('easy', {language = 'C'})
box.schema.user.grant('guest', 'execute', 'function', 'easy')
capi_connection:call('easy')
Consult the documentation of box.schema.func.create(), box.schema.user.grant() and conn:call() for more details.
The matter in hand is the capi_connection:call('easy')
function, which has three features.
One is to find the ‘easy’ function, which is easy indeed since by default Tarantool looks inside the current directory
for a file named easy.so
.
Another is to call the ‘easy’ function. Since the easy()
function in lib.rs
begins with println!("hello world")
,
the words “hello world” will be printed in the terminal.
The third feature is to make sure the call was successful. Since the easy()
function in lib.rs
ends with return 0, there is no error message to display and therefore the request is over.
The result should look like this:
tarantool> capi_connection:call('easy')
hello world
---
- []
...
Now let’s call the other function in lib.rs - easy2()
. This is almost the same as the easy()
function, but with a difference: when the file name is not the same as the function name,
we have to specify {file-name}.{function-name}.
box.schema.func.create('easy.easy2', {language = 'C'})
box.schema.user.grant('guest', 'execute', 'function', 'easy.easy2')
capi_connection:call('easy.easy2')
… and this time the result will be hello world -- easy2
.
As you can see, calling a Rust function is as straightforward as it can be.
Re-exports
Modules
clock
module returns time values derived from the Posix / C
CLOCK_GETTIME
function or equivalent.net_box
module contains connector to remote Tarantool server instances via a network.Macros
Functions
Type Definitions
Attribute Macros
#[tarantool::proc]
is a macro attribute for creating stored procedure
functions.