Skip to content

Commit 47b17bb

Browse files
committed
---
yaml --- r: 148477 b: refs/heads/try2 c: 232d8e5 h: refs/heads/master i: 148475: 8835e21 v: v3
1 parent 0d43e5d commit 47b17bb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+559
-326
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: d84c3369f732233adf0a80056d43dbc36d813aae
8+
refs/heads/try2: 232d8e560561e07b3ba54c5d0234816e50342fb3
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/compiletest.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,9 @@ pub fn parse_config(args: ~[~str]) -> config {
140140
adb_test_dir:
141141
opt_str2(matches.opt_str("adb-test-dir")).to_str(),
142142
adb_device_status:
143-
if (opt_str2(matches.opt_str("target")) ==
144-
~"arm-linux-androideabi") {
145-
if (opt_str2(matches.opt_str("adb-test-dir")) !=
146-
~"(none)" &&
147-
opt_str2(matches.opt_str("adb-test-dir")) !=
148-
~"") { true }
149-
else { false }
150-
} else { false },
143+
"arm-linux-androideabi" == opt_str2(matches.opt_str("target")) &&
144+
"(none)" != opt_str2(matches.opt_str("adb-test-dir")) &&
145+
!opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
151146
test_shard: test::opt_shard(matches.opt_str("test-shard")),
152147
verbose: matches.opt_present("verbose")
153148
}

branches/try2/src/compiletest/runtest.rs

Lines changed: 4 additions & 3 deletions
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
}
@@ -531,9 +532,9 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError],
531532
if !found_flags[i] {
532533
debug!("prefix={} ee.kind={} ee.msg={} line={}",
533534
prefixes[i], ee.kind, ee.msg, line);
534-
if (prefix_matches(line, prefixes[i]) &&
535+
if prefix_matches(line, prefixes[i]) &&
535536
line.contains(ee.kind) &&
536-
line.contains(ee.msg)) {
537+
line.contains(ee.msg) {
537538
found_flags[i] = true;
538539
was_expected = true;
539540
break;

branches/try2/src/libextra/ebml.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,15 +1025,15 @@ mod bench {
10251025
pub fn vuint_at_A_aligned(bh: &mut BenchHarness) {
10261026
use std::vec;
10271027
let data = vec::from_fn(4*100, |i| {
1028-
match (i % 2) {
1028+
match i % 2 {
10291029
0 => 0x80u8,
10301030
_ => i as u8,
10311031
}
10321032
});
10331033
let mut sum = 0u;
10341034
bh.iter(|| {
10351035
let mut i = 0;
1036-
while (i < data.len()) {
1036+
while i < data.len() {
10371037
sum += reader::vuint_at(data, i).val;
10381038
i += 4;
10391039
}
@@ -1044,15 +1044,15 @@ mod bench {
10441044
pub fn vuint_at_A_unaligned(bh: &mut BenchHarness) {
10451045
use std::vec;
10461046
let data = vec::from_fn(4*100+1, |i| {
1047-
match (i % 2) {
1047+
match i % 2 {
10481048
1 => 0x80u8,
10491049
_ => i as u8
10501050
}
10511051
});
10521052
let mut sum = 0u;
10531053
bh.iter(|| {
10541054
let mut i = 1;
1055-
while (i < data.len()) {
1055+
while i < data.len() {
10561056
sum += reader::vuint_at(data, i).val;
10571057
i += 4;
10581058
}
@@ -1063,7 +1063,7 @@ mod bench {
10631063
pub fn vuint_at_D_aligned(bh: &mut BenchHarness) {
10641064
use std::vec;
10651065
let data = vec::from_fn(4*100, |i| {
1066-
match (i % 4) {
1066+
match i % 4 {
10671067
0 => 0x10u8,
10681068
3 => i as u8,
10691069
_ => 0u8
@@ -1072,7 +1072,7 @@ mod bench {
10721072
let mut sum = 0u;
10731073
bh.iter(|| {
10741074
let mut i = 0;
1075-
while (i < data.len()) {
1075+
while i < data.len() {
10761076
sum += reader::vuint_at(data, i).val;
10771077
i += 4;
10781078
}
@@ -1083,7 +1083,7 @@ mod bench {
10831083
pub fn vuint_at_D_unaligned(bh: &mut BenchHarness) {
10841084
use std::vec;
10851085
let data = vec::from_fn(4*100+1, |i| {
1086-
match (i % 4) {
1086+
match i % 4 {
10871087
1 => 0x10u8,
10881088
0 => i as u8,
10891089
_ => 0u8
@@ -1092,7 +1092,7 @@ mod bench {
10921092
let mut sum = 0u;
10931093
bh.iter(|| {
10941094
let mut i = 1;
1095-
while (i < data.len()) {
1095+
while i < data.len() {
10961096
sum += reader::vuint_at(data, i).val;
10971097
i += 4;
10981098
}

branches/try2/src/libextra/enum_set.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl<E:CLike> Items<E> {
114114

115115
impl<E:CLike> Iterator<E> for Items<E> {
116116
fn next(&mut self) -> Option<E> {
117-
if (self.bits == 0) {
117+
if self.bits == 0 {
118118
return None;
119119
}
120120

branches/try2/src/libextra/getopts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ impl Matches {
195195

196196
fn opt_val(&self, nm: &str) -> Option<Optval> {
197197
let vals = self.opt_vals(nm);
198-
if (vals.is_empty()) {
198+
if vals.is_empty() {
199199
None
200200
} else {
201201
Some(vals[0].clone())
@@ -797,7 +797,7 @@ pub mod groups {
797797
let slice: || = || { cont = it(ss.slice(slice_start, last_end)) };
798798

799799
// if the limit is larger than the string, lower it to save cycles
800-
if (lim >= fake_i) {
800+
if lim >= fake_i {
801801
lim = fake_i;
802802
}
803803

branches/try2/src/libextra/json.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ impl<T : Iterator<char>> Parser<T> {
929929
return self.error(~"EOF while parsing string");
930930
}
931931

932-
if (escape) {
932+
if escape {
933933
match self.ch {
934934
'"' => res.push_char('"'),
935935
'\\' => res.push_char('\\'),
@@ -1360,7 +1360,7 @@ impl serialize::Decoder for Decoder {
13601360
/// Test if two json values are less than one another
13611361
impl Ord for Json {
13621362
fn lt(&self, other: &Json) -> bool {
1363-
match (*self) {
1363+
match *self {
13641364
Number(f0) => {
13651365
match *other {
13661366
Number(f1) => f0 < f1,

branches/try2/src/libextra/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ Rust extras are part of the standard Rust distribution.
2020
2121
*/
2222

23-
// NOTE: upgrade to 0.10-pre after the next snapshot
24-
#[crate_id = "extra#0.9"];
23+
#[crate_id = "extra#0.10-pre"];
2524
#[comment = "Rust extras"];
2625
#[license = "MIT/ASL2"];
2726
#[crate_type = "rlib"];

branches/try2/src/libextra/num/bigint.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,9 +561,9 @@ impl ToPrimitive for BigUint {
561561
impl FromPrimitive for BigUint {
562562
#[inline]
563563
fn from_i64(n: i64) -> Option<BigUint> {
564-
if (n > 0) {
564+
if n > 0 {
565565
FromPrimitive::from_u64(n as u64)
566-
} else if (n == 0) {
566+
} else if n == 0 {
567567
Some(Zero::zero())
568568
} else {
569569
None

branches/try2/src/libextra/terminfo/parser/compiled.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ pub fn parse(file: &mut io::Reader,
178178

179179
// Check magic number
180180
let magic = file.read_le_u16();
181-
if (magic != 0x011A) {
181+
if magic != 0x011A {
182182
return Err(format!("invalid magic number: expected {:x} but found {:x}",
183183
0x011A, magic as uint));
184184
}

branches/try2/src/libextra/time.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, ~str> {
808808
/// Formats the time according to the format string.
809809
pub fn strftime(format: &str, tm: &Tm) -> ~str {
810810
fn days_in_year(year: int) -> i32 {
811-
if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))) {
811+
if (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) {
812812
366 /* Days in a leap year */
813813
} else {
814814
365 /* Days in a non-leap year */
@@ -838,14 +838,14 @@ pub fn strftime(format: &str, tm: &Tm) -> ~str {
838838
let mut year: int = tm.tm_year as int + 1900;
839839
let mut days: int = iso_week_days (tm.tm_yday, tm.tm_wday);
840840

841-
if (days < 0) {
841+
if days < 0 {
842842
/* This ISO week belongs to the previous year. */
843843
year -= 1;
844844
days = iso_week_days (tm.tm_yday + (days_in_year(year)), tm.tm_wday);
845845
} else {
846846
let d: int = iso_week_days (tm.tm_yday - (days_in_year(year)),
847847
tm.tm_wday);
848-
if (0 <= d) {
848+
if 0 <= d {
849849
/* This ISO week belongs to the next year. */
850850
year += 1;
851851
days = d;

branches/try2/src/libextra/uuid.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -614,16 +614,16 @@ mod test {
614614

615615
// Test error reporting
616616
let e = Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c").unwrap_err();
617-
assert!(match(e){ ErrorInvalidLength(n) => n==31, _ => false });
617+
assert!(match e { ErrorInvalidLength(n) => n==31, _ => false });
618618

619619
let e = Uuid::parse_string("67e550X410b1426f9247bb680e5fe0cd").unwrap_err();
620-
assert!(match(e){ ErrorInvalidCharacter(c, n) => c=='X' && n==6, _ => false });
620+
assert!(match e { ErrorInvalidCharacter(c, n) => c=='X' && n==6, _ => false });
621621

622622
let e = Uuid::parse_string("67e550-4105b1426f9247bb680e5fe0c").unwrap_err();
623-
assert!(match(e){ ErrorInvalidGroups(n) => n==2, _ => false });
623+
assert!(match e { ErrorInvalidGroups(n) => n==2, _ => false });
624624

625625
let e = Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4").unwrap_err();
626-
assert!(match(e){ ErrorInvalidGroupLength(g, n, e) => g==3 && n==5 && e==4, _ => false });
626+
assert!(match e { ErrorInvalidGroupLength(g, n, e) => g==3 && n==5 && e==4, _ => false });
627627
}
628628

629629
#[test]

0 commit comments

Comments
 (0)