1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
//
// Copyright 2017 yvt, all rights reserved.
//
// 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.
//
//! Provides a `Send`-able cell type whose contents can be accessed only via an
//! inforgeable token.
//!
//! # Examples
//!
//! ```
//! # use tokenlock::*;
//! let mut token = Token::new();
//!
//! let lock = TokenLock::new(&token, 1);
//! assert_eq!(*lock.read(&token).unwrap(), 1);
//!
//! let mut guard = lock.write(&mut token).unwrap();
//! assert_eq!(*guard, 1);
//! *guard = 2;
//! ```
//!
//! `TokenLock` implements `Send` and `Sync` so it can be shared between threads,
//! but only the thread holding the original `Token` can access its contents.
//! `Token` cannot be cloned:
//!
//! ```
//! # use tokenlock::*;
//! # use std::thread;
//! # use std::sync::Arc;
//! # let mut token = Token::new();
//! let lock = Arc::new(TokenLock::new(&token, 1));
//!
//! let lock_1 = Arc::clone(&lock);
//! thread::Builder::new().spawn(move || {
//!     let lock_1 = lock_1;
//!     let mut token_1 = token;
//!
//!     // I have `Token` so I can get a mutable reference to the contents
//!     lock_1.write(&mut token_1).unwrap();
//! }).unwrap();
//!
//! // can't access the contents; I no longer have `Token`
//! // lock.write(&mut token).unwrap();
//! ```
//!
//! The lifetime of the returned reference is limited by both of the `TokenLock`
//! and `Token`.
//!
//! ```compile_fail
//! # use tokenlock::*;
//! # use std::mem::drop;
//! let mut token = Token::new();
//! let lock = TokenLock::new(&token, 1);
//! let guard = lock.write(&mut token).unwrap();
//! drop(lock); // compile error: `guard` cannot outlive `TokenLock`
//! ```
//!
//! ```compile_fail
//! # use tokenlock::*;
//! # use std::mem::drop;
//! # let mut token = Token::new();
//! # let lock = TokenLock::new(&token, 1);
//! # let guard = lock.write(&mut token).unwrap();
//! drop(token); // compile error: `guard` cannot outlive `Token`
//! ```
//!
//! It also prevents from forming a reference to the contained value when
//! there already is a mutable reference to it:
//!
//! ```compile_fail
//! # use tokenlock::*;
//! # let mut token = Token::new();
//! # let lock = TokenLock::new(&token, 1);
//! let write_guard = lock.write(&mut token).unwrap();
//! let read_guard = lock.read(&token).unwrap(); // compile error
//! ```
//!
//! While allowing multiple immutable references:
//!
//! ```
//! # use tokenlock::*;
//! # let mut token = Token::new();
//! # let lock = TokenLock::new(&token, 1);
//! let read_guard1 = lock.read(&token).unwrap();
//! let read_guard2 = lock.read(&token).unwrap();
//! ```
use std::{mem, fmt};
use std::cell::UnsafeCell;
use std::sync::Arc;

/// An inforgeable token used to access the contents of a `TokenLock`.
///
/// This type is not `Clone` to ensure an exclusive access to `TokenLock`.
///
/// See the [module-level documentation] for more details.
///
/// [module-level documentation]: index.html
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Token(UniqueId);

unsafe impl Send for Token {}
unsafe impl Sync for Token {}

impl Token {
    pub fn new() -> Self {
        Token(UniqueId::new())
    }
}

/// Token that cannot be used to access the contents of a `TokenLock`, but can
/// be used to create a new `TokenLock`.
///
/// See the [module-level documentation] for more details.
///
/// [module-level documentation]: index.html
///
/// # Examples
///
/// The parameter of `TokenLock::new` accepts `Into<TokenRef>`, so the following
/// codes are equivalent:
///
/// ```
/// # use tokenlock::*;
/// # let mut token = Token::new();
/// TokenLock::new(&token, 1);
/// TokenLock::new(TokenRef::from(&token), 1);
/// ```
///
/// `TokenRef` can be cloned while `Token` cannot:
///
/// ```
/// # use tokenlock::*;
/// let mut token = Token::new();
/// let token_ref = TokenRef::from(&token);
/// let lock1 = TokenLock::new(token_ref.clone(), 1);
/// let lock2 = TokenLock::new(token_ref.clone(), 2);
/// ```
///
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct TokenRef(UniqueId);

impl<'a> From<&'a Token> for TokenRef {
    fn from(x: &'a Token) -> TokenRef {
        TokenRef(x.0.clone())
    }
}

/// A mutual exclusive primitive that can be accessed using a `Token`
/// with a very low over-head.
///
/// See the [module-level documentation] for more details.
///
/// [module-level documentation]: index.html
pub struct TokenLock<T: ?Sized> {
    keyhole: UniqueId,
    data: UnsafeCell<T>,
}

unsafe impl<T: ?Sized + Send + Sync> Send for TokenLock<T> {}
unsafe impl<T: ?Sized + Send + Sync> Sync for TokenLock<T> {}

impl<T: ?Sized> fmt::Debug for TokenLock<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("TokenLock")
            .field("keyhole", &self.keyhole)
            .finish()
    }
}

impl<T> TokenLock<T> {
    pub fn new<S: Into<TokenRef>>(token: S, data: T) -> Self {
        Self {
            keyhole: token.into().0,
            data: UnsafeCell::new(data),
        }
    }
}

impl<T: ?Sized> TokenLock<T> {
    #[inline]
    #[allow(dead_code)]
    pub fn get_mut(&mut self) -> &mut T {
        unsafe { mem::transmute(self.data.get()) }
    }

    #[inline]
    #[allow(dead_code)]
    pub fn read<'a>(&'a self, token: &'a Token) -> Option<&'a T> {
        if token.0 == self.keyhole {
            Some(unsafe { &*self.data.get() })
        } else {
            None
        }
    }

    #[inline]
    pub fn write<'a>(&'a self, token: &'a mut Token) -> Option<&'a mut T> {
        if token.0 == self.keyhole {
            Some(unsafe { &mut *self.data.get() })
        } else {
            None
        }
    }
}

#[derive(Debug, Clone, Hash)]
struct UniqueId(Arc<usize>);

impl PartialEq for UniqueId {
    fn eq(&self, other: &Self) -> bool {
        Arc::ptr_eq(&self.0, &other.0)
    }
}
impl Eq for UniqueId {}

impl UniqueId {
    pub fn new() -> Self {
        // This guarantees consistent hash generation even if Rust would
        // implement a moving GC in future
        let mut arc = Arc::new(0);
        let id = &*arc as *const usize as usize;
        *Arc::get_mut(&mut arc).unwrap() = id;
        UniqueId(arc)
    }
}

#[test]
fn basic() {
    let mut token = Token::new();
    let lock = TokenLock::new(&token, 1);
    assert_eq!(*lock.read(&token).unwrap(), 1);

    let guard = lock.write(&mut token).unwrap();
    assert_eq!(*guard, 1);
}

#[test]
fn bad_token() {
    let token1 = Token::new();
    let mut token2 = Token::new();
    let lock = TokenLock::new(&token1, 1);
    assert!(lock.write(&mut token2).is_none());
}