2
2
3
3
# Introduction
4
4
5
- One of Rust's aims, as a system programming language, is to
5
+ Because Rust is a systems programming language, one of its goals is to
6
6
interoperate well with C code.
7
7
8
- We'll start with an example. It's a bit bigger than usual, and
9
- contains a number of new concepts. We'll go over it one piece at a
10
- time.
11
-
12
- This is a program that uses OpenSSL's ` SHA1 ` function to compute the
13
- hash of its first command-line argument, which it then converts to a
14
- hexadecimal string and prints to standard output. If you have the
15
- OpenSSL libraries installed, it should 'just work'.
8
+ We'll start with an example, which is a bit bigger than usual. We'll
9
+ go over it one piece at a time. This is a program that uses OpenSSL's
10
+ ` SHA1 ` function to compute the hash of its first command-line
11
+ argument, which it then converts to a hexadecimal string and prints to
12
+ standard output. If you have the OpenSSL libraries installed, it
13
+ should compile and run without any extra effort.
16
14
17
15
~~~~ {.xfail-test}
18
16
extern mod std;
@@ -32,7 +30,7 @@ fn sha1(data: ~str) -> ~str unsafe {
32
30
let bytes = str::to_bytes(data);
33
31
let hash = crypto::SHA1(vec::raw::to_ptr(bytes),
34
32
vec::len(bytes) as c_uint, ptr::null());
35
- return as_hex(vec::raw::from_buf(hash, 20u ));
33
+ return as_hex(vec::raw::from_buf(hash, 20 ));
36
34
}
37
35
38
36
fn main(args: ~[~str]) {
@@ -42,26 +40,27 @@ fn main(args: ~[~str]) {
42
40
43
41
# Foreign modules
44
42
45
- Before we can call ` SHA1 ` , we have to declare it. That is what this
46
- part of the program is responsible for :
43
+ Before we can call the ` SHA1 ` function defined in the OpenSSL library, we have
44
+ to declare it. That is what this part of the program does :
47
45
48
46
~~~~ {.xfail-test}
49
47
extern mod crypto {
50
- fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
51
- }
48
+ fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8; }
52
49
~~~~
53
50
54
- An ` extern ` module declaration containing function signatures introduces
55
- the functions listed as _ foreign functions_ , that are implemented in some
56
- other language (usually C) and accessed through Rust's foreign function
57
- interface (FFI). An extern module like this is called a foreign module, and
58
- implicitly tells the compiler to link with a library with the same name as
59
- the module, and that it will find the foreign functions in that library.
51
+ An ` extern ` module declaration containing function signatures introduces the
52
+ functions listed as _ foreign functions_ . Foreign functions differ from regular
53
+ Rust functions in that they are implemented in some other language (usually C)
54
+ and called through Rust's foreign function interface (FFI). An extern module
55
+ like this is called a foreign module, and implicitly tells the compiler to
56
+ link with a library that contains the listed foreign functions, and has the
57
+ same name as the module.
60
58
61
- In this case, it'll change the name ` crypto ` to a shared library name
62
- in a platform-specific way (` libcrypto.so ` on Linux, for example), and
63
- link that in. If you want the module to have a different name from the
64
- actual library, you can use the ` "link_name" ` attribute, like:
59
+ In this case, the Rust compiler changes the name ` crypto ` to a shared library
60
+ name in a platform-specific way (` libcrypto.so ` on Linux, for example),
61
+ searches for the shared library with that name, and links the library into the
62
+ program. If you want the module to have a different name from the actual
63
+ library, you can use the ` "link_name" ` attribute, like:
65
64
66
65
~~~~ {.xfail-test}
67
66
#[link_name = "crypto"]
@@ -72,11 +71,11 @@ extern mod something {
72
71
73
72
# Foreign calling conventions
74
73
75
- Most foreign code will be C code, which usually uses the ` cdecl ` calling
74
+ Most foreign code is C code, which usually uses the ` cdecl ` calling
76
75
convention, so that is what Rust uses by default when calling foreign
77
76
functions. Some foreign functions, most notably the Windows API, use other
78
- calling conventions, so Rust provides a way to hint to the compiler which
79
- is expected by using the ` "abi" ` attribute :
77
+ calling conventions. Rust provides the ` "abi" ` attribute as a way to hint to
78
+ the compiler which calling convention to use :
80
79
81
80
~~~~
82
81
#[cfg(target_os = "win32")]
@@ -86,14 +85,14 @@ extern mod kernel32 {
86
85
}
87
86
~~~~
88
87
89
- The ` "abi" ` attribute applies to a foreign module (it can not be applied
88
+ The ` "abi" ` attribute applies to a foreign module (it cannot be applied
90
89
to a single function within a module), and must be either ` "cdecl" `
91
- or ` "stdcall" ` . Other conventions may be defined in the future.
90
+ or ` "stdcall" ` . We may extend the compiler in the future to support other
91
+ calling conventions.
92
92
93
93
# Unsafe pointers
94
94
95
- The foreign ` SHA1 ` function is declared to take three arguments, and
96
- return a pointer.
95
+ The foreign ` SHA1 ` function takes three arguments, and returns a pointer.
97
96
98
97
~~~~ {.xfail-test}
99
98
# extern mod crypto {
@@ -104,21 +103,20 @@ fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
104
103
When declaring the argument types to a foreign function, the Rust
105
104
compiler has no way to check whether your declaration is correct, so
106
105
you have to be careful. If you get the number or types of the
107
- arguments wrong, you're likely to get a segmentation fault. Or,
106
+ arguments wrong, you're likely to cause a segmentation fault. Or,
108
107
probably even worse, your code will work on one platform, but break on
109
108
another.
110
109
111
- In this case, ` SHA1 ` is defined as taking two ` unsigned char* `
112
- arguments and one ` unsigned long ` . The rust equivalents are ` *u8 `
110
+ In this case, we declare that ` SHA1 ` takes two ` unsigned char* `
111
+ arguments and one ` unsigned long ` . The Rust equivalents are ` *u8 `
113
112
unsafe pointers and an ` uint ` (which, like ` unsigned long ` , is a
114
113
machine-word-sized type).
115
114
116
- Unsafe pointers can be created through various functions in the
117
- standard lib, usually with ` unsafe ` somewhere in their name. You can
118
- dereference an unsafe pointer with ` * ` operator, but use
119
- caution—unlike Rust's other pointer types, unsafe pointers are
120
- completely unmanaged, so they might point at invalid memory, or be
121
- null pointers.
115
+ The standard library provides various functions to create unsafe pointers,
116
+ such as those in ` core::cast ` . Most of these functions have ` unsafe ` in their
117
+ name. You can dereference an unsafe pointer with the ` * ` operator, but use
118
+ caution: unlike Rust's other pointer types, unsafe pointers are completely
119
+ unmanaged, so they might point at invalid memory, or be null pointers.
122
120
123
121
# Unsafe blocks
124
122
@@ -134,12 +132,12 @@ fn sha1(data: ~str) -> ~str {
134
132
let bytes = str::to_bytes(data);
135
133
let hash = crypto::SHA1(vec::raw::to_ptr(bytes),
136
134
vec::len(bytes), ptr::null());
137
- return as_hex(vec::raw::from_buf(hash, 20u ));
135
+ return as_hex(vec::raw::from_buf(hash, 20 ));
138
136
}
139
137
}
140
138
~~~~
141
139
142
- Firstly , what does the ` unsafe ` keyword at the top of the function
140
+ First , what does the ` unsafe ` keyword at the top of the function
143
141
mean? ` unsafe ` is a block modifier—it declares the block following it
144
142
to be known to be unsafe.
145
143
@@ -158,8 +156,8 @@ advertise it to the world. An unsafe function is written like this:
158
156
unsafe fn kaboom() { ~"I'm harmless!"; }
159
157
~~~~
160
158
161
- This function can only be called from an unsafe block or another
162
- unsafe function.
159
+ This function can only be called from an ` unsafe ` block or another
160
+ ` unsafe ` function.
163
161
164
162
# Pointer fiddling
165
163
@@ -179,35 +177,36 @@ Let's look at our `sha1` function again.
179
177
let bytes = str::to_bytes(data);
180
178
let hash = crypto::SHA1(vec::raw::to_ptr(bytes),
181
179
vec::len(bytes), ptr::null());
182
- return as_hex(vec::raw::from_buf(hash, 20u ));
180
+ return as_hex(vec::raw::from_buf(hash, 20 ));
183
181
# }
184
182
# }
185
183
~~~~
186
184
187
- The ` str::to_bytes ` function is perfectly safe: it converts a string to
188
- a ` [u8] ` . This byte array is then fed to ` vec::raw::to_ptr ` , which
185
+ The ` str::to_bytes ` function is perfectly safe: it converts a string to a
186
+ ` ~ [u8]` . The program then feeds this byte array to ` vec::raw::to_ptr ` , which
189
187
returns an unsafe pointer to its contents.
190
188
191
- This pointer will become invalid as soon as the vector it points into
192
- is cleaned up, so you should be very careful how you use it. In this
193
- case, the local variable ` bytes ` outlives the pointer, so we're good.
189
+ This pointer will become invalid at the end of the scope in which the vector
190
+ it points to (` bytes ` ) is valid, so you should be very careful how you use
191
+ it. In this case, the local variable ` bytes ` outlives the pointer, so we're
192
+ good.
194
193
195
194
Passing a null pointer as the third argument to ` SHA1 ` makes it use a
196
195
static buffer, and thus save us the effort of allocating memory
197
- ourselves. ` ptr::null ` is a generic function that will return an
198
- unsafe null pointer of the correct type (Rust generics are awesome
199
- like that— they can take the right form depending on the type that they
200
- are expected to return).
201
-
202
- Finally, ` vec::raw::from_buf ` builds up a new ` [u8] ` from the
203
- unsafe pointer that was returned by ` SHA1 ` . SHA1 digests are always
204
- twenty bytes long, so we can pass ` 20u ` for the length of the new
196
+ ourselves. ` ptr::null ` is a generic function that, in this case, returns an
197
+ unsafe null pointer of type ` *u8 ` . (Rust generics are awesome
198
+ like that: they can take the right form depending on the type that they
199
+ are expected to return.)
200
+
201
+ Finally, ` vec::raw::from_buf ` builds up a new ` ~ [u8]` from the
202
+ unsafe pointer that ` SHA1 ` returned . SHA1 digests are always
203
+ twenty bytes long, so we can pass ` 20 ` for the length of the new
205
204
vector.
206
205
207
206
# Passing structures
208
207
209
208
C functions often take pointers to structs as arguments. Since Rust
210
- structs are binary-compatible with C structs, Rust programs can call
209
+ ` struct ` s are binary-compatible with C structs, Rust programs can call
211
210
such functions directly.
212
211
213
212
This program uses the POSIX function ` gettimeofday ` to get a
@@ -241,12 +240,12 @@ fn unix_time_in_microseconds() -> u64 unsafe {
241
240
The ` #[nolink] ` attribute indicates that there's no foreign library to
242
241
link in. The standard C library is already linked with Rust programs.
243
242
244
- A ` timeval ` , in C, is a struct with two 32-bit integers . Thus, we
245
- define a struct type with the same contents, and declare
246
- ` gettimeofday ` to take a pointer to such a struct.
243
+ In C, a ` timeval ` is a struct with two 32-bit integer fields . Thus, we
244
+ define a ` struct ` type with the same contents, and declare
245
+ ` gettimeofday ` to take a pointer to such a ` struct ` .
247
246
248
- The second argument to ` gettimeofday ` (the time zone) is not used by
249
- this program , so it simply declares it to be a pointer to the nil
250
- type. Since all null pointers have the same representation regardless of
251
- their referent type, this is safe.
247
+ This program does not use the second argument to ` gettimeofday ` (the time
248
+ zone) , so the ` extern mod ` declaration for it simply declares this argument
249
+ to be a pointer to the unit type (written ` () ` ) . Since all null pointers have
250
+ the same representation regardless of their referent type, this is safe.
252
251
0 commit comments