]> git.proxmox.com Git - rustc.git/blob - doc/tutorial-ffi.md
Imported Upstream version 0.7
[rustc.git] / doc / tutorial-ffi.md
1 % Rust Foreign Function Interface Tutorial
2
3 # Introduction
4
5 This tutorial will use the [snappy](https://code.google.com/p/snappy/)
6 compression/decompression library as an introduction to writing bindings for
7 foreign code. Rust is currently unable to call directly into a C++ library, but
8 snappy includes a C interface (documented in
9 [`snappy-c.h`](https://code.google.com/p/snappy/source/browse/trunk/snappy-c.h)).
10
11 The following is a minimal example of calling a foreign function which will compile if snappy is
12 installed:
13
14 ~~~~ {.xfail-test}
15 use std::libc::size_t;
16
17 #[link_args = "-lsnappy"]
18 extern {
19 fn snappy_max_compressed_length(source_length: size_t) -> size_t;
20 }
21
22 fn main() {
23 let x = unsafe { snappy_max_compressed_length(100) };
24 println(fmt!("max compressed length of a 100 byte buffer: %?", x));
25 }
26 ~~~~
27
28 The `extern` block is a list of function signatures in a foreign library, in this case with the
29 platform's C ABI. The `#[link_args]` attribute is used to instruct the linker to link against the
30 snappy library so the symbols are resolved.
31
32 Foreign functions are assumed to be unsafe so calls to them need to be wrapped with `unsafe {}` as a
33 promise to the compiler that everything contained within truly is safe. C libraries often expose
34 interfaces that aren't thread-safe, and almost any function that takes a pointer argument isn't
35 valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of
36 Rust's safe memory model.
37
38 When declaring the argument types to a foreign function, the Rust compiler will not check if the
39 declaration is correct, so specifying it correctly is part of keeping the binding correct at
40 runtime.
41
42 The `extern` block can be extended to cover the entire snappy API:
43
44 ~~~~ {.xfail-test}
45 use std::libc::{c_int, size_t};
46
47 #[link_args = "-lsnappy"]
48 extern {
49 fn snappy_compress(input: *u8,
50 input_length: size_t,
51 compressed: *mut u8,
52 compressed_length: *mut size_t) -> c_int;
53 fn snappy_uncompress(compressed: *u8,
54 compressed_length: size_t,
55 uncompressed: *mut u8,
56 uncompressed_length: *mut size_t) -> c_int;
57 fn snappy_max_compressed_length(source_length: size_t) -> size_t;
58 fn snappy_uncompressed_length(compressed: *u8,
59 compressed_length: size_t,
60 result: *mut size_t) -> c_int;
61 fn snappy_validate_compressed_buffer(compressed: *u8,
62 compressed_length: size_t) -> c_int;
63 }
64 ~~~~
65
66 # Creating a safe interface
67
68 The raw C API needs to be wrapped to provide memory safety and make use of higher-level concepts
69 like vectors. A library can choose to expose only the safe, high-level interface and hide the unsafe
70 internal details.
71
72 Wrapping the functions which expect buffers involves using the `vec::raw` module to manipulate Rust
73 vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The
74 length is number of elements currently contained, and the capacity is the total size in elements of
75 the allocated memory. The length is less than or equal to the capacity.
76
77 ~~~~ {.xfail-test}
78 pub fn validate_compressed_buffer(src: &[u8]) -> bool {
79 unsafe {
80 snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0
81 }
82 }
83 ~~~~
84
85 The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the
86 guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
87 signature.
88
89 The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
90 allocated to hold the output too.
91
92 The `snappy_max_compressed_length` function can be used to allocate a vector with the maximum
93 required capacity to hold the compressed output. The vector can then be passed to the
94 `snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
95 the true length after compression for setting the length.
96
97 ~~~~ {.xfail-test}
98 pub fn compress(src: &[u8]) -> ~[u8] {
99 unsafe {
100 let srclen = src.len() as size_t;
101 let psrc = vec::raw::to_ptr(src);
102
103 let mut dstlen = snappy_max_compressed_length(srclen);
104 let mut dst = vec::with_capacity(dstlen as uint);
105 let pdst = vec::raw::to_mut_ptr(dst);
106
107 snappy_compress(psrc, srclen, pdst, &mut dstlen);
108 vec::raw::set_len(&mut dst, dstlen as uint);
109 dst
110 }
111 }
112 ~~~~
113
114 Decompression is similar, because snappy stores the uncompressed size as part of the compression
115 format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
116
117 ~~~~ {.xfail-test}
118 pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
119 unsafe {
120 let srclen = src.len() as size_t;
121 let psrc = vec::raw::to_ptr(src);
122
123 let mut dstlen: size_t = 0;
124 snappy_uncompressed_length(psrc, srclen, &mut dstlen);
125
126 let mut dst = vec::with_capacity(dstlen as uint);
127 let pdst = vec::raw::to_mut_ptr(dst);
128
129 if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
130 vec::raw::set_len(&mut dst, dstlen as uint);
131 Some(dst)
132 } else {
133 None // SNAPPY_INVALID_INPUT
134 }
135 }
136 }
137 ~~~~
138
139 For reference, the examples used here are also available as an [library on
140 GitHub](https://github.com/thestinger/rust-snappy).
141
142 # Destructors
143
144 Foreign libraries often hand off ownership of resources to the calling code,
145 which should be wrapped in a destructor to provide safety and guarantee their
146 release.
147
148 A type with the same functionality as owned boxes can be implemented by
149 wrapping `malloc` and `free`:
150
151 ~~~~
152 use std::cast;
153 use std::libc::{c_void, size_t, malloc, free};
154 use std::ptr;
155 use std::unstable::intrinsics;
156
157 // a wrapper around the handle returned by the foreign code
158 pub struct Unique<T> {
159 priv ptr: *mut T
160 }
161
162 impl<T: Send> Unique<T> {
163 pub fn new(value: T) -> Unique<T> {
164 unsafe {
165 let ptr = malloc(std::sys::size_of::<T>() as size_t) as *mut T;
166 assert!(!ptr::is_null(ptr));
167 // `*ptr` is uninitialized, and `*ptr = value` would attempt to destroy it
168 intrinsics::move_val_init(&mut *ptr, value);
169 Unique{ptr: ptr}
170 }
171 }
172
173 // the 'r lifetime results in the same semantics as `&*x` with ~T
174 pub fn borrow<'r>(&'r self) -> &'r T {
175 unsafe { cast::copy_lifetime(self, &*self.ptr) }
176 }
177
178 // the 'r lifetime results in the same semantics as `&mut *x` with ~T
179 pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T {
180 unsafe { cast::copy_mut_lifetime(self, &mut *self.ptr) }
181 }
182 }
183
184 #[unsafe_destructor]
185 impl<T: Send> Drop for Unique<T> {
186 fn drop(&self) {
187 unsafe {
188 let x = intrinsics::init(); // dummy value to swap in
189 // moving the object out is needed to call the destructor
190 ptr::replace_ptr(self.ptr, x);
191 free(self.ptr as *c_void)
192 }
193 }
194 }
195
196 // A comparison between the built-in ~ and this reimplementation
197 fn main() {
198 {
199 let mut x = ~5;
200 *x = 10;
201 } // `x` is freed here
202
203 {
204 let mut y = Unique::new(5);
205 *y.borrow_mut() = 10;
206 } // `y` is freed here
207 }
208 ~~~~
209
210 # Linking
211
212 In addition to the `#[link_args]` attribute for explicitly passing arguments to the linker, an
213 `extern mod` block will pass `-lmodname` to the linker by default unless it has a `#[nolink]`
214 attribute applied.
215
216 # Unsafe blocks
217
218 Some operations, like dereferencing unsafe pointers or calling functions that have been marked
219 unsafe are only allowed inside unsafe blocks. Unsafe blocks isolate unsafety and are a promise to
220 the compiler that the unsafety does not leak out of the block.
221
222 Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like
223 this:
224
225 ~~~~
226 unsafe fn kaboom(ptr: *int) -> int { *ptr }
227 ~~~~
228
229 This function can only be called from an `unsafe` block or another `unsafe` function.
230
231 # Foreign calling conventions
232
233 Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when
234 calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
235 conventions. Rust provides the `abi` attribute as a way to hint to the compiler which calling
236 convention to use:
237
238 ~~~~
239 #[cfg(target_os = "win32")]
240 #[abi = "stdcall"]
241 #[link_name = "kernel32"]
242 extern {
243 fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
244 }
245 ~~~~
246
247 The `abi` attribute applies to a foreign module (it cannot be applied to a single function within a
248 module), and must be either `"cdecl"` or `"stdcall"`. The compiler may eventually support other
249 calling conventions.
250
251 # Interoperability with foreign code
252
253 Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C.
254 A `#[packed]` attribute is available, which will lay out the struct members without padding.
255 However, there are currently no guarantees about the layout of an `enum`.
256
257 Rust's owned and managed boxes use non-nullable pointers as handles which point to the contained
258 object. However, they should not be manually created because they are managed by internal
259 allocators. Borrowed pointers can safely be assumed to be non-nullable pointers directly to the
260 type. However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so
261 prefer using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions
262 about them.
263
264 Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and
265 `str` modules for working with C APIs. Strings are terminated with `\0` for interoperability with C,
266 but it should not be assumed because a slice will not always be nul-terminated. Instead, the
267 `str::as_c_str` function should be used.
268
269 The standard library includes type aliases and function definitions for the C standard library in
270 the `libc` module, and Rust links against `libc` and `libm` by default.