Crate stack_tokens
source ·Expand description
This library implements stack tokens which can be used to safely borrow values with stack-local lifetimes.
StackToken
s are zero sized objects that can be placed on the call
stack with the stack_token!
macro which then can be used to safely
borrow from places such as thread local storage with reduced lifetimes.
Without stack tokens the only safe API for such constructs are callback
based such as the LocalKey::with
API.
This problem however is not always restricted to thread local storage
directly as some APIs are internally constrained by similar challenges.
The problem usually appears when a proxy object wants to lend out some
memory but it does not have a better lifetime than itself to constrain
the value, but it does not directly own the value it’s trying to lend
out. As a Rust programmer one is enticed to try to constrain it by
the lifetime of &self
but thanks to Box::leak
that lifetime can
become &'static
.
For more information see the the blog post describing the concept.
Ref Cells
This example shows how stack tokens can be used with the
RefCellLocalKeyExt
extension trait to directly borrow into RefCell
s
in a thread local.
use stack_tokens::{stack_token, RefCellLocalKeyExt};
use std::cell::RefCell;
thread_local! {
static VEC: RefCell<Vec<i32>> = RefCell::default();
}
// places a token on the stack.
stack_token!(scope);
// you can now directly deref the thread local without closures
VEC.as_mut(scope).push(42);
assert_eq!(VEC.as_ref(scope).len(), 1);
Basic Use
This example shows how stack tokens can be used with the LocalKeyExt
extension trait to get stack local borrows from a standard library thread
local.
use stack_tokens::{stack_token, LocalKeyExt};
use std::sync::atomic::{AtomicUsize, Ordering};
thread_local! {
static COUNTER: AtomicUsize = AtomicUsize::new(0);
}
// places a token on the stack
stack_token!(scope);
// borrow can be used to get a stack local reference
COUNTER.borrow(scope).fetch_add(1, Ordering::Acquire);
assert_eq!(COUNTER.borrow(scope).load(Ordering::Acquire), 1);
Implementing Stack Local APIs
To implement your own methods that use stack tokens introduce a new lifetime
(eg: 'stack
) and constrain both &self
and the passed token with it:
use stack_tokens::StackToken;
use std::marker::PhantomData;
struct MyTls<T>(PhantomData::<T>);
impl<T> MyTls<T> {
pub fn get<'stack>(&'stack self, token: &'stack StackToken) -> &'stack T {
let _ = token;
todo!()
}
}
Macros
StackToken
with a given name on the stack.Structs
Traits
StackToken
support to the standard library’s LocalKey
.