use std::cell::Cell;
thread_local! {
static LOCAL_SETTINGS: Cell<Settings> = Cell::new(Settings::default())
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Settings {
pub gc_probability: usize,
pub max_garbage_before_export: usize,
pub max_non_free_hazards: usize,
}
impl Default for Settings {
fn default() -> Settings {
Settings {
gc_probability: (!0) / 128,
max_garbage_before_export: 64,
max_non_free_hazards: 16,
}
}
}
impl Settings {
pub fn low_memory() -> Settings {
Settings {
gc_probability: (!0) / 32,
max_garbage_before_export: 16,
max_non_free_hazards: 4,
}
}
pub fn low_cpu() -> Settings {
Settings {
gc_probability: (!0) / 256,
max_garbage_before_export: 128,
max_non_free_hazards: 32,
}
}
pub fn disable_automatic_gc(&mut self) {
self.gc_probability = 0;
}
pub fn disable_automatic_export(&mut self) {
self.max_garbage_before_export = !0;
}
}
pub fn get() -> Settings {
LOCAL_SETTINGS.with(|x| x.get())
}
pub fn set_local(settings: Settings) {
LOCAL_SETTINGS.with(|x| x.set(settings))
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
use {Garbage, local};
#[test]
fn set_get() {
set_local(Settings {
max_garbage_before_export: 22,
.. Default::default()
});
assert_eq!(get().max_garbage_before_export, 22);
}
#[test]
fn default() {
thread::spawn(|| {
assert_eq!(get(), Settings::default());
}).join().unwrap();
}
#[test]
fn disable_automatic_gc() {
thread_local! {
static X: Cell<bool> = Cell::default();
}
fn dtor(_: *const u8) {
X.with(|x| x.set(true));
}
let mut settings = get();
settings.disable_automatic_gc();
set_local(settings);
for _ in 0..100000 {
local::add_garbage(Garbage::new(0x1 as *const u8, dtor));
assert!(!X.with(|x| x.get()));
}
set_local(Settings::default());
}
#[test]
fn disable_automatic_exportation() {
fn dtor(x: *const u8) {
unsafe {
*(x as *mut u8) = 1;
}
}
let mut settings = get();
settings.disable_automatic_export();
set_local(settings);
for _ in 0..100000 {
let b = Box::new(0);
local::add_garbage(Garbage::new(&*b, dtor));
assert_eq!(*b, 0);
}
set_local(Settings::default());
}
#[test]
fn compare_presets() {
let low = Settings::low_memory();
let high = Settings::low_cpu();
assert!(low.gc_probability > high.gc_probability);
assert!(high.max_garbage_before_export > low.max_garbage_before_export);
assert!(high.max_non_free_hazards > low.max_non_free_hazards);
}
}