Crates.io | generic_static |
lib.rs | generic_static |
version | 0.2.0 |
source | src |
created_at | 2019-01-17 10:07:24.996733 |
updated_at | 2020-05-11 11:57:21.725732 |
description | Generic static variables in generic functions. |
homepage | |
repository | https://github.com/hukumka/generic_static |
max_upload_size | |
id | 109114 |
size | 9,246 |
lets consider following code:
use once_cell::sync::OnceCell;
trait X{
fn string() -> String;
}
// having to recompute string() over and over might be expensive (not in this example, but still)
// so we use lazy initialization
fn generic<T: X>() -> &'static str{
static VALUE: OnceCell<String> = OnceCell::new();
VALUE.get_or_init(||{
T::string()
})
}
// And now it can be used like this
struct A;
impl X for A{
fn string() -> String{
"A".to_string()
}
}
struct B;
impl X for B{
fn string() -> String{
"B".to_string()
}
}
fn main(){
assert_eq!(generic::<A>(), "A");
assert_eq!(generic::<B>(), "A"); // Wait what?
// Not completely behaviour I was expecting
// This is due to fact that static variable placed inside of generic function
// wont be cloned into each version of function, but will be shared
// Thus second call does not initialize value for B, but takes value
// initialized in previous call.
}
This crate was designed to solve this particular problem.
Lets make some changes:
use generic_static::StaticTypeMap;
use once_cell::sync::OnceCell;
trait X{
fn string() -> String;
}
// having to recompute string() over and over might be expensive (not in this example, but still)
// so we use lazy initialization
fn generic<T: X + 'static>() -> &'static str{ // T is bound to 'static
static VALUE: OnceCell<StaticTypeMap<String>> = OnceCell::new();
let map = VALUE.get_or_init(|| StaticTypeMap::new());
map.call_once::<T, _>(||{
T::string()
})
}
// And now it can be used like this
struct A;
impl X for A{
fn string() -> String{
"A".to_string()
}
}
struct B;
impl X for B{
fn string() -> String{
"B".to_string()
}
}
fn main(){
assert_eq!(generic::<A>(), "A");
assert_eq!(generic::<B>(), "B");
}
Current implementation uses RwLock to make it safe in concurrent applications, which will be slightly slower then regular