parent
505016f160
commit
28564b11bd
@ -0,0 +1,38 @@ |
||||
use std::any::{Any, TypeId, type_name}; |
||||
use std::convert::TryFrom; |
||||
use std::cell::RefCell; |
||||
use std::ops::Deref; |
||||
use std::rc::Rc; |
||||
|
||||
#[derive(Clone)] |
||||
pub struct Component<T: Any + ?Sized + 'static>(Rc<RefCell<T>>); |
||||
|
||||
impl <T> Deref for Component<T> { |
||||
type Target = RefCell<T>; |
||||
|
||||
fn deref(&self) -> &Self::Target { |
||||
self.0.deref() |
||||
} |
||||
} |
||||
|
||||
#[allow(dead_code)] |
||||
impl <T: Any + Sized + 'static> Component<T> { |
||||
pub fn from(t: T) -> Component<T> { |
||||
Component(Rc::new(RefCell::new(t))) |
||||
} |
||||
|
||||
pub fn type_id() -> TypeId { |
||||
TypeId::of::<T>() |
||||
} |
||||
|
||||
pub fn type_name() -> &'static str { |
||||
type_name::<T>() |
||||
} |
||||
} |
||||
|
||||
impl <T: Any + Sized + 'static> TryFrom<Rc<dyn Any + 'static>> for Component<T> { |
||||
type Error = Rc<dyn Any + 'static>; |
||||
fn try_from(rc: Rc<dyn Any + 'static>) -> Result<Component<T>, Self::Error> { |
||||
Ok(Component(rc.downcast::<RefCell<T>>()?)) |
||||
} |
||||
} |
@ -0,0 +1,28 @@ |
||||
use std::any::{Any, TypeId}; |
||||
use std::cell::RefCell; |
||||
use std::collections::HashMap; |
||||
use std::convert::TryInto; |
||||
use std::rc::Rc; |
||||
|
||||
use super::component::Component; |
||||
|
||||
pub struct ComponentMap(HashMap<TypeId, Rc<dyn Any + 'static>>); |
||||
|
||||
#[allow(dead_code)] |
||||
impl ComponentMap { |
||||
pub fn new() -> ComponentMap { |
||||
ComponentMap(HashMap::new()) |
||||
} |
||||
|
||||
pub fn contains<T: Any + Sized + 'static>(&self) -> bool { |
||||
self.0.contains_key(&TypeId::of::<T>()) |
||||
} |
||||
|
||||
pub fn get<T: Any + Sized + 'static>(&self) -> Option<Component<T>> { |
||||
self.0.get(&TypeId::of::<T>()).cloned().map(|c| c.try_into().unwrap()) |
||||
} |
||||
|
||||
pub fn set<T: Any + Sized + 'static>(&mut self, component: T) { |
||||
self.0.insert(TypeId::of::<T>(), Rc::new(RefCell::new(component))); |
||||
} |
||||
} |
@ -0,0 +1,3 @@ |
||||
mod model_i; |
||||
mod component; |
||||
mod component_map; |
@ -0,0 +1,111 @@ |
||||
use std::any::Any; |
||||
|
||||
use super::component::*; |
||||
use super::component_map::*; |
||||
|
||||
#[allow(dead_code)] |
||||
struct Context<'t> { |
||||
map: ComponentMap, |
||||
base_context: Option<&'t Context<'t>>, |
||||
} |
||||
|
||||
#[allow(dead_code)] |
||||
impl<'t> Context<'t> { |
||||
fn new() -> Context<'t> { |
||||
Context { |
||||
map: ComponentMap::new(), |
||||
base_context: None, |
||||
} |
||||
} |
||||
|
||||
fn get<T: Any + Sized + 'static>(&self) -> Option<Component<T>> { |
||||
match self.map.get() { |
||||
component @ Some(_) => component, |
||||
_ => match self.base_context { |
||||
Some(context) => context.get(), |
||||
None => None, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
fn set<T: Any + Sized + 'static>(&mut self, component: T) { |
||||
self.map.set(component) |
||||
} |
||||
|
||||
fn subcontext(&self) -> Context { |
||||
let mut context = Context::new(); |
||||
context.base_context = Some(self); |
||||
context |
||||
} |
||||
} |
||||
|
||||
trait FromContext: Sized { |
||||
fn from(context: &Context) -> Option<Self>; |
||||
} |
||||
|
||||
impl <T> FromContext for Component<T> { |
||||
fn from(context: &Context) -> Option<Self> { |
||||
context.get() |
||||
} |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod tests { |
||||
use super::*; |
||||
|
||||
#[test] |
||||
fn get_from_context() { |
||||
// Given
|
||||
#[derive(Debug, Eq, PartialEq)] |
||||
struct TestStruct(&'static str); |
||||
let context = { |
||||
let mut tmp = Context::new(); |
||||
tmp.set(TestStruct("hello")); |
||||
tmp |
||||
}; |
||||
|
||||
// When
|
||||
let test_struct = context.get::<TestStruct>().unwrap(); |
||||
|
||||
// Then
|
||||
assert_eq!(*test_struct.borrow(), TestStruct("hello")); |
||||
} |
||||
|
||||
#[test] |
||||
fn get_from_base_context() { |
||||
// Given
|
||||
#[derive(Debug, Eq, PartialEq)] |
||||
struct TestStruct(&'static str); |
||||
let context = { |
||||
let mut tmp = Context::new(); |
||||
tmp.set(TestStruct("hello")); |
||||
tmp |
||||
}; |
||||
let subcontext = context.subcontext(); |
||||
|
||||
// When
|
||||
let test_struct = subcontext.get::<TestStruct>().unwrap(); |
||||
|
||||
// Then
|
||||
assert_eq!(*test_struct.borrow(), TestStruct("hello")); |
||||
} |
||||
|
||||
#[test] |
||||
fn get_from_subcontext() { |
||||
// Given
|
||||
#[derive(Debug, Eq, PartialEq)] |
||||
struct TestStruct(&'static str); |
||||
let context = Context::new(); |
||||
let subcontext = { |
||||
let mut tmp = context.subcontext();
|
||||
tmp.set(TestStruct("hello")); |
||||
tmp |
||||
}; |
||||
|
||||
// When
|
||||
let test_struct = subcontext.get::<TestStruct>().unwrap(); |
||||
|
||||
// Then
|
||||
assert_eq!(*test_struct.borrow(), TestStruct("hello")); |
||||
} |
||||
} |
Loading…
Reference in new issue