--- /dev/null
+use std::fs::File;
+use std::io::prelude::*;
+use std::collections::HashMap;
+
+pub fn read_file(path: &str) -> Result<String, std::io::Error> {
+ let mut s = String::new();
+ File::open(path)?
+ .read_to_string(&mut s)?;
+ Ok(s)
+}
+
+// needs Copy trait, good for simple types
+pub fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
+ let mut result = list[0];
+ for &i in list {
+ if i > result {
+ result = i;
+ }
+ }
+ result
+}
+
+// expensive for large strings, don't use that
+pub fn largest_clone<T: PartialOrd + Clone>(list: &[T]) -> T {
+ let mut result = list[0].clone();
+ for i in list {
+ if *i > result {
+ result = i.clone();
+ }
+ }
+ result
+}
+
+// good for everything, but more expensive for simple types
+pub fn largest_ref<T: PartialOrd>(list: &[T]) -> &T {
+ let mut result = &list[0];
+ for i in list {
+ if i > result {
+ result = i;
+ }
+ }
+ result
+}
+
+pub fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
+ if x.len() > y.len() {
+ x
+ } else {
+ y
+ }
+}
+
+/// Wrap and cache an expensive calculation
+///
+/// This calls a closure just once for every distinct argument. Any subsequent
+/// call to `.value()` with the same argument uses the cached value.
+pub struct Cacher<T, A, V>
+where
+ T: Fn(A) -> V,
+ A: Eq + Copy + std::hash::Hash,
+ V: Copy,
+{
+ calc: T,
+ values: HashMap<A, V>,
+}
+
+impl<T, A, V> Cacher<T, A, V>
+where
+ T: Fn(A) -> V,
+ A: Eq + Copy + std::hash::Hash,
+ V: Copy,
+{
+ pub fn new(calc: T) -> Cacher<T, A, V> {
+ Cacher { calc, values: HashMap::new() }
+ }
+
+ pub fn value(&mut self, arg: A) -> V {
+ match self.values.get(&arg) {
+ Some(v) => *v,
+ None => {
+ let v = (self.calc)(arg);
+ self.values.insert(arg, v);
+ v
+ }
+ }
+ }
+}
+
+pub struct Counter5 {
+ count: u32
+}
+
+impl Counter5 {
+ pub fn new() -> Counter5 {
+ Counter5 { count: 0 }
+ }
+}
+
+impl Iterator for Counter5 {
+ type Item = u32;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.count < 5 {
+ self.count += 1;
+ Some(self.count)
+ } else {
+ None
+ }
+ }
+}