forked from rust-lang/rust
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Based off of blake2-ppc's work in rust-lang#9429.
- Loading branch information
Showing
3 changed files
with
317 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -164,6 +164,7 @@ pub mod result; | |
pub mod either; | ||
pub mod hashmap; | ||
pub mod cell; | ||
pub mod mutable; | ||
pub mod trie; | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// 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. | ||
|
||
use std::mutable::Mut; | ||
|
||
fn f<T: Freeze>(_: T) {} | ||
|
||
fn main() { | ||
let x = Mut::new(0); | ||
f(x); //~ ERROR: which does not fulfill `Freeze` | ||
} |