├── .gitignore ├── .travis.yml ├── CONTRIBUTORS.md ├── Cargo.toml ├── LICENSE.md ├── README.md ├── src ├── example.rs └── module.rs └── test.lua /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | target/ 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: rust 3 | rust: 4 | - stable 5 | - beta 6 | - nightly 7 | matrix: 8 | allow_failures: 9 | - rust: nightly 10 | 11 | addons: 12 | apt: 13 | sources: 14 | - sourceline: 'deb https://packagecloud.io/tarantool/1_7/ubuntu/ precise main' 15 | key_url: 'https://packagecloud.io/gpg.key' 16 | packages: 17 | - tarantool 18 | 19 | script: 20 | - cargo build --verbose 21 | - cargo test --verbose 22 | - ./test.lua 23 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | Roman Tsisyk 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tarantool" 3 | version = "0.0.1" 4 | description = "Tarantool bindings for Rust" 5 | homepage = "https://github.com/rtsisyk/tarantool-rust" 6 | repository = "https://github.com/rtsisyk/tarantool-rust.git" 7 | readme = "README.md" 8 | keywords = ["tarantool", "ffi"] 9 | categories = ["database", "api-bindings", "external-ffi-bindings"] 10 | license = "BSD-2-Clause" 11 | authors = [ "Roman Tsisyk " ] 12 | 13 | [badges] 14 | travis-ci = { repository = "rtsisyk/tarantool-rust", branch = "master" } 15 | 16 | [lib] 17 | name = "tarantool_rust_module" 18 | path = "src/example.rs" 19 | crate-type = ["dylib"] 20 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | BSD-2-Clause License 2 | 3 | Copyright (c) 2017 Roman Tsisyk 4 | 5 | Redistribution and use in source and binary forms, with or 6 | without modification, are permitted provided that the following 7 | conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above 10 | copyright notice, this list of conditions and the 11 | following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following 15 | disclaimer in the documentation and/or other materials 16 | provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 23 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 26 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 29 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust for Tarantool 2 | 3 | [![Tarantool][tarantool-badge]][Tarantool] 4 | [![Rust][rust-badge]][Rust] 5 | [![License][license-badge]][license-url] 6 | [![Build Status][travis-badge]][travis-url] 7 | 8 | A proof-of-concept **Rust** module for **Tarantool**. 9 | 10 | This example demonstrates how to use [Rust Programming Language][Rust] 11 | to write stored procedures for [Tarantool]. 12 | 13 | **[Tarantool]** is a full-featured general-purpose database and an application server. 14 | 15 | **[Rust]** is a systems programming language that runs blazingly fast, 16 | prevents segfaults, and guarantees thread safety. 17 | 18 | ## Prerequisites 19 | 20 | * Tarantool 1.6.8+ 21 | * rustc 1.14.0 and cargo 0.15.0 (other versions untested) 22 | 23 | ```bash 24 | sudo apt-get -y install rustc cargo 25 | ``` 26 | 27 | ## Usage 28 | 29 | ```bash 30 | git clone https://github.com/rtsisyk/tarantool-rust.git 31 | cargo build 32 | ./test.lua 33 | ``` 34 | 35 | ``` 36 | rust fiber 102: before sleep 37 | rust fiber 103: before sleep 38 | rust fiber 104: before sleep 39 | rust fiber 105: before sleep 40 | rust fiber 106: before sleep 41 | rust fiber 102: after sleep 42 | rust fiber 102: before sleep 43 | rust fiber 103: after sleep 44 | rust fiber 103: before sleep 45 | ``` 46 | 47 | The example above demonstrates that Rust libraries can be used inside Tarantool without any conflicts with cooperative-multistasking model implemented by Tarantool. 48 | 49 | ## Future Plans 50 | 51 | * Implement Rust-friendly wrappers for Fibers, Box and [other](src/module.rs) Tarantool API 52 | * Add examples 53 | * Write documentation 54 | 55 | [][Telegram] 56 | 57 | Fall in love with [Tarantool]? Wanna learn [Rust]? 58 | 59 | **Your contribution is needed!** 60 | 61 | Feel free to contact us on [Telegram] channel or send a pull request. 62 | 63 | See Also 64 | -------- 65 | 66 | * [Tarantool] 67 | * [Rust] 68 | * [Maillist] 69 | * [Telegram] 70 | * roman@tsisyk.com 71 | 72 | [tarantool-badge]: https://img.shields.io/badge/Tarantool-1.7-blue.svg?style=flat 73 | [Tarantool]: https://tarantool.org/ 74 | [rust-badge]: https://img.shields.io/badge/Rust-1.14.0-black.svg?style=flat 75 | [Rust]: https://www.rust-lang.org 76 | [license-badge]: https://img.shields.io/badge/License-BSD--2-lightgray.svg?style=flat 77 | [license-url]: LICENSE.md 78 | [travis-badge]: https://api.travis-ci.org/rtsisyk/tarantool-rust.svg?branch=master 79 | [travis-url]: https://travis-ci.org/rtsisyk/tarantool-rust 80 | [Telegram]: http://telegram.me/tarantool 81 | [Maillist]: https://groups.google.com/forum/#!forum/tarantool 82 | -------------------------------------------------------------------------------- /src/example.rs: -------------------------------------------------------------------------------- 1 | extern crate core; 2 | include!("./module.rs"); 3 | 4 | #[no_mangle] 5 | pub extern fn rustproc(fiber_id: u64) { 6 | for _ in 0..5 { 7 | println!("rust fiber {}: before sleep", fiber_id); 8 | unsafe { 9 | fiber_sleep(0.1); 10 | } 11 | println!("rust fiber {}: after sleep", fiber_id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/module.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by rust-bindgen from a minified version 3 | * of /usr/include/tarantool.h and then edited manually. 4 | */ 5 | 6 | /* {{{ Logging */ 7 | 8 | #[repr(u32)] 9 | /** Log levels */ 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub enum SayLevel { 12 | Fatal = 0, 13 | System = 1, 14 | Error = 2, 15 | Crit = 3, 16 | Warn = 4, 17 | Info = 5, 18 | Debug = 6, 19 | } 20 | extern "C" { 21 | #[link_name = "log_level"] 22 | pub static mut log_level: ::std::os::raw::c_int; 23 | pub fn say_log_level_is_enabled(level: ::std::os::raw::c_int) -> bool; 24 | } 25 | pub type SayFunc = 26 | ::core::option::Option; 34 | extern "C" { 35 | #[link_name = "_say"] 36 | pub static mut _say: SayFunc; 37 | } 38 | 39 | /* }}} Logging */ 40 | 41 | /* {{{ Fiber */ 42 | 43 | #[repr(C)] 44 | #[derive(Debug, Copy)] 45 | pub struct fiber { 46 | pub _address: u8, 47 | } 48 | impl Clone for fiber { 49 | fn clone(&self) -> Self { *self } 50 | } 51 | 52 | /* TODO: remove valist */ 53 | #[repr(C)] 54 | #[derive(Debug, Copy)] 55 | pub struct BuiltinVaListTag { 56 | pub gp_offset: ::std::os::raw::c_uint, 57 | pub fp_offset: ::std::os::raw::c_uint, 58 | pub overflow_arg_area: *mut ::std::os::raw::c_void, 59 | pub reg_save_area: *mut ::std::os::raw::c_void, 60 | } 61 | impl Clone for BuiltinVaListTag { 62 | fn clone(&self) -> Self { *self } 63 | } 64 | pub type BuiltinVaList = [BuiltinVaListTag; 1usize]; 65 | 66 | /** 67 | * Fiber - contains information about fiber 68 | */ 69 | pub type FiberFunc = 70 | ::core::option::Option ::std::os::raw::c_int>; 72 | 73 | 74 | extern "C" { 75 | /** 76 | * Create a new fiber. 77 | * 78 | * Takes a fiber from fiber cache, if it's not empty. 79 | * Can fail only if there is not enough memory for 80 | * the fiber structure or fiber stack. 81 | * 82 | * The created fiber automatically returns itself 83 | * to the fiber cache when its "main" function 84 | * completes. 85 | * 86 | * \param name string with fiber name 87 | * \param FiberFunc func for run inside fiber 88 | * 89 | * \sa fiber_start 90 | */ 91 | pub fn fiber_new(name: *const ::std::os::raw::c_char, f: FiberFunc) 92 | -> *mut fiber; 93 | /** 94 | * Return control to another fiber and wait until it'll be woken. 95 | * 96 | * \sa fiber_wakeup 97 | */ 98 | pub fn fiber_yield(); 99 | /** 100 | * Start execution of created fiber. 101 | * 102 | * \param callee fiber to start 103 | * \param ... arguments to start the fiber with 104 | * 105 | * \sa fiber_new 106 | */ 107 | pub fn fiber_start(callee: *mut fiber, ...); 108 | /** 109 | * Interrupt a synchronous wait of a fiber 110 | * 111 | * \param f fiber to be woken up 112 | */ 113 | pub fn fiber_wakeup(f: *mut fiber); 114 | /** 115 | * Cancel the subject fiber. (set FIBER_IS_CANCELLED flag) 116 | * 117 | * If target fiber's flag FIBER_IS_CANCELLABLE set, then it would 118 | * be woken up (maybe prematurely). Then current fiber yields 119 | * until the target fiber is dead (or is woken up by 120 | * \sa fiber_wakeup). 121 | * 122 | * \param f fiber to be cancelled 123 | */ 124 | pub fn fiber_cancel(f: *mut fiber); 125 | /** 126 | * Make it possible or not possible to wakeup the current 127 | * fiber immediately when it's cancelled. 128 | * 129 | * @param yesno status to set 130 | * @return previous state. 131 | */ 132 | pub fn fiber_set_cancellable(yesno: bool) -> bool; 133 | /** 134 | * Set fiber to be joinable (false by default). 135 | * \param yesno status to set 136 | */ 137 | pub fn fiber_set_joinable(fiber: *mut fiber, yesno: bool); 138 | /** 139 | * Wait until the fiber is dead and then move its execution 140 | * status to the caller. 141 | * The fiber must not be detached (@sa fiber_set_joinable()). 142 | * @pre FIBER_IS_JOINABLE flag is set. 143 | * 144 | * \param f fiber to be woken up 145 | * \return fiber function ret code 146 | */ 147 | pub fn fiber_join(f: *mut fiber) -> ::std::os::raw::c_int; 148 | /** 149 | * Put the current fiber to sleep for at least 's' seconds. 150 | * 151 | * \param s time to sleep 152 | * 153 | * \note this is a cancellation point (\sa fiber_is_cancelled) 154 | */ 155 | pub fn fiber_sleep(s: f64); 156 | /** 157 | * Check current fiber for cancellation (it must be checked 158 | * manually). 159 | */ 160 | pub fn fiber_is_cancelled() -> bool; 161 | /** 162 | * Report loop begin time as double (cheap). 163 | */ 164 | pub fn fiber_time() -> f64; 165 | /** 166 | * Report loop begin time as 64-bit int. 167 | */ 168 | pub fn fiber_time64() -> u64; 169 | /** 170 | * Reschedule fiber to end of event loop cycle. 171 | */ 172 | pub fn fiber_reschedule(); 173 | } 174 | 175 | /** 176 | * Return slab_cache suitable to use with tarantool/small library 177 | */ 178 | #[repr(C)] 179 | #[derive(Debug, Copy)] 180 | pub struct slab_cache { 181 | pub _address: u8, 182 | } 183 | impl Clone for slab_cache { 184 | fn clone(&self) -> Self { *self } 185 | } 186 | extern "C" { 187 | pub fn cord_slab_cache() -> *mut slab_cache; 188 | } 189 | 190 | #[repr(u32)] 191 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 192 | pub enum CoioFlags { 193 | Read = 1, 194 | Write = 2, 195 | } 196 | extern "C" { 197 | /** 198 | * Wait until READ or WRITE event on socket (\a fd). Yields. 199 | * \param fd - non-blocking socket file description 200 | * \param events - requested events to wait. 201 | * Combination of TNT_IO_READ | TNT_IO_WRITE bit flags. 202 | * \param timeoout - timeout in seconds. 203 | * \retval 0 - timeout 204 | * \retval >0 - returned events. Combination of TNT_IO_READ | TNT_IO_WRITE 205 | * bit flags. 206 | */ 207 | pub fn coio_wait(fd: ::std::os::raw::c_int, event: ::std::os::raw::c_int, 208 | timeout: f64) -> ::std::os::raw::c_int; 209 | /** 210 | * Close the fd and wake any fiber blocked in 211 | * coio_wait() call on this fd. 212 | */ 213 | pub fn coio_close(fd: ::std::os::raw::c_int) -> ::std::os::raw::c_int; 214 | /** 215 | * Create new eio task with specified function and 216 | * arguments. Yield and wait until the task is complete 217 | * or a timeout occurs. 218 | * 219 | * This function doesn't throw exceptions to avoid double error 220 | * checking: in most cases it's also necessary to check the return 221 | * value of the called function and perform necessary actions. If 222 | * func sets errno, the errno is preserved across the call. 223 | * 224 | * @retval -1 and errno = ENOMEM if failed to create a task 225 | * @retval the function return (errno is preserved). 226 | * 227 | * @code 228 | * static ssize_t openfile_cb(va_list ap) 229 | * { 230 | * const char *filename = va_arg(ap); 231 | * int flags = va_arg(ap); 232 | * return open(filename, flags); 233 | * } 234 | * 235 | * if (coio_call(openfile_cb, 0.10, "/tmp/file", 0) == -1) 236 | * // handle errors. 237 | * ... 238 | * @endcode 239 | */ 240 | pub fn coio_call(func: 241 | ::core::option::Option 244 | ::std::os::raw::c_int>, ...) 245 | -> isize; 246 | } 247 | #[repr(C)] 248 | #[derive(Debug, Copy)] 249 | pub struct addrinfo { 250 | pub _address: u8, 251 | } 252 | impl Clone for addrinfo { 253 | fn clone(&self) -> Self { *self } 254 | } 255 | extern "C" { 256 | /** 257 | * Fiber-friendly version of getaddrinfo(3). 258 | * 259 | * @param host host name, i.e. "tarantool.org" 260 | * @param port service name, i.e. "80" or "http" 261 | * @param hints hints, see getaddrinfo(3) 262 | * @param res[out] result, see getaddrinfo(3) 263 | * @param timeout timeout 264 | * @retval 0 on success, please free @a res using freeaddrinfo(3). 265 | * @retval -1 on error, check diag. 266 | * Please note that the return value is not compatible with 267 | * getaddrinfo(3). 268 | * @sa getaddrinfo() 269 | */ 270 | pub fn coio_getaddrinfo(host: *const ::std::os::raw::c_char, 271 | port: *const ::std::os::raw::c_char, 272 | hints: *const addrinfo, res: *mut *mut addrinfo, 273 | timeout: f64) -> ::std::os::raw::c_int; 274 | } 275 | 276 | /* }}} Fiber */ 277 | 278 | /* {{{ Transaction */ 279 | 280 | extern "C" { 281 | /** 282 | * Return true if there is an active transaction. 283 | */ 284 | pub fn box_txn() -> bool; 285 | /** 286 | * Begin a transaction in the current fiber. 287 | * 288 | * A transaction is attached to caller fiber, therefore one fiber can have 289 | * only one active transaction. 290 | * 291 | * @retval 0 - success 292 | * @retval -1 - failed, perhaps a transaction has already been 293 | * started 294 | */ 295 | pub fn box_txn_begin() -> ::std::os::raw::c_int; 296 | /** 297 | * Commit the current transaction. 298 | * @retval 0 - success 299 | * @retval -1 - failed, perhaps a disk write failure. 300 | * started 301 | */ 302 | pub fn box_txn_commit() -> ::std::os::raw::c_int; 303 | /** 304 | * Rollback the current transaction. 305 | * May fail if called from a nested 306 | * statement. 307 | */ 308 | pub fn box_txn_rollback() -> ::std::os::raw::c_int; 309 | /** 310 | * Allocate memory on txn memory pool. 311 | * The memory is automatically deallocated when the transaction 312 | * is committed or rolled back. 313 | * 314 | * @retval NULL out of memory 315 | */ 316 | pub fn box_txn_alloc(size: usize) -> *mut ::std::os::raw::c_void; 317 | } 318 | 319 | /* }}} Transaction */ 320 | 321 | /* {{{ Tuple */ 322 | 323 | #[repr(C)] 324 | #[derive(Debug, Copy)] 325 | pub struct tuple_format { 326 | pub _address: u8, 327 | } 328 | impl Clone for tuple_format { 329 | fn clone(&self) -> Self { *self } 330 | } 331 | pub type BoxTupleFormat = tuple_format; 332 | extern "C" { 333 | /** 334 | * Tuple Format. 335 | * 336 | * Each Tuple has associated format (class). Default format is used to 337 | * create tuples which are not attach to any particular space. 338 | */ 339 | pub fn box_tuple_format_default() -> *mut BoxTupleFormat; 340 | } 341 | #[repr(C)] 342 | #[derive(Debug, Copy)] 343 | pub struct tuple { 344 | pub _address: u8, 345 | } 346 | impl Clone for tuple { 347 | fn clone(&self) -> Self { *self } 348 | } 349 | /** 350 | * Tuple 351 | */ 352 | pub type BoxTuple = tuple; 353 | extern "C" { 354 | /** 355 | * Allocate and initialize a new tuple from a raw MsgPack Array data. 356 | * 357 | * \param format tuple format. 358 | * Use box_tuple_format_default() to create space-independent tuple. 359 | * \param data tuple data in MsgPack Array format ([field1, field2, ...]). 360 | * \param end the end of \a data 361 | * \retval NULL on out of memory 362 | * \retval tuple otherwise 363 | * \pre data, end is valid MsgPack Array 364 | * \sa \code box.tuple.new(data) \endcode 365 | */ 366 | pub fn box_tuple_new(format: *mut BoxTupleFormat, 367 | data: *const ::std::os::raw::c_char, 368 | end: *const ::std::os::raw::c_char) 369 | -> *mut BoxTuple; 370 | /** 371 | * Increase the reference counter of tuple. 372 | * 373 | * Tuples are reference counted. All functions that return tuples guarantee 374 | * that the last returned tuple is refcounted internally until the next 375 | * call to API function that yields or returns another tuple. 376 | * 377 | * You should increase the reference counter before taking tuples for long 378 | * processing in your code. Such tuples will not be garbage collected even 379 | * if another fiber remove they from space. After processing please 380 | * decrement the reference counter using box_tuple_unref(), otherwise the 381 | * tuple will leak. 382 | * 383 | * \param tuple a tuple 384 | * \retval -1 on error (check box_error_last()) 385 | * \retval 0 on success 386 | * \sa box_tuple_unref() 387 | */ 388 | pub fn box_tuple_ref(tuple: *mut BoxTuple) -> ::std::os::raw::c_int; 389 | /** 390 | * Decrease the reference counter of tuple. 391 | * 392 | * \param tuple a tuple 393 | * \sa box_tuple_ref() 394 | */ 395 | pub fn box_tuple_unref(tuple: *mut BoxTuple); 396 | /** 397 | * Return the number of fields in tuple (the size of MsgPack Array). 398 | * \param tuple a tuple 399 | */ 400 | pub fn box_tuple_field_count(tuple: *const BoxTuple) -> u32; 401 | /** 402 | * Return the number of bytes used to store internal tuple data (MsgPack Array). 403 | * \param tuple a tuple 404 | */ 405 | pub fn box_tuple_bsize(tuple: *const BoxTuple) -> usize; 406 | /** 407 | * Dump raw MsgPack data to the memory byffer \a buf of size \a size. 408 | * 409 | * Store tuple fields in the memory buffer. 410 | * \retval -1 on error. 411 | * \retval number of bytes written on success. 412 | * Upon successful return, the function returns the number of bytes written. 413 | * If buffer size is not enough then the return value is the number of bytes 414 | * which would have been written if enough space had been available. 415 | */ 416 | pub fn BoxTupleo_buf(tuple: *const BoxTuple, 417 | buf: *mut ::std::os::raw::c_char, size: usize) 418 | -> isize; 419 | /** 420 | * Return the associated format. 421 | * \param tuple tuple 422 | * \return tuple_format 423 | */ 424 | pub fn box_tuple_format(tuple: *const BoxTuple) 425 | -> *mut BoxTupleFormat; 426 | /** 427 | * Return the raw tuple field in MsgPack format. 428 | * 429 | * The buffer is valid until next call to box_tuple_* functions. 430 | * 431 | * \param tuple a tuple 432 | * \param fieldno zero-based index in MsgPack array. 433 | * \retval NULL if i >= box_tuple_field_count(tuple) 434 | * \retval msgpack otherwise 435 | */ 436 | pub fn box_tuple_field(tuple: *const BoxTuple, fieldno: u32) 437 | -> *const ::std::os::raw::c_char; 438 | } 439 | 440 | #[repr(C)] 441 | #[derive(Debug, Copy)] 442 | pub struct tuple_iterator { 443 | pub _address: u8, 444 | } 445 | impl Clone for tuple_iterator { 446 | fn clone(&self) -> Self { *self } 447 | } 448 | /** 449 | * Tuple iterator 450 | */ 451 | pub type BoxTupleIterator = tuple_iterator; 452 | extern "C" { 453 | /** 454 | * Allocate and initialize a new tuple iterator. The tuple iterator 455 | * allow to iterate over fields at root level of MsgPack array. 456 | * 457 | * Example: 458 | * \code 459 | * box_tuple_iterator *it = box_tuple_iterator(tuple); 460 | * if (it == NULL) { 461 | * // error handling using box_error_last() 462 | * } 463 | * const char *field; 464 | * while (field = box_tuple_next(it)) { 465 | * // process raw MsgPack data 466 | * } 467 | * 468 | * // rewind iterator to first position 469 | * box_tuple_rewind(it); 470 | * assert(box_tuple_position(it) == 0); 471 | * 472 | * // rewind iterator to first position 473 | * field = box_tuple_seek(it, 3); 474 | * assert(box_tuple_position(it) == 4); 475 | * 476 | * box_iterator_free(it); 477 | * \endcode 478 | * 479 | * \post box_tuple_position(it) == 0 480 | */ 481 | pub fn box_tuple_iterator(tuple: *mut BoxTuple) 482 | -> *mut BoxTupleIterator; 483 | /** 484 | * Destroy and free tuple iterator 485 | */ 486 | pub fn box_tuple_iterator_free(it: *mut BoxTupleIterator); 487 | /** 488 | * Return zero-based next position in iterator. 489 | * That is, this function return the field id of field that will be 490 | * returned by the next call to box_tuple_next(it). Returned value is zero 491 | * after initialization or rewind and box_tuple_field_count(tuple) 492 | * after the end of iteration. 493 | * 494 | * \param it tuple iterator 495 | * \returns position. 496 | */ 497 | pub fn box_tuple_position(it: *mut BoxTupleIterator) -> u32; 498 | /** 499 | * Rewind iterator to the initial position. 500 | * 501 | * \param it tuple iterator 502 | * \post box_tuple_position(it) == 0 503 | */ 504 | pub fn box_tuple_rewind(it: *mut BoxTupleIterator); 505 | /** 506 | * Seek the tuple iterator. 507 | * 508 | * The returned buffer is valid until next call to box_tuple_* API. 509 | * Requested fieldno returned by next call to box_tuple_next(it). 510 | * 511 | * \param it tuple iterator 512 | * \param fieldno - zero-based position in MsgPack array. 513 | * \post box_tuple_position(it) == fieldno if returned value is not NULL 514 | * \post box_tuple_position(it) == box_tuple_field_count(tuple) if returned 515 | * value is NULL. 516 | */ 517 | pub fn box_tuple_seek(it: *mut BoxTupleIterator, fieldno: u32) 518 | -> *const ::std::os::raw::c_char; 519 | /** 520 | * Return the next tuple field from tuple iterator. 521 | * The returned buffer is valid until next call to box_tuple_* API. 522 | * 523 | * \param it tuple iterator. 524 | * \retval NULL if there are no more fields. 525 | * \retval MsgPack otherwise 526 | * \pre box_tuple_position(it) is zerod-based id of returned field 527 | * \post box_tuple_position(it) == box_tuple_field_count(tuple) if returned 528 | * value is NULL. 529 | */ 530 | pub fn box_tuple_next(it: *mut BoxTupleIterator) 531 | -> *const ::std::os::raw::c_char; 532 | pub fn box_tuple_update(tuple: *const BoxTuple, 533 | expr: *const ::std::os::raw::c_char, 534 | expr_end: *const ::std::os::raw::c_char) 535 | -> *mut BoxTuple; 536 | pub fn box_tuple_upsert(tuple: *const BoxTuple, 537 | expr: *const ::std::os::raw::c_char, 538 | expr_end: *const ::std::os::raw::c_char) 539 | -> *mut BoxTuple; 540 | pub fn box_tuple_extract_key(tuple: *const BoxTuple, space_id: u32, 541 | index_id: u32, key_size: *mut u32) 542 | -> *mut ::std::os::raw::c_char; 543 | } 544 | 545 | /* }}} Tuple */ 546 | 547 | /* {{{ Space */ 548 | 549 | pub const BOX_SYSTEM_ID_MIN: u32 = 256; 550 | pub const BOX_SCHEMA_ID: u32 = 272; 551 | pub const BOX_SPACE_ID: u32 = 280; 552 | pub const BOX_VSPACE_ID: u32 = 281; 553 | pub const BOX_INDEX_ID: u32 = 288; 554 | pub const BOX_VINDEX_ID: u32 = 289; 555 | pub const BOX_FUNC_ID: u32 = 296; 556 | pub const BOX_VFUNC_ID: u32 = 297; 557 | pub const BOX_USER_ID: u32 = 304; 558 | pub const BOX_VUSER_ID: u32 = 305; 559 | pub const BOX_PRIV_ID: u32 = 312; 560 | pub const BOX_VPRIV_ID: u32 = 313; 561 | pub const BOX_CLUSTER_ID: u32 = 320; 562 | pub const BOX_SYSTEM_ID_MAX: u32 = 511; 563 | pub const BOX_ID_NIL: u32 = 2147483647; 564 | 565 | #[repr(C)] 566 | #[derive(Debug, Copy)] 567 | pub struct box_function_ctx { 568 | pub _address: u8, 569 | } 570 | impl Clone for box_function_ctx { 571 | fn clone(&self) -> Self { *self } 572 | } 573 | pub type BoxFunctionCtx = box_function_ctx; 574 | extern "C" { 575 | /** 576 | * Return a tuple from stored C procedure. 577 | * 578 | * Returned tuple is automatically reference counted by Tarantool. 579 | * 580 | * \param ctx an opaque structure passed to the stored C procedure by 581 | * Tarantool 582 | * \param tuple a tuple to return 583 | * \retval -1 on error (perhaps, out of memory; check box_error_last()) 584 | * \retval 0 otherwise 585 | */ 586 | pub fn box_return_tuple(ctx: *mut BoxFunctionCtx, 587 | tuple: *mut BoxTuple) -> ::std::os::raw::c_int; 588 | /** 589 | * Find space id by name. 590 | * 591 | * This function performs SELECT request to _vspace system space. 592 | * \param name space name 593 | * \param len length of \a name 594 | * \retval BOX_ID_NIL on error or if not found (check box_error_last()) 595 | * \retval space_id otherwise 596 | * \sa box_index_id_by_name 597 | */ 598 | pub fn box_space_id_by_name(name: *const ::std::os::raw::c_char, len: u32) 599 | -> u32; 600 | /** 601 | * Find index id by name. 602 | * 603 | * This function performs SELECT request to _vindex system space. 604 | * \param space_id space identifier 605 | * \param name index name 606 | * \param len length of \a name 607 | * \retval BOX_ID_NIL on error or if not found (check box_error_last()) 608 | * \retval index_id otherwise 609 | * \sa box_space_id_by_name 610 | */ 611 | pub fn box_index_id_by_name(space_id: u32, 612 | name: *const ::std::os::raw::c_char, len: u32) 613 | -> u32; 614 | /** 615 | * Execute an INSERT request. 616 | * 617 | * \param space_id space identifier 618 | * \param tuple encoded tuple in MsgPack Array format ([ field1, field2, ...]) 619 | * \param tuple_end end of @a tuple 620 | * \param[out] result a new tuple. Can be set to NULL to discard result. 621 | * \retval -1 on error (check box_error_last()) 622 | * \retval 0 on success 623 | * \sa \code box.space[space_id]:insert(tuple) \endcode 624 | */ 625 | pub fn box_insert(space_id: u32, tuple: *const ::std::os::raw::c_char, 626 | tuple_end: *const ::std::os::raw::c_char, 627 | result: *mut *mut BoxTuple) -> ::std::os::raw::c_int; 628 | /** 629 | * Execute an REPLACE request. 630 | * 631 | * \param space_id space identifier 632 | * \param tuple encoded tuple in MsgPack Array format ([ field1, field2, ...]) 633 | * \param tuple_end end of @a tuple 634 | * \param[out] result a new tuple. Can be set to NULL to discard result. 635 | * \retval -1 on error (check box_error_last()) 636 | * \retval 0 on success 637 | * \sa \code box.space[space_id]:replace(tuple) \endcode 638 | */ 639 | pub fn box_replace(space_id: u32, tuple: *const ::std::os::raw::c_char, 640 | tuple_end: *const ::std::os::raw::c_char, 641 | result: *mut *mut BoxTuple) 642 | -> ::std::os::raw::c_int; 643 | /** 644 | * Execute an DELETE request. 645 | * 646 | * \param space_id space identifier 647 | * \param index_id index identifier 648 | * \param key encoded key in MsgPack Array format ([part1, part2, ...]). 649 | * \param key_end the end of encoded \a key. 650 | * \param[out] result an old tuple. Can be set to NULL to discard result. 651 | * \retval -1 on error (check box_error_last()) 652 | * \retval 0 on success 653 | * \sa \code box.space[space_id].index[index_id]:delete(key) \endcode 654 | */ 655 | pub fn box_delete(space_id: u32, index_id: u32, 656 | key: *const ::std::os::raw::c_char, 657 | key_end: *const ::std::os::raw::c_char, 658 | result: *mut *mut BoxTuple) -> ::std::os::raw::c_int; 659 | /** 660 | * Execute an UPDATE request. 661 | * 662 | * \param space_id space identifier 663 | * \param index_id index identifier 664 | * \param key encoded key in MsgPack Array format ([part1, part2, ...]). 665 | * \param key_end the end of encoded \a key. 666 | * \param ops encoded operations in MsgPack Arrat format, e.g. 667 | * [ [ '=', fieldno, value ], ['!', 2, 'xxx'] ] 668 | * \param ops_end the end of encoded \a ops 669 | * \param index_base 0 if fieldnos in update operations are zero-based 670 | * indexed (like C) or 1 if for one-based indexed field ids (like Lua). 671 | * \param[out] result a new tuple. Can be set to NULL to discard result. 672 | * \retval -1 on error (check box_error_last()) 673 | * \retval 0 on success 674 | * \sa \code box.space[space_id].index[index_id]:update(key, ops) \endcode 675 | * \sa box_upsert() 676 | */ 677 | pub fn box_update(space_id: u32, index_id: u32, 678 | key: *const ::std::os::raw::c_char, 679 | key_end: *const ::std::os::raw::c_char, 680 | ops: *const ::std::os::raw::c_char, 681 | ops_end: *const ::std::os::raw::c_char, 682 | index_base: ::std::os::raw::c_int, 683 | result: *mut *mut BoxTuple) -> ::std::os::raw::c_int; 684 | /** 685 | * Execute an UPSERT request. 686 | * 687 | * \param space_id space identifier 688 | * \param index_id index identifier 689 | * \param ops encoded operations in MsgPack Arrat format, e.g. 690 | * [ [ '=', fieldno, value ], ['!', 2, 'xxx'] ] 691 | * \param ops_end the end of encoded \a ops 692 | * \param tuple encoded tuple in MsgPack Array format ([ field1, field2, ...]) 693 | * \param tuple_end end of @a tuple 694 | * \param index_base 0 if fieldnos in update operations are zero-based 695 | * indexed (like C) or 1 if for one-based indexed field ids (like Lua). 696 | * \param[out] result a new tuple. Can be set to NULL to discard result. 697 | * \retval -1 on error (check box_error_last()) 698 | * \retval 0 on success 699 | * \sa \code box.space[space_id].index[index_id]:update(key, ops) \endcode 700 | * \sa box_update() 701 | */ 702 | pub fn box_upsert(space_id: u32, index_id: u32, 703 | tuple: *const ::std::os::raw::c_char, 704 | tuple_end: *const ::std::os::raw::c_char, 705 | ops: *const ::std::os::raw::c_char, 706 | ops_end: *const ::std::os::raw::c_char, 707 | index_base: ::std::os::raw::c_int, 708 | result: *mut *mut BoxTuple) -> ::std::os::raw::c_int; 709 | /** 710 | * Truncate space. 711 | * 712 | * \param space_id space identifier 713 | */ 714 | pub fn box_truncate(space_id: u32) -> ::std::os::raw::c_int; 715 | } 716 | 717 | /* }}} Space */ 718 | 719 | /* {{{ Index */ 720 | 721 | #[repr(C)] 722 | #[derive(Debug, Copy)] 723 | pub struct iterator { 724 | pub _address: u8, 725 | } 726 | impl Clone for iterator { 727 | fn clone(&self) -> Self { *self } 728 | } 729 | /** A space iterator */ 730 | pub type BoxIterator = iterator; 731 | #[repr(u32)] 732 | /** 733 | * Controls how to iterate over tuples in an index. 734 | * Different index types support different iterator types. 735 | * For example, one can start iteration from a particular value 736 | * (request key) and then retrieve all tuples where keys are 737 | * greater or equal (= GE) to this key. 738 | * 739 | * If iterator type is not supported by the selected index type, 740 | * iterator constructor must fail with ER_UNSUPPORTED. To be 741 | * selectable for primary key, an index must support at least 742 | * ITER_EQ and ITER_GE types. 743 | * 744 | * NULL value of request key corresponds to the first or last 745 | * key in the index, depending on iteration direction. 746 | * (first key for GE and GT types, and last key for LE and LT). 747 | * Therefore, to iterate over all tuples in an index, one can 748 | * use ITER_GE or ITER_LE iteration types with start key equal 749 | * to NULL. 750 | * For ITER_EQ, the key must not be NULL. 751 | */ 752 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 753 | pub enum IteratorType { 754 | EQ = 0, 755 | REQ = 1, 756 | ALL = 2, 757 | LT = 3, 758 | LE = 4, 759 | GE = 5, 760 | GT = 6, 761 | BitsAllSet = 7, 762 | BitsAnySet = 8, 763 | BitsAllNotSet = 9, 764 | Ovelaps = 10, 765 | Neigbor = 11, 766 | } 767 | extern "C" { 768 | /** 769 | * Allocate and initialize iterator for space_id, index_id. 770 | * 771 | * A returned iterator must be destroyed by box_iterator_free(). 772 | * 773 | * \param space_id space identifier. 774 | * \param index_id index identifier. 775 | * \param type \link iterator_type iterator type \endlink 776 | * \param key encoded key in MsgPack Array format ([part1, part2, ...]). 777 | * \param key_end the end of encoded \a key 778 | * \retval NULL on error (check box_error_last()) 779 | * \retval iterator otherwise 780 | * \sa box_iterator_next() 781 | * \sa box_iterator_free() 782 | */ 783 | pub fn box_index_iterator(space_id: u32, index_id: u32, 784 | type_: ::std::os::raw::c_int, 785 | key: *const ::std::os::raw::c_char, 786 | key_end: *const ::std::os::raw::c_char) 787 | -> *mut BoxIterator; 788 | /** 789 | * Retrive the next item from the \a iterator. 790 | * 791 | * \param iterator an iterator returned by box_index_iterator(). 792 | * \param[out] result a tuple or NULL if there is no more data. 793 | * \retval -1 on error (check box_error_last() for details) 794 | * \retval 0 on success. The end of data is not an error. 795 | */ 796 | pub fn box_iterator_next(iterator: *mut BoxIterator, 797 | result: *mut *mut BoxTuple) 798 | -> ::std::os::raw::c_int; 799 | /** 800 | * Destroy and deallocate iterator. 801 | * 802 | * \param iterator an interator returned by box_index_iterator() 803 | */ 804 | pub fn box_iterator_free(iterator: *mut BoxIterator); 805 | /** 806 | * Return the number of element in the index. 807 | * 808 | * \param space_id space identifier 809 | * \param index_id index identifier 810 | * \retval -1 on error (check box_error_last()) 811 | * \retval >= 0 otherwise 812 | */ 813 | pub fn box_index_len(space_id: u32, index_id: u32) -> isize; 814 | /** 815 | * Return the number of bytes used in memory by the index. 816 | * 817 | * \param space_id space identifier 818 | * \param index_id index identifier 819 | * \retval -1 on error (check box_error_last()) 820 | * \retval >= 0 otherwise 821 | */ 822 | pub fn box_index_bsize(space_id: u32, index_id: u32) -> isize; 823 | /** 824 | * Return a random tuple from the index (useful for statistical analysis). 825 | * 826 | * \param space_id space identifier 827 | * \param index_id index identifier 828 | * \param rnd random seed 829 | * \param[out] result a tuple or NULL if index is empty 830 | * \retval -1 on error (check box_error_last()) 831 | * \retval 0 on success 832 | * \sa \code box.space[space_id].index[index_id]:random(rnd) \endcode 833 | */ 834 | pub fn box_index_random(space_id: u32, index_id: u32, rnd: u32, 835 | result: *mut *mut BoxTuple) 836 | -> ::std::os::raw::c_int; 837 | /** 838 | * Get a tuple from index by the key. 839 | * 840 | * Please note that this function works much more faster than 841 | * box_select() or box_index_iterator() + box_iterator_next(). 842 | * 843 | * \param space_id space identifier 844 | * \param index_id index identifier 845 | * \param key encoded key in MsgPack Array format ([part1, part2, ...]). 846 | * \param key_end the end of encoded \a key 847 | * \param[out] result a tuple or NULL if index is empty 848 | * \retval -1 on error (check box_error_last()) 849 | * \retval 0 on success 850 | * \pre key != NULL 851 | * \sa \code box.space[space_id].index[index_id]:get(key) \endcode 852 | */ 853 | pub fn box_index_get(space_id: u32, index_id: u32, 854 | key: *const ::std::os::raw::c_char, 855 | key_end: *const ::std::os::raw::c_char, 856 | result: *mut *mut BoxTuple) 857 | -> ::std::os::raw::c_int; 858 | /** 859 | * Return a first (minimal) tuple matched the provided key. 860 | * 861 | * \param space_id space identifier 862 | * \param index_id index identifier 863 | * \param key encoded key in MsgPack Array format ([part1, part2, ...]). 864 | * \param key_end the end of encoded \a key. 865 | * \param[out] result a tuple or NULL if index is empty 866 | * \retval -1 on error (check box_error_last()) 867 | * \retval 0 on success 868 | * \sa \code box.space[space_id].index[index_id]:min(key) \endcode 869 | */ 870 | pub fn box_index_min(space_id: u32, index_id: u32, 871 | key: *const ::std::os::raw::c_char, 872 | key_end: *const ::std::os::raw::c_char, 873 | result: *mut *mut BoxTuple) 874 | -> ::std::os::raw::c_int; 875 | /** 876 | * Return a last (maximal) tuple matched the provided key. 877 | * 878 | * \param space_id space identifier 879 | * \param index_id index identifier 880 | * \param key encoded key in MsgPack Array format ([part1, part2, ...]). 881 | * \param key_end the end of encoded \a key. 882 | * \param[out] result a tuple or NULL if index is empty 883 | * \retval -1 on error (check box_error_last()) 884 | * \retval 0 on success 885 | * \sa \code box.space[space_id].index[index_id]:max(key) \endcode 886 | */ 887 | pub fn box_index_max(space_id: u32, index_id: u32, 888 | key: *const ::std::os::raw::c_char, 889 | key_end: *const ::std::os::raw::c_char, 890 | result: *mut *mut BoxTuple) 891 | -> ::std::os::raw::c_int; 892 | /** 893 | * Count the number of tuple matched the provided key. 894 | * 895 | * \param space_id space identifier 896 | * \param index_id index identifier 897 | * \param type iterator type - enum \link iterator_type \endlink 898 | * \param key encoded key in MsgPack Array format ([part1, part2, ...]). 899 | * \param key_end the end of encoded \a key. 900 | * \retval -1 on error (check box_error_last()) 901 | * \retval >=0 on success 902 | * \sa \code box.space[space_id].index[index_id]:count(key, 903 | * { iterator = type }) \endcode 904 | */ 905 | pub fn box_index_count(space_id: u32, index_id: u32, 906 | type_: ::std::os::raw::c_int, 907 | key: *const ::std::os::raw::c_char, 908 | key_end: *const ::std::os::raw::c_char) -> isize; 909 | } 910 | 911 | /* }}} Index */ 912 | 913 | /* {{{ Error */ 914 | 915 | #[repr(C)] 916 | #[derive(Debug, Copy)] 917 | pub struct error { 918 | pub _address: u8, 919 | } 920 | impl Clone for error { 921 | fn clone(&self) -> Self { *self } 922 | } 923 | /** 924 | * Error - contains information about error. 925 | */ 926 | pub type BoxError = error; 927 | extern "C" { 928 | /** 929 | * Return the error type, e.g. "ClientError", "SocketError", etc. 930 | * \param error 931 | * \return not-null string 932 | */ 933 | pub fn BoxErrorype(error: *const BoxError) 934 | -> *const ::std::os::raw::c_char; 935 | /** 936 | * Return IPROTO error code 937 | * \param error error 938 | * \return enum box_error_code 939 | */ 940 | pub fn box_error_code(error: *const BoxError) -> u32; 941 | /** 942 | * Return the error message 943 | * \param error error 944 | * \return not-null string 945 | */ 946 | pub fn box_error_message(error: *const BoxError) 947 | -> *const ::std::os::raw::c_char; 948 | /** 949 | * Get the information about the last API call error. 950 | * 951 | * The Tarantool error handling works most like libc's errno. All API calls 952 | * return -1 or NULL in the event of error. An internal pointer to 953 | * BoxError type is set by API functions to indicate what went wrong. 954 | * This value is only significant if API call failed (returned -1 or NULL). 955 | * 956 | * Successful function can also touch the last error in some 957 | * cases. You don't have to clear the last error before calling 958 | * API functions. The returned object is valid only until next 959 | * call to **any** API function. 960 | * 961 | * You must set the last error using box_error_set() in your stored C 962 | * procedures if you want to return a custom error message. 963 | * You can re-throw the last API error to IPROTO client by keeping 964 | * the current value and returning -1 to Tarantool from your 965 | * stored procedure. 966 | * 967 | * \return last error. 968 | */ 969 | pub fn box_error_last() -> *mut BoxError; 970 | /** 971 | * Clear the last error. 972 | */ 973 | pub fn box_error_clear(); 974 | /** 975 | * Set the last error. 976 | * 977 | * \param code IPROTO error code (enum \link box_error_code \endlink) 978 | * \param format (const char * ) - printf()-like format string 979 | * \param ... - format arguments 980 | * \returns -1 for convention use 981 | * 982 | * \sa enum box_error_code 983 | */ 984 | pub fn box_error_set(file: *const ::std::os::raw::c_char, 985 | line: ::std::os::raw::c_uint, code: u32, 986 | format: *const ::std::os::raw::c_char, ...) 987 | -> ::std::os::raw::c_int; 988 | } 989 | 990 | /* }}} Error */ 991 | 992 | /* {{{ Latch */ 993 | 994 | #[repr(C)] 995 | #[derive(Debug, Copy)] 996 | pub struct box_latch { 997 | pub _address: u8, 998 | } 999 | impl Clone for box_latch { 1000 | fn clone(&self) -> Self { *self } 1001 | } 1002 | /** 1003 | * A lock for cooperative multitasking environment 1004 | */ 1005 | pub type BoxLatch = box_latch; 1006 | extern "C" { 1007 | /** 1008 | * Allocate and initialize the new latch. 1009 | * \returns latch 1010 | */ 1011 | pub fn box_latch_new() -> *mut BoxLatch; 1012 | /** 1013 | * Destroy and free the latch. 1014 | * \param latch latch 1015 | */ 1016 | pub fn box_latch_delete(latch: *mut BoxLatch); 1017 | /** 1018 | * Lock a latch. Waits indefinitely until the current fiber can gain access to 1019 | * the latch. 1020 | * 1021 | * \param latch a latch 1022 | */ 1023 | pub fn box_latch_lock(latch: *mut BoxLatch); 1024 | /** 1025 | * Try to lock a latch. Return immediately if the latch is locked. 1026 | * \param latch a latch 1027 | * \retval 0 - success 1028 | * \retval 1 - the latch is locked. 1029 | */ 1030 | pub fn BoxLatchrylock(latch: *mut BoxLatch) 1031 | -> ::std::os::raw::c_int; 1032 | /** 1033 | * Unlock a latch. The fiber calling this function must 1034 | * own the latch. 1035 | * 1036 | * \param latch a latch 1037 | */ 1038 | pub fn box_latch_unlock(latch: *mut BoxLatch); 1039 | } 1040 | 1041 | /* }}} Latch */ 1042 | 1043 | /* {{{ Clock */ 1044 | 1045 | extern "C" { 1046 | pub fn clock_realtime() -> f64; 1047 | pub fn clock_monotonic() -> f64; 1048 | pub fn clock_process() -> f64; 1049 | pub fn clock_thread() -> f64; 1050 | pub fn clock_realtime64() -> u64; 1051 | pub fn clock_monotonic64() -> u64; 1052 | pub fn clock_process64() -> u64; 1053 | pub fn clock_thread64() -> u64; 1054 | } 1055 | 1056 | /* }}} Clock */ 1057 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tarantool 2 | 3 | local ffi = require('ffi') 4 | local fiber = require('fiber') 5 | 6 | -- Load compiled library 7 | local rust = ffi.load('./target/debug/libtarantool_rust_module.so') 8 | ffi.cdef('void rustproc(uint64_t fiber_id)'); 9 | 10 | -- 11 | -- Check that fiber_yield() doesn't kill Rust code 12 | -- 13 | 14 | local function rustproc(ch) 15 | rust.rustproc(fiber.id()) -- Rust code that yields 16 | ch:put(true) 17 | end 18 | -- start fibers 19 | local N = 5 20 | local join = fiber.channel(N) 21 | for i=1,N do fiber.create(rustproc, join) end 22 | -- join fibers 23 | for i=1,N do join:get() end 24 | 25 | os.exit(0) 26 | --------------------------------------------------------------------------------