2014-01-07 14:16:38 -06:00
|
|
|
% The Rust Foreign Function Interface Guide
|
2012-09-26 21:00:13 -05:00
|
|
|
|
|
|
|
# Introduction
|
2012-09-05 13:20:04 -05:00
|
|
|
|
2013-12-21 17:29:48 -06:00
|
|
|
This guide will use the [snappy](https://code.google.com/p/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
|
|
|
|
[`snappy-c.h`](https://code.google.com/p/snappy/source/browse/trunk/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
|
|
|
|
2013-01-21 21:39:45 -06:00
|
|
|
~~~~ {.xfail-test}
|
2013-05-23 15:06:29 -05:00
|
|
|
use std::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
|
|
|
}
|
|
|
|
~~~~
|
|
|
|
|
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
|
|
|
|
2013-01-21 21:39:45 -06:00
|
|
|
~~~~ {.xfail-test}
|
2013-05-23 15:06:29 -05:00
|
|
|
use std::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 {
|
|
|
|
fn snappy_compress(input: *u8,
|
|
|
|
input_length: size_t,
|
|
|
|
compressed: *mut u8,
|
|
|
|
compressed_length: *mut size_t) -> c_int;
|
|
|
|
fn snappy_uncompress(compressed: *u8,
|
|
|
|
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;
|
|
|
|
fn snappy_uncompressed_length(compressed: *u8,
|
|
|
|
compressed_length: size_t,
|
|
|
|
result: *mut size_t) -> c_int;
|
|
|
|
fn snappy_validate_compressed_buffer(compressed: *u8,
|
|
|
|
compressed_length: size_t) -> c_int;
|
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
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
Wrapping the functions which expect buffers involves using the `vec::raw` module to manipulate Rust
|
|
|
|
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.
|
|
|
|
|
|
|
|
~~~~ {.xfail-test}
|
|
|
|
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
|
|
|
}
|
|
|
|
~~~~
|
|
|
|
|
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
|
|
|
|
2013-01-21 21:39:45 -06:00
|
|
|
~~~~ {.xfail-test}
|
2013-04-11 22:05:06 -05:00
|
|
|
pub fn compress(src: &[u8]) -> ~[u8] {
|
|
|
|
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);
|
|
|
|
let mut dst = vec::with_capacity(dstlen as uint);
|
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);
|
2013-12-15 06:05:30 -06:00
|
|
|
dst.set_len(dstlen as uint);
|
2013-04-11 22:05:06 -05:00
|
|
|
dst
|
|
|
|
}
|
|
|
|
}
|
|
|
|
~~~~
|
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
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
~~~~ {.xfail-test}
|
|
|
|
pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
|
|
|
|
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
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
let mut dst = vec::with_capacity(dstlen as uint);
|
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 {
|
2013-12-15 06:05:30 -06:00
|
|
|
dst.set_len(dstlen as uint);
|
2013-04-11 22:05:06 -05:00
|
|
|
Some(dst)
|
|
|
|
} else {
|
|
|
|
None // SNAPPY_INVALID_INPUT
|
|
|
|
}
|
2012-09-05 13:20:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
~~~~
|
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
For reference, the examples used here are also available as an [library on
|
|
|
|
GitHub](https://github.com/thestinger/rust-snappy).
|
2012-09-05 13:20:04 -05:00
|
|
|
|
2013-11-06 17:16:04 -06:00
|
|
|
# Stack management
|
|
|
|
|
|
|
|
Rust tasks by default run on a "large stack". This is actually implemented as a
|
|
|
|
reserving a large segment of the address space and then lazily mapping in pages
|
|
|
|
as they are needed. When calling an external C function, the code is invoked on
|
|
|
|
the same stack as the rust stack. This means that there is no extra
|
|
|
|
stack-switching mechanism in place because it is assumed that the large stack
|
|
|
|
for the rust task is plenty for the C function to have.
|
|
|
|
|
|
|
|
A planned future improvement (net yet implemented at the time of this writing)
|
|
|
|
is to have a guard page at the end of every rust stack. No rust function will
|
2013-12-05 04:58:30 -06:00
|
|
|
hit this guard page (due to Rust's usage of LLVM's `__morestack`). The intention
|
2013-11-06 17:16:04 -06:00
|
|
|
for this unmapped page is to prevent infinite recursion in C from overflowing
|
|
|
|
onto other rust stacks. If the guard page is hit, then the process will be
|
|
|
|
terminated with a message saying that the guard page was hit.
|
|
|
|
|
|
|
|
For normal external function usage, this all means that there shouldn't be any
|
|
|
|
need for any extra effort on a user's perspective. The C stack naturally
|
|
|
|
interleaves with the rust stack, and it's "large enough" for both to
|
|
|
|
interoperate. If, however, it is determined that a larger stack is necessary,
|
|
|
|
there are appropriate functions in the task spawning API to control the size of
|
|
|
|
the stack of the task which is spawned.
|
2013-08-14 20:41:40 -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
|
|
|
|
the release of these resources (especially in the case of failure).
|
2013-04-25 21:08:29 -05:00
|
|
|
|
2013-12-05 04:58:30 -06:00
|
|
|
As an example, we give a reimplementation of owned boxes by wrapping `malloc`
|
|
|
|
and `free`:
|
2013-04-25 21:08:29 -05:00
|
|
|
|
|
|
|
~~~~
|
2013-05-24 21:35:29 -05:00
|
|
|
use std::cast;
|
2013-05-23 15:06:29 -05:00
|
|
|
use std::libc::{c_void, size_t, malloc, free};
|
2013-05-24 21:35:29 -05:00
|
|
|
use std::ptr;
|
2013-05-23 15:06:29 -05:00
|
|
|
use std::unstable::intrinsics;
|
2013-04-25 21:08:29 -05:00
|
|
|
|
2013-12-05 04:58:30 -06:00
|
|
|
// Define a wrapper around the handle returned by the foreign code.
|
|
|
|
// Unique<T> has the same semantics as ~T
|
2013-04-25 21:08:29 -05:00
|
|
|
pub struct Unique<T> {
|
2013-12-05 04:58:30 -06:00
|
|
|
// It contains a single raw, mutable pointer to the object in question.
|
2013-04-25 21:08:29 -05:00
|
|
|
priv ptr: *mut T
|
|
|
|
}
|
|
|
|
|
2013-12-05 04:58:30 -06:00
|
|
|
// Implement methods for creating and using the values in the box.
|
|
|
|
// NB: For simplicity and correctness, we require that T has kind Send
|
|
|
|
// (owned boxes relax this restriction, and can contain managed (GC) boxes).
|
|
|
|
// This is because, as implemented, the garbage collector would not know
|
|
|
|
// about any shared boxes stored in the malloc'd region of memory.
|
2013-06-06 20:54:14 -05:00
|
|
|
impl<T: Send> Unique<T> {
|
2013-06-04 23:43:41 -05:00
|
|
|
pub fn new(value: T) -> Unique<T> {
|
2013-04-25 21:08:29 -05:00
|
|
|
unsafe {
|
2013-10-16 20:34:01 -05:00
|
|
|
let ptr = malloc(std::mem::size_of::<T>() as size_t) as *mut T;
|
2013-04-25 21:08:29 -05:00
|
|
|
assert!(!ptr::is_null(ptr));
|
2013-05-04 20:53:43 -05:00
|
|
|
// `*ptr` is uninitialized, and `*ptr = value` would attempt to destroy it
|
2013-12-05 04:58:30 -06:00
|
|
|
// move_val_init moves a value into this memory without
|
|
|
|
// attempting to drop the original value.
|
2013-05-04 20:53:43 -05:00
|
|
|
intrinsics::move_val_init(&mut *ptr, value);
|
2013-04-25 21:08:29 -05:00
|
|
|
Unique{ptr: ptr}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-08 14:03:39 -05:00
|
|
|
// the 'r lifetime results in the same semantics as `&*x` with ~T
|
2013-06-04 23:43:41 -05:00
|
|
|
pub fn borrow<'r>(&'r self) -> &'r T {
|
2013-05-08 14:03:39 -05:00
|
|
|
unsafe { cast::copy_lifetime(self, &*self.ptr) }
|
2013-04-25 21:08:29 -05:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:03:39 -05:00
|
|
|
// the 'r lifetime results in the same semantics as `&mut *x` with ~T
|
2013-06-04 23:43:41 -05:00
|
|
|
pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T {
|
2013-05-08 14:03:39 -05:00
|
|
|
unsafe { cast::copy_mut_lifetime(self, &mut *self.ptr) }
|
2013-04-25 21:08:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-05 04:58:30 -06:00
|
|
|
// The key ingredient for safety, we associate a destructor with
|
|
|
|
// Unique<T>, making the struct manage the raw pointer: when the
|
|
|
|
// struct goes out of scope, it will automatically free the raw pointer.
|
|
|
|
// NB: This is an unsafe destructor, because rustc will not normally
|
|
|
|
// allow destructors to be associated with parametrized types, due to
|
|
|
|
// bad interaction with managed boxes. (With the Send restriction,
|
|
|
|
// we don't have this problem.)
|
2013-04-25 21:08:29 -05:00
|
|
|
#[unsafe_destructor]
|
2013-06-06 20:54:14 -05:00
|
|
|
impl<T: Send> Drop for Unique<T> {
|
2013-09-16 20:18:07 -05:00
|
|
|
fn drop(&mut self) {
|
2013-04-25 21:08:29 -05:00
|
|
|
unsafe {
|
2013-12-05 04:58:30 -06:00
|
|
|
let x = intrinsics::uninit(); // dummy value to swap in
|
|
|
|
// We need to move the object out of the box, so that
|
|
|
|
// the destructor is called (at the end of this scope.)
|
2013-05-31 09:21:29 -05:00
|
|
|
ptr::replace_ptr(self.ptr, x);
|
2013-04-25 21:08:29 -05:00
|
|
|
free(self.ptr as *c_void)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// A comparison between the built-in ~ and this reimplementation
|
|
|
|
fn main() {
|
|
|
|
{
|
|
|
|
let mut x = ~5;
|
|
|
|
*x = 10;
|
|
|
|
} // `x` is freed here
|
|
|
|
|
|
|
|
{
|
|
|
|
let mut y = Unique::new(5);
|
|
|
|
*y.borrow_mut() = 10;
|
|
|
|
} // `y` is freed here
|
|
|
|
}
|
|
|
|
~~~~
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
The callback function that can then be sent to through a registration call
|
|
|
|
to the C library and afterwards be invoked from there.
|
|
|
|
|
|
|
|
A basic example is:
|
|
|
|
|
|
|
|
Rust code:
|
2014-01-20 14:44:41 -06:00
|
|
|
~~~~ {.xfail-test}
|
2014-01-12 06:27:59 -06: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 {
|
|
|
|
fn register_callback(cb: extern "C" 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
|
|
|
}
|
|
|
|
}
|
|
|
|
~~~~
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
C code:
|
2014-01-20 14:44:41 -06:00
|
|
|
~~~~ {.xfail-test}
|
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
|
|
|
|
}
|
|
|
|
~~~~
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
In this example will Rust's `main()` will call `do_callback()` in C,
|
|
|
|
which would call back to `callback()` in Rust.
|
|
|
|
|
2014-01-11 17:47:30 -06:00
|
|
|
|
|
|
|
## Targetting callbacks to Rust objects
|
|
|
|
|
|
|
|
The former example showed how a global function can be called from C-Code.
|
|
|
|
However it is often desired that the callback is targetted to a special
|
|
|
|
Rust object. This could be the object that represents the wrapper for the
|
|
|
|
respective C object.
|
|
|
|
|
|
|
|
This can be achieved by passing an unsafe pointer to the object down to the
|
|
|
|
C library. The C library can then include the pointer to the Rust object in
|
|
|
|
the notification. This will provide a unsafe possibility to access the
|
|
|
|
referenced Rust object in callback.
|
|
|
|
|
|
|
|
Rust code:
|
2014-01-20 14:44:41 -06:00
|
|
|
~~~~ {.xfail-test}
|
2014-01-11 17:47:30 -06:00
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
struct RustObject {
|
|
|
|
a: i32,
|
|
|
|
// other members
|
2014-01-11 17:47:30 -06:00
|
|
|
}
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
extern fn callback(target: *RustObject, a:i32) {
|
|
|
|
println!("I'm called from C with value {0}", a);
|
|
|
|
(*target).a = a; // Update the value in RustObject with the value received from the callback
|
2014-01-11 17:47:30 -06:00
|
|
|
}
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
#[link(name = "extlib")]
|
|
|
|
extern {
|
|
|
|
fn register_callback(target: *RustObject, cb: extern "C" fn(*RustObject, i32)) -> i32;
|
|
|
|
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
|
|
|
|
let rust_object = ~RustObject{a: 5, ...};
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
// Gets a raw pointer to the object
|
|
|
|
let target_addr:*RustObject = ptr::to_unsafe_ptr(rust_object);
|
|
|
|
register_callback(target_addr, callback);
|
|
|
|
trigger_callback(); // Triggers the callback
|
2014-01-11 17:47:30 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
~~~~
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
C code:
|
2014-01-20 14:44:41 -06:00
|
|
|
~~~~ {.xfail-test}
|
2014-01-12 06:27:59 -06:00
|
|
|
typedef void (*rust_callback)(int32_t);
|
|
|
|
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
|
|
|
}
|
|
|
|
~~~~
|
|
|
|
|
2014-01-12 06:27:59 -06:00
|
|
|
## Asynchronous callbacks
|
|
|
|
|
|
|
|
In the already given examples the callbacks are invoked as a direct reaction
|
|
|
|
to a function call to the external C library.
|
|
|
|
The control over the current thread switched from Rust to C to Rust for the
|
|
|
|
execution of the callback, but in the end the callback is executed on the
|
|
|
|
same thread (and Rust task) that lead called the function which triggered
|
|
|
|
the callback.
|
|
|
|
|
|
|
|
Things get more complicated when the external library spawns it's own threads
|
|
|
|
and invokes callbacks from there.
|
|
|
|
In these cases access to Rust data structures inside he callbacks is
|
|
|
|
especially unsafe and proper synchronization mechanisms must be used.
|
|
|
|
Besides classical synchronization mechanisms like mutexes one possibility in
|
|
|
|
Rust is to use channels (in `std::comm`) to forward data from the C thread
|
|
|
|
that invoked the callback into a Rust task.
|
|
|
|
|
|
|
|
If an asychronous callback targets a special object in the Rust address space
|
|
|
|
it is also absolutely necessary that no more callbacks are performed by the
|
|
|
|
C library after the respective Rust object get's destroyed.
|
|
|
|
This can be achieved by unregistering the callback it the object's
|
|
|
|
destructor and designing the library in a way that guarantees that no
|
|
|
|
callback will be performed after unregistration.
|
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:
|
|
|
|
|
|
|
|
* Dynamic - `#[link(name = "readline")]
|
|
|
|
* Static - `#[link(name = "my_build_dependency", kind = "static")]
|
|
|
|
* Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]
|
|
|
|
|
|
|
|
Note that frameworks are only available on OSX targets.
|
|
|
|
|
|
|
|
The different `kind` values are meant to differentiate how the native library
|
|
|
|
participates in linkage. From a linkage perspective, the rust compiler creates
|
|
|
|
two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary).
|
|
|
|
Native dynamic libraries and frameworks are propagated to the final artifact
|
|
|
|
boundary, while static libraries are not propagated at all.
|
|
|
|
|
|
|
|
A few examples of how this model can be used are:
|
|
|
|
|
|
|
|
* A native build dependency. Sometimes some C/C++ glue is needed when writing
|
|
|
|
some rust code, but distribution of the C/C++ code in a library format is just
|
|
|
|
a burden. In this case, the code will be archived into `libfoo.a` and then the
|
|
|
|
rust crate would declare a dependency via `#[link(name = "foo", kind =
|
|
|
|
"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
|
|
|
|
libraries cannot be found. When this dependency is included in a rust crate,
|
|
|
|
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.
|
|
|
|
|
|
|
|
## The `link_args` attribute
|
|
|
|
|
|
|
|
There is one other way to tell rustc how to customize linking, and that is via
|
|
|
|
the `link_args` attribute. This attribute is applied to `extern` blocks and
|
|
|
|
specifies raw flags which need to get passed to the linker when producing an
|
|
|
|
artifact. An example usage would be:
|
|
|
|
|
|
|
|
~~~ {.xfail-test}
|
|
|
|
#[link_args = "-foo -bar -baz"]
|
|
|
|
extern {}
|
|
|
|
~~~
|
|
|
|
|
|
|
|
Note that this feature is currently hidden behind the `feature(link_args)` gate
|
|
|
|
because this is not a sanctioned way of performing linking. Right now rustc
|
|
|
|
shells out to the system linker, so it makes sense to provide extra command line
|
|
|
|
arguments, but this will not always be the case. In the future rustc may use
|
|
|
|
LLVM directly to link native libraries in which case `link_args` will have no
|
|
|
|
meaning.
|
|
|
|
|
|
|
|
It is highly recommended to *not* use this attribute, and rather use the more
|
|
|
|
formal `#[link(...)]` attribute on `extern` blocks instead.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
# Unsafe blocks
|
2012-09-05 13:20:04 -05:00
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
Some operations, like dereferencing unsafe pointers or calling functions that have been marked
|
|
|
|
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
|
|
|
|
|
|
|
~~~~
|
2013-04-11 22:05:06 -05:00
|
|
|
unsafe fn kaboom(ptr: *int) -> int { *ptr }
|
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:
|
|
|
|
|
|
|
|
~~~{.xfail-test}
|
|
|
|
use std::libc;
|
|
|
|
|
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.",
|
|
|
|
rl_readline_version as int);
|
2013-08-05 21:16:29 -05:00
|
|
|
}
|
|
|
|
~~~
|
|
|
|
|
|
|
|
Alternatively, you may need to alter global state provided by a foreign
|
|
|
|
interface. To do this, statics can be declared with `mut` so rust can mutate
|
|
|
|
them.
|
|
|
|
|
|
|
|
~~~{.xfail-test}
|
|
|
|
use std::libc;
|
|
|
|
use std::ptr;
|
|
|
|
|
2013-11-30 15:26:46 -06:00
|
|
|
#[link(name = "readline")]
|
2013-08-05 21:16:29 -05:00
|
|
|
extern {
|
|
|
|
static mut rl_prompt: *libc::c_char;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
do "[my-awesome-shell] $".as_c_str |buf| {
|
|
|
|
unsafe { rl_prompt = buf; }
|
|
|
|
// get a line, process it
|
|
|
|
unsafe { rl_prompt = ptr::null(); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
~~~
|
|
|
|
|
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
|
|
|
|
|
|
|
~~~~
|
2013-11-08 13:06:57 -06:00
|
|
|
#[cfg(target_os = "win32", target_arch = "x86")]
|
2013-05-09 16:14:42 -05:00
|
|
|
#[link_name = "kernel32"]
|
2013-09-29 09:46:26 -05:00
|
|
|
extern "stdcall" {
|
2013-11-13 23:00:05 -06:00
|
|
|
fn SetEnvironmentVariableA(n: *u8, v: *u8) -> std::libc::c_int;
|
2012-09-26 18:41:14 -05:00
|
|
|
}
|
2013-04-11 22:05:06 -05: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`
|
|
|
|
|
|
|
|
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
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C.
|
|
|
|
A `#[packed]` attribute is available, which will lay out the struct members without padding.
|
|
|
|
However, there are currently no guarantees about the layout of an `enum`.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
Rust's owned and managed boxes use non-nullable pointers as handles which point to the contained
|
2013-04-12 05:31:54 -05:00
|
|
|
object. However, they should not be manually created because they are managed by internal
|
2014-01-07 20:49:13 -06:00
|
|
|
allocators. References can safely be assumed to be non-nullable pointers directly to the
|
2013-04-12 05:31:54 -05:00
|
|
|
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.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and
|
2013-08-22 19:03:06 -05:00
|
|
|
`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 `c_str::to_c_str` function.
|
2012-09-05 13:20:04 -05:00
|
|
|
|
2013-04-11 22:05:06 -05:00
|
|
|
The standard library includes type aliases and function definitions for the C standard library in
|
|
|
|
the `libc` module, and Rust links against `libc` and `libm` by default.
|