2015-01-16 14:30:27 -06:00
|
|
|
|
% Foreign Function Interface
|
2012-09-26 21:00:13 -05:00
|
|
|
|
|
|
|
|
|
# Introduction
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2014-05-30 23:27:47 -05:00
|
|
|
|
This guide will use the [snappy](https://github.com/google/snappy)
|
2013-04-11 22:05:06 -05:00
|
|
|
|
compression/decompression library as an introduction to writing bindings for
|
|
|
|
|
foreign code. Rust is currently unable to call directly into a C++ library, but
|
|
|
|
|
snappy includes a C interface (documented in
|
2014-05-30 23:27:47 -05:00
|
|
|
|
[`snappy-c.h`](https://github.com/google/snappy/blob/master/snappy-c.h)).
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-11-30 15:26:46 -06:00
|
|
|
|
The following is a minimal example of calling a foreign function which will
|
|
|
|
|
compile if snappy is installed:
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```no_run
|
2015-03-13 17:28:35 -05:00
|
|
|
|
# #![feature(libc)]
|
2014-02-26 11:58:41 -06:00
|
|
|
|
extern crate libc;
|
|
|
|
|
use libc::size_t;
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-11-30 15:26:46 -06:00
|
|
|
|
#[link(name = "snappy")]
|
2013-04-11 22:05:06 -05:00
|
|
|
|
extern {
|
|
|
|
|
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
|
2012-09-05 13:20:04 -05:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-23 01:58:27 -06:00
|
|
|
|
fn main() {
|
2013-04-11 22:05:06 -05:00
|
|
|
|
let x = unsafe { snappy_max_compressed_length(100) };
|
2013-11-06 17:16:04 -06:00
|
|
|
|
println!("max compressed length of a 100 byte buffer: {}", x);
|
2012-09-05 13:20:04 -05:00
|
|
|
|
}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-11-30 15:26:46 -06:00
|
|
|
|
The `extern` block is a list of function signatures in a foreign library, in
|
|
|
|
|
this case with the platform's C ABI. The `#[link(...)]` attribute is used to
|
|
|
|
|
instruct the linker to link against the snappy library so the symbols are
|
|
|
|
|
resolved.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-11-30 15:26:46 -06:00
|
|
|
|
Foreign functions are assumed to be unsafe so calls to them need to be wrapped
|
|
|
|
|
with `unsafe {}` as a promise to the compiler that everything contained within
|
|
|
|
|
truly is safe. C libraries often expose interfaces that aren't thread-safe, and
|
|
|
|
|
almost any function that takes a pointer argument isn't valid for all possible
|
|
|
|
|
inputs since the pointer could be dangling, and raw pointers fall outside of
|
2013-04-11 22:05:06 -05:00
|
|
|
|
Rust's safe memory model.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-11-30 15:26:46 -06:00
|
|
|
|
When declaring the argument types to a foreign function, the Rust compiler can
|
|
|
|
|
not check if the declaration is correct, so specifying it correctly is part of
|
|
|
|
|
keeping the binding correct at runtime.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
The `extern` block can be extended to cover the entire snappy API:
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```no_run
|
2015-03-13 17:28:35 -05:00
|
|
|
|
# #![feature(libc)]
|
2014-02-26 11:58:41 -06:00
|
|
|
|
extern crate libc;
|
|
|
|
|
use libc::{c_int, size_t};
|
2013-04-11 22:05:06 -05:00
|
|
|
|
|
2013-11-30 15:26:46 -06:00
|
|
|
|
#[link(name = "snappy")]
|
2013-04-11 22:05:06 -05:00
|
|
|
|
extern {
|
2014-06-25 14:47:34 -05:00
|
|
|
|
fn snappy_compress(input: *const u8,
|
2013-04-11 22:05:06 -05:00
|
|
|
|
input_length: size_t,
|
|
|
|
|
compressed: *mut u8,
|
|
|
|
|
compressed_length: *mut size_t) -> c_int;
|
2014-06-25 14:47:34 -05:00
|
|
|
|
fn snappy_uncompress(compressed: *const u8,
|
2013-04-11 22:05:06 -05:00
|
|
|
|
compressed_length: size_t,
|
|
|
|
|
uncompressed: *mut u8,
|
|
|
|
|
uncompressed_length: *mut size_t) -> c_int;
|
|
|
|
|
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
|
2014-06-25 14:47:34 -05:00
|
|
|
|
fn snappy_uncompressed_length(compressed: *const u8,
|
2013-04-11 22:05:06 -05:00
|
|
|
|
compressed_length: size_t,
|
|
|
|
|
result: *mut size_t) -> c_int;
|
2014-06-25 14:47:34 -05:00
|
|
|
|
fn snappy_validate_compressed_buffer(compressed: *const u8,
|
2013-04-11 22:05:06 -05:00
|
|
|
|
compressed_length: size_t) -> c_int;
|
2012-09-05 13:20:04 -05:00
|
|
|
|
}
|
2014-05-02 19:19:19 -05:00
|
|
|
|
# fn main() {}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
# Creating a safe interface
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-12 02:14:26 -05:00
|
|
|
|
The raw C API needs to be wrapped to provide memory safety and make use of higher-level concepts
|
|
|
|
|
like vectors. A library can choose to expose only the safe, high-level interface and hide the unsafe
|
2013-04-11 22:05:06 -05:00
|
|
|
|
internal details.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2014-03-08 17:11:52 -06:00
|
|
|
|
Wrapping the functions which expect buffers involves using the `slice::raw` module to manipulate Rust
|
2013-04-11 22:05:06 -05:00
|
|
|
|
vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The
|
|
|
|
|
length is number of elements currently contained, and the capacity is the total size in elements of
|
|
|
|
|
the allocated memory. The length is less than or equal to the capacity.
|
|
|
|
|
|
2015-05-18 13:56:00 -05:00
|
|
|
|
```rust
|
2015-03-13 17:28:35 -05:00
|
|
|
|
# #![feature(libc)]
|
2014-04-11 08:29:54 -05:00
|
|
|
|
# extern crate libc;
|
|
|
|
|
# use libc::{c_int, size_t};
|
2014-06-25 14:47:34 -05:00
|
|
|
|
# unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 }
|
2014-04-11 08:29:54 -05:00
|
|
|
|
# fn main() {}
|
2013-04-11 22:05:06 -05:00
|
|
|
|
pub fn validate_compressed_buffer(src: &[u8]) -> bool {
|
|
|
|
|
unsafe {
|
2013-12-15 06:35:12 -06:00
|
|
|
|
snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0
|
2013-04-11 22:05:06 -05:00
|
|
|
|
}
|
2012-09-05 13:20:04 -05:00
|
|
|
|
}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the
|
|
|
|
|
guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
|
|
|
|
|
signature.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
|
|
|
|
|
allocated to hold the output too.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
The `snappy_max_compressed_length` function can be used to allocate a vector with the maximum
|
|
|
|
|
required capacity to hold the compressed output. The vector can then be passed to the
|
|
|
|
|
`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
|
|
|
|
|
the true length after compression for setting the length.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2015-05-18 13:56:00 -05:00
|
|
|
|
```rust
|
2015-03-13 17:28:35 -05:00
|
|
|
|
# #![feature(libc)]
|
2014-04-11 08:29:54 -05:00
|
|
|
|
# extern crate libc;
|
|
|
|
|
# use libc::{size_t, c_int};
|
2014-06-25 14:47:34 -05:00
|
|
|
|
# unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8,
|
2014-04-11 08:29:54 -05:00
|
|
|
|
# d: *mut size_t) -> c_int { 0 }
|
|
|
|
|
# unsafe fn snappy_max_compressed_length(a: size_t) -> size_t { a }
|
|
|
|
|
# fn main() {}
|
|
|
|
|
pub fn compress(src: &[u8]) -> Vec<u8> {
|
2013-04-11 22:05:06 -05:00
|
|
|
|
unsafe {
|
|
|
|
|
let srclen = src.len() as size_t;
|
2013-12-15 06:35:12 -06:00
|
|
|
|
let psrc = src.as_ptr();
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
let mut dstlen = snappy_max_compressed_length(srclen);
|
2015-01-13 09:40:18 -06:00
|
|
|
|
let mut dst = Vec::with_capacity(dstlen as usize);
|
2013-12-15 06:35:12 -06:00
|
|
|
|
let pdst = dst.as_mut_ptr();
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
snappy_compress(psrc, srclen, pdst, &mut dstlen);
|
2015-01-13 09:40:18 -06:00
|
|
|
|
dst.set_len(dstlen as usize);
|
2013-04-11 22:05:06 -05:00
|
|
|
|
dst
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
Decompression is similar, because snappy stores the uncompressed size as part of the compression
|
|
|
|
|
format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2015-05-18 13:56:00 -05:00
|
|
|
|
```rust
|
2015-03-13 17:28:35 -05:00
|
|
|
|
# #![feature(libc)]
|
2014-04-11 08:29:54 -05:00
|
|
|
|
# extern crate libc;
|
|
|
|
|
# use libc::{size_t, c_int};
|
2014-06-25 14:47:34 -05:00
|
|
|
|
# unsafe fn snappy_uncompress(compressed: *const u8,
|
2014-04-11 08:29:54 -05:00
|
|
|
|
# compressed_length: size_t,
|
|
|
|
|
# uncompressed: *mut u8,
|
|
|
|
|
# uncompressed_length: *mut size_t) -> c_int { 0 }
|
2014-06-25 14:47:34 -05:00
|
|
|
|
# unsafe fn snappy_uncompressed_length(compressed: *const u8,
|
2014-04-11 08:29:54 -05:00
|
|
|
|
# compressed_length: size_t,
|
|
|
|
|
# result: *mut size_t) -> c_int { 0 }
|
|
|
|
|
# fn main() {}
|
|
|
|
|
pub fn uncompress(src: &[u8]) -> Option<Vec<u8>> {
|
2013-04-11 22:05:06 -05:00
|
|
|
|
unsafe {
|
|
|
|
|
let srclen = src.len() as size_t;
|
2013-12-15 06:35:12 -06:00
|
|
|
|
let psrc = src.as_ptr();
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
let mut dstlen: size_t = 0;
|
|
|
|
|
snappy_uncompressed_length(psrc, srclen, &mut dstlen);
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2015-01-13 09:40:18 -06:00
|
|
|
|
let mut dst = Vec::with_capacity(dstlen as usize);
|
2013-12-15 06:35:12 -06:00
|
|
|
|
let pdst = dst.as_mut_ptr();
|
2013-04-11 22:05:06 -05:00
|
|
|
|
|
|
|
|
|
if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
|
2015-01-13 09:40:18 -06:00
|
|
|
|
dst.set_len(dstlen as usize);
|
2013-04-11 22:05:06 -05:00
|
|
|
|
Some(dst)
|
|
|
|
|
} else {
|
|
|
|
|
None // SNAPPY_INVALID_INPUT
|
|
|
|
|
}
|
2012-09-05 13:20:04 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2015-04-15 14:56:01 -05:00
|
|
|
|
For reference, the examples used here are also available as a [library on
|
2013-04-11 22:05:06 -05:00
|
|
|
|
GitHub](https://github.com/thestinger/rust-snappy).
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-25 21:08:29 -05:00
|
|
|
|
# Destructors
|
|
|
|
|
|
2013-12-05 04:58:30 -06:00
|
|
|
|
Foreign libraries often hand off ownership of resources to the calling code.
|
|
|
|
|
When this occurs, we must use Rust's destructors to provide safety and guarantee
|
2014-10-09 14:17:22 -05:00
|
|
|
|
the release of these resources (especially in the case of panic).
|
2013-04-25 21:08:29 -05:00
|
|
|
|
|
2015-03-19 17:11:35 -05:00
|
|
|
|
For more about destructors, see the [Drop trait](../std/ops/trait.Drop.html).
|
|
|
|
|
|
2014-01-11 17:47:30 -06:00
|
|
|
|
# Callbacks from C code to Rust functions
|
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
|
Some external libraries require the usage of callbacks to report back their
|
|
|
|
|
current state or intermediate data to the caller.
|
2014-01-11 17:47:30 -06:00
|
|
|
|
It is possible to pass functions defined in Rust to an external library.
|
|
|
|
|
The requirement for this is that the callback function is marked as `extern`
|
|
|
|
|
with the correct calling convention to make it callable from C code.
|
|
|
|
|
|
2014-07-04 13:09:28 -05:00
|
|
|
|
The callback function can then be sent through a registration call
|
2014-01-11 17:47:30 -06:00
|
|
|
|
to the C library and afterwards be invoked from there.
|
|
|
|
|
|
|
|
|
|
A basic example is:
|
|
|
|
|
|
|
|
|
|
Rust code:
|
2014-03-08 05:05:20 -06:00
|
|
|
|
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```no_run
|
2014-09-12 02:10:03 -05:00
|
|
|
|
extern fn callback(a: i32) {
|
2014-01-11 17:47:30 -06:00
|
|
|
|
println!("I'm called from C with value {0}", a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[link(name = "extlib")]
|
|
|
|
|
extern {
|
2014-04-11 08:29:54 -05:00
|
|
|
|
fn register_callback(cb: extern fn(i32)) -> i32;
|
2014-01-12 06:27:59 -06:00
|
|
|
|
fn trigger_callback();
|
2014-01-11 17:47:30 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
unsafe {
|
|
|
|
|
register_callback(callback);
|
2014-01-12 06:27:59 -06:00
|
|
|
|
trigger_callback(); // Triggers the callback
|
2014-01-11 17:47:30 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2014-01-11 17:47:30 -06:00
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
|
C code:
|
2014-03-08 05:05:20 -06:00
|
|
|
|
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```c
|
2014-01-11 17:47:30 -06:00
|
|
|
|
typedef void (*rust_callback)(int32_t);
|
|
|
|
|
rust_callback cb;
|
|
|
|
|
|
|
|
|
|
int32_t register_callback(rust_callback callback) {
|
|
|
|
|
cb = callback;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
|
void trigger_callback() {
|
2014-01-11 17:47:30 -06:00
|
|
|
|
cb(7); // Will call callback(7) in Rust
|
|
|
|
|
}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2014-01-11 17:47:30 -06:00
|
|
|
|
|
2014-09-12 02:03:15 -05:00
|
|
|
|
In this example Rust's `main()` will call `trigger_callback()` in C,
|
2014-07-04 13:09:28 -05:00
|
|
|
|
which would, in turn, call back to `callback()` in Rust.
|
2014-01-12 06:27:59 -06:00
|
|
|
|
|
2014-01-11 17:47:30 -06:00
|
|
|
|
|
2014-07-04 13:09:28 -05:00
|
|
|
|
## Targeting callbacks to Rust objects
|
2014-01-11 17:47:30 -06:00
|
|
|
|
|
2014-01-25 14:35:28 -06:00
|
|
|
|
The former example showed how a global function can be called from C code.
|
2014-07-04 13:09:28 -05:00
|
|
|
|
However it is often desired that the callback is targeted to a special
|
2014-01-11 17:47:30 -06:00
|
|
|
|
Rust object. This could be the object that represents the wrapper for the
|
2014-02-14 17:42:01 -06:00
|
|
|
|
respective C object.
|
2014-01-11 17:47:30 -06:00
|
|
|
|
|
2015-06-09 15:49:24 -05:00
|
|
|
|
This can be achieved by passing an raw pointer to the object down to the
|
2014-01-11 17:47:30 -06:00
|
|
|
|
C library. The C library can then include the pointer to the Rust object in
|
2014-01-25 14:35:28 -06:00
|
|
|
|
the notification. This will allow the callback to unsafely access the
|
|
|
|
|
referenced Rust object.
|
2014-01-11 17:47:30 -06:00
|
|
|
|
|
|
|
|
|
Rust code:
|
2014-03-08 05:05:20 -06:00
|
|
|
|
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```no_run
|
2014-08-21 11:58:42 -05:00
|
|
|
|
#[repr(C)]
|
2014-01-12 06:27:59 -06:00
|
|
|
|
struct RustObject {
|
|
|
|
|
a: i32,
|
|
|
|
|
// other members
|
2014-01-11 17:47:30 -06:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-12 02:10:03 -05:00
|
|
|
|
extern "C" fn callback(target: *mut RustObject, a: i32) {
|
2014-01-12 06:27:59 -06:00
|
|
|
|
println!("I'm called from C with value {0}", a);
|
2014-04-11 08:29:54 -05:00
|
|
|
|
unsafe {
|
|
|
|
|
// Update the value in RustObject with the value received from the callback
|
|
|
|
|
(*target).a = a;
|
|
|
|
|
}
|
2014-01-11 17:47:30 -06:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
|
#[link(name = "extlib")]
|
|
|
|
|
extern {
|
2014-04-11 08:29:54 -05:00
|
|
|
|
fn register_callback(target: *mut RustObject,
|
|
|
|
|
cb: extern fn(*mut RustObject, i32)) -> i32;
|
2014-01-12 06:27:59 -06:00
|
|
|
|
fn trigger_callback();
|
2014-01-11 17:47:30 -06:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
|
fn main() {
|
|
|
|
|
// Create the object that will be referenced in the callback
|
2015-01-07 20:53:58 -06:00
|
|
|
|
let mut rust_object = Box::new(RustObject { a: 5 });
|
2014-02-14 17:42:01 -06:00
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
|
unsafe {
|
2014-04-11 08:29:54 -05:00
|
|
|
|
register_callback(&mut *rust_object, callback);
|
|
|
|
|
trigger_callback();
|
2014-01-11 17:47:30 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2014-01-11 17:47:30 -06:00
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
|
C code:
|
2014-03-08 05:05:20 -06:00
|
|
|
|
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```c
|
2014-10-13 00:36:10 -05:00
|
|
|
|
typedef void (*rust_callback)(void*, int32_t);
|
2014-01-12 06:27:59 -06:00
|
|
|
|
void* cb_target;
|
2014-01-11 17:47:30 -06:00
|
|
|
|
rust_callback cb;
|
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
|
int32_t register_callback(void* callback_target, rust_callback callback) {
|
|
|
|
|
cb_target = callback_target;
|
2014-01-11 17:47:30 -06:00
|
|
|
|
cb = callback;
|
2014-01-12 06:27:59 -06:00
|
|
|
|
return 1;
|
2014-01-11 17:47:30 -06:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
|
void trigger_callback() {
|
|
|
|
|
cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust
|
2014-01-11 17:47:30 -06:00
|
|
|
|
}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2014-01-11 17:47:30 -06:00
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
|
## Asynchronous callbacks
|
|
|
|
|
|
2014-01-25 14:35:28 -06:00
|
|
|
|
In the previously given examples the callbacks are invoked as a direct reaction
|
2014-01-12 06:27:59 -06:00
|
|
|
|
to a function call to the external C library.
|
2014-01-25 14:35:28 -06:00
|
|
|
|
The control over the current thread is switched from Rust to C to Rust for the
|
2014-01-12 06:27:59 -06:00
|
|
|
|
execution of the callback, but in the end the callback is executed on the
|
2015-01-10 03:45:51 -06:00
|
|
|
|
same thread that called the function which triggered the callback.
|
2014-01-12 06:27:59 -06:00
|
|
|
|
|
2014-01-25 14:35:28 -06:00
|
|
|
|
Things get more complicated when the external library spawns its own threads
|
2014-01-12 06:27:59 -06:00
|
|
|
|
and invokes callbacks from there.
|
2014-01-25 14:35:28 -06:00
|
|
|
|
In these cases access to Rust data structures inside the callbacks is
|
2014-01-12 06:27:59 -06:00
|
|
|
|
especially unsafe and proper synchronization mechanisms must be used.
|
2014-01-25 14:35:28 -06:00
|
|
|
|
Besides classical synchronization mechanisms like mutexes, one possibility in
|
2015-06-24 22:08:55 -05:00
|
|
|
|
Rust is to use channels (in `std::sync::mpsc`) to forward data from the C
|
|
|
|
|
thread that invoked the callback into a Rust thread.
|
2014-01-12 06:27:59 -06:00
|
|
|
|
|
2014-04-20 00:35:14 -05:00
|
|
|
|
If an asynchronous callback targets a special object in the Rust address space
|
2014-02-14 17:42:01 -06:00
|
|
|
|
it is also absolutely necessary that no more callbacks are performed by the
|
|
|
|
|
C library after the respective Rust object gets destroyed.
|
2014-01-25 14:35:28 -06:00
|
|
|
|
This can be achieved by unregistering the callback in the object's
|
2014-01-12 06:27:59 -06:00
|
|
|
|
destructor and designing the library in a way that guarantees that no
|
2014-07-04 13:09:28 -05:00
|
|
|
|
callback will be performed after deregistration.
|
2014-01-11 17:47:30 -06:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
# Linking
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-11-30 15:26:46 -06:00
|
|
|
|
The `link` attribute on `extern` blocks provides the basic building block for
|
|
|
|
|
instructing rustc how it will link to native libraries. There are two accepted
|
|
|
|
|
forms of the link attribute today:
|
|
|
|
|
|
|
|
|
|
* `#[link(name = "foo")]`
|
|
|
|
|
* `#[link(name = "foo", kind = "bar")]`
|
|
|
|
|
|
|
|
|
|
In both of these cases, `foo` is the name of the native library that we're
|
|
|
|
|
linking to, and in the second case `bar` is the type of native library that the
|
|
|
|
|
compiler is linking to. There are currently three known types of native
|
|
|
|
|
libraries:
|
|
|
|
|
|
2014-08-12 02:13:50 -05:00
|
|
|
|
* Dynamic - `#[link(name = "readline")]`
|
|
|
|
|
* Static - `#[link(name = "my_build_dependency", kind = "static")]`
|
|
|
|
|
* Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]`
|
2013-11-30 15:26:46 -06:00
|
|
|
|
|
|
|
|
|
Note that frameworks are only available on OSX targets.
|
|
|
|
|
|
|
|
|
|
The different `kind` values are meant to differentiate how the native library
|
2015-07-21 14:40:11 -05:00
|
|
|
|
participates in linkage. From a linkage perspective, the Rust compiler creates
|
2013-11-30 15:26:46 -06:00
|
|
|
|
two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary).
|
2015-06-09 14:17:25 -05:00
|
|
|
|
Native dynamic library and framework dependencies are propagated to the final
|
|
|
|
|
artifact boundary, while static library dependencies are not propagated at
|
|
|
|
|
all, because the static libraries are integrated directly into the subsequent
|
|
|
|
|
artifact.
|
2013-11-30 15:26:46 -06:00
|
|
|
|
|
|
|
|
|
A few examples of how this model can be used are:
|
|
|
|
|
|
|
|
|
|
* A native build dependency. Sometimes some C/C++ glue is needed when writing
|
2015-07-21 14:40:11 -05:00
|
|
|
|
some Rust code, but distribution of the C/C++ code in a library format is just
|
2013-11-30 15:26:46 -06:00
|
|
|
|
a burden. In this case, the code will be archived into `libfoo.a` and then the
|
2015-07-21 14:40:11 -05:00
|
|
|
|
Rust crate would declare a dependency via `#[link(name = "foo", kind =
|
2013-11-30 15:26:46 -06:00
|
|
|
|
"static")]`.
|
|
|
|
|
|
|
|
|
|
Regardless of the flavor of output for the crate, the native static library
|
|
|
|
|
will be included in the output, meaning that distribution of the native static
|
|
|
|
|
library is not necessary.
|
|
|
|
|
|
|
|
|
|
* A normal dynamic dependency. Common system libraries (like `readline`) are
|
|
|
|
|
available on a large number of systems, and often a static copy of these
|
2015-07-21 14:40:11 -05:00
|
|
|
|
libraries cannot be found. When this dependency is included in a Rust crate,
|
2013-11-30 15:26:46 -06:00
|
|
|
|
partial targets (like rlibs) will not link to the library, but when the rlib
|
|
|
|
|
is included in a final target (like a binary), the native library will be
|
|
|
|
|
linked in.
|
|
|
|
|
|
|
|
|
|
On OSX, frameworks behave with the same semantics as a dynamic library.
|
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
# Unsafe blocks
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2015-06-09 15:49:24 -05:00
|
|
|
|
Some operations, like dereferencing raw pointers or calling functions that have been marked
|
2013-04-11 22:05:06 -05:00
|
|
|
|
unsafe are only allowed inside unsafe blocks. Unsafe blocks isolate unsafety and are a promise to
|
|
|
|
|
the compiler that the unsafety does not leak out of the block.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like
|
|
|
|
|
this:
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2015-05-18 13:56:00 -05:00
|
|
|
|
```rust
|
2015-03-25 19:06:52 -05:00
|
|
|
|
unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr }
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
This function can only be called from an `unsafe` block or another `unsafe` function.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-08-05 21:16:29 -05:00
|
|
|
|
# Accessing foreign globals
|
|
|
|
|
|
|
|
|
|
Foreign APIs often export a global variable which could do something like track
|
|
|
|
|
global state. In order to access these variables, you declare them in `extern`
|
|
|
|
|
blocks with the `static` keyword:
|
|
|
|
|
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```no_run
|
2015-03-13 17:28:35 -05:00
|
|
|
|
# #![feature(libc)]
|
2014-02-26 11:58:41 -06:00
|
|
|
|
extern crate libc;
|
2013-08-05 21:16:29 -05:00
|
|
|
|
|
2013-11-30 15:26:46 -06:00
|
|
|
|
#[link(name = "readline")]
|
2013-08-05 21:16:29 -05:00
|
|
|
|
extern {
|
|
|
|
|
static rl_readline_version: libc::c_int;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
2013-11-06 17:16:04 -06:00
|
|
|
|
println!("You have readline version {} installed.",
|
2015-03-25 19:06:52 -05:00
|
|
|
|
rl_readline_version as i32);
|
2013-08-05 21:16:29 -05:00
|
|
|
|
}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2013-08-05 21:16:29 -05:00
|
|
|
|
|
|
|
|
|
Alternatively, you may need to alter global state provided by a foreign
|
2015-02-13 13:57:55 -06:00
|
|
|
|
interface. To do this, statics can be declared with `mut` so we can mutate
|
2013-08-05 21:16:29 -05:00
|
|
|
|
them.
|
|
|
|
|
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```no_run
|
2015-03-13 17:28:35 -05:00
|
|
|
|
# #![feature(libc)]
|
2014-02-26 11:58:41 -06:00
|
|
|
|
extern crate libc;
|
2014-12-22 11:04:23 -06:00
|
|
|
|
|
2014-11-25 15:28:35 -06:00
|
|
|
|
use std::ffi::CString;
|
2013-08-05 21:16:29 -05:00
|
|
|
|
use std::ptr;
|
|
|
|
|
|
2013-11-30 15:26:46 -06:00
|
|
|
|
#[link(name = "readline")]
|
2013-08-05 21:16:29 -05:00
|
|
|
|
extern {
|
2014-06-25 14:47:34 -05:00
|
|
|
|
static mut rl_prompt: *const libc::c_char;
|
2013-08-05 21:16:29 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
2015-02-18 00:47:40 -06:00
|
|
|
|
let prompt = CString::new("[my-awesome-shell] $").unwrap();
|
|
|
|
|
unsafe {
|
2015-02-13 13:57:55 -06:00
|
|
|
|
rl_prompt = prompt.as_ptr();
|
|
|
|
|
|
2015-02-15 10:50:38 -06:00
|
|
|
|
println!("{:?}", rl_prompt);
|
2015-02-13 13:57:55 -06:00
|
|
|
|
|
|
|
|
|
rl_prompt = ptr::null();
|
|
|
|
|
}
|
2013-08-05 21:16:29 -05:00
|
|
|
|
}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2013-08-05 21:16:29 -05:00
|
|
|
|
|
2015-02-13 13:57:55 -06:00
|
|
|
|
Note that all interaction with a `static mut` is unsafe, both reading and
|
|
|
|
|
writing. Dealing with global mutable state requires a great deal of care.
|
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
# Foreign calling conventions
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when
|
|
|
|
|
calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
|
2013-09-29 09:46:26 -05:00
|
|
|
|
conventions. Rust provides a way to tell the compiler which convention to use:
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2015-05-18 13:56:00 -05:00
|
|
|
|
```rust
|
2015-03-13 17:28:35 -05:00
|
|
|
|
# #![feature(libc)]
|
2014-02-26 11:58:41 -06:00
|
|
|
|
extern crate libc;
|
|
|
|
|
|
2014-10-11 20:05:54 -05:00
|
|
|
|
#[cfg(all(target_os = "win32", target_arch = "x86"))]
|
2014-02-06 17:54:25 -06:00
|
|
|
|
#[link(name = "kernel32")]
|
2014-07-18 07:45:17 -05:00
|
|
|
|
#[allow(non_snake_case)]
|
2013-09-29 09:46:26 -05:00
|
|
|
|
extern "stdcall" {
|
2014-06-25 14:47:34 -05:00
|
|
|
|
fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int;
|
2012-09-26 18:41:14 -05:00
|
|
|
|
}
|
2014-02-26 11:58:41 -06:00
|
|
|
|
# fn main() { }
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
2012-09-26 18:41:14 -05:00
|
|
|
|
|
2013-11-08 13:06:57 -06:00
|
|
|
|
This applies to the entire `extern` block. The list of supported ABI constraints
|
|
|
|
|
are:
|
|
|
|
|
|
|
|
|
|
* `stdcall`
|
|
|
|
|
* `aapcs`
|
|
|
|
|
* `cdecl`
|
|
|
|
|
* `fastcall`
|
|
|
|
|
* `Rust`
|
|
|
|
|
* `rust-intrinsic`
|
|
|
|
|
* `system`
|
|
|
|
|
* `C`
|
2014-05-21 23:22:58 -05:00
|
|
|
|
* `win64`
|
2013-11-08 13:06:57 -06:00
|
|
|
|
|
|
|
|
|
Most of the abis in this list are self-explanatory, but the `system` abi may
|
|
|
|
|
seem a little odd. This constraint selects whatever the appropriate ABI is for
|
|
|
|
|
interoperating with the target's libraries. For example, on win32 with a x86
|
|
|
|
|
architecture, this means that the abi used would be `stdcall`. On x86_64,
|
|
|
|
|
however, windows uses the `C` calling convention, so `C` would be used. This
|
|
|
|
|
means that in our previous example, we could have used `extern "system" { ... }`
|
|
|
|
|
to define a block for all windows systems, not just x86 ones.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
|
# Interoperability with foreign code
|
2012-09-05 13:20:04 -05:00
|
|
|
|
|
2014-11-25 15:28:35 -06:00
|
|
|
|
Rust guarantees that the layout of a `struct` is compatible with the platform's
|
|
|
|
|
representation in C only if the `#[repr(C)]` attribute is applied to it.
|
|
|
|
|
`#[repr(C, packed)]` can be used to lay out struct members without padding.
|
|
|
|
|
`#[repr(C)]` can also be applied to an enum.
|
|
|
|
|
|
|
|
|
|
Rust's owned boxes (`Box<T>`) use non-nullable pointers as handles which point
|
|
|
|
|
to the contained object. However, they should not be manually created because
|
|
|
|
|
they are managed by internal allocators. References can safely be assumed to be
|
|
|
|
|
non-nullable pointers directly to the type. However, breaking the borrow
|
|
|
|
|
checking or mutability rules is not guaranteed to be safe, so prefer using raw
|
|
|
|
|
pointers (`*`) if that's needed because the compiler can't make as many
|
|
|
|
|
assumptions about them.
|
|
|
|
|
|
|
|
|
|
Vectors and strings share the same basic memory layout, and utilities are
|
|
|
|
|
available in the `vec` and `str` modules for working with C APIs. However,
|
|
|
|
|
strings are not terminated with `\0`. If you need a NUL-terminated string for
|
|
|
|
|
interoperability with C, you should use the `CString` type in the `std::ffi`
|
|
|
|
|
module.
|
|
|
|
|
|
2015-08-28 10:43:23 -05:00
|
|
|
|
The [`libc` crate on crates.io][libc] includes type aliases and function
|
|
|
|
|
definitions for the C standard library in the `libc` module, and Rust links
|
|
|
|
|
against `libc` and `libm` by default.
|
|
|
|
|
|
|
|
|
|
[libc]: https://crates.io/crates/libc
|
2014-04-10 19:29:09 -05:00
|
|
|
|
|
|
|
|
|
# The "nullable pointer optimization"
|
|
|
|
|
|
|
|
|
|
Certain types are defined to not be `null`. This includes references (`&T`,
|
2014-08-09 17:01:14 -05:00
|
|
|
|
`&mut T`), boxes (`Box<T>`), and function pointers (`extern "abi" fn()`).
|
|
|
|
|
When interfacing with C, pointers that might be null are often used.
|
2014-04-10 19:29:09 -05:00
|
|
|
|
As a special case, a generic `enum` that contains exactly two variants, one of
|
|
|
|
|
which contains no data and the other containing a single field, is eligible
|
|
|
|
|
for the "nullable pointer optimization". When such an enum is instantiated
|
|
|
|
|
with one of the non-nullable types, it is represented as a single pointer,
|
|
|
|
|
and the non-data variant is represented as the null pointer. So
|
|
|
|
|
`Option<extern "C" fn(c_int) -> c_int>` is how one represents a nullable
|
|
|
|
|
function pointer using the C ABI.
|
2015-01-16 14:27:44 -06:00
|
|
|
|
|
|
|
|
|
# Calling Rust code from C
|
|
|
|
|
|
|
|
|
|
You may wish to compile Rust code in a way so that it can be called from C. This is
|
|
|
|
|
fairly easy, but requires a few things:
|
|
|
|
|
|
2015-05-18 13:56:00 -05:00
|
|
|
|
```rust
|
2015-01-16 14:27:44 -06:00
|
|
|
|
#[no_mangle]
|
|
|
|
|
pub extern fn hello_rust() -> *const u8 {
|
|
|
|
|
"Hello, world!\0".as_ptr()
|
|
|
|
|
}
|
2015-01-17 14:25:42 -06:00
|
|
|
|
# fn main() {}
|
2015-01-16 14:27:44 -06:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `extern` makes this function adhere to the C calling convention, as
|
|
|
|
|
discussed above in "[Foreign Calling
|
2015-02-18 02:16:22 -06:00
|
|
|
|
Conventions](ffi.html#foreign-calling-conventions)". The `no_mangle`
|
2015-01-16 14:27:44 -06:00
|
|
|
|
attribute turns off Rust's name mangling, so that it is easier to link to.
|
2015-06-20 11:00:29 -05:00
|
|
|
|
|
|
|
|
|
# FFI and panics
|
|
|
|
|
|
2015-07-03 11:56:51 -05:00
|
|
|
|
It’s important to be mindful of `panic!`s when working with FFI. A `panic!`
|
|
|
|
|
across an FFI boundary is undefined behavior. If you’re writing code that may
|
|
|
|
|
panic, you should run it in another thread, so that the panic doesn’t bubble up
|
|
|
|
|
to C:
|
2015-06-20 11:00:29 -05:00
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
use std::thread;
|
|
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
|
pub extern fn oh_no() -> i32 {
|
|
|
|
|
let h = thread::spawn(|| {
|
|
|
|
|
panic!("Oops!");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
match h.join() {
|
|
|
|
|
Ok(_) => 1,
|
|
|
|
|
Err(_) => 0,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
# fn main() {}
|
|
|
|
|
```
|
|
|
|
|
|
2015-08-05 13:51:35 -05:00
|
|
|
|
# Representing opaque structs
|
|
|
|
|
|
|
|
|
|
Sometimes, a C library wants to provide a pointer to something, but not let you
|
|
|
|
|
know the internal details of the thing it wants. The simplest way is to use a
|
|
|
|
|
`void *` argument:
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
void foo(void *arg);
|
|
|
|
|
void bar(void *arg);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
We can represent this in Rust with the `c_void` type:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
# #![feature(libc)]
|
|
|
|
|
extern crate libc;
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
pub fn foo(arg: *mut libc::c_void);
|
|
|
|
|
pub fn bar(arg: *mut libc::c_void);
|
|
|
|
|
}
|
|
|
|
|
# fn main() {}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This is a perfectly valid way of handling the situation. However, we can do a bit
|
|
|
|
|
better. To solve this, some C libraries will instead create a `struct`, where
|
|
|
|
|
the details and memory layout of the struct are private. This gives some amount
|
|
|
|
|
of type safety. These structures are called ‘opaque’. Here’s an example, in C:
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
struct Foo; /* Foo is a structure, but its contents are not part of the public interface */
|
|
|
|
|
struct Bar;
|
|
|
|
|
void foo(struct Foo *arg);
|
|
|
|
|
void bar(struct Bar *arg);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
To do this in Rust, let’s create our own opaque types with `enum`:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
pub enum Foo {}
|
|
|
|
|
pub enum Bar {}
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
pub fn foo(arg: *mut Foo);
|
|
|
|
|
pub fn bar(arg: *mut Bar);
|
|
|
|
|
}
|
|
|
|
|
# fn main() {}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
By using an `enum` with no variants, we create an opaque type that we can’t
|
|
|
|
|
instantiate, as it has no variants. But because our `Foo` and `Bar` types are
|
|
|
|
|
different, we’ll get type safety between the two of them, so we cannot
|
|
|
|
|
accidentally pass a pointer to `Foo` to `bar()`.
|