Skip to content

Remove @fn from the language #9310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Sep 24, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions doc/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -1469,34 +1469,6 @@ cannot be stored in data structures or returned from
functions. Despite these limitations, stack closures are used
pervasively in Rust code.

## Managed closures

When you need to store a closure in a data structure, a stack closure
will not do, since the compiler will refuse to let you store it. For
this purpose, Rust provides a type of closure that has an arbitrary
lifetime, written `@fn` (boxed closure, analogous to the `@` pointer
type described earlier). This type of closure *is* first-class.

A managed closure does not directly access its environment, but merely
copies out the values that it closes over into a private data
structure. This means that it can not assign to these variables, and
cannot observe updates to them.

This code creates a closure that adds a given string to its argument,
returns it from a function, and then calls it:

~~~~
fn mk_appender(suffix: ~str) -> @fn(~str) -> ~str {
// The compiler knows that we intend this closure to be of type @fn
return |s| s + suffix;
}

fn main() {
let shout = mk_appender(~"!");
println(shout(~"hey ho, let's go"));
}
~~~~

## Owned closures

Owned closures, written `~fn` in analogy to the `~` pointer type,
Expand Down
59 changes: 37 additions & 22 deletions src/libextra/c_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,37 +36,39 @@
* still held if needed.
*/


use std::option;
use std::ptr;
use std::routine::Runnable;
use std::util;

/**
* The type representing a foreign chunk of memory
*
*/
pub struct CVec<T> {
priv base: *mut T,
priv len: uint,
priv rsrc: @DtorRes
priv rsrc: @DtorRes,
}

struct DtorRes {
dtor: Option<@fn()>,
dtor: Option<~Runnable>,
}

#[unsafe_destructor]
impl Drop for DtorRes {
fn drop(&mut self) {
match self.dtor {
option::None => (),
option::Some(f) => f()
let dtor = util::replace(&mut self.dtor, None);
match dtor {
None => (),
Some(f) => f.run()
}
}
}

fn DtorRes(dtor: Option<@fn()>) -> DtorRes {
DtorRes {
dtor: dtor
impl DtorRes {
fn new(dtor: Option<~Runnable>) -> DtorRes {
DtorRes {
dtor: dtor,
}
}
}

Expand All @@ -83,10 +85,10 @@ fn DtorRes(dtor: Option<@fn()>) -> DtorRes {
* * len - The number of elements in the buffer
*/
pub unsafe fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
return CVec{
return CVec {
base: base,
len: len,
rsrc: @DtorRes(option::None)
rsrc: @DtorRes::new(None)
};
}

Expand All @@ -101,12 +103,12 @@ pub unsafe fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
* * dtor - A function to run when the value is destructed, useful
* for freeing the buffer, etc.
*/
pub unsafe fn c_vec_with_dtor<T>(base: *mut T, len: uint, dtor: @fn())
-> CVec<T> {
pub unsafe fn c_vec_with_dtor<T>(base: *mut T, len: uint, dtor: ~Runnable)
-> CVec<T> {
return CVec{
base: base,
len: len,
rsrc: @DtorRes(option::Some(dtor))
rsrc: @DtorRes::new(Some(dtor))
};
}

Expand Down Expand Up @@ -153,6 +155,20 @@ mod tests {

use std::libc::*;
use std::libc;
use std::routine::Runnable;

struct LibcFree {
mem: *c_void,
}

impl Runnable for LibcFree {
#[fixed_stack_segment]
fn run(~self) {
unsafe {
libc::free(self.mem)
}
}
}

fn malloc(n: size_t) -> CVec<u8> {
#[fixed_stack_segment];
Expand All @@ -163,12 +179,11 @@ mod tests {

assert!(mem as int != 0);

return c_vec_with_dtor(mem as *mut u8, n as uint, || f(mem));
}

fn f(mem: *c_void) {
#[fixed_stack_segment]; #[inline(never)];
unsafe { libc::free(mem) }
return c_vec_with_dtor(mem as *mut u8,
n as uint,
~LibcFree {
mem: mem,
} as ~Runnable);
}
}

Expand Down
52 changes: 32 additions & 20 deletions src/libextra/rl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub mod rustrt {

macro_rules! locked {
($expr:expr) => {
unsafe {
{
// FIXME #9105: can't use a static mutex in pure Rust yet.
rustrt::rust_take_linenoise_lock();
let x = $expr;
Expand All @@ -43,35 +43,46 @@ macro_rules! locked {
/// Add a line to history
pub fn add_history(line: &str) -> bool {
do line.with_c_str |buf| {
(locked!(rustrt::linenoiseHistoryAdd(buf))) == 1 as c_int
unsafe {
(locked!(rustrt::linenoiseHistoryAdd(buf))) == 1 as c_int
}
}
}

/// Set the maximum amount of lines stored
pub fn set_history_max_len(len: int) -> bool {
(locked!(rustrt::linenoiseHistorySetMaxLen(len as c_int))) == 1 as c_int
unsafe {
(locked!(rustrt::linenoiseHistorySetMaxLen(len as c_int))) == 1
as c_int
}
}

/// Save line history to a file
pub fn save_history(file: &str) -> bool {
do file.with_c_str |buf| {
// 0 on success, -1 on failure
(locked!(rustrt::linenoiseHistorySave(buf))) == 0 as c_int
unsafe {
(locked!(rustrt::linenoiseHistorySave(buf))) == 0 as c_int
}
}
}

/// Load line history from a file
pub fn load_history(file: &str) -> bool {
do file.with_c_str |buf| {
// 0 on success, -1 on failure
(locked!(rustrt::linenoiseHistoryLoad(buf))) == 0 as c_int
unsafe {
(locked!(rustrt::linenoiseHistoryLoad(buf))) == 0 as c_int
}
}
}

/// Print out a prompt and then wait for input and return it
pub fn read(prompt: &str) -> Option<~str> {
do prompt.with_c_str |buf| {
let line = locked!(rustrt::linenoise(buf));
let line = unsafe {
locked!(rustrt::linenoise(buf))
};

if line.is_null() { None }
else {
Expand All @@ -88,35 +99,36 @@ pub fn read(prompt: &str) -> Option<~str> {
}
}

pub type CompletionCb = @fn(~str, @fn(~str));
/// The callback used to perform completions.
pub trait CompletionCb {
/// Performs a completion.
fn complete(&self, line: ~str, suggestion: &fn(~str));
}

local_data_key!(complete_key: CompletionCb)
local_data_key!(complete_key: @CompletionCb)

/// Bind to the main completion callback in the current task.
///
/// The completion callback should not call any `extra::rl` functions
/// other than the closure that it receives as its second
/// argument. Calling such a function will deadlock on the mutex used
/// to ensure that the calls are thread-safe.
pub fn complete(cb: CompletionCb) {
pub unsafe fn complete(cb: @CompletionCb) {
local_data::set(complete_key, cb);

extern fn callback(c_line: *c_char, completions: *()) {
extern fn callback(line: *c_char, completions: *()) {
do local_data::get(complete_key) |opt_cb| {
// only fetch completions if a completion handler has been
// registered in the current task.
match opt_cb {
None => {},
None => {}
Some(cb) => {
let line = unsafe { str::raw::from_c_str(c_line) };
do (*cb)(line) |suggestion| {
do suggestion.with_c_str |buf| {
// This isn't locked, because `callback` gets
// called inside `rustrt::linenoise`, which
// *is* already inside the mutex, so
// re-locking would be a deadlock.
unsafe {
rustrt::linenoiseAddCompletion(completions, buf);
unsafe {
do cb.complete(str::raw::from_c_str(line))
|suggestion| {
do suggestion.with_c_str |buf| {
rustrt::linenoiseAddCompletion(completions,
buf);
}
}
}
Expand Down
5 changes: 0 additions & 5 deletions src/libextra/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -807,11 +807,6 @@ pub fn filter_tests(
}
}

struct TestFuture {
test: TestDesc,
wait: @fn() -> TestResult,
}

pub fn run_test(force_ignore: bool,
test: TestDescAndFn,
monitor_ch: SharedChan<MonitorMsg>) {
Expand Down
Loading