about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-02-11 15:06:49 -0800
committerbors <bors@rust-lang.org>2014-02-11 15:06:49 -0800
commit0ac6e5afda2a9741d50d6b5c557ee16fee44878f (patch)
treef3911877e062ef2c5a2188a91b38a128dbd35c2b /src/libstd
parent2ab248af38c982f42a0a1acf0769e71fa7e77db7 (diff)
parent484f0f11e6e49c530cd0351e76989ec6706fa2ce (diff)
downloadrust-0ac6e5afda2a9741d50d6b5c557ee16fee44878f.tar.gz
rust-0ac6e5afda2a9741d50d6b5c557ee16fee44878f.zip
auto merge of #12158 : nikomatsakis/rust/issue-6801-borrowck-closures, r=pcwalton
I factored the commits by affected files, for the most part. The last 7 or 8 contain the meat of the PR. The rest are small changes to closures found in the codebase. Maybe interesting to read to see some of the impact of the rules.

r? @pcwalton

Fixes #6801
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/io/mod.rs42
-rw-r--r--src/libstd/io/net/udp.rs3
-rw-r--r--src/libstd/str.rs12
-rw-r--r--src/libstd/unstable/finally.rs114
-rw-r--r--src/libstd/vec.rs41
5 files changed, 135 insertions, 77 deletions
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 1c1df691a52..54c0d98c798 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -277,7 +277,7 @@ use str::{StrSlice, OwnedStr};
 use str;
 use to_str::ToStr;
 use uint;
-use unstable::finally::Finally;
+use unstable::finally::try_finally;
 use vec::{OwnedVector, MutableVector, ImmutableVector, OwnedCloneableVector};
 use vec;
 
@@ -473,25 +473,33 @@ pub trait Reader {
     /// pushed on to the vector, otherwise the amount `len` bytes couldn't be
     /// read (an error was encountered), and the error is returned.
     fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) -> IoResult<()> {
+        struct State<'a> {
+            buf: &'a mut ~[u8],
+            total_read: uint
+        }
+
         let start_len = buf.len();
-        let mut total_read = 0;
-
-        buf.reserve_additional(len);
-        unsafe { buf.set_len(start_len + len); }
-
-        (|| {
-            while total_read < len {
-                let len = buf.len();
-                let slice = buf.mut_slice(start_len + total_read, len);
-                match self.read(slice) {
-                    Ok(nread) => {
-                        total_read += nread;
+        let mut s = State { buf: buf, total_read: 0 };
+
+        s.buf.reserve_additional(len);
+        unsafe { s.buf.set_len(start_len + len); }
+
+        try_finally(
+            &mut s, (),
+            |s, _| {
+                while s.total_read < len {
+                    let len = s.buf.len();
+                    let slice = s.buf.mut_slice(start_len + s.total_read, len);
+                    match self.read(slice) {
+                        Ok(nread) => {
+                            s.total_read += nread;
+                        }
+                        Err(e) => return Err(e)
                     }
-                    Err(e) => return Err(e)
                 }
-            }
-            Ok(())
-        }).finally(|| unsafe { buf.set_len(start_len + total_read) })
+                Ok(())
+            },
+            |s| unsafe { s.buf.set_len(start_len + s.total_read) })
     }
 
     /// Reads `len` bytes and gives you back a new vector of length `len`
diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs
index ae99101e179..aeec36a932c 100644
--- a/src/libstd/io/net/udp.rs
+++ b/src/libstd/io/net/udp.rs
@@ -83,7 +83,8 @@ impl Reader for UdpStream {
 
 impl Writer for UdpStream {
     fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.as_socket(|sock| sock.sendto(buf, self.connectedTo))
+        let connectedTo = self.connectedTo;
+        self.as_socket(|sock| sock.sendto(buf, connectedTo))
     }
 }
 
diff --git a/src/libstd/str.rs b/src/libstd/str.rs
index 3225bb3a678..bc5991c6eeb 100644
--- a/src/libstd/str.rs
+++ b/src/libstd/str.rs
@@ -625,15 +625,17 @@ impl<'a> Iterator<char> for Normalizations<'a> {
 
         if !self.sorted {
             for ch in self.iter {
+                let buffer = &mut self.buffer;
+                let sorted = &mut self.sorted;
                 decomposer(ch, |d| {
                     let class = canonical_combining_class(d);
-                    if class == 0 && !self.sorted {
-                        canonical_sort(self.buffer);
-                        self.sorted = true;
+                    if class == 0 && !*sorted {
+                        canonical_sort(*buffer);
+                        *sorted = true;
                     }
-                    self.buffer.push((d, class));
+                    buffer.push((d, class));
                 });
-                if self.sorted { break }
+                if *sorted { break }
             }
         }
 
diff --git a/src/libstd/unstable/finally.rs b/src/libstd/unstable/finally.rs
index 6faf69d2bb9..433accecdbc 100644
--- a/src/libstd/unstable/finally.rs
+++ b/src/libstd/unstable/finally.rs
@@ -12,6 +12,11 @@
 The Finally trait provides a method, `finally` on
 stack closures that emulates Java-style try/finally blocks.
 
+Using the `finally` method is sometimes convenient, but the type rules
+prohibit any shared, mutable state between the "try" case and the
+"finally" case. For advanced cases, the `try_finally` function can
+also be used. See that function for more details.
+
 # Example
 
  ```
@@ -31,53 +36,89 @@ pub trait Finally<T> {
     fn finally(&self, dtor: ||) -> T;
 }
 
-macro_rules! finally_fn {
-    ($fnty:ty) => {
-        impl<T> Finally<T> for $fnty {
-            fn finally(&self, dtor: ||) -> T {
-                let _d = Finallyalizer {
-                    dtor: dtor
-                };
-                (*self)()
-            }
-        }
+impl<'a,T> Finally<T> for 'a || -> T {
+    fn finally(&self, dtor: ||) -> T {
+        try_finally(&mut (), (),
+                    |_, _| (*self)(),
+                    |_| dtor())
     }
 }
 
-impl<'a,T> Finally<T> for 'a || -> T {
+impl<T> Finally<T> for fn() -> T {
     fn finally(&self, dtor: ||) -> T {
-        let _d = Finallyalizer {
-            dtor: dtor
-        };
-
-        (*self)()
+        try_finally(&mut (), (),
+                    |_, _| (*self)(),
+                    |_| dtor())
     }
 }
 
-finally_fn!(extern "Rust" fn() -> T)
+/**
+ * The most general form of the `finally` functions. The function
+ * `try_fn` will be invoked first; whether or not it fails, the
+ * function `finally_fn` will be invoked next. The two parameters
+ * `mutate` and `drop` are used to thread state through the two
+ * closures. `mutate` is used for any shared, mutable state that both
+ * closures require access to; `drop` is used for any state that the
+ * `try_fn` requires ownership of.
+ *
+ * **WARNING:** While shared, mutable state between the try and finally
+ * function is often necessary, one must be very careful; the `try`
+ * function could have failed at any point, so the values of the shared
+ * state may be inconsistent.
+ *
+ * # Example
+ *
+ * ```
+ * struct State<'a> { buffer: &'a mut [u8], len: uint }
+ * let mut state = State { buffer: buf, len: 0 };
+ * try_finally(
+ *     &mut state, (),
+ *     |state, ()| {
+ *         // use state.buffer, state.len
+ *     }
+ *     |state| {
+ *         // use state.buffer, state.len to cleanup
+ *     })
+ * ```
+ */
+pub fn try_finally<T,U,R>(mutate: &mut T,
+                          drop: U,
+                          try_fn: |&mut T, U| -> R,
+                          finally_fn: |&mut T|)
+                          -> R {
+    let f = Finallyalizer {
+        mutate: mutate,
+        dtor: finally_fn,
+    };
+    try_fn(&mut *f.mutate, drop)
+}
 
-struct Finallyalizer<'a> {
-    dtor: 'a ||
+struct Finallyalizer<'a,A> {
+    mutate: &'a mut A,
+    dtor: 'a |&mut A|
 }
 
 #[unsafe_destructor]
-impl<'a> Drop for Finallyalizer<'a> {
+impl<'a,A> Drop for Finallyalizer<'a,A> {
     #[inline]
     fn drop(&mut self) {
-        (self.dtor)();
+        (self.dtor)(self.mutate);
     }
 }
 
 #[test]
 fn test_success() {
     let mut i = 0;
-    (|| {
-        i = 10;
-    }).finally(|| {
-        assert!(!failing());
-        assert_eq!(i, 10);
-        i = 20;
-    });
+    try_finally(
+        &mut i, (),
+        |i, ()| {
+            *i = 10;
+        },
+        |i| {
+            assert!(!failing());
+            assert_eq!(*i, 10);
+            *i = 20;
+        });
     assert_eq!(i, 20);
 }
 
@@ -85,13 +126,16 @@ fn test_success() {
 #[should_fail]
 fn test_fail() {
     let mut i = 0;
-    (|| {
-        i = 10;
-        fail!();
-    }).finally(|| {
-        assert!(failing());
-        assert_eq!(i, 10);
-    })
+    try_finally(
+        &mut i, (),
+        |i, ()| {
+            *i = 10;
+            fail!();
+        },
+        |i| {
+            assert!(failing());
+            assert_eq!(*i, 10);
+        })
 }
 
 #[test]
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index b58e0820cfd..2acafecf957 100644
--- a/src/libstd/vec.rs
+++ b/src/libstd/vec.rs
@@ -119,7 +119,7 @@ use mem;
 use mem::size_of;
 use kinds::marker;
 use uint;
-use unstable::finally::Finally;
+use unstable::finally::try_finally;
 use unstable::raw::{Repr, Slice, Vec};
 
 /**
@@ -132,15 +132,16 @@ pub fn from_fn<T>(n_elts: uint, op: |uint| -> T) -> ~[T] {
     unsafe {
         let mut v = with_capacity(n_elts);
         let p = v.as_mut_ptr();
-        let mut i: uint = 0u;
-        (|| {
-            while i < n_elts {
-                mem::move_val_init(&mut(*ptr::mut_offset(p, i as int)), op(i));
-                i += 1u;
-            }
-        }).finally(|| {
-            v.set_len(i);
-        });
+        let mut i = 0;
+        try_finally(
+            &mut i, (),
+            |i, ()| while *i < n_elts {
+                mem::move_val_init(
+                    &mut(*ptr::mut_offset(p, *i as int)),
+                    op(*i));
+                *i += 1u;
+            },
+            |i| v.set_len(*i));
         v
     }
 }
@@ -160,14 +161,15 @@ pub fn from_elem<T:Clone>(n_elts: uint, t: T) -> ~[T] {
         let mut v = with_capacity(n_elts);
         let p = v.as_mut_ptr();
         let mut i = 0u;
-        (|| {
-            while i < n_elts {
-                mem::move_val_init(&mut(*ptr::mut_offset(p, i as int)), t.clone());
-                i += 1u;
-            }
-        }).finally(|| {
-            v.set_len(i);
-        });
+        try_finally(
+            &mut i, (),
+            |i, ()| while *i < n_elts {
+                mem::move_val_init(
+                    &mut(*ptr::mut_offset(p, *i as int)),
+                    t.clone());
+                *i += 1u;
+            },
+            |i| v.set_len(*i));
         v
     }
 }
@@ -294,7 +296,8 @@ impl<'a, T> Iterator<&'a [T]> for RevSplits<'a, T> {
             return Some(self.v);
         }
 
-        match self.v.iter().rposition(|x| (self.pred)(x)) {
+        let pred = &mut self.pred;
+        match self.v.iter().rposition(|x| (*pred)(x)) {
             None => {
                 self.finished = true;
                 Some(self.v)