diff rust/src/types.rs @ 610:af0dac00d40b rust

untested step integrator
author Matt Johnston <matt@ucc.asn.au>
date Thu, 23 Feb 2017 23:27:09 +0800
parents 7bda01659426
children f3e39e2107fd
line wrap: on
line diff
--- 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<Instant>,
+}
 
+pub struct StepIntegrator {
+    on_periods: Vec<Period>,
+    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);
+        }
+    }
+}
+