# tokenlock
[](https://docs.rs/tokenlock/)
This crate provides a cell type, `TokenLock`, which can only be borrowed
by presenting the correct unforgeable token, thus decoupling permissions
from data.
## Examples
### Basics
```rust
// Create a token
let mut token = IcToken::new();
// Create a keyhole by `token.id()` and use this to create a `TokenLock`.
let lock: IcTokenLock = TokenLock::new(token.id(), 1);
assert_eq!(*lock.read(&token), 1);
// Unlock the `TokenLock` using the matching token
let mut guard = lock.write(&mut token);
assert_eq!(*guard, 1);
*guard = 2;
```
Only the matching `Token`'s owner can access its contents. `Token`
cannot be cloned:
```rust
let lock = Arc::new(TokenLock::new(token.id(), 1));
let lock_1 = Arc::clone(&lock);
std::thread::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);
});
// can't access the contents; I no longer have `Token`
// lock.write(&mut token);
```
### Zero-sized tokens
Some token types, such as `BrandedToken` and `SingletonToken`, rely
solely on type safety and compile-time checks to guarantee uniqueness and
don't use runtime data for identification. As such, the keyholes for such
tokens can be default-constructed. `TokenLock::wrap` lets you construct a
`TokenLock` with a default-constructed keyhole.
On the other hand, creating such tokens usually has specific requirements.
See the following example that uses `with_branded_token`:
```rust
with_branded_token(|mut token| {
// The lifetime of `token: BrandedToken<'brand>` is bound to
// this closure.
// lock: BrandedTokenLock<'brand, i32>
let lock = BrandedTokenLock::wrap(42);
lock.set(&mut token, 56);
assert_eq!(lock.get(&token), 56);
});
```
### Lifetimes
The lifetime of the returned reference is limited by both of the `TokenLock`
and `Token`.
```rust
let mut token = IcToken::new();
let lock = TokenLock::new(token.id(), 1);
let guard = lock.write(&mut token);
drop(lock); // compile error: `guard` cannot outlive `TokenLock`
drop(guard);
```
```rust
drop(token); // compile error: `guard` cannot outlive `Token`
drop(guard);
```
It also prevents from forming a reference to the contained value when
there already is a mutable reference to it:
```rust
let write_guard = lock.write(&mut token);
let read_guard = lock.read(&token); // compile error
drop(write_guard);
```
While allowing multiple immutable references:
```rust
let read_guard1 = lock.read(&token);
let read_guard2 = lock.read(&token);
```
### Use case: Linked lists
An operating system kernel often needs to store the global state in a global
variable. Linked lists are a common data structure used in a kernel, but
Rust's ownership does not allow forming `'static` references into values
protected by a mutex. Common work-arounds, such as smart pointers and index
references, take a heavy toll on a small microcontroller with a single-issue
in-order pipeline and no hardware multiplier.
```rust
struct Process {
prev: Option<& /* what lifetime? */ Process>,
next: Option<& /* what lifetime? */ Process>,
state: u8,
/* ... */
}
struct SystemState {
first_process: Option<& /* what lifetime? */ Process>,
process_pool: [Process; 64],
}
static STATE: Mutex = todo!();
```
`tokenlock` makes the `'static` reference approach possible by detaching the
lock granularity from the protected data's granularity.
```rust
use tokenlock::*;
use std::cell::Cell;
struct Tag;
impl_singleton_token_factory!(Tag);
type KLock = UnsyncSingletonTokenLock;
type KLockToken = UnsyncSingletonToken;
type KLockTokenId = SingletonTokenId;
struct Process {
prev: KLock