]> piware.de Git - learn-rust.git/blob - concepts/src/lib.rs
ca0624142dea4d751e4506184bf84508de7e0696
[learn-rust.git] / concepts / src / lib.rs
1 use std::fs::File;
2 use std::io::prelude::*;
3 use std::collections::HashMap;
4
5 pub fn read_file(path: &str) -> Result<String, std::io::Error> {
6     let mut s = String::new();
7     File::open(path)?
8         .read_to_string(&mut s)?;
9     Ok(s)
10 }
11
12 // needs Copy trait, good for simple types
13 pub fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
14     let mut result = list[0];
15     for &i in list {
16         if i > result {
17             result = i;
18         }
19     }
20     result
21 }
22
23 // expensive for large strings, don't use that
24 pub fn largest_clone<T: PartialOrd + Clone>(list: &[T]) -> T {
25     let mut result = list[0].clone();
26     for i in list {
27         if *i > result {
28             result = i.clone();
29         }
30     }
31     result
32 }
33
34 // good for everything, but more expensive for simple types
35 pub fn largest_ref<T: PartialOrd>(list: &[T]) -> &T {
36     let mut result = &list[0];
37     for i in list {
38         if i > result {
39             result = i;
40         }
41     }
42     result
43 }
44
45 pub fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
46     if x.len() > y.len() {
47         x
48     } else {
49         y
50     }
51 }
52
53 /// Wrap and cache an expensive calculation
54 ///
55 /// This calls a closure just once for every distinct argument. Any subsequent
56 /// call to `.value()` with the same argument uses the cached value.
57 pub struct Cacher<T, A, V>
58 where
59     T: Fn(A) -> V,
60     A: Eq + Copy + std::hash::Hash,
61     V: Copy,
62 {
63     calc: T,
64     values: HashMap<A, V>,
65 }
66
67 impl<T, A, V> Cacher<T, A, V>
68 where
69     T: Fn(A) -> V,
70     A: Eq + Copy + std::hash::Hash,
71     V: Copy,
72 {
73     pub fn new(calc: T) -> Cacher<T, A, V> {
74         Cacher { calc, values: HashMap::new() }
75     }
76
77     pub fn value(&mut self, arg: A) -> V {
78         match self.values.get(&arg) {
79             Some(v) => *v,
80             None => {
81                 let v = (self.calc)(arg);
82                 self.values.insert(arg, v);
83                 v
84             }
85         }
86     }
87 }
88
89 pub struct Counter5 {
90     count: u32
91 }
92
93 impl Counter5 {
94     pub fn new() -> Counter5 {
95         Counter5 { count: 0 }
96     }
97 }
98
99 impl Iterator for Counter5 {
100     type Item = u32;
101
102     fn next(&mut self) -> Option<Self::Item> {
103         if self.count < 5 {
104             self.count += 1;
105             Some(self.count)
106         } else {
107             None
108         }
109     }
110 }
111
112 pub struct Post {
113     state: Option<Box<dyn State>>,
114     content: String,
115 }
116
117 impl Post {
118     pub fn new() -> Post {
119         Post {
120             state: Some(Box::new(Draft {})),
121             content: String::new(),
122         }
123     }
124
125     pub fn add_text(&mut self, text: &str) {
126         self.content.push_str(text);
127     }
128
129     pub fn content(&self) -> &str {
130         // as_ref() converts Option<Box<State>> to Option<&Box<State>>
131         // state can never be None, all state transitions return a new one
132         self.state.as_ref().unwrap().content(self)
133     }
134
135     pub fn request_review(&mut self) {
136         if let Some(s) = self.state.take() {
137             self.state = Some(s.request_review());
138         }
139     }
140
141     pub fn approve(&mut self) {
142         if let Some(s) = self.state.take() {
143             self.state = Some(s.approve());
144         }
145     }
146 }
147
148 trait State {
149     fn request_review(self: Box::<Self>) -> Box<dyn State>;
150     fn approve(self: Box::<Self>) -> Box<dyn State>;
151
152     #[allow(unused_variables)]
153     fn content<'a>(&self, post: &'a Post) -> &'a str {
154         ""
155     }
156 }
157
158 struct Draft {}
159 impl State for Draft {
160     fn request_review(self: Box::<Self>) -> Box<dyn State> {
161         Box::new(PendingReview {})
162     }
163
164     fn approve(self: Box::<Self>) -> Box<dyn State> {
165         self
166     }
167 }
168
169 struct PendingReview {}
170 impl State for PendingReview {
171     fn request_review(self: Box::<Self>) -> Box<dyn State> {
172         self
173     }
174
175     fn approve(self: Box::<Self>) -> Box<dyn State> {
176         Box::new(Published {})
177     }
178 }
179
180 struct Published {}
181 impl State for Published {
182     fn request_review(self: Box::<Self>) -> Box<dyn State> {
183         self
184     }
185
186     fn approve(self: Box::<Self>) -> Box<dyn State> {
187         Box::new(Published {})
188     }
189
190     fn content<'a>(&self, post: &'a Post) -> &'a str {
191         &post.content
192     }
193 }