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