# HG changeset patch # User Matt Johnston # Date 1487863629 -28800 # Node ID af0dac00d40b30dbf73eb02eb057c625f176758b # Parent 7bda01659426600c9b938988c02ade67eaf82622 untested step integrator diff -r 7bda01659426 -r af0dac00d40b rust/src/types.rs --- a/rust/src/types.rs Sat Feb 18 00:21:10 2017 +0800 +++ b/rust/src/types.rs Thu Feb 23 23:27:09 2017 +0800 @@ -2,7 +2,9 @@ use std::time::{Duration,Instant}; use std::error::Error; use std::fmt; +use std::cmp; use std::cell::Cell; +use std::iter::FromIterator; use serde::{Deserialize,Serialize}; @@ -126,4 +128,75 @@ } } +struct Period { + start: Instant, + end: Option, +} +pub struct StepIntegrator { + on_periods: Vec, + limit: Duration, +} + +impl StepIntegrator { + pub fn new(limit: Duration) -> Self { + StepIntegrator { + on_periods: Vec::new(), + limit: limit, + } + } + + pub fn turn(&mut self, on: bool) { + self.trim(); + + if self.on_periods.is_empty() { + self.on_periods.push( Period { start: Instant::now(), end: None }); + return; + } + + let current_on = self.on_periods.last().unwrap().end.is_none(); + if on == current_on { + // state is unchanged + return; + } + + if on { + self.on_periods.push( Period { start: Instant::now(), end: None }); + } else { + self.on_periods.last_mut().unwrap().end = Some(Instant::now()); + } + } + + pub fn set_limit(&mut self, limit: Duration) { + self.limit = limit; + self.trim(); + } + + fn integrate(&self) -> Duration { + let durs = self.on_periods.iter().map(|p| { + let end = p.end.unwrap_or_else(|| Instant::now()); + end - p.start + }); + // TODO rust 1.16: impl Sum for Duration + // durs.sum() + durs.fold(Duration::new(0,0), |acc, d| acc + d) + } + + fn trim(&mut self) { + let begin = Instant::now() - self.limit; + + self.on_periods.retain(|p| { + // remove expired endtimes + if let Some(e) = p.end { + e >= begin && e != p.start + } else { + true + } + }); + + for p in &mut self.on_periods { + p.start = cmp::max(p.start, begin); + } + } +} +