about summary refs log tree commit diff
path: root/src/doc/book
diff options
context:
space:
mode:
authorAlex Burka <durka42+github@gmail.com>2016-06-13 13:22:38 -0400
committerAlex Burka <aburka@seas.upenn.edu>2016-07-27 13:58:51 -0400
commit032ea41e99b39f6af2aa26c0ba049d0d215d8ebb (patch)
tree9d7fea0346308076811c77460b860158fb5171d6 /src/doc/book
parenta373b8437b205cce01a19e7cdef17a50ff7ec84a (diff)
downloadrust-032ea41e99b39f6af2aa26c0ba049d0d215d8ebb.tar.gz
rust-032ea41e99b39f6af2aa26c0ba049d0d215d8ebb.zip
book/ffi: nullable pointer, libc cleanups
Expand the "nullable pointer optimization" section with a code example.

Change examples to use std::os::raw instead of libc, when applicable.
Diffstat (limited to 'src/doc/book')
-rw-r--r--src/doc/book/ffi.md67
1 files changed, 46 insertions, 21 deletions
diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md
index 3cbe5d60267..873d078f053 100644
--- a/src/doc/book/ffi.md
+++ b/src/doc/book/ffi.md
@@ -461,12 +461,11 @@ global state. In order to access these variables, you declare them in `extern`
 blocks with the `static` keyword:
 
 ```rust,no_run
-# #![feature(libc)]
-extern crate libc;
+use std::os::raw::c_int;
 
 #[link(name = "readline")]
 extern {
-    static rl_readline_version: libc::c_int;
+    static rl_readline_version: c_int;
 }
 
 fn main() {
@@ -480,15 +479,14 @@ interface. To do this, statics can be declared with `mut` so we can mutate
 them.
 
 ```rust,no_run
-# #![feature(libc)]
-extern crate libc;
 
 use std::ffi::CString;
+use std::os::raw::c_char;
 use std::ptr;
 
 #[link(name = "readline")]
 extern {
-    static mut rl_prompt: *const libc::c_char;
+    static mut rl_prompt: *const c_char;
 }
 
 fn main() {
@@ -513,14 +511,13 @@ calling foreign functions. Some foreign functions, most notably the Windows API,
 conventions. Rust provides a way to tell the compiler which convention to use:
 
 ```rust
-# #![feature(libc)]
-extern crate libc;
+use std::os::raw::c_int;
 
 #[cfg(all(target_os = "win32", target_arch = "x86"))]
 #[link(name = "kernel32")]
 #[allow(non_snake_case)]
 extern "stdcall" {
-    fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int;
+    fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> c_int;
 }
 # fn main() { }
 ```
@@ -575,16 +572,45 @@ against `libc` and `libm` by default.
 
 # The "nullable pointer optimization"
 
-Certain types are defined to not be NULL. This includes references (`&T`,
-`&mut T`), boxes (`Box<T>`), and function pointers (`extern "abi" fn()`).
-When interfacing with C, pointers that might be NULL are often used.
-As a special case, a generic `enum` that contains exactly two variants, one of
+Certain Rust types are defined to never be `null`. This includes references (`&T`,
+`&mut T`), boxes (`Box<T>`), and function pointers (`extern "abi" fn()`). When
+interfacing with C, pointers that might be `null` are often used, which would seem to
+require some messy `transmute`s and/or unsafe code to handle conversions to/from Rust types.
+However, the language provides a workaround.
+
+As a special case, an `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.
+with one of the non-nullable types listed above, it is represented as a single pointer,
+and the non-data variant is represented as the null pointer. This is called an
+"optimization", but unlike other optimizations it is guaranteed to apply to
+eligible types.
+
+The most common type that takes advantage of the nullable pointer optimization is `Option<T>`,
+where `None` corresponds to `null`. So `Option<extern "C" fn(c_int) -> c_int>` is a correct way
+to represent a nullable function pointer using the C ABI (corresponding to the C type
+`int (*)(int)`). (However, generics are not required to get the optimization. A simple
+`enum NullableIntRef { Int(Box<i32>), NotInt }` is also represented as a single pointer.)
+
+Here is an example:
+
+```rust
+use std::os::raw::c_int;
+
+/// This fairly useless function receives a function pointer and an integer
+/// from C, and returns the result of calling the function with the integer.
+/// In case no function is provided, it squares the integer by default.
+#[no_mangle]
+pub extern fn apply(process: Option<extern "C" fn(c_int) -> c_int>, int: c_int) -> c_int {
+    match process {
+        Some(f) => unsafe { f(int) },
+        None    => int * int
+    }
+}
+# fn main() {}
+```
+
+No `tranmsute` required!
 
 # Calling Rust code from C
 
@@ -642,12 +668,11 @@ void bar(void *arg);
 We can represent this in Rust with the `c_void` type:
 
 ```rust
-# #![feature(libc)]
-extern crate libc;
+use std::os::raw::c_void;
 
 extern "C" {
-    pub fn foo(arg: *mut libc::c_void);
-    pub fn bar(arg: *mut libc::c_void);
+    pub fn foo(arg: *mut c_void);
+    pub fn bar(arg: *mut c_void);
 }
 # fn main() {}
 ```