WIP: contexts

feature/battle
brnrs 5 years ago
parent 505016f160
commit 28564b11bd
  1. 38
      src/contexts/component.rs
  2. 28
      src/contexts/component_map.rs
  3. 3
      src/contexts/mod.rs
  4. 111
      src/contexts/model_i.rs
  5. 2
      src/main.rs

@ -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"));
}
}

@ -1,6 +1,7 @@
#![feature(trait_alias, option_unwrap_none)]
mod battle;
mod context;
mod contexts;
use battle::actor::*;
use battle::base::*;
@ -8,6 +9,7 @@ use battle::skill::*;
use battle::uic::Uic;
use context::Context;
fn main() {
println!("Hello, world!");

Loading…
Cancel
Save