badcontext 0.1.0

A small crate for creating Context structs that contain application components
Documentation
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,
            ))
        }
    }
}