use slog;
use slog_scope;
use std::any::Any;
use std::rc::Rc;
use std::sync::RwLock;
use typemap::{Key as TypeMapKey, TypeMap};
use wlc::{Callback, Handle, Output, Size, View};
pub struct StoreHandler {
logger: slog::Logger,
}
impl Default for StoreHandler {
fn default() -> StoreHandler {
StoreHandler::new()
}
}
impl StoreHandler {
pub fn new() -> StoreHandler {
StoreHandler { logger: slog_scope::logger().new(o!("handler" => "Store")) }
}
}
impl Callback for StoreHandler {
fn output_resolution(&mut self, output: &Output, _from: Size, _to: Size) {
self.output_created(output); }
fn output_created(&mut self, output: &Output) -> bool {
let is_initialized = unsafe { output.user_data::<RwLock<TypeMap>>().is_some() };
if !is_initialized {
debug!(self.logger, "Output initialized");
let data = RwLock::new(TypeMap::new());
output.set_user_data(data);
}
true
}
fn view_created(&mut self, view: &View) -> bool {
let is_initialized = unsafe { view.user_data::<RwLock<TypeMap>>().is_some() };
if !is_initialized {
debug!(self.logger, "View initialized");
let data = RwLock::new(TypeMap::new());
view.set_user_data(data);
}
true
}
}
struct KeyWrapper<K: StoreKey>(K);
pub trait StoreKey: Any {
type Value: Any;
}
impl<K: StoreKey> TypeMapKey for KeyWrapper<K> {
type Value = Rc<RwLock<K::Value>>;
}
pub trait Store {
fn insert<T: StoreKey + 'static>(&self, value: T::Value) -> Option<T::Value>;
fn contains<T: StoreKey + 'static>(&self) -> bool;
fn get<T: StoreKey + 'static>(&self) -> Option<Rc<RwLock<T::Value>>>;
fn remove<T: StoreKey + 'static>(&self) -> Option<T::Value>;
}
impl<T: Handle> Store for T {
fn insert<A: StoreKey + 'static>(&self, value: A::Value) -> Option<A::Value> {
if let Some(x) = unsafe { self.user_data::<RwLock<TypeMap>>() } {
if let Ok(mut x) = x.write() {
if let Some(x) = x.insert::<KeyWrapper<A>>(Rc::new(RwLock::new(value))) {
return Rc::try_unwrap(x)
.ok()
.and_then(|x| x.into_inner().ok());
}
}
}
None
}
fn contains<A: StoreKey + 'static>(&self) -> bool {
match unsafe { self.user_data::<RwLock<TypeMap>>() }.map(|x| match x.read().ok() {
Some(x) => x.contains::<KeyWrapper<A>>(),
None => false,
}) {
Some(x) => x,
None => false,
}
}
fn get<A: StoreKey + 'static>(&self) -> Option<Rc<RwLock<A::Value>>> {
if let Some(x) = unsafe { self.user_data::<RwLock<TypeMap>>() } {
if let Ok(x) = x.read() {
if let Some(x) = x.get::<KeyWrapper<A>>() {
return Some(x.clone());
}
}
}
None
}
fn remove<A: StoreKey + 'static>(&self) -> Option<A::Value> {
if let Some(x) = unsafe { self.user_data::<RwLock<TypeMap>>() } {
if let Ok(mut x) = x.write() {
if let Some(x) = x.remove::<KeyWrapper<A>>() {
return Rc::try_unwrap(x)
.ok()
.and_then(|x| x.into_inner().ok());
}
}
}
None
}
}