From 812a3d3d42aea4b1f53bfa47982fd35a070a4612 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Sun, 10 Jun 2018 11:55:59 +0200 Subject: first iteration of multiplexer --- src/event.rs | 67 ++++++++++++++++++++++++++++++++++++ src/statistics/trackers.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) (limited to 'src') diff --git a/src/event.rs b/src/event.rs index 02f4686..f87688e 100644 --- a/src/event.rs +++ b/src/event.rs @@ -104,6 +104,73 @@ pub enum EventKind { }, } +impl EventKind { + /// Returns the source agent address for this event, if one exists. + pub fn source_agent_addr(&self) -> Option { + use EventKind::*; + match *self { + EnterCombat { agent_addr, .. } => return Some(agent_addr), + ExitCombat { agent_addr } => return Some(agent_addr), + ChangeUp { agent_addr } => return Some(agent_addr), + ChangeDown { agent_addr } => return Some(agent_addr), + ChangeDead { agent_addr } => return Some(agent_addr), + Spawn { agent_addr } => return Some(agent_addr), + Despawn { agent_addr } => return Some(agent_addr), + HealthUpdate { agent_addr, .. } => return Some(agent_addr), + WeaponSwap { agent_addr, .. } => return Some(agent_addr), + MaxHealthUpdate { agent_addr, .. } => return Some(agent_addr), + PointOfView { agent_addr } => return Some(agent_addr), + SkillUse { + source_agent_addr, .. + } => return Some(source_agent_addr), + ConditionTick { + source_agent_addr, .. + } => return Some(source_agent_addr), + InvulnTick { + source_agent_addr, .. + } => return Some(source_agent_addr), + Physical { + source_agent_addr, .. + } => return Some(source_agent_addr), + BuffApplication { + source_agent_addr, .. + } => return Some(source_agent_addr), + BuffRemove { + source_agent_addr, .. + } => return Some(source_agent_addr), + _ => return None, + } + } + + /// Returns the destination agent address for this event, if one exists. + pub fn destination_agent_addr(&self) -> Option { + use EventKind::*; + match *self { + ConditionTick { + destination_agent_addr, + .. + } => return Some(destination_agent_addr), + InvulnTick { + destination_agent_addr, + .. + } => return Some(destination_agent_addr), + Physical { + destination_agent_addr, + .. + } => return Some(destination_agent_addr), + BuffApplication { + destination_agent_addr, + .. + } => return Some(destination_agent_addr), + BuffRemove { + destination_agent_addr, + .. + } => return Some(destination_agent_addr), + _ => return None, + } + } +} + /// A higher-level representation of a combat event. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Event { diff --git a/src/statistics/trackers.rs b/src/statistics/trackers.rs index bcf5e90..8381a43 100644 --- a/src/statistics/trackers.rs +++ b/src/statistics/trackers.rs @@ -13,6 +13,7 @@ //! trackers on the same log. use std::collections::HashMap; use std::error::Error; +use std::hash::Hash; use super::super::{Event, EventKind, Log}; use super::boon::BoonQueue; @@ -76,6 +77,91 @@ impl> RunnableTracker for } } +/// A trait that allows a tracker to be multiplexed. +/// +/// Basically, this is a factory that allows new trackers to be created. Each +/// tracker can be given a key that it should listen on, which is expressed by +/// the `K` type parameter and the `key` parameter to `create`. +pub trait Multiplexable { + /// The type of tracker that this multiplexable/factory creates. + type T: Tracker; + + /// Create a new tracker, listening for the given key. + fn create(&mut self, key: K) -> Self::T; +} + +/// A helper that wraps (decorates) another tracker and separates the results +/// based on the given criteria. +/// +/// Instead of outputting a single statistic, it outputs a `HashMap`, mapping +/// the criteria to its own tracker. +/// +/// This can be used for example to count damage per player: The damage tracker +/// itself only counts damage for a single player, and together with a +/// multiplexer, it will count the damage per player. +/// +/// Type parameters: +/// * `K` Key that is used to distinguish criteria. For example, `u64` for a +/// multiplexer that separates based on agents. +/// * `F` Factory that creates new trackers for each key. +/// * `T` Inner tracker type. Usually determined by the factory. +/// * `S` Selection function type. Takes an event and outputs a key. +pub struct Multiplexer { + factory: F, + trackers: HashMap, + selector: S, +} + +impl Multiplexer { + /// Create a new multiplexer that multiplexes on the source agent. + pub fn multiplex_on_source>( + factory: Factory, + ) -> Multiplexer Option> { + Multiplexer { + factory, + trackers: HashMap::new(), + selector: |event: &Event| event.kind.source_agent_addr(), + } + } + + /// Create a new multiplexer that multiplexes on the destination agent. + pub fn multiplex_on_destination>( + factory: Factory, + ) -> Multiplexer Option> { + Multiplexer { + factory, + trackers: HashMap::new(), + selector: |event: &Event| event.kind.destination_agent_addr(), + } + } +} + +impl, S: FnMut(&Event) -> Option> Tracker + for Multiplexer +{ + type Stat = HashMap::Stat>; + type Error = ::Error; + + fn feed(&mut self, event: &Event) -> Result<(), Self::Error> { + if let Some(key) = (self.selector)(event) { + let factory = &mut self.factory; + let entry = self + .trackers + .entry(key.clone()) + .or_insert_with(|| factory.create(key)); + entry.feed(event)?; + } + Ok(()) + } + + fn finalize(self) -> Result { + self.trackers + .into_iter() + .map(|(k, v)| v.finalize().map(|inner| (k, inner))) + .collect() + } +} + /// A tracker that tracks per-target damage of all agents. pub struct DamageTracker<'l> { log: &'l Log, -- cgit v1.2.3