Skip to content

Commit 9055d5c

Browse files
committed
---
yaml --- r: 148464 b: refs/heads/try2 c: 813db08 h: refs/heads/master v: v3
1 parent 51428fa commit 9055d5c

32 files changed

+595
-384
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: 1089bfef608dc0f6d9efc57d8daa8da76db823a8
8+
refs/heads/try2: 813db08fe6ffb7795b4c6db59b2f9d149c890242
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/doc/guide-ffi.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,143 @@ fn main() {
249249
}
250250
~~~~
251251

252+
# Callbacks from C code to Rust functions
253+
254+
Some external libraries require the usage of callbacks to report back their
255+
current state or intermediate data to the caller.
256+
It is possible to pass functions defined in Rust to an external library.
257+
The requirement for this is that the callback function is marked as `extern`
258+
with the correct calling convention to make it callable from C code.
259+
260+
The callback function that can then be sent to through a registration call
261+
to the C library and afterwards be invoked from there.
262+
263+
A basic example is:
264+
265+
Rust code:
266+
~~~~ {.xfail-test}
267+
extern fn callback(a:i32) {
268+
println!("I'm called from C with value {0}", a);
269+
}
270+
271+
#[link(name = "extlib")]
272+
extern {
273+
fn register_callback(cb: extern "C" fn(i32)) -> i32;
274+
fn trigger_callback();
275+
}
276+
277+
fn main() {
278+
unsafe {
279+
register_callback(callback);
280+
trigger_callback(); // Triggers the callback
281+
}
282+
}
283+
~~~~
284+
285+
C code:
286+
~~~~ {.xfail-test}
287+
typedef void (*rust_callback)(int32_t);
288+
rust_callback cb;
289+
290+
int32_t register_callback(rust_callback callback) {
291+
cb = callback;
292+
return 1;
293+
}
294+
295+
void trigger_callback() {
296+
cb(7); // Will call callback(7) in Rust
297+
}
298+
~~~~
299+
300+
In this example will Rust's `main()` will call `do_callback()` in C,
301+
which would call back to `callback()` in Rust.
302+
303+
304+
## Targetting callbacks to Rust objects
305+
306+
The former example showed how a global function can be called from C-Code.
307+
However it is often desired that the callback is targetted to a special
308+
Rust object. This could be the object that represents the wrapper for the
309+
respective C object.
310+
311+
This can be achieved by passing an unsafe pointer to the object down to the
312+
C library. The C library can then include the pointer to the Rust object in
313+
the notification. This will provide a unsafe possibility to access the
314+
referenced Rust object in callback.
315+
316+
Rust code:
317+
~~~~ {.xfail-test}
318+
319+
struct RustObject {
320+
a: i32,
321+
// other members
322+
}
323+
324+
extern fn callback(target: *RustObject, a:i32) {
325+
println!("I'm called from C with value {0}", a);
326+
(*target).a = a; // Update the value in RustObject with the value received from the callback
327+
}
328+
329+
#[link(name = "extlib")]
330+
extern {
331+
fn register_callback(target: *RustObject, cb: extern "C" fn(*RustObject, i32)) -> i32;
332+
fn trigger_callback();
333+
}
334+
335+
fn main() {
336+
// Create the object that will be referenced in the callback
337+
let rust_object = ~RustObject{a: 5, ...};
338+
339+
unsafe {
340+
// Gets a raw pointer to the object
341+
let target_addr:*RustObject = ptr::to_unsafe_ptr(rust_object);
342+
register_callback(target_addr, callback);
343+
trigger_callback(); // Triggers the callback
344+
}
345+
}
346+
~~~~
347+
348+
C code:
349+
~~~~ {.xfail-test}
350+
typedef void (*rust_callback)(int32_t);
351+
void* cb_target;
352+
rust_callback cb;
353+
354+
int32_t register_callback(void* callback_target, rust_callback callback) {
355+
cb_target = callback_target;
356+
cb = callback;
357+
return 1;
358+
}
359+
360+
void trigger_callback() {
361+
cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust
362+
}
363+
~~~~
364+
365+
## Asynchronous callbacks
366+
367+
In the already given examples the callbacks are invoked as a direct reaction
368+
to a function call to the external C library.
369+
The control over the current thread switched from Rust to C to Rust for the
370+
execution of the callback, but in the end the callback is executed on the
371+
same thread (and Rust task) that lead called the function which triggered
372+
the callback.
373+
374+
Things get more complicated when the external library spawns it's own threads
375+
and invokes callbacks from there.
376+
In these cases access to Rust data structures inside he callbacks is
377+
especially unsafe and proper synchronization mechanisms must be used.
378+
Besides classical synchronization mechanisms like mutexes one possibility in
379+
Rust is to use channels (in `std::comm`) to forward data from the C thread
380+
that invoked the callback into a Rust task.
381+
382+
If an asychronous callback targets a special object in the Rust address space
383+
it is also absolutely necessary that no more callbacks are performed by the
384+
C library after the respective Rust object get's destroyed.
385+
This can be achieved by unregistering the callback it the object's
386+
destructor and designing the library in a way that guarantees that no
387+
callback will be performed after unregistration.
388+
252389
# Linking
253390

254391
The `link` attribute on `extern` blocks provides the basic building block for

branches/try2/doc/rust.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ include:
484484

485485
* `fmt!` : format data into a string
486486
* `env!` : look up an environment variable's value at compile time
487+
* `file!`: return the path to the file being compiled
487488
* `stringify!` : pretty-print the Rust expression given as an argument
488489
* `include!` : include the Rust expression in the given file
489490
* `include_str!` : include the contents of the given file as a string

branches/try2/src/compiletest/runtest.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,8 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
206206
}
207207

208208
fn make_pp_args(config: &config, _testfile: &Path) -> ProcArgs {
209-
let args = ~[~"-", ~"--pretty", ~"normal"];
209+
let args = ~[~"-", ~"--pretty", ~"normal",
210+
~"--target=" + config.target];
210211
// FIXME (#9639): This needs to handle non-utf8 paths
211212
return ProcArgs {prog: config.rustc_path.as_str().unwrap().to_owned(), args: args};
212213
}
@@ -237,9 +238,15 @@ actual:\n\
237238

238239
fn make_typecheck_args(config: &config, props: &TestProps, testfile: &Path) -> ProcArgs {
239240
let aux_dir = aux_output_dir_name(config, testfile);
241+
let target = if props.force_host {
242+
config.host.as_slice()
243+
} else {
244+
config.target.as_slice()
245+
};
240246
// FIXME (#9639): This needs to handle non-utf8 paths
241247
let mut args = ~[~"-",
242248
~"--no-trans", ~"--lib",
249+
~"--target=" + target,
243250
~"-L", config.build_base.as_str().unwrap().to_owned(),
244251
~"-L",
245252
aux_dir.as_str().unwrap().to_owned()];

branches/try2/src/libextra/uuid.rs

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Examples of string representations:
5757

5858
use std::str;
5959
use std::vec;
60-
use std::num::{FromStrRadix, Zero};
60+
use std::num::FromStrRadix;
6161
use std::char::Char;
6262
use std::container::Container;
6363
use std::to_str::ToStr;
@@ -158,9 +158,8 @@ static UuidGroupLens: [uint, ..5] = [8u, 4u, 4u, 4u, 12u];
158158

159159
/// UUID support
160160
impl Uuid {
161-
162161
/// Returns a nil or empty UUID (containing all zeroes)
163-
pub fn new_nil() -> Uuid {
162+
pub fn nil() -> Uuid {
164163
let uuid = Uuid{ bytes: [0, .. 16] };
165164
uuid
166165
}
@@ -423,24 +422,17 @@ impl Uuid {
423422

424423
Ok(Uuid::from_bytes(ub).unwrap())
425424
}
426-
}
427425

428-
impl Default for Uuid {
429-
/// Returns the nil UUID, which is all zeroes
430-
fn default() -> Uuid {
431-
Uuid::new_nil()
426+
/// Tests if the UUID is nil
427+
pub fn is_nil(&self) -> bool {
428+
return self.bytes.iter().all(|&b| b == 0);
432429
}
433430
}
434431

435-
impl Zero for Uuid {
432+
impl Default for Uuid {
436433
/// Returns the nil UUID, which is all zeroes
437-
fn zero() -> Uuid {
438-
Uuid::new_nil()
439-
}
440-
441-
/// Tests if the UUID is nil or all zeroes
442-
fn is_zero(&self) -> bool {
443-
return self.bytes.iter().all(|&b| b == 0);
434+
fn default() -> Uuid {
435+
Uuid::nil()
444436
}
445437
}
446438

@@ -521,24 +513,15 @@ mod test {
521513
use super::*;
522514
use std::str;
523515
use std::rand;
524-
use std::num::Zero;
525516
use std::io::MemWriter;
526517

527518
#[test]
528-
fn test_new_nil() {
529-
let nil = Uuid::new_nil();
530-
let nb = nil.to_bytes();
531-
532-
assert!(nb.iter().all(|&b| b == 0));
533-
}
534-
535-
#[test]
536-
fn test_zero() {
537-
let uz: Uuid = Zero::zero();
538-
let nz = Uuid::new_v4();
519+
fn test_nil() {
520+
let nil = Uuid::nil();
521+
let not_nil = Uuid::new_v4();
539522

540-
assert!(uz.is_zero());
541-
assert!(! nz.is_zero());
523+
assert!(nil.is_nil());
524+
assert!(!not_nil.is_nil());
542525
}
543526

544527
#[test]
@@ -619,7 +602,7 @@ mod test {
619602
assert!(Uuid::parse_string("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
620603

621604
// Nil
622-
let nil = Uuid::new_nil();
605+
let nil = Uuid::nil();
623606
assert!(Uuid::parse_string("00000000000000000000000000000000").unwrap() == nil);
624607
assert!(Uuid::parse_string("00000000-0000-0000-0000-000000000000").unwrap() == nil);
625608

branches/try2/src/librustc/middle/check_const.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,10 @@ pub fn check_expr(v: &mut CheckCrateVisitor,
177177
}
178178
}
179179
}
180-
ExprParen(e) => { check_expr(v, sess, def_map, method_map,
181-
tcx, e, is_const); }
182180
ExprVstore(_, ExprVstoreSlice) |
183181
ExprVec(_, MutImmutable) |
184182
ExprAddrOf(MutImmutable, _) |
183+
ExprParen(..) |
185184
ExprField(..) |
186185
ExprIndex(..) |
187186
ExprTup(..) |

branches/try2/src/librustc/middle/lang_items.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,27 @@ use std::hashmap::HashMap;
3333
use std::iter::Enumerate;
3434
use std::vec;
3535

36+
37+
// Get the last "argument" (has to be done recursively to avoid phoney local ambiguity error)
38+
macro_rules! last {
39+
( $first:expr, $( $remainder:expr, )+ ) => ( last!( $( $remainder, )+ ) );
40+
( $first:expr, ) => ( $first )
41+
}
42+
3643
// The actual lang items defined come at the end of this file in one handy table.
3744
// So you probably just want to nip down to the end.
3845
macro_rules! lets_do_this {
46+
// secondary rule to allow us to use `$num` as both an expression
47+
// and a pattern.
48+
(
49+
$( $num:tt, $variant:ident, $name:expr, $method:ident; )*
50+
) => {
51+
lets_do_this!(count = 1 + last!($($num,)*),
52+
$($num, $variant, $name, $method; )*)
53+
};
54+
3955
(
40-
There are $num_lang_items:expr lang items.
41-
$( $num:pat, $variant:ident, $name:expr, $method:ident; )*
56+
count = $num_lang_items:expr, $( $num:pat, $variant:ident, $name:expr, $method:ident; )*
4257
) => {
4358

4459
pub enum LangItem {
@@ -207,8 +222,6 @@ pub fn collect_language_items(crate: &ast::Crate,
207222
}
208223

209224
lets_do_this! {
210-
There are 40 lang items.
211-
212225
// ID, Variant name, Name, Method name;
213226
0, FreezeTraitLangItem, "freeze", freeze_trait;
214227
1, SendTraitLangItem, "send", send_trait;
@@ -261,4 +274,3 @@ lets_do_this! {
261274
38, ExchangeHeapLangItem, "exchange_heap", exchange_heap;
262275
39, GcLangItem, "gc", gc;
263276
}
264-

branches/try2/src/librustc/middle/trans/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ pub fn invoke<'a>(
940940
}
941941
}
942942

943-
if bcx.fcx.needs_invoke() {
943+
if need_invoke(bcx) {
944944
unsafe {
945945
debug!("invoking {} at {}", llfn, bcx.llbb);
946946
for &llarg in llargs.iter() {

branches/try2/src/librustc/middle/ty.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,6 +2287,12 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
22872287
::util::ppaux::ty_to_str(cx, ty));
22882288

22892289
let r = match get(ty).sty {
2290+
// fixed length vectors need special treatment compared to
2291+
// normal vectors, since they don't necessarily have the
2292+
// possibilty to have length zero.
2293+
ty_vec(_, vstore_fixed(0)) => false, // don't need no contents
2294+
ty_vec(mt, vstore_fixed(_)) => type_requires(cx, seen, r_ty, mt.ty),
2295+
22902296
ty_nil |
22912297
ty_bot |
22922298
ty_bool |

branches/try2/src/librustuv/addrinfo.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
use ai = std::io::net::addrinfo;
12+
use std::cast;
1213
use std::libc::c_int;
1314
use std::ptr::null;
1415
use std::rt::task::BlockedTask;
@@ -138,7 +139,8 @@ pub fn accum_addrinfo(addr: &Addrinfo) -> ~[ai::Info] {
138139

139140
let mut addrs = ~[];
140141
loop {
141-
let rustaddr = net::sockaddr_to_socket_addr((*addr).ai_addr);
142+
let rustaddr = net::sockaddr_to_addr(cast::transmute((*addr).ai_addr),
143+
(*addr).ai_addrlen as uint);
142144

143145
let mut flags = 0;
144146
each_ai_flag(|cval, aival| {

branches/try2/src/librustuv/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ via `close` and `delete` methods.
4747
use std::cast;
4848
use std::io;
4949
use std::io::IoError;
50-
use std::libc::{c_int, malloc};
50+
use std::libc::c_int;
5151
use std::ptr::null;
5252
use std::ptr;
5353
use std::rt::local::Local;

0 commit comments

Comments
 (0)