diff options
| author | Steven Fackler <sfackler@gmail.com> | 2013-11-13 23:46:47 -0800 |
|---|---|---|
| committer | Steven Fackler <sfackler@gmail.com> | 2013-11-22 21:19:53 -0800 |
| commit | 0fade3a714f7a7f9bff5c11f9f37528d0ab168a1 (patch) | |
| tree | 1cb937b524ddb7c7bc223cab00ccea916ceaf131 /src/libstd | |
| parent | fb279aa02a7ff2ed069791f60a5159d73c8ed993 (diff) | |
| download | rust-0fade3a714f7a7f9bff5c11f9f37528d0ab168a1.tar.gz rust-0fade3a714f7a7f9bff5c11f9f37528d0ab168a1.zip | |
Introduce Mut<T> to libstd
Based off of blake2-ppc's work in #9429.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/lib.rs | 1 | ||||
| -rw-r--r-- | src/libstd/mutable.rs | 298 |
2 files changed, 299 insertions, 0 deletions
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ffa91df4e8a..10887369b15 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -164,6 +164,7 @@ pub mod result; pub mod either; pub mod hashmap; pub mod cell; +pub mod mutable; pub mod trie; diff --git a/src/libstd/mutable.rs b/src/libstd/mutable.rs new file mode 100644 index 00000000000..63caa52d3af --- /dev/null +++ b/src/libstd/mutable.rs @@ -0,0 +1,298 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A mutable memory location with dynamically checked borrow rules + +use prelude::*; + +use cast; +use util::NonCopyable; + +/// A mutable memory location with dynamically checked borrow rules +#[no_freeze] +pub struct Mut<T> { + priv value: T, + priv borrow: BorrowFlag, + priv nc: NonCopyable +} + +// Values [1, MAX-1] represent the number of `Ref` active +// (will not outgrow its range since `uint` is the size of the address space) +type BorrowFlag = uint; +static UNUSED: BorrowFlag = 0; +static WRITING: BorrowFlag = -1; + +impl<T> Mut<T> { + /// Create a new `Mut` containing `value` + pub fn new(value: T) -> Mut<T> { + Mut { + value: value, + borrow: UNUSED, + nc: NonCopyable + } + } + + /// Consumes the `Mut`, returning the wrapped value. + pub fn unwrap(self) -> T { + assert!(self.borrow == UNUSED); + self.value + } + + unsafe fn as_mut<'a>(&'a self) -> &'a mut Mut<T> { + cast::transmute_mut(self) + } + + /// Attempts to immutably borrow the wrapped value. + /// + /// The borrow lasts until the returned `Ref` exits scope. Multiple + /// immutable borrows can be taken out at the same time. + /// + /// Returns `None` if the value is currently mutably borrowed. + pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> { + match self.borrow { + WRITING => None, + _ => { + unsafe { self.as_mut().borrow += 1; } + Some(Ref { parent: self }) + } + } + } + + /// Immutably borrows the wrapped value. + /// + /// The borrow lasts until the returned `Ref` exits scope. Multiple + /// immutable borrows can be taken out at the same time. + /// + /// # Failure + /// + /// Fails if the value is currently mutably borrowed. + pub fn borrow<'a>(&'a self) -> Ref<'a, T> { + match self.try_borrow() { + Some(ptr) => ptr, + None => fail!("Mut<T> already mutably borrowed") + } + } + + /// Mutably borrows the wrapped value. + /// + /// The borrow lasts untile the returned `MutRef` exits scope. The value + /// cannot be borrowed while this borrow is active. + /// + /// Returns `None` if the value is currently borrowed. + pub fn try_borrow_mut<'a>(&'a self) -> Option<MutRef<'a, T>> { + match self.borrow { + UNUSED => unsafe { + let mut_self = self.as_mut(); + mut_self.borrow = WRITING; + Some(MutRef { parent: mut_self }) + }, + _ => None + } + } + + /// Mutably borrows the wrapped value. + /// + /// The borrow lasts untile the returned `MutRef` exits scope. The value + /// cannot be borrowed while this borrow is active. + /// + /// # Failure + /// + /// Fails if the value is currently borrowed. + pub fn borrow_mut<'a>(&'a self) -> MutRef<'a, T> { + match self.try_borrow_mut() { + Some(ptr) => ptr, + None => fail!("Mut<T> already borrowed") + } + } + + /// Immutably borrows the wrapped value and applies `blk` to it. + /// + /// # Failure + /// + /// Fails if the value is currently mutably borrowed. + #[inline] + pub fn map<U>(&self, blk: |&T| -> U) -> U { + let ptr = self.borrow(); + blk(ptr.get()) + } + + /// Mutably borrows the wrapped value and applies `blk` to it. + /// + /// # Failure + /// + /// Fails if the value is currently borrowed. + #[inline] + pub fn map_mut<U>(&self, blk: |&mut T| -> U) -> U { + let mut ptr = self.borrow_mut(); + blk(ptr.get()) + } +} + +impl<T: Clone> Clone for Mut<T> { + fn clone(&self) -> Mut<T> { + let x = self.borrow(); + Mut::new(x.get().clone()) + } +} + +impl<T: DeepClone> DeepClone for Mut<T> { + fn deep_clone(&self) -> Mut<T> { + let x = self.borrow(); + Mut::new(x.get().deep_clone()) + } +} + +impl<T: Eq> Eq for Mut<T> { + fn eq(&self, other: &Mut<T>) -> bool { + let a = self.borrow(); + let b = other.borrow(); + a.get() == b.get() + } +} + +/// Wraps a borrowed reference to a value in a `Mut` box. +pub struct Ref<'box, T> { + priv parent: &'box Mut<T> +} + +#[unsafe_destructor] +impl<'box, T> Drop for Ref<'box, T> { + fn drop(&mut self) { + assert!(self.parent.borrow != WRITING && self.parent.borrow != UNUSED); + unsafe { self.parent.as_mut().borrow -= 1; } + } +} + +impl<'box, T> Ref<'box, T> { + /// Retrieve an immutable reference to the stored value. + #[inline] + pub fn get<'a>(&'a self) -> &'a T { + &self.parent.value + } +} + +/// Wraps a mutable borrowed reference to a value in a `Mut` box. +pub struct MutRef<'box, T> { + priv parent: &'box mut Mut<T> +} + +#[unsafe_destructor] +impl<'box, T> Drop for MutRef<'box, T> { + fn drop(&mut self) { + assert!(self.parent.borrow == WRITING); + unsafe { self.parent.as_mut().borrow = UNUSED; } + } +} + +impl<'box, T> MutRef<'box, T> { + /// Retrieve a mutable reference to the stored value. + #[inline] + pub fn get<'a>(&'a mut self) -> &'a mut T { + &mut self.parent.value + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn double_imm_borrow() { + let x = Mut::new(0); + let _b1 = x.borrow(); + x.borrow(); + } + + #[test] + fn no_mut_then_imm_borrow() { + let x = Mut::new(0); + let _b1 = x.borrow_mut(); + assert!(x.try_borrow().is_none()); + } + + #[test] + fn no_imm_then_borrow_mut() { + let x = Mut::new(0); + let _b1 = x.borrow(); + assert!(x.try_borrow_mut().is_none()); + } + + #[test] + fn no_double_borrow_mut() { + let x = Mut::new(0); + let _b1 = x.borrow_mut(); + assert!(x.try_borrow_mut().is_none()); + } + + #[test] + fn imm_release_borrow_mut() { + let x = Mut::new(0); + { + let _b1 = x.borrow(); + } + x.borrow_mut(); + } + + #[test] + fn mut_release_borrow_mut() { + let x = Mut::new(0); + { + let _b1 = x.borrow_mut(); + } + x.borrow(); + } + + #[test] + fn double_borrow_single_release_no_borrow_mut() { + let x = Mut::new(0); + let _b1 = x.borrow(); + { + let _b2 = x.borrow(); + } + assert!(x.try_borrow_mut().is_none()); + } + + #[test] + fn map_ok() { + let x = Mut::new(0); + assert_eq!(1, x.map(|x| *x+1)); + } + + #[test] + #[should_fail] + fn mut_borrow_map() { + let x = Mut::new(0); + let _b1 = x.borrow_mut(); + x.map(|x| *x+1); + } + + #[test] + fn borrow_map() { + let x = Mut::new(0); + let _b1 = x.borrow(); + assert_eq!(1, x.map(|x| *x+1)); + } + + #[test] + fn map_mut_ok() { + let x = Mut::new(0); + x.map_mut(|x| *x += 1); + let b = x.borrow(); + assert_eq!(1, *b.get()); + } + + #[test] + #[should_fail] + fn borrow_map_mut() { + let x = Mut::new(0); + let _b = x.borrow(); + x.map_mut(|x| *x += 1); + } +} |
