tokenlock
This crate provides a cell type, TokenLock
, whose contents can only be
accessed by an unforgeable token.
Examples
Basics
let mut token = new;
let lock = new;
assert_eq!;
let mut guard = lock.write;
assert_eq!;
*guard = 2;
Only the original Token
's owner can access its contents. Token
cannot be cloned:
let lock = new;
let lock_1 = clone;
new.spawn.unwrap;
// can't access the contents; I no longer have `Token`
// lock.write(&mut token);
Lifetimes
The lifetime of the returned reference is limited by both of the TokenLock
and Token
.
let mut token = new;
let lock = new;
let guard = lock.write;
drop; // compile error: `guard` cannot outlive `TokenLock`
drop;
drop; // compile error: `guard` cannot outlive `Token`
drop;
It also prevents from forming a reference to the contained value when there already is a mutable reference to it:
let write_guard = lock.write;
let read_guard = lock.read; // compile error
drop;
While allowing multiple immutable references:
let read_guard1 = lock.read;
let read_guard2 = lock.read;
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.
static STATE: = todo!;
tokenlock
makes the 'static
reference approach possible by detaching the
lock granularity from the protected data's granularity.
use *;
use Cell;
;
impl_singleton_token_factory!;
type KLock<T> = ;
type KLockToken = ;
type KLockTokenId = ;
static STATE: SystemState = SystemState ;
Token types
This crate provides the following types implementing Token
.
(std
only) RcToken
and ArcToken
ensure their uniqueness by
reference-counted memory allocations.
SingletonToken<Tag>
is a singleton token, meaning only one of such
instance can exist at any point of time during the program's execution.
impl_singleton_token_factory!
instantiates a static
flag to indicate
SingletonToken
's liveness and allows you to construct it safely by
SingletonToken::new
. Alternatively, you can use
SingletonToken::new_unchecked
, but this is unsafe if misused.
!Sync
tokens
UnsyncTokenLock
is similar to TokenLock
but designed for non-Sync
tokens and has relaxed requirements on the inner type for thread safety.
Specifically, it can be Sync
even if the inner type is not Sync
. This
allows for storing non-Sync
cells such as Cell
and reading and
writing them using shared references (all of which must be on the same
thread because the token is !Sync
) to the token.
use Cell;
let mut token = new;
let lock = new;
let lock_1 = clone;
new.spawn.unwrap;
!Sync
tokens, of course, cannot be shared between threads:
let mut token = new;
let token = token.borrow_as_unsync;
let = ;
// compile error: `&ArcTokenUnsyncRef` is not `Send` because
// `ArcTokenUnsyncRef` is not `Sync`
new.spawn;
let _ = token_1;
License: MIT/Apache-2.0