use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
use super::context::Context;
use super::error::{AlreadyRegisteredError, Error, NotRegisteredError};
pub struct Component<T: 'static>(Rc<RefCell<T>>);
impl<T: 'static> Component<T> {
pub fn from(t: T) -> Self {
Component(Rc::new(RefCell::new(t)))
}
}
impl<T: 'static> Deref for Component<T> {
type Target = RefCell<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: 'static> Clone for Component<T> {
fn clone(&self) -> Self {
Component(self.0.clone())
}
}
pub trait ContextComponentExtension {
fn get_component<T: 'static>(&self) -> Option<Component<T>>;
fn register_component<T: 'static>(
&mut self,
t: T,
) -> Result<Component<T>, (AlreadyRegisteredError, T)>;
fn replace_component<T: 'static>(&self, t: T) -> Result<(Component<T>, T), (Error, T)>;
}
impl ContextComponentExtension for Context {
fn get_component<T: 'static>(&self) -> Option<Component<T>> {
self.get::<Component<T>>().cloned()
}
fn register_component<T: 'static>(
&mut self,
t: T,
) -> Result<Component<T>, (AlreadyRegisteredError, T)> {
if self.get::<T>().is_none() {
let component = Component::from(t);
self.set(component.clone());
Ok(component)
} else {
Err((AlreadyRegisteredError::of_type::<Component<T>>(), t))
}
}
fn replace_component<T: 'static>(&self, mut t: T) -> Result<(Component<T>, T), (Error, T)> {
if let Some(component) = self.get_component::<T>() {
match component.try_borrow_mut() {
Err(borrow_mut_error) => return Err((Error::Borrowed(borrow_mut_error), t)),
Ok(mut ref_mut) => {
std::mem::swap(&mut *ref_mut, &mut t);
Ok((component.clone(), t))
}
}
} else {
Err((
Error::NotRegistered(NotRegisteredError::of_type::<Component<T>>()),
t,
))
}
}
}