]> piware.de Git - learn-rust.git/blob - concepts/src/lib.rs
concepts: rustfmt
[learn-rust.git] / concepts / src / lib.rs
1 use std::collections::HashMap;
2 use std::fs::File;
3 use std::io::prelude::*;
4
5 pub fn read_file(path: &str) -> Result<String, std::io::Error> {
6     let mut s = String::new();
7     File::open(path)?.read_to_string(&mut s)?;
8     Ok(s)
9 }
10
11 // needs Copy trait, good for simple types
12 pub fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
13     let mut result = list[0];
14     for &i in list {
15         if i > result {
16             result = i;
17         }
18     }
19     result
20 }
21
22 // expensive for large strings, don't use that
23 pub fn largest_clone<T: PartialOrd + Clone>(list: &[T]) -> T {
24     let mut result = list[0].clone();
25     for i in list {
26         if *i > result {
27             result = i.clone();
28         }
29     }
30     result
31 }
32
33 // good for everything, but more expensive for simple types
34 pub fn largest_ref<T: PartialOrd>(list: &[T]) -> &T {
35     let mut result = &list[0];
36     for i in list {
37         if i > result {
38             result = i;
39         }
40     }
41     result
42 }
43
44 pub fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
45     if x.len() > y.len() {
46         x
47     } else {
48         y
49     }
50 }
51
52 /// Wrap and cache an expensive calculation
53 ///
54 /// This calls a closure just once for every distinct argument. Any subsequent
55 /// call to `.value()` with the same argument uses the cached value.
56 pub struct Cacher<T, A, V>
57 where
58     T: Fn(A) -> V,
59     A: Eq + Copy + std::hash::Hash,
60     V: Copy,
61 {
62     calc: T,
63     values: HashMap<A, V>,
64 }
65
66 impl<T, A, V> Cacher<T, A, V>
67 where
68     T: Fn(A) -> V,
69     A: Eq + Copy + std::hash::Hash,
70     V: Copy,
71 {
72     pub fn new(calc: T) -> Cacher<T, A, V> {
73         Cacher {
74             calc,
75             values: HashMap::new(),
76         }
77     }
78
79     pub fn value(&mut self, arg: A) -> V {
80         match self.values.get(&arg) {
81             Some(v) => *v,
82             None => {
83                 let v = (self.calc)(arg);
84                 self.values.insert(arg, v);
85                 v
86             }
87         }
88     }
89 }
90
91 pub struct Counter5 {
92     count: u32,
93 }
94
95 impl Counter5 {
96     pub fn new() -> Counter5 {
97         Counter5 { count: 0 }
98     }
99 }
100
101 impl Iterator for Counter5 {
102     type Item = u32;
103
104     fn next(&mut self) -> Option<Self::Item> {
105         if self.count < 5 {
106             self.count += 1;
107             Some(self.count)
108         } else {
109             None
110         }
111     }
112 }
113
114 pub struct Post {
115     state: Box<dyn State>,
116     content: String,
117 }
118
119 impl Post {
120     pub fn new() -> Post {
121         Post {
122             state: Box::new(Draft {}),
123             content: String::new(),
124         }
125     }
126
127     pub fn add_text(&mut self, text: &str) {
128         self.content.push_str(text);
129     }
130
131     pub fn content(&self) -> &str {
132         self.state.content(self)
133     }
134
135     pub fn request_review(&mut self) {
136         self.state = self.state.request_review();
137     }
138
139     pub fn approve(&mut self) {
140         self.state = self.state.approve();
141     }
142
143     pub fn reject(&mut self) {
144         self.state = self.state.reject();
145     }
146 }
147
148 trait State {
149     fn request_review(&self) -> Box<dyn State>;
150     fn approve(&mut self) -> Box<dyn State>;
151     fn reject(&self) -> Box<dyn State>;
152
153     #[allow(unused_variables)]
154     fn content<'a>(&self, post: &'a Post) -> &'a str {
155         ""
156     }
157 }
158
159 struct Draft {}
160 impl State for Draft {
161     fn request_review(&self) -> Box<dyn State> {
162         Box::new(PendingReview { acks: 0 })
163     }
164
165     fn approve(&mut self) -> Box<dyn State> {
166         // don't change state
167         Box::new(Self {})
168     }
169
170     fn reject(&self) -> Box<dyn State> {
171         Box::new(Self {})
172     }
173 }
174
175 struct PendingReview {
176     acks: u32,
177 }
178
179 impl State for PendingReview {
180     fn request_review(&self) -> Box<dyn State> {
181         Box::new(Self { acks: self.acks })
182     }
183
184     fn approve(&mut self) -> Box<dyn State> {
185         if self.acks >= 1 {
186             Box::new(Published {})
187         } else {
188             Box::new(Self {
189                 acks: self.acks + 1,
190             })
191         }
192     }
193
194     fn reject(&self) -> Box<dyn State> {
195         Box::new(Draft {})
196     }
197 }
198
199 struct Published {}
200 impl State for Published {
201     fn request_review(&self) -> Box<dyn State> {
202         Box::new(Self {})
203     }
204
205     fn approve(&mut self) -> Box<dyn State> {
206         Box::new(Published {})
207     }
208
209     fn reject(&self) -> Box<dyn State> {
210         Box::new(Self {})
211     }
212
213     fn content<'a>(&self, post: &'a Post) -> &'a str {
214         &post.content
215     }
216 }
217
218 // state encoded as types; this is the "approved" state
219 pub struct TPost {
220     content: String,
221 }
222
223 impl TPost {
224     pub fn new() -> TPostDraft {
225         TPostDraft {
226             content: String::new(),
227         }
228     }
229
230     pub fn content(&self) -> &str {
231         &self.content
232     }
233 }
234
235 pub struct TPostDraft {
236     content: String,
237 }
238
239 impl TPostDraft {
240     pub fn add_text(&mut self, text: &str) {
241         self.content.push_str(text);
242     }
243
244     pub fn request_review(self) -> TPostReview {
245         TPostReview {
246             content: self.content,
247         }
248     }
249 }
250
251 pub struct TPostReview {
252     content: String,
253 }
254
255 impl TPostReview {
256     pub fn approve(self) -> TPost {
257         TPost {
258             content: self.content,
259         }
260     }
261
262     pub fn reject(self) -> TPostDraft {
263         TPostDraft {
264             content: self.content,
265         }
266     }
267 }