As this now contains multiple projects, it was too messy.
+++ /dev/null
-[package]
-name = "learning"
-version = "0.1.0"
-edition = "2018"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-global_counter = { version = "0.2.2", default-features = false }
--- /dev/null
+[package]
+name = "learning"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+global_counter = { version = "0.2.2", default-features = false }
--- /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
+ }
+ }
+}
--- /dev/null
+mod word_utils;
+mod lib;
+
+use std::collections::HashMap;
+use std::io::{prelude::*, ErrorKind};
+use std::fs::{self, File};
+
+use lib::*;
+use word_utils::{first_word, second_word};
+
+fn test_strings() {
+ let s = String::from("Hello world");
+ println!("first word: '{}'", first_word(&s));
+ println!("second word: '{}'", second_word(&s).unwrap());
+
+ let s2 = "hello dude blah";
+ println!("second word of single: '{}'", second_word(s2).unwrap_or("(none)"));
+
+ match second_word(s2) {
+ Some(w) => println!("match: second word of '{}' exists: {}", s2, w),
+ None => println!("match: second word of '{}' does not exist", s2),
+ }
+}
+
+fn test_vectors() {
+ let v1 = vec![1, 2, 3];
+ println!("statically initialized vector: {:?}", v1);
+
+ let mut v2: Vec<String> = Vec::new();
+ v2.push("Hello".to_string());
+ v2.push(String::from("world"));
+ println!("dynamically built vector: {:?}", v2);
+ println!("first element: {}", v2[0]);
+ for el in &mut v2 {
+ *el += "xx";
+ }
+ for el in &v2 {
+ println!("{}", el);
+ }
+}
+
+fn test_hashmaps() {
+ let mut scores = HashMap::new();
+ scores.insert("john", 10);
+ scores.insert("mary", 20);
+
+ println!("scores: {:?}", scores);
+
+ // hash map with .collect()
+ let persons = vec![("homer", 42), ("marge", 30)];
+ let collect_scores: HashMap<_, _> = persons.into_iter().collect();
+ println!("collect_scores: {:?}", collect_scores);
+
+ for (p, s) in &collect_scores {
+ println!("person {}: score {}", p, s);
+ }
+
+ println!("john's score: {}", scores.get("john").unwrap());
+ println!("jake's score: {}", scores.get("jake").unwrap_or(&-1));
+
+ // double scores
+ for (_, v) in scores.iter_mut() {
+ *v *= 2;
+ }
+ println!("scores after doubling: {:?}", scores);
+
+ // double scores of immutable hashmap (rebuild it)
+ let collect_scores: HashMap<_, _> = collect_scores.into_iter()
+ .map(|(k, v)| (k, 2 * v))
+ .collect();
+ println!("collect_scores after rebuilding with doubling: {:?}", collect_scores);
+}
+
+fn test_files() {
+ if let Ok(mut f) = File::open("Cargo.toml") {
+ let mut contents = String::new();
+ match f.read_to_string(&mut contents) {
+ Ok(len) => println!("successfully opened Cargo.toml: {:?}, contents {} bytes:\n{}\n----------", f, len, contents),
+ Err(e) => panic!("could not read file: {:?}", e)
+ }
+ } else {
+ println!("could not open Cargo.toml");
+ }
+
+ // alternative form, more specific error checking
+ let mut f = File::open("Cargo.toml").unwrap_or_else(|e| {
+ if e.kind() == ErrorKind::NotFound {
+ println!("Cargo.toml not found, falling back to /dev/null");
+ // need to return a File
+ File::open("/dev/null").unwrap()
+ } else {
+ panic!("Could not open Cargo.toml: {:?}", e);
+ }
+ });
+ let mut contents = String::new();
+ let len = f.read_to_string(&mut contents).unwrap_or_else(|e| {
+ panic!("Could not read file: {:?}", e);
+ });
+ println!("successfully opened Cargo.toml with unwrap_or_else: {:?}, contents {} bytes:\n{}\n----------", f, len, contents);
+
+ // using the '?' operator
+ match read_file("Cargo.toml") {
+ Ok(s) => println!("Cargo.toml contents:\n{}\n-------------", s),
+ Err(e) => println!("Could not open Cargo.toml: {:?}", e)
+ }
+
+ // using std API
+ match fs::read_to_string("Cargo.toml") {
+ Ok(s) => println!("Cargo.toml contents:\n{}\n-------------", s),
+ Err(e) => println!("Could not open Cargo.toml: {:?}", e)
+ }
+}
+
+fn test_generics() {
+ let num_list = vec![3, 42, -7, 100, 0];
+ println!("largest number: {}", largest(&num_list));
+ println!("num_list: {:?}", num_list);
+
+ let char_list = vec!['a', 'y', 'q', 'm'];
+ println!("largest char: {}", largest(&char_list));
+
+ let str_list = vec!["hello", "world", "blue", "planet"];
+ println!("largest str: {}", largest(&str_list));
+ println!("str_list: {:?}", str_list);
+
+ let string_list = vec!["aaaa".to_string(), "xxxxx".to_string(), "ffff".to_string()];
+ println!("largest string (with cloning): {}", largest_clone(&string_list));
+ println!("largest string (with ref): {}", largest_ref(&string_list));
+ println!("string_list: {:?}", string_list);
+
+ let s1 = String::from("abcd");
+ let l;
+ {
+ let s2 = "efghi";
+ l = longest(&s1, s2);
+ }
+ println!("longest string: {}", l);
+}
+
+fn test_closures() {
+ let mut expensive_int_result = Cacher::new(|x| {
+ println!("calculating expensive int result for {}", x);
+ 2 * x
+ });
+
+ println!("1st int call for value 1: {}", expensive_int_result.value(1));
+ println!("2nd int call for value 1: {}", expensive_int_result.value(1));
+ println!("1st int call for value 2: {}", expensive_int_result.value(2));
+
+ let mut expensive_str_result = Cacher::new(|x: &str| {
+ println!("calculating expensive str result for {}", x);
+ x.len()
+ });
+
+ println!("1st int call for value abc: {}", expensive_str_result.value("abc"));
+ println!("2nd int call for value abc: {}", expensive_str_result.value("abc"));
+ println!("1st int call for value defg: {}", expensive_str_result.value("defg"));
+}
+
+fn test_iterators() {
+ let v1 = vec!["Hello", "good", "world"];
+ // implied default is .into_iter() which consumes v1
+ for s in v1.iter() {
+ println!("element: {}", s);
+ }
+ // can still use it now
+ println!("v1: {:?}", &v1);
+
+ // manual iteration
+ let mut v1_iter = v1.iter();
+ while let Some(e) = v1_iter.next() {
+ println!("while loop over iter: {}", e);
+ }
+
+ for l_element in v1.iter().filter(|x| x.contains('l')) {
+ println!("v1 element containing 'l': {}", l_element);
+ }
+
+ let v2 = vec![1, 2, 3];
+ let double_v2: Vec<_> = v2.iter().map(|x| x * 2).collect();
+ println!("doubled v2: {:?}", double_v2);
+
+ for i in v2.into_iter().map(|x| x * 3) {
+ println!("for loop triplicating v2: {}", i);
+ }
+
+ for i in Counter5::new() {
+ println!("Counter 5 value: {}", i);
+ }
+}
+
+fn main() {
+ test_strings();
+ test_vectors();
+ test_hashmaps();
+ test_files();
+ test_generics();
+ test_closures();
+ test_iterators();
+}
--- /dev/null
+pub fn first_word(s: &str) -> &str {
+ for (i, &item) in s.as_bytes().iter().enumerate() {
+ if item == b' ' {
+ return &s[..i];
+ }
+ }
+
+ s
+}
+
+pub fn second_word(s: &str) -> Option<&str> {
+ for (i, &item) in s.as_bytes().iter().enumerate() {
+ if item == b' ' {
+ return Some(first_word(&s[(i + 1)..]));
+ }
+ }
+
+ None
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_first_word() {
+ assert_eq!(first_word(""), "");
+ assert_eq!(first_word("one"), "one");
+ assert_eq!(first_word("one two"), "one");
+
+ assert_eq!(first_word(&String::from("one two")), "one");
+ }
+
+ #[test]
+ fn test_second_word() {
+ assert_eq!(second_word(""), None);
+ assert_eq!(second_word("one"), None);
+ assert_eq!(second_word("one two"), Some("two"));
+ assert_eq!(second_word("one two three"), Some("two"));
+
+ assert_eq!(second_word(&String::from("one two three")), Some("two"));
+ }
+}
--- /dev/null
+#[macro_use]
+extern crate global_counter;
+
+use learning::*;
+
+#[test]
+fn test_longest() {
+ assert_eq!(longest("abc", "de"), "abc");
+ assert_eq!(longest("abc", "def"), "def");
+ assert_eq!(longest("abc", "defg"), "defg");
+}
+
+#[test]
+fn test_cacher_int_int() {
+ global_default_counter!(CALLED, u32);
+ let mut cacher = Cacher::new(|x| {
+ CALLED.inc();
+ 2 * x
+ });
+ assert_eq!(cacher.value(1), 2);
+ assert_eq!(CALLED.get_cloned(), 1);
+ // second time cached
+ assert_eq!(cacher.value(1), 2);
+ assert_eq!(CALLED.get_cloned(), 1);
+ // re-evaluated for new value
+ assert_eq!(cacher.value(-2), -4);
+ assert_eq!(CALLED.get_cloned(), 2);
+ // old arg still cached
+ assert_eq!(cacher.value(1), 2);
+ assert_eq!(CALLED.get_cloned(), 2);
+}
+
+#[test]
+fn test_cacher_str_usize() {
+ global_default_counter!(CALLED, u32);
+ let mut cacher = Cacher::new(|x: &str| {
+ CALLED.inc();
+ x.len()
+ });
+ assert_eq!(cacher.value("abc"), 3);
+ assert_eq!(CALLED.get_cloned(), 1);
+ // second time cached
+ assert_eq!(cacher.value("abc"), 3);
+ assert_eq!(CALLED.get_cloned(), 1);
+ // re-evaluated for new value
+ assert_eq!(cacher.value("defg"), 4);
+ assert_eq!(CALLED.get_cloned(), 2);
+ // old arg still cached
+ assert_eq!(cacher.value("abc"), 3);
+ assert_eq!(CALLED.get_cloned(), 2);
+}
+++ /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
- }
- }
-}
+++ /dev/null
-mod word_utils;
-mod lib;
-
-use std::collections::HashMap;
-use std::io::{prelude::*, ErrorKind};
-use std::fs::{self, File};
-
-use lib::*;
-use word_utils::{first_word, second_word};
-
-fn test_strings() {
- let s = String::from("Hello world");
- println!("first word: '{}'", first_word(&s));
- println!("second word: '{}'", second_word(&s).unwrap());
-
- let s2 = "hello dude blah";
- println!("second word of single: '{}'", second_word(s2).unwrap_or("(none)"));
-
- match second_word(s2) {
- Some(w) => println!("match: second word of '{}' exists: {}", s2, w),
- None => println!("match: second word of '{}' does not exist", s2),
- }
-}
-
-fn test_vectors() {
- let v1 = vec![1, 2, 3];
- println!("statically initialized vector: {:?}", v1);
-
- let mut v2: Vec<String> = Vec::new();
- v2.push("Hello".to_string());
- v2.push(String::from("world"));
- println!("dynamically built vector: {:?}", v2);
- println!("first element: {}", v2[0]);
- for el in &mut v2 {
- *el += "xx";
- }
- for el in &v2 {
- println!("{}", el);
- }
-}
-
-fn test_hashmaps() {
- let mut scores = HashMap::new();
- scores.insert("john", 10);
- scores.insert("mary", 20);
-
- println!("scores: {:?}", scores);
-
- // hash map with .collect()
- let persons = vec![("homer", 42), ("marge", 30)];
- let collect_scores: HashMap<_, _> = persons.into_iter().collect();
- println!("collect_scores: {:?}", collect_scores);
-
- for (p, s) in &collect_scores {
- println!("person {}: score {}", p, s);
- }
-
- println!("john's score: {}", scores.get("john").unwrap());
- println!("jake's score: {}", scores.get("jake").unwrap_or(&-1));
-
- // double scores
- for (_, v) in scores.iter_mut() {
- *v *= 2;
- }
- println!("scores after doubling: {:?}", scores);
-
- // double scores of immutable hashmap (rebuild it)
- let collect_scores: HashMap<_, _> = collect_scores.into_iter()
- .map(|(k, v)| (k, 2 * v))
- .collect();
- println!("collect_scores after rebuilding with doubling: {:?}", collect_scores);
-}
-
-fn test_files() {
- if let Ok(mut f) = File::open("Cargo.toml") {
- let mut contents = String::new();
- match f.read_to_string(&mut contents) {
- Ok(len) => println!("successfully opened Cargo.toml: {:?}, contents {} bytes:\n{}\n----------", f, len, contents),
- Err(e) => panic!("could not read file: {:?}", e)
- }
- } else {
- println!("could not open Cargo.toml");
- }
-
- // alternative form, more specific error checking
- let mut f = File::open("Cargo.toml").unwrap_or_else(|e| {
- if e.kind() == ErrorKind::NotFound {
- println!("Cargo.toml not found, falling back to /dev/null");
- // need to return a File
- File::open("/dev/null").unwrap()
- } else {
- panic!("Could not open Cargo.toml: {:?}", e);
- }
- });
- let mut contents = String::new();
- let len = f.read_to_string(&mut contents).unwrap_or_else(|e| {
- panic!("Could not read file: {:?}", e);
- });
- println!("successfully opened Cargo.toml with unwrap_or_else: {:?}, contents {} bytes:\n{}\n----------", f, len, contents);
-
- // using the '?' operator
- match read_file("Cargo.toml") {
- Ok(s) => println!("Cargo.toml contents:\n{}\n-------------", s),
- Err(e) => println!("Could not open Cargo.toml: {:?}", e)
- }
-
- // using std API
- match fs::read_to_string("Cargo.toml") {
- Ok(s) => println!("Cargo.toml contents:\n{}\n-------------", s),
- Err(e) => println!("Could not open Cargo.toml: {:?}", e)
- }
-}
-
-fn test_generics() {
- let num_list = vec![3, 42, -7, 100, 0];
- println!("largest number: {}", largest(&num_list));
- println!("num_list: {:?}", num_list);
-
- let char_list = vec!['a', 'y', 'q', 'm'];
- println!("largest char: {}", largest(&char_list));
-
- let str_list = vec!["hello", "world", "blue", "planet"];
- println!("largest str: {}", largest(&str_list));
- println!("str_list: {:?}", str_list);
-
- let string_list = vec!["aaaa".to_string(), "xxxxx".to_string(), "ffff".to_string()];
- println!("largest string (with cloning): {}", largest_clone(&string_list));
- println!("largest string (with ref): {}", largest_ref(&string_list));
- println!("string_list: {:?}", string_list);
-
- let s1 = String::from("abcd");
- let l;
- {
- let s2 = "efghi";
- l = longest(&s1, s2);
- }
- println!("longest string: {}", l);
-}
-
-fn test_closures() {
- let mut expensive_int_result = Cacher::new(|x| {
- println!("calculating expensive int result for {}", x);
- 2 * x
- });
-
- println!("1st int call for value 1: {}", expensive_int_result.value(1));
- println!("2nd int call for value 1: {}", expensive_int_result.value(1));
- println!("1st int call for value 2: {}", expensive_int_result.value(2));
-
- let mut expensive_str_result = Cacher::new(|x: &str| {
- println!("calculating expensive str result for {}", x);
- x.len()
- });
-
- println!("1st int call for value abc: {}", expensive_str_result.value("abc"));
- println!("2nd int call for value abc: {}", expensive_str_result.value("abc"));
- println!("1st int call for value defg: {}", expensive_str_result.value("defg"));
-}
-
-fn test_iterators() {
- let v1 = vec!["Hello", "good", "world"];
- // implied default is .into_iter() which consumes v1
- for s in v1.iter() {
- println!("element: {}", s);
- }
- // can still use it now
- println!("v1: {:?}", &v1);
-
- // manual iteration
- let mut v1_iter = v1.iter();
- while let Some(e) = v1_iter.next() {
- println!("while loop over iter: {}", e);
- }
-
- for l_element in v1.iter().filter(|x| x.contains('l')) {
- println!("v1 element containing 'l': {}", l_element);
- }
-
- let v2 = vec![1, 2, 3];
- let double_v2: Vec<_> = v2.iter().map(|x| x * 2).collect();
- println!("doubled v2: {:?}", double_v2);
-
- for i in v2.into_iter().map(|x| x * 3) {
- println!("for loop triplicating v2: {}", i);
- }
-
- for i in Counter5::new() {
- println!("Counter 5 value: {}", i);
- }
-}
-
-fn main() {
- test_strings();
- test_vectors();
- test_hashmaps();
- test_files();
- test_generics();
- test_closures();
- test_iterators();
-}
+++ /dev/null
-pub fn first_word(s: &str) -> &str {
- for (i, &item) in s.as_bytes().iter().enumerate() {
- if item == b' ' {
- return &s[..i];
- }
- }
-
- s
-}
-
-pub fn second_word(s: &str) -> Option<&str> {
- for (i, &item) in s.as_bytes().iter().enumerate() {
- if item == b' ' {
- return Some(first_word(&s[(i + 1)..]));
- }
- }
-
- None
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_first_word() {
- assert_eq!(first_word(""), "");
- assert_eq!(first_word("one"), "one");
- assert_eq!(first_word("one two"), "one");
-
- assert_eq!(first_word(&String::from("one two")), "one");
- }
-
- #[test]
- fn test_second_word() {
- assert_eq!(second_word(""), None);
- assert_eq!(second_word("one"), None);
- assert_eq!(second_word("one two"), Some("two"));
- assert_eq!(second_word("one two three"), Some("two"));
-
- assert_eq!(second_word(&String::from("one two three")), Some("two"));
- }
-}
+++ /dev/null
-#[macro_use]
-extern crate global_counter;
-
-use learning::*;
-
-#[test]
-fn test_longest() {
- assert_eq!(longest("abc", "de"), "abc");
- assert_eq!(longest("abc", "def"), "def");
- assert_eq!(longest("abc", "defg"), "defg");
-}
-
-#[test]
-fn test_cacher_int_int() {
- global_default_counter!(CALLED, u32);
- let mut cacher = Cacher::new(|x| {
- CALLED.inc();
- 2 * x
- });
- assert_eq!(cacher.value(1), 2);
- assert_eq!(CALLED.get_cloned(), 1);
- // second time cached
- assert_eq!(cacher.value(1), 2);
- assert_eq!(CALLED.get_cloned(), 1);
- // re-evaluated for new value
- assert_eq!(cacher.value(-2), -4);
- assert_eq!(CALLED.get_cloned(), 2);
- // old arg still cached
- assert_eq!(cacher.value(1), 2);
- assert_eq!(CALLED.get_cloned(), 2);
-}
-
-#[test]
-fn test_cacher_str_usize() {
- global_default_counter!(CALLED, u32);
- let mut cacher = Cacher::new(|x: &str| {
- CALLED.inc();
- x.len()
- });
- assert_eq!(cacher.value("abc"), 3);
- assert_eq!(CALLED.get_cloned(), 1);
- // second time cached
- assert_eq!(cacher.value("abc"), 3);
- assert_eq!(CALLED.get_cloned(), 1);
- // re-evaluated for new value
- assert_eq!(cacher.value("defg"), 4);
- assert_eq!(CALLED.get_cloned(), 2);
- // old arg still cached
- assert_eq!(cacher.value("abc"), 3);
- assert_eq!(CALLED.get_cloned(), 2);
-}