use crate::Handler;
use crate::world::World;
pub struct Adapt<F, H> {
decode: F,
inner: H,
}
impl<F, H> Adapt<F, H> {
pub fn new(decode: F, inner: H) -> Self {
Self { decode, inner }
}
}
impl<Wire, T, F, H> Handler<Wire> for Adapt<F, H>
where
F: FnMut(Wire) -> Option<T> + Send,
H: Handler<T>,
{
fn run(&mut self, world: &mut World, event: Wire) {
if let Some(decoded) = (self.decode)(event) {
self.inner.run(world, decoded);
}
}
fn name(&self) -> &'static str {
self.inner.name()
}
}
pub struct ByRef<H>(pub H);
impl<E, H> Handler<E> for ByRef<H>
where
H: for<'e> Handler<&'e E> + Send,
{
fn run(&mut self, world: &mut World, event: E) {
self.0.run(world, &event);
}
fn name(&self) -> &'static str {
self.0.name()
}
}
pub struct Cloned<H>(pub H);
impl<'e, E: Clone + 'e, H: Handler<E> + Send> Handler<&'e E> for Cloned<H> {
fn run(&mut self, world: &mut World, event: &'e E) {
self.0.run(world, event.clone());
}
fn name(&self) -> &'static str {
self.0.name()
}
}
pub struct Owned<H, E: ?Sized> {
handler: H,
_event: std::marker::PhantomData<fn(&E)>,
}
impl<H, E: ?Sized> Owned<H, E> {
pub fn new(handler: H) -> Self {
Self {
handler,
_event: std::marker::PhantomData,
}
}
}
impl<'e, E, H> Handler<&'e E> for Owned<H, E>
where
E: ToOwned + 'e + ?Sized,
H: Handler<E::Owned> + Send,
{
fn run(&mut self, world: &mut World, event: &'e E) {
self.handler.run(world, event.to_owned());
}
fn name(&self) -> &'static str {
self.handler.name()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{IntoHandler, ResMut, WorldBuilder};
struct WireMsg(u32);
#[allow(clippy::unnecessary_wraps)]
fn decode_wire(wire: &WireMsg) -> Option<u64> {
Some(wire.0 as u64)
}
fn decode_filter(wire: &WireMsg) -> Option<u64> {
if wire.0 > 0 {
Some(wire.0 as u64)
} else {
None
}
}
fn accumulate(mut counter: ResMut<u64>, event: u64) {
*counter += event;
}
#[test]
fn dispatch_decodes_and_forwards() {
let mut builder = WorldBuilder::new();
builder.register::<u64>(0);
let mut world = builder.build();
let handler = accumulate.into_handler(world.registry());
let mut adapted = Adapt::new(decode_wire, handler);
adapted.run(&mut world, &WireMsg(10));
adapted.run(&mut world, &WireMsg(5));
assert_eq!(*world.resource::<u64>(), 15);
}
#[test]
fn none_skips_dispatch() {
let mut builder = WorldBuilder::new();
builder.register::<u64>(0);
let mut world = builder.build();
let handler = accumulate.into_handler(world.registry());
let mut adapted = Adapt::new(decode_filter, handler);
adapted.run(&mut world, &WireMsg(10));
adapted.run(&mut world, &WireMsg(0)); adapted.run(&mut world, &WireMsg(3));
assert_eq!(*world.resource::<u64>(), 13);
}
#[test]
fn delegates_name() {
let mut builder = WorldBuilder::new();
builder.register::<u64>(0);
let world = builder.build();
let handler = accumulate.into_handler(world.registry());
let expected = handler.name();
let adapted = Adapt::new(decode_wire, handler);
assert_eq!(adapted.name(), expected);
}
fn ref_accumulate(mut counter: ResMut<u64>, event: &u64) {
*counter += *event;
}
#[test]
fn by_ref_dispatch() {
let mut builder = WorldBuilder::new();
builder.register::<u64>(0);
let mut world = builder.build();
let h = ref_accumulate.into_handler(world.registry());
let mut adapted = ByRef(h);
adapted.run(&mut world, 10u64);
adapted.run(&mut world, 5u64);
assert_eq!(*world.resource::<u64>(), 15);
}
#[test]
fn by_ref_delegates_name() {
let mut builder = WorldBuilder::new();
builder.register::<u64>(0);
let world = builder.build();
let handler = ref_accumulate.into_handler(world.registry());
let expected = handler.name();
let adapted = ByRef(handler);
assert_eq!(adapted.name(), expected);
}
#[test]
fn cloned_dispatch() {
let mut builder = WorldBuilder::new();
builder.register::<u64>(0);
let mut world = builder.build();
let h = accumulate.into_handler(world.registry());
let mut adapted = Cloned(h);
adapted.run(&mut world, &10u64);
adapted.run(&mut world, &5u64);
assert_eq!(*world.resource::<u64>(), 15);
}
#[test]
fn cloned_delegates_name() {
let mut builder = WorldBuilder::new();
builder.register::<u64>(0);
let world = builder.build();
let handler = accumulate.into_handler(world.registry());
let expected = handler.name();
let adapted = Cloned(handler);
assert_eq!(adapted.name(), expected);
}
#[test]
fn cloned_copy_type() {
let mut builder = WorldBuilder::new();
builder.register::<u64>(0);
let mut world = builder.build();
fn add_u32(mut counter: ResMut<u64>, event: u32) {
*counter += event as u64;
}
let h = add_u32.into_handler(world.registry());
let mut adapted = Cloned(h);
adapted.run(&mut world, &42u32);
assert_eq!(*world.resource::<u64>(), 42);
}
fn append_string(mut buf: ResMut<String>, event: String) {
buf.push_str(&event);
}
#[test]
fn owned_str_to_string() {
let mut builder = WorldBuilder::new();
builder.register::<String>(String::new());
let mut world = builder.build();
let h = append_string.into_handler(world.registry());
let mut adapted = Owned::<_, str>::new(h);
adapted.run(&mut world, "hello");
adapted.run(&mut world, " world");
assert_eq!(world.resource::<String>().as_str(), "hello world");
}
#[test]
fn owned_delegates_name() {
let mut builder = WorldBuilder::new();
builder.register::<String>(String::new());
let world = builder.build();
let handler = append_string.into_handler(world.registry());
let expected = handler.name();
let adapted = Owned::<_, str>::new(handler);
assert_eq!(adapted.name(), expected);
}
#[test]
fn owned_clone_type() {
let mut builder = WorldBuilder::new();
builder.register::<u64>(0);
let mut world = builder.build();
let h = accumulate.into_handler(world.registry());
let mut adapted = Owned::<_, u64>::new(h);
adapted.run(&mut world, &10u64);
adapted.run(&mut world, &5u64);
assert_eq!(*world.resource::<u64>(), 15);
}
}