├── .gitignore ├── .travis.yml ├── Cargo.toml ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: rust 4 | rust: 5 | - nightly 6 | - beta 7 | - 1.0.0 8 | - stable 9 | env: 10 | global: 11 | secure: "..." 12 | before_script: 13 | - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH 14 | script: 15 | - | 16 | travis-cargo build && 17 | travis-cargo test && 18 | travis-cargo bench && 19 | travis-cargo doc 20 | after_success: 21 | - travis-cargo --only stable doc-upload 22 | notifications: 23 | webhooks: http://huon.me:54856/travis 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alias" 3 | version = "0.1.0" 4 | authors = ["Huon Wilson "] 5 | 6 | homepage = "https://github.com/huonw/alias" 7 | repository = "https://github.com/huonw/alias" 8 | documentation = "http://huonw.github.io/alias/alias/" 9 | license = "MIT/Apache-2.0" 10 | keywords = ["aliased-mutability", "aliasing", "cell"] 11 | readme = "README.md" 12 | description = """ 13 | `alias` offers some basic ways to mutate data while 14 | aliased. 15 | """ 16 | 17 | [features] 18 | unstable = [] 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # alias 2 | 3 | [![Build Status](https://travis-ci.org/huonw/alias.png)](https://travis-ci.org/huonw/alias) [![Coverage Status](https://coveralls.io/repos/huonw/alias/badge.svg)](https://coveralls.io/r/huonw/alias) [![crates.io](https://img.shields.io/crates/v/alias.svg)](https://crates.io/crates/alias) 4 | 5 | `alias` offers some basic ways to mutate data while 6 | aliased. 7 | 8 | [**Documentation**](http://huonw.github.io/alias/alias/) 9 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `alias` offers some basic ways to mutate data while 2 | //! aliased. [![crates.io](https://img.shields.io/crates/v/alias.svg)](https://crates.io/crates/alias) 3 | //! 4 | //! [*Source*](https://github.com/huonw/alias) 5 | //! 6 | //! # Examples 7 | //! 8 | //! ```rust 9 | //! let mut x = 0; 10 | //! 11 | //! let y = alias::one(&mut x); 12 | //! let z = y; 13 | //! 14 | //! // now we can read/write through multiple references 15 | //! z.set(10); 16 | //! y.set(y.get() + 2); 17 | //! assert_eq!(z.get(), 12); 18 | //! ``` 19 | //! 20 | //! ```rust 21 | //! let mut x = [0, 0, 0, 0]; 22 | //! 23 | //! let y = alias::slice(&mut x); 24 | //! let z = y; 25 | //! 26 | //! // now we can read/write through multiple references 27 | //! for i in 0..4 { 28 | //! z[i].set(10); 29 | //! y[i].set(y[i].get() + i); 30 | //! } 31 | //! 32 | //! assert_eq!(z[0].get(), 10); 33 | //! assert_eq!(z[1].get(), 11); 34 | //! assert_eq!(z[2].get(), 12); 35 | //! assert_eq!(z[3].get(), 13); 36 | //! ``` 37 | //! 38 | //! # How is this OK? 39 | //! 40 | //! Rust's safety guarantees hinge around control how data is 41 | //! aliased/can be manipulated while aliased. Key to this are the `&` 42 | //! (shared/"immutable") and `&mut` (unique/mutable) reference types. 43 | //! 44 | //! The latter essentially has the guarantee that if `x: &mut T` is 45 | //! accessible, then it is the only usable path to the `T` to which it 46 | //! points. This ensures arbitrary mutation is entirely safe, 47 | //! e.g. there's no way to invalidate other references because there 48 | //! are no other references. 49 | //! 50 | //! On the other hand, `&T` references can be arbitrarily aliased 51 | //! (possibly in a large number of threads), and so mutation cannot 52 | //! occur by default. However, it can occur via specialised types that 53 | //! control what mutation can happen, such as 54 | //! `std::cell::Cell`. That type is a plain wrapper around `T` that 55 | //! only works with a subset of possible `T`s (`T: Copy`). These types 56 | //! all assume they have full control over access to their internal 57 | //! data: they mediate every interaction. 58 | //! 59 | //! If one has unique access to some piece of data (`&mut T`), it is 60 | //! definitely safe to treat it as aliased (`&T`), but it is also safe 61 | //! to treat it as aliased and mutable (`&Cell`). No other piece of 62 | //! code can be manipulating the `T` via any other path while the 63 | //! `&mut T` reference exists (and lifetimes ensures `&Cell` cannot 64 | //! outlive it), so no other piece of code can do anything that 65 | //! violates the assumption that the `Cell` controls every 66 | //! interaction. 67 | //! 68 | //! This also relies on `T` → `Cell` being a valid transmute, that 69 | //! is, the layouts being identical. Strictly speaking, this isn't 70 | //! guaranteed, but it is likely for it to remain this way. (There's 71 | //! an additional factor of `Cell` theoretically having more layout 72 | //! optimisations possible due to the way it restricts access to its 73 | //! internals.) 74 | 75 | use std::mem; 76 | use std::cell::Cell; 77 | 78 | /// Allow the mutable reference `data` to be mutated while aliased. 79 | /// 80 | /// # Examples 81 | /// 82 | /// ```rust 83 | /// let mut x = 0; 84 | /// 85 | /// let y = alias::one(&mut x); 86 | /// let z = y; 87 | /// 88 | /// // now we can read/write through multiple references 89 | /// z.set(10); 90 | /// y.set(y.get() + 2); 91 | /// assert_eq!(z.get(), 12); 92 | /// ``` 93 | pub fn one<'a, T: Copy>(data: &'a mut T) -> &'a Cell { 94 | unsafe { mem::transmute(data) } 95 | } 96 | 97 | /// Allow the contents of the mutable slice `data` to be mutated while 98 | /// aliased. 99 | /// 100 | /// # Examples 101 | /// 102 | /// ```rust 103 | /// let mut x = [0, 0, 0, 0]; 104 | /// 105 | /// let y = alias::slice(&mut x); 106 | /// let z = y; 107 | /// 108 | /// // now we can read/write through multiple references 109 | /// for i in 0..4 { 110 | /// z[i].set(10); 111 | /// y[i].set(y[i].get() + i); 112 | /// } 113 | /// 114 | /// assert_eq!(z[0].get(), 10); 115 | /// assert_eq!(z[1].get(), 11); 116 | /// assert_eq!(z[2].get(), 12); 117 | /// assert_eq!(z[3].get(), 13); 118 | /// ``` 119 | pub fn slice<'a, T: Copy>(data: &'a mut [T]) -> &'a [Cell] { 120 | unsafe { mem::transmute(data) } 121 | } 122 | 123 | #[cfg(test)] 124 | mod tests { 125 | use super::*; 126 | 127 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 128 | struct X<'a> { 129 | x: u8, 130 | y: u64, 131 | z: i8, 132 | w: &'a u32 133 | } 134 | 135 | #[test] 136 | fn smoke_one() { 137 | let a = 1; 138 | let b = 2; 139 | let val = X { x: 0xAA, y: !0, z: 0x77, w: &a }; 140 | let val2 = X { x: 0x33, y: !0, z: 0x55, w: &b }; 141 | let mut x = Some(val); 142 | 143 | { 144 | let y = one(&mut x); 145 | let z = y; 146 | y.set(z.get()); 147 | assert_eq!(y.get(), Some(val)); 148 | assert_eq!(z.get(), Some(val)); 149 | 150 | z.set(Some(X { x: 1, .. y.get().unwrap()})); 151 | assert_eq!(y.get(), Some(X { x: 1, .. val })); 152 | assert_eq!(z.get(), Some(X { x: 1, .. val })); 153 | 154 | z.set(None); 155 | assert!(y.get().is_none()); 156 | assert!(z.get().is_none()); 157 | 158 | y.set(Some(val2)); 159 | assert_eq!(y.get(), Some(val2)); 160 | assert_eq!(z.get(), Some(val2)); 161 | } 162 | 163 | assert_eq!(x, Some(val2)); 164 | } 165 | #[test] 166 | fn smoke_slice() { 167 | let a = 1; 168 | let b = 2; 169 | let val = X { x: 0xAA, y: !0, z: 0x77, w: &a }; 170 | let val2 = X { x: 0x33, y: !0, z: 0x55, w: &b }; 171 | 172 | let mut x = [Some(val), Some(val2), None]; 173 | 174 | { 175 | let y = slice(&mut x); 176 | let z = y; 177 | assert_eq!(y.len(), 3); 178 | 179 | let y0 = &y[0]; 180 | let y1 = &y[1]; 181 | let y2 = &y[2]; 182 | let z0 = &z[0]; 183 | let z1 = &z[1]; 184 | let z2 = &z[2]; 185 | 186 | y0.set(z0.get()); 187 | assert_eq!(y0.get(), Some(val)); 188 | assert_eq!(z0.get(), Some(val)); 189 | 190 | y1.set(None); 191 | assert!(y1.get().is_none()); 192 | assert!(z1.get().is_none()); 193 | 194 | z2.set(Some(val2)); 195 | assert_eq!(y2.get(), Some(val2)); 196 | assert_eq!(z2.get(), Some(val2)); 197 | } 198 | assert_eq!(x, [Some(val), None, Some(val2)]); 199 | } 200 | } 201 | --------------------------------------------------------------------------------