]> git.lizzy.rs Git - rust.git/commitdiff
std -- replaces uses where const borrows would be required
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 7 Feb 2014 11:33:11 +0000 (06:33 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 11 Feb 2014 21:55:10 +0000 (16:55 -0500)
src/libstd/io/mod.rs
src/libstd/unstable/finally.rs
src/libstd/vec.rs

index 1c1df691a52406fb334943eb612b532af231fc52..54c0d98c79897c1283fe7c195ac31a65b6f343c8 100644 (file)
 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 @@ fn read_byte(&mut self) -> IoResult<u8> {
     /// 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`
index 6faf69d2bb98f4a8d03e2926c2a46433694e6770..433accecdbcfdbff270ee337aa383265ee08403a 100644 (file)
 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]
index b58e0820cfd204ae903a6109d610e07d967eacad..bbb11d774b09a1bca8a92da7d8747e29596dd779 100644 (file)
 use mem::size_of;
 use kinds::marker;
 use uint;
-use unstable::finally::Finally;
+use unstable::finally::try_finally;
+use unstable::intrinsics;
 use unstable::raw::{Repr, Slice, Vec};
 
 /**
@@ -132,15 +133,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 +162,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
     }
 }