use std::borrow::ToOwned;
use std::any::{ Any, TypeId };
use std::hash::{ hash, SipHasher };
use input::{ Button, Input, Motion };
use {
Event,
FocusEvent,
PressEvent,
ReleaseEvent,
MouseCursorEvent,
MouseRelativeEvent,
MouseScrollEvent,
TextEvent,
ResizeEvent,
UpdateEvent,
RenderEvent,
IdleEvent,
UpdateArgs,
RenderArgs,
IdleArgs,
};
pub trait GenericEvent {
fn event_id(&self) -> u64;
fn with_args<'a, F, U>(&'a self, f: F) -> U
where F: FnMut(&Any) -> U
;
fn from_args(event_id: u64, any: &Any) -> Option<Self>;
}
impl GenericEvent for Input {
fn event_id(&self) -> u64 {
match self {
&Input::Focus(_) => {
hash::<_, SipHasher>(&TypeId::of::<Box<FocusEvent>>())
}
&Input::Press(_) => {
hash::<_, SipHasher>(&TypeId::of::<Box<PressEvent>>())
}
&Input::Release(_) => {
hash::<_, SipHasher>(&TypeId::of::<Box<ReleaseEvent>>())
}
&Input::Move(Motion::MouseCursor(_, _)) => {
hash::<_, SipHasher>(&TypeId::of::<Box<MouseCursorEvent>>())
}
&Input::Move(Motion::MouseRelative(_, _)) => {
hash::<_, SipHasher>(&TypeId::of::<Box<MouseRelativeEvent>>())
}
&Input::Move(Motion::MouseScroll(_, _)) => {
hash::<_, SipHasher>(&TypeId::of::<Box<MouseScrollEvent>>())
}
&Input::Text(_) => {
hash::<_, SipHasher>(&TypeId::of::<Box<TextEvent>>())
}
&Input::Resize(_, _) => {
hash::<_, SipHasher>(&TypeId::of::<Box<ResizeEvent>>())
}
}
}
fn with_args<'a, F, U>(&'a self, mut f: F) -> U
where F: FnMut(&Any) -> U
{
match self {
&Input::Focus(focused) => {
f(&focused as &Any)
}
&Input::Press(button) => {
f(&button as &Any)
}
&Input::Release(button) => {
f(&button as &Any)
}
&Input::Move(Motion::MouseCursor(x, y)) => {
f(&(x, y) as &Any)
}
&Input::Move(Motion::MouseRelative(x, y)) => {
f(&(x, y) as &Any)
}
&Input::Move(Motion::MouseScroll(x, y)) => {
f(&(x, y) as &Any)
}
&Input::Text(ref text) => {
f(text as &Any)
}
&Input::Resize(w, h) => {
f(&(w, h) as &Any)
}
}
}
fn from_args(event_id: u64, any: &Any) -> Option<Self> {
let focus_id = hash::<_, SipHasher>(&TypeId::of::<Box<FocusEvent>>());
let mouse_cursor_id = hash::<_, SipHasher>(&TypeId::of::<Box<MouseCursorEvent>>());
let mouse_relative_id = hash::<_, SipHasher>(&TypeId::of::<Box<MouseRelativeEvent>>());
let mouse_scroll_id = hash::<_, SipHasher>(&TypeId::of::<Box<MouseScrollEvent>>());
let press_id = hash::<_, SipHasher>(&TypeId::of::<Box<PressEvent>>());
let release_id = hash::<_, SipHasher>(&TypeId::of::<Box<ReleaseEvent>>());
let resize_id = hash::<_, SipHasher>(&TypeId::of::<Box<ResizeEvent>>());
let text_id = hash::<_, SipHasher>(&TypeId::of::<Box<TextEvent>>());
match event_id {
x if x == focus_id => {
if let Some(&focused) = any.downcast_ref::<bool>() {
Some(Input::Focus(focused))
} else {
panic!("Expected bool")
}
}
x if x == mouse_cursor_id => {
if let Some(&(x, y)) = any.downcast_ref::<(f64, f64)>() {
Some(Input::Move(Motion::MouseCursor(x, y)))
} else {
panic!("Expected (f64, f64)")
}
}
x if x == mouse_relative_id => {
if let Some(&(x, y)) = any.downcast_ref::<(f64, f64)>() {
Some(Input::Move(Motion::MouseRelative(x, y)))
} else {
panic!("Expected (f64, f64)")
}
}
x if x == mouse_scroll_id => {
if let Some(&(x, y)) = any.downcast_ref::<(f64, f64)>() {
Some(Input::Move(Motion::MouseScroll(x, y)))
} else {
panic!("Expected (f64, f64)")
}
}
x if x == press_id => {
if let Some(&button) = any.downcast_ref::<Button>() {
Some(Input::Press(button))
} else {
panic!("Expected Button")
}
}
x if x == release_id => {
if let Some(&button) = any.downcast_ref::<Button>() {
Some(Input::Release(button))
} else {
panic!("Expected Button")
}
}
x if x == resize_id => {
if let Some(&(w, h)) = any.downcast_ref::<(u32, u32)>() {
Some(Input::Resize(w as u32, h as u32))
} else {
panic!("Expected (u32, u32))")
}
}
x if x == text_id => {
if let Some(text) = any.downcast_ref::<String>() {
Some(Input::Text(text.to_owned()))
} else {
panic!("Expected &str")
}
}
_ => { return None; }
}
}
}
impl<I: GenericEvent> GenericEvent for Event<I> {
fn event_id(&self) -> u64 {
match self {
&Event::Update(_) => {
hash::<_, SipHasher>(&TypeId::of::<Box<UpdateEvent>>())
}
&Event::Render(_) => {
hash::<_, SipHasher>(&TypeId::of::<Box<RenderEvent>>())
}
&Event::Idle(_) => {
hash::<_, SipHasher>(&TypeId::of::<Box<IdleEvent>>())
}
&Event::Input(ref input) => {
input.event_id()
}
}
}
fn with_args<'a, F, U>(&'a self, mut f: F) -> U
where F: FnMut(&Any) -> U
{
match self {
&Event::Update(ref args) => {
f(args as &Any)
}
&Event::Render(ref args) => {
f(args as &Any)
}
&Event::Idle(ref args) => {
f(args as &Any)
}
&Event::Input(ref input) => {
input.with_args(f)
}
}
}
fn from_args(event_id: u64, any: &Any) -> Option<Self> {
let update_id = hash::<_, SipHasher>(&TypeId::of::<Box<UpdateEvent>>());
let render_id = hash::<_, SipHasher>(&TypeId::of::<Box<RenderEvent>>());
let idle_id = hash::<_, SipHasher>(&TypeId::of::<Box<IdleEvent>>());
match event_id {
x if x == update_id => {
if let Some(&args) = any.downcast_ref::<UpdateArgs>() {
Some(Event::Update(args))
} else {
panic!("Expected UpdateArgs")
}
}
x if x == render_id => {
if let Some(&args) = any.downcast_ref::<RenderArgs>() {
Some(Event::Render(args))
} else {
panic!("Expected RenderArgs")
}
}
x if x == idle_id => {
if let Some(&args) = any.downcast_ref::<IdleArgs>() {
Some(Event::Idle(args))
} else {
panic!("Expected IdleArgs")
}
}
_ => {
let input: Option<I> =
GenericEvent::from_args(event_id, any);
match input {
Some(x) => Some(Event::Input(x)),
None => None
}
}
}
}
}