]> git.lizzy.rs Git - rust.git/blob - doc/tutorial-ffi.md
047b57e56a61aa950e1e93228a217c72a9608c6d
[rust.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.