├── .gitignore ├── LICENSE ├── README.md ├── basics ├── Cargo.toml ├── benches │ └── expr.rs └── src │ ├── bintree.rs │ ├── bounds.rs │ ├── break.rs │ ├── cast.rs │ ├── closures.rs │ ├── collect.rs │ ├── collect1.rs │ ├── compare.rs │ ├── copytypes.rs │ ├── enum.rs │ ├── enum2.rs │ ├── expr.rs │ ├── expr2.rs │ ├── f64.rs │ ├── foo.rs │ ├── generics.rs │ ├── grep.rs │ ├── impl.rs │ ├── impl2.rs │ ├── io.rs │ ├── iter.rs │ ├── json.rs │ ├── lib.rs │ ├── main.rs │ ├── mod2.rs │ ├── modules.rs │ ├── mutable.rs │ ├── operators.rs │ ├── ownership.rs │ ├── panic.rs │ ├── pattern.rs │ ├── rc.rs │ ├── result.rs │ ├── sharing.rs │ ├── struct.rs │ ├── trait.rs │ ├── types.rs │ ├── unicode.rs │ ├── unlines.rs │ ├── utility.rs │ └── vecdeque.rs ├── difference-list ├── Cargo.toml └── src │ ├── lib.rs │ └── tests.rs ├── fern_sim ├── Cargo.toml └── src │ ├── bin │ └── efern.rs │ └── lib.rs ├── iron-gcd ├── Cargo.toml └── src │ └── main.rs ├── mandelbrot ├── Cargo.toml └── src │ └── main.rs └── stream-fusion ├── Cargo.toml ├── benches └── basics.rs └── src ├── bin.rs ├── closure.rs ├── lib.rs ├── trait.rs └── traitnoskip.rs /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Don Stewart 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # experiments-rust 2 | Working through the Rust book 3 | 4 | Examples and experiments while working through "Programming Rust" 5 | -------------------------------------------------------------------------------- /basics/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "basics" 3 | version = "0.1.0" 4 | authors = ["Don Stewart "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | num = "0.3.0" 11 | pretty = "0.10.0" 12 | num-traits = "0.2" 13 | regex = "0.2.2" 14 | -------------------------------------------------------------------------------- /basics/benches/expr.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId}; 2 | 3 | criterion_group!(benches, bench); 4 | criterion_main!(benches); 5 | 6 | use basics::sum_f1; 7 | use basics::sum_f2; 8 | use basics::sum_f3; 9 | 10 | // criterion benchmarks 11 | pub fn bench(c: &mut Criterion) { 12 | let mut group = c.benchmark_group("sums"); 13 | for i in [10000000000].iter() { 14 | group.bench_with_input(BenchmarkId::new("Low level", i), i, 15 | |b, i| b.iter(|| sum_f2(*i))); 16 | group.bench_with_input(BenchmarkId::new("Iteration", i), i, 17 | |b, i| b.iter(|| sum_f3(*i))); 18 | group.bench_with_input(BenchmarkId::new("Recursive", i), i, 19 | |b, i| b.iter(|| sum_f1(*i))); 20 | } 21 | group.finish(); 22 | } 23 | -------------------------------------------------------------------------------- /basics/src/bintree.rs: -------------------------------------------------------------------------------- 1 | // binary trees as iterators 2 | #[derive(Copy,Clone)] 3 | enum Tree<'a, T> { 4 | Empty, 5 | NonEmpty(Node<'a, T>) 6 | } 7 | 8 | #[derive(Copy,Clone)] 9 | struct Node<'a,T> { 10 | e: T, 11 | left: &'a Tree<'a,T>, 12 | right: &'a Tree<'a,T> 13 | } 14 | 15 | #[allow(clippy::many_single_char_names)] 16 | pub fn main() { 17 | let a = make_node(&Empty, 1, &Empty); 18 | assert_eq!(count(&a), 1); 19 | let sub = a; // copy 20 | let b = make_node(&sub, 2, &Empty); 21 | assert_eq!(count(&b), 2); 22 | let sub1 = make_node(&Empty, 7 , &Empty); 23 | let c = make_node(&b, 3, &sub1); 24 | assert_eq!(count(&c), 4); 25 | 26 | // iterate over a binary tree 27 | let mut v = Vec::new(); 28 | for i in &c { 29 | v.push(*i); 30 | } 31 | println!("{:?}", v); 32 | 33 | let d = c.iter().map(|e| e * 2).collect::>(); 34 | println!("{:?}", d); 35 | } 36 | 37 | fn count(t: &Tree) -> usize { 38 | match t { 39 | Tree::Empty => 0, 40 | Tree::NonEmpty(n) => count(&n.left) + count(&n.right) + 1 41 | } 42 | } 43 | 44 | use self::Tree::*; 45 | 46 | struct TreeIter<'a, T> { 47 | // maintain our own stack to iterate 48 | unvisited: Vec<&'a Node<'a, T>> 49 | } 50 | 51 | // define a method on TreeIter 52 | impl<'a, T: 'a> TreeIter<'a, T> { 53 | fn push_left_edge(&mut self, mut tree: &'a Tree) { 54 | while let NonEmpty(ref node) = *tree { 55 | self.unvisited.push(node); 56 | tree = &node.left; 57 | } 58 | } 59 | } 60 | 61 | // "give" an iter method to Tree 62 | impl Tree<'_, T> { 63 | fn iter(&self) -> TreeIter { 64 | let mut iter = TreeIter { unvisited: Vec::new() }; 65 | iter.push_left_edge(self); 66 | iter 67 | } 68 | } 69 | 70 | impl<'a, T: 'a> IntoIterator for &'a Tree<'a, T> { 71 | type Item = &'a T; 72 | type IntoIter = TreeIter<'a, T>; 73 | fn into_iter(self) -> Self::IntoIter { 74 | self.iter() 75 | } 76 | } 77 | 78 | // a flattening transformation 79 | impl<'a, T> Iterator for TreeIter<'a, T> { 80 | type Item = &'a T; 81 | fn next(&mut self) -> Option<&'a T> { 82 | let node = match self.unvisited.pop() { 83 | None => return None, // short circuit 84 | Some(n) => n 85 | }; 86 | self.push_left_edge(&node.right); 87 | Some(&node.e) 88 | } 89 | } 90 | 91 | fn make_node<'a, T>(left: &'a Tree<'a, T>, e: T, right: &'a Tree<'a, T>) -> Tree<'a, T> { 92 | NonEmpty(Node{e, left, right}) 93 | } 94 | -------------------------------------------------------------------------------- /basics/src/bounds.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Add, Mul}; 2 | 3 | // num-generic dot product 4 | fn dot(v1: &[N], v2: &[N]) -> N 5 | where 6 | N: Copy + Mul + Add + Default, 7 | { 8 | let mut total: N = N::default(); 9 | for i in 0..v1.len() { 10 | total = total + v1[i] * v2[i]; 11 | } 12 | total 13 | } 14 | 15 | pub fn main() { 16 | let a: &[f64] = &[1., 2., 3., 4., 5.]; 17 | let b: &[f64] = &[2., 7., 9., 3., 1.]; 18 | 19 | println!("{}", dot(&a, &b)); 20 | } 21 | -------------------------------------------------------------------------------- /basics/src/break.rs: -------------------------------------------------------------------------------- 1 | pub fn break_main() { 2 | // 1. can't borrow a reference to a local variable and take it out of scope 3 | { 4 | let r: &i64 = &1; // empty ref binding 5 | // assert_eq!(*r, 1); // uniitialized *r. 6 | { 7 | let _x = 2; 8 | // NO: r = &x; // borrowed value doesn't live long enough 9 | // ref to x can't outlive x 10 | } // dropped here 11 | assert_eq!(*r, 1); 12 | } 13 | 14 | // 2. a valid example 15 | { 16 | let x = 1; 17 | { 18 | let r = &x; // inner life time is subset of lifetime of x 19 | assert_eq!(*r, 1); 20 | } 21 | } 22 | 23 | // 3. borrwing a ref to a data structure 24 | { 25 | let v = vec![1, 2, 3]; 26 | { 27 | let r = &v[1]; 28 | assert_eq!(*r, 2); 29 | } 30 | } 31 | 32 | // 4. references in parameters 33 | { 34 | // threadsafety. this is a top-level IORef. 35 | // need to treat like an MVar 36 | // mutable static is pretty unsafe 37 | static mut STASH: &i32 = &128; // needs to be initialized 38 | // f can only applied to things with static lifetime 39 | fn f(p: &'static i32) { 40 | // tick A 41 | // ignore the threadsafety explicitly 42 | unsafe { 43 | STASH = p; // but lifetime of p 44 | } 45 | } 46 | f(&17); 47 | // lifetime genericity , most specific lifetime etc 48 | // not ok: let WORTH_POINTING_AT: i32 = 1000; 49 | static WORTH_POINTING_AT: i32 = 1000; 50 | // also ok: const WORTH_POINTING_AT: i32 = 1000; 51 | f(&WORTH_POINTING_AT); 52 | } 53 | 54 | // 5. passing references as arguments 55 | { 56 | // polymorphic in lifetime 57 | #[allow(clippy::needless_lifetimes)] 58 | fn g<'a>(_p: &'a i32) {} 59 | fn h(_p: &'static i32) {} 60 | 61 | let x = 10; 62 | g(&x); 63 | const UY: i32 = 10; 64 | h(&UY); 65 | } 66 | 67 | // 6. slices 68 | { 69 | // with a single ref in and return a single ref, assume same lifetime 70 | // fn smallest(v: &[i32]) -> &i32 { 71 | #[allow(clippy::needless_lifetimes)] 72 | fn smallest<'a>(v: &'a [i32]) -> &'a i32 { 73 | let mut s = &v[0]; 74 | for r in &v[1..] { 75 | // iterate by ref 76 | if *r < *s { 77 | s = r; 78 | } 79 | } 80 | s 81 | } 82 | 83 | { 84 | let parabola = [9, 4, 1, 0, 1, 4, 9]; 85 | let s = smallest(¶bola); 86 | assert_eq!(*s, 0); 87 | } 88 | } 89 | 90 | // 7. structs with references 91 | // you must pass a lifetime param through the struct to any references contained 92 | { 93 | #[derive(Debug,PartialEq,Clone)] 94 | struct S<'a> { 95 | r: &'a i32, 96 | } 97 | 98 | let x = 10; 99 | let s = S { r: &x }; // some lifetime 'a, which must be within x's lifetime 100 | assert_eq!(*s.r, 10); 101 | 102 | // and they're contagious 103 | struct T<'a> { 104 | s: S<'a> 105 | } 106 | 107 | let u = s.clone(); 108 | let t = T { s }; // move 's' 109 | 110 | // can't do this: assert_eq!(t.s, s); 111 | assert_eq!(t.s, u); 112 | } 113 | 114 | // 8. lifetime params: more 115 | // this works (the book says it shouldn't because lifetime of x and y are different) 116 | { 117 | struct U<'a,'b> { 118 | x: &'a i32, 119 | y: &'b i32 120 | } 121 | 122 | let a = 10; 123 | let r1; 124 | let r2; 125 | { 126 | let y = 20; 127 | { 128 | let s = U { x: &a, y: &y }; 129 | r1 = s.x; 130 | assert_eq!(*r1, 10); 131 | r2 = s.y; 132 | assert_eq!(*r2, 20); 133 | } 134 | } 135 | assert_eq!(*r1, 10); // this extends the lifetime until it works 136 | /* 137 | * [Know PR] 138 | * Page 111 bottom code example 139 | * 140 | * The reader is correct: the book says that code doesn't compile, but it does with recent 141 | * versions of Rust. This is because the borrow checker has been improved: despite its 142 | * scope `r` is never actually used beyond the lifetime of `y`, so the borrow checker 143 | * concludes that the lifetime of the two references in `S` does not actually extend too 144 | * far to be safe. 145 | * 146 | * To be fixed in the second edition 147 | */ 148 | 149 | } 150 | 151 | // 9. omitting parameters 152 | { 153 | struct S<'a, 'b> { 154 | x: &'a i32, 155 | y: &'b i32 156 | } 157 | let a = S { x: &10 , y: &20}; 158 | 159 | // interesting type conversion through references 160 | #[allow(clippy::needless_lifetimes)] 161 | fn sum_r_xy<'a, 'b, 'c>(r: &'a i32, s: S<'b, 'c>) -> i32 { 162 | r + s.x + s.y 163 | } 164 | 165 | assert_eq!(sum_r_xy(&8, a), 38); 166 | 167 | // single lifetime: so you can elide them 168 | fn first_third(point: &[i32; 3]) -> [i32; 2] { 169 | [point[0], point[2]] 170 | } 171 | 172 | let v: [i32; 3] = [1, 2, 3]; 173 | let w: [i32; 2] = [1, 3]; 174 | assert_eq!(first_third(&v), w); 175 | 176 | } 177 | 178 | // 10. methods 179 | { 180 | struct T { 181 | els: Vec, 182 | } 183 | impl T { 184 | fn findl_by_prefix(&self, prefix: &str) -> Option<&String> { 185 | for e in &self.els { 186 | if e.starts_with(prefix) { 187 | return Some(&e); // a ref. 188 | } 189 | } 190 | None 191 | } 192 | } 193 | 194 | let ks = vec!["aardvark".to_string(),"aaple".to_string(), "boo".to_string()]; 195 | let t = T { els: ks }; 196 | match t.findl_by_prefix(&"aa") { 197 | None => { println!("None found"); } 198 | Some(xs) => println!("{:?}", xs) 199 | }; 200 | 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /basics/src/cast.rs: -------------------------------------------------------------------------------- 1 | // UB? 2 | // https://github.com/rust-lang/rust/issues/10184 ? 3 | pub fn cast_main() { 4 | { 5 | let a: f64 = 1000000.; 6 | let b = a as i16; 7 | 8 | // 1 as 1 9 | println!("{} as {}", b, b); 10 | } 11 | { 12 | let a: f64 = 1000000.; 13 | let b = a as i16; 14 | 15 | // 1000000 as 16960 16 | println!("{} as {}", a, b); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /basics/src/closures.rs: -------------------------------------------------------------------------------- 1 | // pg 303 / ch14 closures 2 | 3 | pub fn main() { 4 | let a = vec![S{a:"foo".to_string(),b:7,c:"c".to_string()} 5 | ,S{a:"foo".to_string(),b:6,c:"x".to_string()} 6 | ,S{a:"bar".to_string(),b:700,c:"y".to_string()} 7 | ]; 8 | let b = sort_s_pure(&a); 9 | println!("{:?}", a); 10 | println!("{:?}", b); 11 | 12 | start_sorting_thread(b, 42); 13 | } 14 | 15 | #[derive(Clone,PartialEq,Debug,Eq,Ord,PartialOrd)] 16 | struct S { 17 | a: String, 18 | b: i64, 19 | c: String 20 | } 21 | 22 | fn sort_s_pure(c: &[S]) -> Vec { 23 | let mut d = c.to_owned(); // own a new d from borrowed c 24 | let x = 2; // to be captured 25 | d.sort_by_key(|c| {-c.b + x} ); 26 | d 27 | } 28 | 29 | use std::thread; 30 | 31 | fn start_sorting_thread(mut cs: Vec, x: i64) -> thread::JoinHandle> { 32 | 33 | // move 'x' the lambda 34 | let ky_fn = move |c: &S| -> i64 { -c.b + x } ; 35 | 36 | thread::spawn(move || { 37 | cs.sort_by_key(ky_fn); 38 | cs 39 | }) 40 | 41 | } 42 | -------------------------------------------------------------------------------- /basics/src/collect.rs: -------------------------------------------------------------------------------- 1 | // references let you access a value without changing its ownership 2 | use std::collections::HashMap; 3 | 4 | type Table = HashMap>; 5 | 6 | // this is like an ownership destructor. the function param takes ownership of the table, and then 7 | // destorys the ks and values. 8 | // 9 | // so instead we pass a ref T , to access without taking ownership of the lifetime 10 | fn show(t: &Table) { // ref to Table 11 | for (k,vs) in t { // n.b. iterating over a shared ref produces shared refs to components 12 | println!("key : {}:", k); 13 | for v in vs { 14 | println!(" {}", v); 15 | } 16 | } 17 | } 18 | 19 | fn sort_works(t: &mut Table) { 20 | for vs in t.values_mut() { 21 | vs.sort(); 22 | } 23 | } 24 | 25 | pub fn main() { 26 | let mut t = Table::new(); 27 | 28 | t.insert("a".to_string(), 29 | vec!["x".to_string() , "y".to_string(), "z".to_string()]); 30 | t.insert("b".to_string(), 31 | vec!["2".to_string() , "3".to_string(), "1".to_string()]); 32 | 33 | show(&t); // create a shared ref T (read-only is fine) 34 | sort_works(&mut t); // mutate the table 35 | show(&t); // create a shared ref T (read-only is fine) 36 | 37 | ref_1(); 38 | ref_2(); 39 | ref_3(true); 40 | ref_3(false); 41 | ref_4(); 42 | } 43 | 44 | fn ref_1() { 45 | let x:i64 = 10; 46 | let r:&i64 = &x; 47 | assert!(r == &10); 48 | assert!(*r == 10); 49 | 50 | let mut y = 32; 51 | let m = &mut y; //mut ref to y 52 | *m += 32; 53 | assert!(*m == 64); 54 | } 55 | 56 | // since references are so widely used the '.' operator on methods implicitly dereferences its 57 | // left operand 58 | fn ref_2() { 59 | struct A { name: &'static str, _bechdel_pass: bool } // note the static lifetimes 60 | #[allow(dead_code)] 61 | struct B { name: String } // note the static lifetimes 62 | let aria = A { name: "Aria: The Animation", _bechdel_pass: true }; 63 | #[allow(unused_variables)] 64 | let brib = B { name: "Aria: The Animation".to_string() }; 65 | let a_ref = &aria; 66 | assert_eq!(a_ref.name, "Aria: The Animation"); 67 | assert_eq!((*a_ref).name, "Aria: The Animation"); 68 | 69 | let mut v = vec![1973, 1968]; 70 | v.sort(); 71 | (&mut v).sort(); 72 | } 73 | 74 | fn ref_3(b: bool) { // bottom of stack 75 | let x = 10; // stack 76 | let y = 20; // stack 77 | 78 | // assignment writes to the location of the referent. simple. 79 | let r = if b { &y } else { &x }; 80 | 81 | assert!(*r == 10 || *r == 20); 82 | } 83 | 84 | fn ref_4() { 85 | struct P { x: i32, y: i32 } 86 | let p = P {x: 1000, y: 729 }; 87 | let r: &P = &p; // r has type ref to P; value is ref to p 88 | let rr: &&P = &r; 89 | let rrr: &&&P = &rr; 90 | assert_eq!(rrr.y, 729); 91 | assert_eq!(rrr.x, 1000); 92 | } 93 | -------------------------------------------------------------------------------- /basics/src/collect1.rs: -------------------------------------------------------------------------------- 1 | // ch 16: collections 2 | #[allow(clippy::many_single_char_names)] 3 | pub fn main() { 4 | // vectors 5 | { 6 | let mut ns: Vec = Vec::with_capacity(1); 7 | 8 | let words = vec!["step","on","no","pets"]; 9 | 10 | let buf = [0u8; 1024]; 11 | 12 | for i in words.iter().rev() { 13 | println!("{}",i); 14 | } 15 | assert_eq!(ns.get(0), None); 16 | 17 | let x = words[2]; 18 | assert_eq!(x, "no"); 19 | ns.push(3); 20 | 21 | let r = &buf[4..8]; 22 | assert_eq!(Some(&r[0]), r.first()); 23 | 24 | use std::collections::HashSet; 25 | 26 | // nub . sort 27 | let mut byte = b"Misssisssissssippppii".to_vec(); 28 | let mut seen = HashSet::new(); 29 | byte.retain(|r| seen.insert(*r)); // "Misp" 30 | println!("{}", String::from_utf8(byte).unwrap()); 31 | 32 | } 33 | 34 | // concats and slices 35 | { 36 | assert_eq!([[1,2], [2,3]].concat(), [1,2,2,3]); 37 | println!("{}", [["foo","bar"], ["baz","qux"]].concat().join(", ")); 38 | } 39 | 40 | // splitting 41 | { 42 | let i = 1; 43 | let j = 2; 44 | let mut v = vec![0, 1, 2, 3]; 45 | let a = &mut v[i]; 46 | *a += 2; // region of mutability ends 47 | let b = &v[j]; 48 | let c = &v[i]; 49 | 50 | println!("{:?}", c + b); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /basics/src/compare.rs: -------------------------------------------------------------------------------- 1 | // structural equality. 2 | pub fn main() { 3 | let x = 10; 4 | let y = 10; 5 | let rx = &x; 6 | let ry = &y; 7 | let rrx = ℞ 8 | let rry = &ry; 9 | assert!(rrx <= rry); 10 | assert!(rrx == rry); 11 | assert!(*rrx <= *rry); 12 | assert!(*rrx == *rry); 13 | assert!(*rx <= *ry); 14 | assert!(*rx == *ry); 15 | assert!(rx <= ry); 16 | assert!(rx == ry); 17 | 18 | assert!(!std::ptr::eq(rx, ry)); 19 | 20 | let a = factorial(10); 21 | println!("{}", a); 22 | let a = factorial(33); 23 | println!("{}", a); 24 | 25 | let r = &factorial; 26 | println!("{}",(*r)(6)); 27 | println!("{}",r(6)); 28 | 29 | // arith sees through one level of indirection 30 | // assert_eq!(&r(6) + &1009, 1729); // fun 31 | assert_eq!(r(6) + 1009, 1729); // fun 32 | // &1009 is an anonymous ref with scope of args of assert_eq 33 | } 34 | 35 | fn factorial(n: i128) -> i128 { 36 | // (1..n+1).fold(1, |a, b| a * b) 37 | (1..n+1).product() 38 | } 39 | -------------------------------------------------------------------------------- /basics/src/copytypes.rs: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | 3 | #[derive(Copy,Clone)] // make it a copy type 4 | struct Label { 5 | ns: u32 6 | } 7 | 8 | fn print(l: Label) { println!("STAMP: {}", l.ns); } 9 | 10 | let l = Label { ns: 3 }; 11 | print(l); // move 12 | println!("My label number is: {}", l.ns) 13 | 14 | } 15 | -------------------------------------------------------------------------------- /basics/src/enum.rs: -------------------------------------------------------------------------------- 1 | // Chapter 10: Enums. page 212 2 | 3 | use std::cmp::Ordering; 4 | use std::mem::size_of; 5 | 6 | // n.b. #[repr]!! 7 | 8 | #[derive(Debug, PartialEq)] 9 | enum O { 10 | LT_ = -1, 11 | EQ_ = 0, 12 | GT_ = 1, 13 | } 14 | 15 | // import the constructors 16 | use self::O::*; 17 | 18 | impl O { 19 | fn i32_to_maybe_o(n: i32) -> Option { 20 | match n { 21 | -1 => Some(LT_), 22 | 0 => Some(EQ_), 23 | 1 => Some(GT_), 24 | _ => None, 25 | } 26 | } 27 | 28 | fn compare_(n: i32, m: i32) -> O { 29 | match n.cmp(&m) /*urgh*/ { 30 | Ordering::Greater => GT_, 31 | Ordering::Less => LT_, 32 | Ordering::Equal => EQ_, 33 | } 34 | 35 | /* 36 | if n < m { 37 | LT_ 38 | } else if n > m { 39 | GT_ 40 | } else { 41 | EQ_ 42 | } 43 | */ 44 | } 45 | } 46 | 47 | #[derive(Debug, PartialEq)] 48 | enum A { 49 | Z, 50 | X, 51 | F(Option), 52 | G { left: u32, right: u32 }, 53 | } 54 | 55 | pub fn main() { 56 | println!("{:?}", O::compare_(7, 32)); 57 | 58 | // assertions about size of objects 59 | assert_eq!(size_of::(), 1); 60 | assert_eq!(LT_ as i32, -1); 61 | 62 | assert_eq!(O::i32_to_maybe_o(42), None); 63 | assert_eq!(O::i32_to_maybe_o(1), Some(GT_)); 64 | 65 | assert_ne!(A::Z, A::X); 66 | assert_ne!(A::F(None), A::G { left: 0, right: 1 }); 67 | 68 | let t1: Tree = empty(); 69 | let t2: Tree = single(42); 70 | 71 | println!("{:?}, {:?}", t1, t2); 72 | 73 | } 74 | 75 | /* trees */ 76 | #[derive(Debug, Clone, PartialEq)] 77 | enum Tree { 78 | Empty, 79 | /* tag */ 80 | Full(Box>), 81 | /* tag , ptr */ 82 | } 83 | 84 | #[derive(Debug, Clone, PartialEq)] 85 | struct Node { 86 | element: T, 87 | left: Tree, 88 | right: Tree, 89 | } 90 | 91 | use Tree::*; 92 | 93 | fn empty() -> Tree { 94 | Empty 95 | } 96 | 97 | fn single(e: T) -> Tree { 98 | let n = Box::new(Node { 99 | element: e, 100 | left: Empty, 101 | right: Empty, 102 | }); 103 | 104 | Full(n) 105 | } 106 | -------------------------------------------------------------------------------- /basics/src/enum2.rs: -------------------------------------------------------------------------------- 1 | // Chapter 10: Enums. page 212 2 | 3 | /* trees */ 4 | #[derive(Debug, Clone, PartialEq)] 5 | enum Tree { 6 | Empty, 7 | /* tag */ 8 | Full(Box>), 9 | /* tag , ptr */ 10 | } 11 | 12 | #[derive(Debug, Clone, PartialEq)] 13 | struct Node { 14 | element: T, 15 | left: Tree, 16 | right: Tree, 17 | } 18 | 19 | use Tree::*; 20 | 21 | fn empty() -> Tree { 22 | Empty 23 | } 24 | 25 | // box a singleton tree 26 | fn single(e: T) -> Tree { 27 | let n = Box::new(Node { 28 | element: e, 29 | left: Empty, 30 | right: Empty, 31 | }); 32 | 33 | Full(n) 34 | } 35 | 36 | // for all T in Ord, Tree has impl ... 37 | impl Tree { 38 | 39 | // mutable insertion with pattern matching 40 | fn add_mut(&mut self, v: T) { 41 | match *self { 42 | Empty => { 43 | *self = single(v); 44 | }, 45 | Full(ref mut n) => { 46 | if v <= n.element { 47 | Tree::add_mut(&mut n.left, v); 48 | } else { 49 | Tree::add_mut(&mut n.right, v); 50 | } 51 | } 52 | } 53 | } 54 | } 55 | 56 | // functional insertion 57 | #[allow(clippy::many_single_char_names)] 58 | fn add(t: Tree, v: T) -> Tree { 59 | match t { 60 | Empty => { 61 | single(v) 62 | }, 63 | Full(n) => { 64 | let Node { element: e, left: l, right: r } = *n; 65 | if v <= e { 66 | Full(Box::new(Node { 67 | element: e, 68 | left : add(l,v), 69 | right: r 70 | })) 71 | 72 | } else { 73 | Full(Box::new(Node { 74 | element: e, 75 | left : l, 76 | right: add(r,v) 77 | })) 78 | } 79 | } 80 | } 81 | } 82 | 83 | // both functional and mutable trees 84 | pub fn main() { 85 | let mut t1 = empty(); 86 | t1.add_mut(7); 87 | t1.add_mut(8); 88 | t1.add_mut(3); 89 | println!("{:?}", t1); 90 | 91 | let t2 = empty(); 92 | let t3 = add(t2, 7); 93 | let t4 = add(t3, 8); 94 | let t5 = add(t4, 3); 95 | println!("{:?}", t5); 96 | 97 | assert_eq!(t1, t5); 98 | 99 | } 100 | -------------------------------------------------------------------------------- /basics/src/expr.rs: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | 3 | println!("** exp.rs **"); 4 | 5 | let x: &str = match Some(("foo", 7)) { 6 | None => "none", 7 | Some((y @ "bar", _)) => y, 8 | Some(("foo", 7)) => "foo_7", 9 | _ => "anything else", 10 | }; 11 | println!("{}", x); 12 | 13 | // 1. declarations 14 | { 15 | let name: i64 = if 1 > 2 { 7 } else { 8 }; 16 | let name2 = if 1 > 2 { 7 } else { 8 }; 17 | assert_eq!(name, name2); 18 | } 19 | 20 | // 2 case analysis 21 | { 22 | // interesting: blocks evaluate to () 23 | #[allow(clippy::if_same_then_else)] 24 | let _v = if true { 25 | } else if 7 > 8 { 26 | } else { 27 | }; 28 | } 29 | 30 | // 3. matching 31 | { 32 | let _v = match (42, 3) { 33 | (0, 6) => "7", 34 | (1, 4) => "8", 35 | (2, 5) => "9", 36 | (3, 6) => "10", 37 | (4, 7) => "11", 38 | // non-exhaustive patterns, nice! 39 | _ => "sure", 40 | }; 41 | } 42 | 43 | // 4.0 enums 44 | { 45 | #[allow(dead_code)] 46 | enum Message { 47 | Quit, 48 | Move { x: i32, y: i32 }, 49 | Write(String), 50 | ChangeColor(i32, i32, i32), 51 | } 52 | let msg = Message::Write("my custom message".to_string()); 53 | 54 | let v: String = match msg { 55 | Message::Quit => "The Quit variant has no data to destructure.".to_string(), 56 | Message::Move { x, y } => { 57 | format!("Move in the x direction {} and in the y direction {}", x, y) 58 | } 59 | Message::Write(text) => text, 60 | Message::ChangeColor(r, g, b) => { 61 | format!("Change the color to red {}, green {}, and blue {}", r, g, b) 62 | } 63 | }; 64 | println!("{}", v); 65 | } 66 | 67 | // 4. matching on sum types 68 | { 69 | // generic ADT-like 70 | enum ETy { 71 | A { f: T, sz: u32 }, 72 | B { f: T, sz: u32, _a: u64 }, 73 | C { f: T, sz: u32, _count: u32 }, 74 | } 75 | 76 | let v1 = ETy::A { 77 | f: "my_v1".to_string(), 78 | sz: 7, 79 | }; 80 | let v2 = ETy::B { 81 | f: "my_v2".to_string(), 82 | sz: 8, 83 | _a: 7, 84 | }; 85 | let v3 = ETy::C { 86 | f: "my_v3".to_string(), 87 | sz: 7, 88 | _count: 0, 89 | }; 90 | 91 | let res = match (v2, v1, v3) { 92 | (ETy::A { f, sz, .. }, _, _) => format!("first is A : {} @ {}", f, sz), 93 | (ETy::B { f, sz, .. }, _, _) => format!("first is B : {} @ {}", f, sz), 94 | (ETy::C { f, sz, .. }, _, _) => format!("first is C : {} @ {}", f, sz), 95 | // unreachable!! _ => "fall through".to_string(), 96 | }; 97 | 98 | println!("{:?}", res); 99 | } 100 | 101 | // 5. if let 102 | { 103 | let v = Some("foo"); 104 | 105 | #[allow(clippy::redundant_pattern_matching)] 106 | if let None = v { 107 | println!("WAT"); 108 | } else { 109 | println!("OK"); 110 | }; 111 | } 112 | 113 | // 6. loops 114 | { 115 | let mut n: u64 = 1; 116 | while n < 100 { 117 | n *= 2; 118 | } 119 | println!("{}", n); 120 | 121 | let mut n: Option = Some(1); 122 | while let Some(x) = n { 123 | if x < 100 { 124 | n = Some(x * 2); 125 | } else { 126 | break; 127 | } 128 | } 129 | println!("{:?}", n); 130 | 131 | let mut i: u64 = 1; 132 | loop { 133 | if i >= 100 { 134 | break; 135 | } 136 | i *= 2; 137 | } 138 | println!("{:?}", i); 139 | 140 | // for is a 'map' over a collection. nice. 141 | let mut n: u64 = 0; 142 | for i in 0..20 { 143 | // n.b. while < 20!!! 144 | n += i; 145 | } 146 | println!("{:?}", n); 147 | 148 | let mut v = vec![]; 149 | for i in 0..20 { 150 | // 20 elements. last element has value '19' 151 | v.push(i); 152 | } 153 | println!("{:?}", v); 154 | println!("{:?}", v.len()); 155 | 156 | let strs: Vec = vec!["a".to_string(), "b".to_string()]; 157 | for s in &strs { 158 | println!("{}", s); 159 | } 160 | println!("{}", strs.len()); 161 | 162 | let mut strs: Vec = vec!["a".to_string(), "b".to_string()]; 163 | for s in &mut strs { 164 | s.push('#'); 165 | } 166 | println!("{:?}", strs); 167 | 168 | // interesting. loop lifetimes 169 | let bs = [1, 2, 3]; 170 | #[allow(clippy::never_loop)] 171 | 'foo: for _ in &bs { 172 | break 'foo; 173 | } 174 | 175 | // return expressions (!) 176 | { 177 | fn f0() { 178 | // return; // value of (). 179 | } 180 | #[allow(unreachable_code)] 181 | #[allow(clippy::diverging_sub_expression)] 182 | fn f1() -> usize { 183 | let _v = return 2 * 128; // weird 184 | 0 /* dead code */ 185 | } 186 | println!("{:?}", f0()); 187 | println!("{:?}", f1()); 188 | 189 | #[allow(unreachable_code)] 190 | #[allow(clippy::diverging_sub_expression)] 191 | fn f2<'a>() -> &'a [u64] { 192 | let _a: &[u64] = &[ 193 | 1, 194 | 2, 195 | return &[FOO], //f2 evaluates to this 196 | ]; 197 | println!("{:?}", _a); 198 | } 199 | println!("{:?}", f2()); 200 | } 201 | } 202 | 203 | // whoa. flow sensitive typing 204 | #[allow(unreachable_code)] 205 | { 206 | // break and return don't produce a value 207 | let mut n: u64 = 1; 208 | let a: () = while n < 10 { 209 | n *= 2 210 | }; 211 | println!("{:?}", a); 212 | println!("about to fix:"); 213 | 214 | // this produces a value of any type 215 | // this type is that it can be cast to any other one 216 | // a bottom value 217 | #[allow(dead_code)] 218 | fn fix() -> ! { 219 | loop { 220 | //break; // can't break if it diverges 221 | panic!(); 222 | } 223 | } 224 | // let _v: Option = fix(); 225 | 226 | // let _x: &[i32] = &[1, 2, undefined()]; 227 | 228 | // fix(); 229 | 230 | println!("fixed"); 231 | } 232 | 233 | // some syntax stuff 234 | { 235 | let mut x = /* Vec::with_capacity(1024); */ 236 | Vec::::with_capacity(1024); 237 | println!("{:?}", x.pop()); 238 | } 239 | 240 | } 241 | 242 | // can't have a 'return' outside of fn body : 243 | const FOO: u64 = /*return*/ 0xdeadbeef; 244 | 245 | #[allow(dead_code)] 246 | fn undefined() -> ! { 247 | loop {panic!()} 248 | } 249 | -------------------------------------------------------------------------------- /basics/src/expr2.rs: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | // ranges 3 | // ranges are 'half open'. they include the start value but not the end 4 | { 5 | // range full 6 | let a: std::ops::RangeFull = ..; 7 | let b: std::ops::RangeFull = std::ops::RangeFull; 8 | println!("{:?}", a); 9 | assert_eq!(a, b); 10 | 11 | // range full 12 | let a: std::ops::RangeFrom = true..; 13 | let b: std::ops::RangeFrom = std::ops::RangeFrom { start: true }; 14 | println!("{:?}", a); 15 | assert_eq!(a, b); 16 | 17 | // interesting. this goes to infinity and will die with a overflow error 18 | // NOT like enumFrom 19 | // let b: std::ops::RangeFrom = 1..; 20 | let b: std::ops::Range = 1..255; 21 | for i in b { 22 | print!("{}, ", i); 23 | } 24 | println!("done"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /basics/src/f64.rs: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | let m = 10.0_f64; 3 | let x = 4.0_f64; 4 | let b = 60.0_f64; 5 | 6 | // 100.0 7 | let abs_difference = (m.mul_add(x, b) - ((m * x) + b)).abs(); 8 | 9 | assert!(abs_difference < 1e-10); 10 | } 11 | -------------------------------------------------------------------------------- /basics/src/foo.rs: -------------------------------------------------------------------------------- 1 | // a module 2 | // public type 3 | #[derive(Debug)] 4 | pub struct Foo { 5 | deep_foo : u64, 6 | } 7 | 8 | // public interface 9 | pub fn new_foo(deep_foo: u64) -> Foo { 10 | new_secret_foo(deep_foo) 11 | } 12 | 13 | // not exported from the module 14 | fn new_secret_foo(deep_foo: u64) -> Foo { 15 | Foo { deep_foo } 16 | } 17 | 18 | #[test] 19 | fn main() { 20 | let foo = new_foo(42); 21 | println!("Foo: {:?}", foo); 22 | } 23 | -------------------------------------------------------------------------------- /basics/src/generics.rs: -------------------------------------------------------------------------------- 1 | // page 236: generics and traits 2 | 3 | fn min(a: T, b: T) -> T { 4 | if a < b { 5 | a 6 | } else { 7 | b 8 | } 9 | } 10 | 11 | pub fn main() { 12 | assert_eq!(min('a','b'), 'a'); 13 | assert_eq!(min("foo","bar"),"bar"); 14 | 15 | let vs = &vec![1,2,3,4,5,6,7]; 16 | println!("{}", elem(vs, 5)); 17 | println!("{}", elem(vs, 8)); 18 | println!("{}", elem(vs, -1)); 19 | println!("{}", elem(vs, 1)); 20 | 21 | let vs = &vec!['a','c']; 22 | println!("{}", elem(vs, 'a')); 23 | println!("{}", elem(vs, 'b')); 24 | println!("{}", elem(vs, 'c')); 25 | 26 | ex1(); 27 | } 28 | 29 | // write is a trait 30 | use std::io::Write; 31 | 32 | pub fn ex1() { 33 | let mut buf: Vec = vec![]; 34 | 35 | // trait object. 36 | let _w: &mut dyn Write = &mut buf; 37 | } 38 | 39 | pub fn elem

(vec:&[P], x: P) -> bool 40 | where P : PartialEq 41 | { 42 | for i in vec { 43 | if *i == x { 44 | return true 45 | } 46 | } 47 | false 48 | } 49 | -------------------------------------------------------------------------------- /basics/src/grep.rs: -------------------------------------------------------------------------------- 1 | // grep like thing pg 432 2 | 3 | use std::io; 4 | use std::io::prelude::*; 5 | 6 | fn grep(target: &str, reader: R) -> io::Result<()> 7 | where R: BufRead 8 | { 9 | // let stdin = io::stdin(); 10 | 11 | // taking the lock is in the api of stdin. interesting. not hidden in an mvar. 12 | for res in reader.lines() { 13 | let l = res?; 14 | if l.contains(target) { 15 | println!("{}", l); 16 | } 17 | } 18 | Ok(()) 19 | } 20 | 21 | pub fn main() { 22 | grep("for", io::stdin().lock()).unwrap(); 23 | } 24 | -------------------------------------------------------------------------------- /basics/src/impl.rs: -------------------------------------------------------------------------------- 1 | // page 198: impls 2 | #[derive(Debug)] 3 | pub struct Q { 4 | old: Vec, 5 | new: Vec, 6 | } 7 | 8 | impl Q { 9 | pub fn push(&mut self, c: char) { 10 | self.new.push(c); 11 | } 12 | 13 | pub fn is_empty(&self) -> bool { 14 | self.old.is_empty() && self.new.is_empty() 15 | } 16 | 17 | pub fn split(self) -> (Vec, Vec) { 18 | (self.old , self.new) 19 | } 20 | 21 | pub fn pop(&mut self) -> Option { 22 | use std::mem::swap; 23 | 24 | match (self.old.is_empty(), self.new.is_empty()) { 25 | (true, true) => None, 26 | 27 | (true, _) => { 28 | swap(&mut self.old, &mut self.new); 29 | self.old.reverse(); 30 | self.old.pop() 31 | } 32 | 33 | (false, _) => self.old.pop(), 34 | } 35 | } 36 | } 37 | 38 | pub fn main() { 39 | let mut q = Q { 40 | old: Vec::new(), 41 | new: Vec::new(), 42 | }; 43 | q.push('a'); // borrows a mutable ref to q 44 | q.push('b'); 45 | println!("{:?}", q); 46 | let c = q.pop(); 47 | println!("{:?}", c); 48 | let c = q.pop(); 49 | println!("{:?}", c); 50 | let c = q.pop(); 51 | println!("{:?}", c); 52 | 53 | println!("{}", q.is_empty()); 54 | 55 | let (a,_) = q.split(); 56 | println!("{:?}", a); 57 | } 58 | -------------------------------------------------------------------------------- /basics/src/impl2.rs: -------------------------------------------------------------------------------- 1 | pub struct Q { 2 | left: Vec, 3 | right: Vec 4 | } 5 | 6 | // holds references with the lifetime 'e 7 | #[derive(Debug)] 8 | struct E<'e> { 9 | biggest: &'e i32, 10 | smallest: &'e i32 11 | } 12 | 13 | #[derive(Copy, Clone, Debug, PartialEq)] 14 | struct P { 15 | x: T, 16 | y: T 17 | } 18 | 19 | fn find_e<'s>(slice: &'s [i32]) -> E/* lifetime omitted */ { 20 | let mut biggest: &'s i32 = &slice[0]; 21 | let mut smallest: &'s i32 = &slice[0]; 22 | for p in slice.iter().skip(1) { 23 | if *p < *smallest { smallest = p; } 24 | if *p > *biggest { biggest = p; } 25 | } 26 | E { biggest, smallest } 27 | } 28 | 29 | // OO style 30 | impl Q { 31 | pub fn new() -> Self /* interesting */ { 32 | Q { left: Vec::new(), right: Vec::new() } 33 | } 34 | 35 | pub fn push(&mut self, t: T) { 36 | self.right.push(t); 37 | } 38 | 39 | pub fn is_empty(&self) -> bool { 40 | self.right.is_empty() && self.left.is_empty() 41 | } 42 | } 43 | 44 | // free functions style 45 | pub fn new_q() -> Q { 46 | Q::new() 47 | } 48 | 49 | pub fn push_q(q: &mut Q, t: T) { 50 | Q::push(q, t); 51 | } 52 | 53 | pub fn is_empty_q(q: &Q) -> bool { 54 | Q::is_empty(q) 55 | } 56 | 57 | // interesting bias towards mutable state 58 | pub fn main() { 59 | let mut q1: Q = Q::new(); 60 | let r1: Q = new_q(); 61 | assert_eq!(is_empty_q(&r1), true); 62 | assert_eq!(is_empty_q(&q1), true); 63 | assert_eq!(q1.is_empty(), true); 64 | push_q(&mut q1,42); 65 | q1.push(42); 66 | assert_eq!(!q1.is_empty(), true); 67 | 68 | let a = [0, -3, 2, 1, 15, 100, 98]; 69 | let e = find_e(&a); 70 | println!("{:?}", e); 71 | 72 | let a = P { x: 0., y: 0.}; 73 | let b = a; // copy 74 | println!("{:?}", a); 75 | if a == b { 76 | println!("equal"); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /basics/src/io.rs: -------------------------------------------------------------------------------- 1 | // ch18: IO . page 432. 2 | // 3 | use std::fs::File; 4 | 5 | pub fn main() { 6 | let h = File::open("io.rs").unwrap(); 7 | let m = h.metadata().unwrap(); 8 | println!("{:?}", m); 9 | 10 | assert_eq!(false, m.is_dir()); 11 | 12 | let mut one = File::open("io.rs").unwrap(); 13 | let mut two = File::create("/tmp/io.rs").unwrap(); 14 | copy(&mut one, &mut two).unwrap(); 15 | 16 | // higher level io 17 | { 18 | let mut one = File::open("io.rs").unwrap(); 19 | let mut v = Vec::new(); 20 | one.read_to_end(&mut v).unwrap(); 21 | println!("{}", v.len()); 22 | 23 | let mut one = File::open("io.rs").unwrap(); 24 | let mut s = String::new(); 25 | one.read_to_string(&mut s).unwrap(); 26 | println!("{}", &s[0..22]); 27 | } 28 | } 29 | 30 | use std::io::{self, Read, Write, ErrorKind}; 31 | 32 | const DEFAULT_BUF_SIZE: usize = 8 * 1024; 33 | 34 | // generic copy of buffers 35 | pub fn copy(reader: &mut R, writer: &mut W) 36 | -> io::Result 37 | where R: Read, W: Write 38 | { 39 | let mut buf = [0; DEFAULT_BUF_SIZE]; 40 | let mut count = 0; 41 | 42 | loop { 43 | let len = match reader.read(&mut buf) { 44 | Ok(0) => return Ok(count), 45 | Ok(len) => len, 46 | Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, 47 | Err(e) => return Err(e), 48 | }; 49 | writer.write_all(&buf[..len])?; 50 | count += len as u64; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /basics/src/iter.rs: -------------------------------------------------------------------------------- 1 | // ch 15: pg 322 2 | 3 | pub fn main() { 4 | // introduction 5 | 6 | #[allow(clippy::while_let_on_iterator)] 7 | #[allow(clippy::into_iter_on_ref)] 8 | { 9 | let v = vec!["abc", "abcd", "foo", "bar"]; 10 | for e in &v { 11 | println!("{}", e); 12 | } 13 | 14 | // vec ref to iterator 15 | let mut i = (&v).into_iter(); 16 | while let Some(e) = i.next() { 17 | println!("{}", e); 18 | } 19 | 20 | // vec ref to iterator 21 | let mut i = 1..10; // directly construct an iterator object 22 | while let Some(e) = i.next() { 23 | println!("{}", e); 24 | } 25 | println!("{:?}", i.next()); 26 | println!("{:?}", i.next()); 27 | } 28 | 29 | // generation 30 | 31 | // generating iterators by references and values 32 | #[allow(clippy::into_iter_on_ref)] 33 | { 34 | use std::collections::BTreeSet; 35 | let mut f = BTreeSet::new(); 36 | f.insert("foos".to_string()); 37 | f.insert("bars".to_string()); 38 | 39 | // some kind of traversal 40 | let r = &f; 41 | let mut i = r.into_iter(); // shared mut ref 42 | assert_eq!(i.next(), Some(&"bars".to_string())); 43 | assert_eq!(i.next(), Some(&"foos".to_string())); 44 | assert_eq!(i.next(), None); 45 | 46 | let mut i = f.into_iter(); 47 | assert_eq!(i.next(), Some("bars".to_string())); 48 | 49 | // by value 50 | } 51 | 52 | // generics 53 | { 54 | use std::fmt::Debug; 55 | 56 | fn dump(t: T) 57 | where 58 | T: IntoIterator, 59 | U: Debug, 60 | { 61 | for u in t { 62 | println!("{:?}", u); 63 | } 64 | } 65 | let v = vec!["abc", "abcd", "foo", "bar"]; 66 | dump(v); 67 | } 68 | 69 | // drain: passes ownership , drops the rest 70 | { 71 | use std::iter::FromIterator; 72 | 73 | // take a slice 74 | let mut outer = "Earth".to_string(); 75 | let inner = String::from_iter(outer.drain(1..4)); 76 | assert_eq!(outer, "Eh"); 77 | assert_eq!(inner, "art"); 78 | } 79 | 80 | // instances 81 | #[allow(clippy::unnecessary_fold)] 82 | { 83 | let i = 1i32..100; // .into_iter(); 84 | println!("{}", i.fold(0, |n, i| n + i)); 85 | 86 | // loops 0 or 1 times 87 | for i in Some(1).iter() { 88 | println!("{}", i); 89 | } 90 | 91 | // interesting slices on vectors 92 | let v = vec![1i64; 1024]; 93 | println!("{}", v.windows(4).len()); // 4-element long prefix scans? 94 | println!("{}", v.chunks(16).len()); // 64 * 16 chunks of v 95 | 96 | // tokenize 97 | let o = &[ 98 | "asdbaf".to_string(), 99 | "df".to_string(), 100 | "ASDfdsa".to_string(), 101 | "TOK".to_string(), 102 | "Dsdfa".to_string(), 103 | ]; 104 | for i in o.split(|b| *b == "TOK") { 105 | for l in i { 106 | print!("{}-", l); 107 | } 108 | println!(); 109 | } 110 | } 111 | 112 | // adaptors ("transformers") 113 | // more parsing stuff 114 | { 115 | let text = " ponies \n giraffes \n monkeys\nsquid".to_string(); 116 | let v: Vec<&str> = 117 | text.lines() 118 | .map(str::trim) 119 | .filter(|s| *s != "monkeys") 120 | .collect(); 121 | assert_eq!(v, ["ponies","giraffes","squid"]); 122 | 123 | } 124 | 125 | // laziness 126 | #[allow(unused_must_use)] 127 | { 128 | // this does nothing 129 | ["launch","the","missles"].iter().map(|e|println!("fire: {}",e)); 130 | } 131 | 132 | // more functions 133 | { 134 | let j = (0i64..100) // twice to avoid sharing 135 | .filter_map(|n| if n % 2 == 0 { Some (n*2) } else { None }) 136 | .take(10); 137 | for i in j { 138 | println!("{}",i); 139 | } 140 | let k = (0i64..100) 141 | .filter(|n| n % 2 == 0) 142 | .map(|n| n * 2) 143 | .take(10); 144 | for i in k { 145 | println!("{}",i); 146 | } 147 | 148 | use std::str::FromStr; 149 | 150 | let text ="1\nfrond .25 289\n3.1415 estuary\n"; 151 | for n in text.split_whitespace() 152 | .filter_map(|w| f64::from_str(w).ok()) { 153 | println!("{:4.2}", n.sqrt()); 154 | } 155 | } 156 | 157 | // flat_map / concat_map 158 | { 159 | let j = 0i64 .. 20; 160 | let k: Vec> = j.map(|i| { (0 .. i).collect() }).collect(); 161 | for x in k { 162 | let l = x.len(); 163 | for _ in x { 164 | print!("#"); 165 | } 166 | println!("{}",l); 167 | } 168 | 169 | use std::collections::HashMap; 170 | 171 | let mut ms = HashMap::new(); 172 | ms.insert("Japan", vec!["Tokyo", "Kyoto"]); 173 | ms.insert("Australia", vec!["Sydney", "Darwin"]); 174 | 175 | let countries = ["Australia", "Japan"]; 176 | 177 | // flatten a set of keys. index into a hashtable 178 | for &city in countries.iter().flat_map(|c| &ms[c]) { 179 | println!("{}",city); 180 | } 181 | } 182 | 183 | // scan 184 | { 185 | let iter = (0..20) 186 | .scan(0, |sum, i| { // short circuiting scanl 187 | *sum += i; 188 | if *sum > 1000 { 189 | None 190 | } else { 191 | Some(i * i) 192 | } 193 | }); 194 | 195 | for x in iter.collect::>() { 196 | print!("{}-",x); 197 | } 198 | println!(); 199 | 200 | } 201 | 202 | // take , take_while 203 | { 204 | let iter = (0..20) 205 | .take_while(|n| *n <= 10) 206 | .take(3); 207 | for x in iter.collect::>() { 208 | print!("{}-",x); 209 | } 210 | println!(); 211 | 212 | } 213 | 214 | // skips (can't call it drop!) 215 | { 216 | let iter = (0..20) 217 | .skip_while(|n| *n <= 10) 218 | .skip(3); 219 | for x in iter.collect::>() { 220 | print!("{}-",x); 221 | } 222 | println!(); 223 | } 224 | 225 | // peekable... look at the next item in the iterator but dont' consume it. lookahead? 226 | { 227 | use std::iter::Peekable; 228 | 229 | // pull first set of digits off a string 230 | fn parse_number (toks: &mut Peekable) -> u32 231 | where I: Iterator 232 | { 233 | let mut n = 0; 234 | loop { 235 | match toks.peek() { 236 | Some(r) if r.is_digit(10) => { 237 | n = n*10 + r.to_digit(10).unwrap(); 238 | } 239 | _ => return n 240 | } 241 | toks.next(); 242 | } 243 | } 244 | // iterator of characters 245 | let mut chars = "226153290,112312321".chars().peekable(); 246 | 247 | let x = parse_number(&mut chars); 248 | println!("{:?}",x); 249 | let x = parse_number(&mut chars); 250 | println!("{:?}",x); 251 | chars.next(); // bump state. 252 | let x = parse_number(&mut chars); 253 | println!("{:?}",x); 254 | } 255 | 256 | // fuse : Iterators are stateful, you can observe if they have been evaluated 257 | { 258 | // fuse ensures an adaptor that returns None idempotently continues to do so 259 | struct Flaky(bool); 260 | 261 | impl Iterator for Flaky { 262 | type Item = &'static str; 263 | 264 | // sort of a boolean state machine 265 | fn next(&mut self) -> Option { 266 | if self.0 { 267 | self.0 = false; 268 | Some("the last item") 269 | } else { 270 | self.0 = true; // flip flop 271 | None 272 | } 273 | } 274 | } 275 | 276 | let mut f = Flaky(true); 277 | assert_eq!(f.next(), Some("the last item")); 278 | assert_eq!(f.next(), None); 279 | assert_eq!(f.next(), Some("the last item")); 280 | 281 | let mut f1 = Flaky(true).fuse(); 282 | assert_eq!(f1.next(), Some("the last item")); 283 | assert_eq!(f1.next(), None); 284 | assert_ne!(f1.next(), Some("the last item")); 285 | } 286 | 287 | // reversible/ double ended iterators. a next_back() method 288 | // useful for arrays/slices 289 | { 290 | let bee = ["head", "thorax", "abdomen"]; 291 | 292 | let mut iter = bee.iter(); 293 | 294 | assert_eq!(iter.next() , Some(&"head")); 295 | assert_eq!(iter.next_back() , Some(&"abdomen")); 296 | assert_eq!(iter.next() , Some(&"thorax")); 297 | assert_eq!(iter.next_back() , None); 298 | 299 | let ns: std::ops::Range = 1..100; 300 | let mut i = ns.rev(); 301 | assert_eq!(i.next() , Some(99)); 302 | 303 | } 304 | 305 | // inspect: debugging the composition of iterators 306 | { 307 | let uc: String = "groSsse".chars() 308 | .inspect(|c| println!("before: {:?}", c)) 309 | .flat_map(|c| c.to_uppercase()) 310 | .inspect(|c| println!("after: {:?}", c)) 311 | .collect(); 312 | assert_eq!(uc, "GROSSSE"); 313 | } 314 | 315 | // chaining - appending. 316 | { 317 | let a = 1..10; 318 | let b = -20..-10; 319 | let vs: Vec = a.chain(b).collect(); 320 | println!("{:?}", vs); 321 | } 322 | 323 | // enumerate. zipwith count 324 | { 325 | let a = -20 .. -10; 326 | let vs: Vec<(usize,i64)> = a.enumerate().collect(); 327 | println!("{:?}", vs); 328 | } 329 | 330 | // zip. length of the shortest iterator 331 | { 332 | let a = -20 .. -10; 333 | let b = -2 .. 10; 334 | let vs: Vec<(i64,i64)> = a.zip(b).collect(); 335 | println!("{:?}", vs); 336 | } 337 | 338 | // using by ref than handing it back 339 | { 340 | let ms = "To: foo\r\n\ 341 | From: id\r\n\ 342 | \r\n 343 | Ooooh\r\n"; 344 | let mut lines = ms.lines(); 345 | println!("Headers:"); 346 | for h in lines.by_ref().take_while(|l| !l.is_empty()) { 347 | println!("{}", h); 348 | } 349 | println!("Body:"); 350 | for b in lines { 351 | println!("{}", b); 352 | } 353 | 354 | } 355 | 356 | // a cloning iterator 357 | { 358 | let a = ['1', '2', '3']; 359 | assert_eq!(a.iter().next(), Some(&'1')); 360 | assert_eq!(a.iter().cloned().next(), Some('1')); 361 | } 362 | 363 | // cycle! 364 | { 365 | let a = 0i64..4; 366 | let v = a.cycle(); 367 | println!("{:?}", v.take(20).collect::>()); 368 | 369 | } 370 | 371 | // fizz buzz in a lazy list style 372 | { 373 | use std::iter::{once, repeat}; 374 | 375 | let fizzes = repeat("").take(2).chain(once("fizz")).cycle(); 376 | let buzzes = repeat("").take(4).chain(once("buzz")).cycle(); 377 | 378 | let fizz_buzz = (1..10).zip(fizzes.zip(buzzes)) 379 | .map(|i| 380 | match i { 381 | (i, ("","")) => i.to_string(), 382 | (_, (f,b)) => format!("{}{}", f, b) 383 | }); 384 | for l in fizz_buzz { 385 | println!("{}", l); 386 | } 387 | 388 | } 389 | 390 | // consuming 391 | { 392 | println!("{}", (1..30).by_ref().product::()); 393 | println!("{}", (1..30).sum::()); 394 | println!("{:?}", (1..30).max()); 395 | println!("{:?}", (1..30).min()); 396 | 397 | println!("{}", [0., 1. , 3.].iter().sum::()); 398 | 399 | use std::cmp::Ordering; 400 | 401 | fn cmp(lhs: &&f64, rhs: &&f64) -> Ordering { 402 | match lhs.partial_cmp(rhs) { 403 | Some(x) => x, 404 | _ => Ordering::Less 405 | } 406 | } 407 | let ns = [1., 4., std::f64::NAN, 2.]; 408 | assert_eq!(ns.iter().max_by(cmp), Some(&2.)); 409 | } 410 | 411 | } 412 | -------------------------------------------------------------------------------- /basics/src/json.rs: -------------------------------------------------------------------------------- 1 | // 2 | // barebones 2008-era JSON pretty printer 3 | // Rough port of 4 | // https://github.com/GaloisInc/json/blob/master/Text/JSON/Pretty.hs 5 | // https://github.com/GaloisInc/json/blob/master/Text/JSON/Types.hs 6 | // 7 | 8 | extern crate num; 9 | extern crate pretty; 10 | 11 | use num::rational::{Ratio, Rational64}; 12 | use pretty::RcDoc as R; 13 | 14 | // type of JSON values 15 | #[derive(Debug, PartialEq)] 16 | pub enum JSValue { 17 | JSNull, 18 | JSBool(bool), 19 | JSRational(Rational64), 20 | JSString(String), 21 | JSArray(Vec), 22 | JSObject(Vec<(JSLabel, JSValue)>), 23 | } 24 | 25 | #[derive(Debug, PartialEq)] 26 | pub struct JSLabel(String); 27 | 28 | // pretty printing 29 | impl JSValue { 30 | pub fn to_doc(&self) -> R<()> { 31 | pp_value(self) 32 | } 33 | 34 | pub fn to_pretty(&self, width: usize) -> String { 35 | let mut w = Vec::new(); 36 | self.to_doc().render(width, &mut w).unwrap(); 37 | String::from_utf8(w).unwrap() 38 | } 39 | } 40 | 41 | // Print a generic value 42 | fn pp_value(v: &JSValue) -> R<()> { 43 | match *v { 44 | J::JSNull => pp_null(), 45 | J::JSBool(b) => pp_bool(b), 46 | J::JSRational(r) => pp_number(r), 47 | J::JSString(ref s) => pp_string(s), 48 | J::JSArray(ref v) => pp_array(v), 49 | J::JSObject(ref v) => pp_object(v), 50 | } 51 | } 52 | 53 | fn pp_null<'a>() -> R<'a, ()> { 54 | R::text("null") 55 | } 56 | 57 | fn pp_bool<'a>(v: bool) -> R<'a, ()> { 58 | R::text(if v { "true" } else { "false" }) 59 | } 60 | 61 | fn pp_number<'a>(x: Rational64) -> R<'a, ()> { 62 | // denominator == 1 63 | if Ratio::is_integer(&x) { 64 | R::text(format!("{}", x)) 65 | } else { /* hack */ 66 | let y:f64 = *Ratio::numer(&x) as f64 / *Ratio::denom(&x) as f64; 67 | R::text(format!("{}", y)) 68 | } 69 | } 70 | 71 | fn pp_string(s: &str) -> R<()> { 72 | let ts: Vec> = s.chars().map(pp_char).collect(); 73 | double_quotes(R::concat(ts)) 74 | } 75 | 76 | fn pp_char<'a>(c: char) -> R<'a, ()> { 77 | match c { 78 | '\\' => R::text("\\\\"), 79 | '"' => R::text(r#"\\""#), 80 | c if c.is_control() => { 81 | let s: String = c.escape_unicode().collect(); 82 | R::text(s) 83 | } 84 | _ => R::text(c.to_string()), 85 | } 86 | } 87 | 88 | fn pp_array(vs: &[JSValue]) -> R<()> { 89 | let ts: Vec> = vs.iter().map(pp_value).collect(); 90 | brackets(R::intersperse(ts, R::text(COMMA))) 91 | } 92 | 93 | fn pp_object(vs: &[(JSLabel, JSValue)]) -> R<()> { 94 | let ts: Vec> = vs.iter().map(pp_field).collect(); 95 | braces(R::intersperse(ts, R::text(COMMA))) 96 | } 97 | 98 | fn pp_field((JSLabel(k), v): &(JSLabel, JSValue)) -> R<()> { 99 | pp_string(k) 100 | .append(R::text(":")) 101 | .append(R::space()) 102 | .append(pp_value(v)) 103 | } 104 | 105 | const DOUBLE_QUOTE: &str = &r#"""#; 106 | const LEFT_BRACKET: &str = &r#"["#; 107 | const RIGHT_BRACKET: &str = &r#"]"#; 108 | const LEFT_BRACE: &str = &r#"{"#; 109 | const RIGHT_BRACE: &str = &r#"}"#; 110 | const COMMA: &str = &r#","#; 111 | 112 | fn double_quotes(d: R<()>) -> R<()> { 113 | R::text(DOUBLE_QUOTE) 114 | .append(d) 115 | .append(R::text(DOUBLE_QUOTE)) 116 | } 117 | 118 | fn brackets(d: R<()>) -> R<()> { 119 | R::text(LEFT_BRACKET) 120 | .append(d) 121 | .append(R::text(RIGHT_BRACKET)) 122 | } 123 | 124 | fn braces(d: R<()>) -> R<()> { 125 | R::text(LEFT_BRACE).append(d).append(R::text(RIGHT_BRACE)) 126 | } 127 | 128 | // test 129 | 130 | use self::JSValue as J; 131 | 132 | pub fn main() { 133 | assert_eq!("null", J::JSNull.to_pretty(80)); 134 | assert_eq!("true", J::JSBool(true).to_pretty(80)); 135 | assert_eq!("false", J::JSBool(false).to_pretty(80)); 136 | 137 | let n = Ratio::from_integer(12); 138 | assert_eq!("12", J::JSRational(n).to_pretty(80)); 139 | 140 | let n = Ratio::new_raw(1, 2); 141 | assert_eq!("0.5", J::JSRational(n).to_pretty(80)); 142 | 143 | assert_eq!(r#""foo""#, J::JSString("foo".to_string()).to_pretty(80)); 144 | assert_eq!( 145 | r#""f\\"oo""#, 146 | J::JSString(r#"f"oo"#.to_string()).to_pretty(80) 147 | ); 148 | assert_eq!( 149 | r#""f❤o\u{9c}""#, 150 | J::JSString(r#"f❤oœ"#.to_string()).to_pretty(80) 151 | ); 152 | 153 | let v = J::JSArray(vec![J::JSNull, J::JSBool(true), J::JSBool(false)]); 154 | assert_eq!("[null,true,false]", v.to_pretty(80)); 155 | 156 | let o = J::JSObject(vec![ 157 | (JSLabel("A".to_string()), J::JSNull), 158 | (JSLabel("B".to_string()), J::JSBool(true)), 159 | ]); 160 | assert_eq!(r#"{"A": null,"B": true}"#, o.to_pretty(80)); 161 | } 162 | -------------------------------------------------------------------------------- /basics/src/lib.rs: -------------------------------------------------------------------------------- 1 | // interesting. no tail recursion 2 | // the obvious way: 3 | #[inline] 4 | pub fn sum_f1(n: u64) -> u64 { 5 | f1_go(n,0) 6 | } 7 | 8 | fn f1_go(n:u64, acc:u64) -> u64 { 9 | if n == 0 { 10 | acc 11 | } else { 12 | f1_go(n-1, acc + n) 13 | } 14 | } 15 | 16 | // explicit loop with mutable params 17 | #[inline] 18 | pub fn sum_f2(n: u64) -> u64 { 19 | let mut acc = 0; 20 | let mut m = n; 21 | loop { 22 | if m == 0 { 23 | return acc; 24 | } else { 25 | acc += m; 26 | m -= 1; 27 | } 28 | } 29 | } 30 | 31 | // 32 | #[inline] 33 | pub fn sum_f3(n: u64) -> u64 { 34 | let mut acc = 0; 35 | for m in 1 .. (n+1) { 36 | acc += m; 37 | } 38 | acc 39 | } 40 | -------------------------------------------------------------------------------- /basics/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | use std::panic as std_panic; 3 | 4 | mod bintree; 5 | mod bounds; 6 | mod cast; 7 | mod closures; 8 | mod collect; 9 | mod collect1; 10 | mod compare; 11 | mod copytypes; 12 | mod r#enum; 13 | mod r#enum2; 14 | mod expr2; 15 | mod expr; 16 | mod foo; 17 | mod generics; 18 | mod r#impl; 19 | mod r#impl2; 20 | mod io; 21 | mod iter; 22 | mod r#json; 23 | mod lib; 24 | mod mod2; 25 | mod modules; 26 | mod mutable; 27 | mod operators; 28 | mod ownership; 29 | mod panic; 30 | mod pattern; 31 | mod r#break; 32 | mod r#f64; 33 | mod rc; 34 | mod result; 35 | mod sharing; 36 | mod r#struct; 37 | mod r#trait; 38 | mod types; 39 | mod vecdeque; 40 | mod unicode; 41 | 42 | fn main() { 43 | let mut ns: Vec = Vec::new(); 44 | 45 | for arg in std::env::args().skip(1) { 46 | let i = u64::from_str(&arg); 47 | let r = i.expect("Parser error on numeric argument"); 48 | ns.push(r); 49 | } 50 | 51 | if ns.is_empty() { 52 | eprintln!("Usage: gcd NUMBER ..."); 53 | std::process::exit(1); 54 | } 55 | 56 | // foldl1 over args 57 | let mut r1 = ns[0]; // there's at least one argument 58 | for p in &ns[1..] { 59 | r1 = gcd(r1, *p); 60 | } 61 | 62 | println!("The GCD of {:?} is {}", ns, r1); 63 | 64 | let s1 = str_games("I see the eigenvalue in thine eye"); 65 | println!("{}", s1); 66 | 67 | let b1 = array_stuff_2(); 68 | for _ in 2 .. 10 { 69 | println!("{:?}", b1[0]); 70 | } 71 | 72 | let (v1,u1) = vec_stuff(); 73 | for i in &v1 { 74 | println!("{:?}", *i); 75 | } 76 | let f = |x: Vec| x.iter().product::(); // fold(1, |a,b| a*b); 77 | println!("PRODUCT = {}", f(v1)); 78 | println!("PRODUCT = {}", f(u1)); 79 | 80 | let s: Vec<&str> = vec!["a man", "a plan", "a canal", "panama"]; 81 | let t = vec_reverse_functional(s); // moves s to vec_stuff 82 | // can't use s now 83 | for l in t { 84 | println!("str := {}", l); 85 | } 86 | 87 | // foo module 88 | let f = foo::new_foo(43); 89 | println!("Foo: {:?}", f); 90 | 91 | // break module 92 | r#break::break_main(); 93 | 94 | bintree::main(); 95 | bounds::main(); 96 | cast::cast_main(); 97 | closures::main(); 98 | collect::main(); 99 | collect1::main(); 100 | compare::main(); 101 | copytypes::main(); 102 | r#enum::main(); 103 | r#enum2::main(); 104 | expr::main(); 105 | expr2::main(); 106 | generics::main(); 107 | r#f64::main(); 108 | r#impl::main(); 109 | r#impl2::main(); 110 | io::main(); 111 | iter::main(); 112 | r#json::main(); 113 | modules::main(); 114 | mutable::main(); 115 | mod2::main(); 116 | 117 | println!("{}", lib::sum_f1(1000)); 118 | println!("{}", lib::sum_f2(1000)); 119 | println!("{}", lib::sum_f3(1000)); 120 | 121 | operators::main(); 122 | ownership::main(); 123 | 124 | { 125 | let r = std_panic::catch_unwind(|| { 126 | panic::main(); // done 127 | }); 128 | assert!(r.is_err()); 129 | } 130 | pattern::main(); 131 | 132 | rc::main(); 133 | result::main(); 134 | sharing::main(); 135 | r#struct::main(); 136 | r#trait::main(); 137 | types::main(); 138 | vecdeque::main(); 139 | unicode::main(); 140 | 141 | println!("All done, thankyou."); 142 | } 143 | 144 | fn gcd(mut n: u64, mut m: u64) -> u64 { 145 | assert!(n != 0 && m != 0); 146 | while m != 0 { 147 | if m < n { 148 | std::mem::swap(&mut m, &mut n); 149 | } 150 | m %= n; 151 | } 152 | n 153 | } 154 | 155 | #[test] 156 | fn test_gcd() { 157 | assert_eq!(gcd(14, 15), 1); 158 | assert_eq!(gcd(2 * 3 * 5 * 11 * 17, 3 * 77 * 11 * 13 * 19), 3 * 11); 159 | } 160 | 161 | #[allow(dead_code)] 162 | // allocate a new vector and poke some values in 163 | fn build_vector() -> Vec { 164 | let mut v = Vec::new(); 165 | v.push(10i16); 166 | v.push(20); 167 | v 168 | } 169 | 170 | fn str_games(t: &str) -> String { 171 | let (x, _xs) = str::split_at(t,21); 172 | let t = (12, "eggs"); // stack allocated. unboxed 173 | let _b = Box::new(t); 174 | x.to_string() 175 | } 176 | 177 | #[test] 178 | fn array_stuff() { 179 | let lazy_caterer: [u32; 6] = [1, 2, 4, 7, 11, 16]; 180 | let taxonomy = ["Animalia", "Anthropoda", "Insecta"]; 181 | 182 | assert_eq!(lazy_caterer[3], 7); 183 | assert_eq!(taxonomy.len(), 3); 184 | } 185 | 186 | 187 | 188 | fn array_stuff_2() -> Box<[bool]> { 189 | const A_LIM: usize = 10000; 190 | let mut sieve = [true; A_LIM]; 191 | for i in 2..100 { 192 | if sieve[i] { 193 | let mut j = i * i; 194 | while j < A_LIM { 195 | sieve[j] = false; 196 | j += i; 197 | } 198 | } 199 | } 200 | assert!(sieve[211]); 201 | assert!(!sieve[9876]); 202 | 203 | Box::new(sieve) 204 | } 205 | 206 | fn vec_stuff() -> (Vec, Vec) { 207 | let v: Vec = vec![2, 3, 5, 7]; // via a macro 208 | 209 | let u: Vec = (1..6).collect(); 210 | 211 | assert_eq!(v.iter().product::(), 210); //fold(1, |a, b| a * b), 210); 212 | (u,v) 213 | } 214 | 215 | fn vec_reverse_functional(mut s: Vec<&str>) -> Vec<&str> { 216 | s.reverse(); 217 | s // returns the borrowed value 218 | } 219 | 220 | #[allow(dead_code)] 221 | fn str_stuff() { 222 | let noodles: String = "noodles".to_string(); // copied, construct a boxed String 223 | let _oodles: &str = &noodles[1..]; // a slice 224 | let _poodles: &str = "abc"; 225 | let _zoodles = &noodles[0..2]; 226 | } 227 | 228 | -------------------------------------------------------------------------------- /basics/src/mod2.rs: -------------------------------------------------------------------------------- 1 | // rebinding a path 2 | // extern crate std as prelude; 3 | 4 | // extern crate std::prelude::v1; 5 | 6 | // items 7 | pub mod m { 8 | 9 | pub fn mk_e_v() -> E { 10 | E::EV(V { v: 7 }) 11 | } 12 | 13 | #[derive(Debug)] 14 | pub struct V { 15 | v: T, 16 | } 17 | #[derive(Debug)] 18 | pub struct U { 19 | u: T, 20 | } 21 | 22 | #[derive(Debug)] 23 | pub enum E { 24 | EV(V), 25 | _EU(U), 26 | } 27 | 28 | #[derive(Debug)] 29 | pub enum Tree<'a, T> { 30 | Node { 31 | left: &'a Tree<'a, T>, 32 | right: &'a Tree<'a, T>, 33 | value: T, // unboxed 34 | }, 35 | Empty, 36 | } 37 | 38 | // inlined: 39 | // pub const EMPTY_TREE_CONST: Tree = Tree::Empty; 40 | 41 | // at program initialization time 42 | pub static EMPTY_TREE: Tree = Tree::Empty; 43 | 44 | // constructors 45 | pub fn mk_one_node<'a, T>(v: T) -> Tree<'a, T> { 46 | Tree::Node { 47 | left: &Tree::Empty, 48 | right: &Tree::Empty, 49 | value: v, 50 | } 51 | } 52 | } 53 | 54 | pub fn main() { 55 | let x: m::E = m::mk_e_v(); 56 | println!("{:?}", x); 57 | 58 | use m::Tree; 59 | 60 | type T<'a> = Tree<'a, u64>; 61 | 62 | // Empty 63 | let zero: &Tree<'static,u64> = &m::EMPTY_TREE; 64 | 65 | // Node { left: Empty, right: Empty, value: 1 } 66 | let one: T = m::mk_one_node(1); 67 | 68 | let two: T = Tree::Node { 69 | left: &one, 70 | right: &one, 71 | value: 1, 72 | }; 73 | 74 | println!("{:?}", zero); 75 | println!("{:?}", one); 76 | println!("{:?}", two); 77 | } 78 | -------------------------------------------------------------------------------- /basics/src/modules.rs: -------------------------------------------------------------------------------- 1 | // examples with modules 2 | 3 | // 'mem' becomes a local alias for 'std::mem' path 4 | use std::mem; 5 | use std::collections::HashMap; 6 | 7 | pub fn main() { 8 | // paths and imports 9 | { 10 | let mut s1 = 1; 11 | let mut s2 = 2; 12 | if s1 > s2 { 13 | mem::swap(&mut s1, &mut s2); 14 | } 15 | println!("swapped: {} {}", s2, s1); 16 | 17 | } 18 | 19 | // local aliases 20 | { 21 | let mut x = HashMap::::new(); 22 | x.insert("foo".to_string(), 42); 23 | x.insert("bar".to_string(), 41); 24 | println!("{}", x.len()); 25 | } 26 | 27 | // module use 28 | { 29 | let x = m::new_a(42); 30 | println!("{:?}", x); 31 | } 32 | } 33 | 34 | #[derive(Debug)] 35 | pub struct A { a : u64 } 36 | 37 | mod m { 38 | // super is an alias for the parent module 39 | // 'self' is an alias for the currnent one 40 | use super::A; // only imports public things 41 | 42 | pub fn new_a(a: u64) -> A { 43 | A { a } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /basics/src/mutable.rs: -------------------------------------------------------------------------------- 1 | // Interior mutability 2 | 3 | use std::fs::File; 4 | use std::mem::MaybeUninit; 5 | use std::cell::RefCell; 6 | 7 | #[derive(Debug)] 8 | pub struct Spider { 9 | species: String, 10 | web: bool, 11 | legs: [File;8], 12 | err_count: RefCell, 13 | } 14 | 15 | fn mk_spider() -> Result { 16 | 17 | let fs: [File;8] = { 18 | 19 | let mut fs: [MaybeUninit;8] = unsafe { 20 | MaybeUninit::uninit().assume_init() 21 | }; 22 | 23 | for (i,p) in fs.iter_mut().enumerate() { 24 | let f = File::create(format!("/tmp/f-{}.txt", i))?; 25 | *p = MaybeUninit::new(f); 26 | } 27 | 28 | // now convert 29 | unsafe { std::mem::transmute::<_,[File;8]>(fs) } 30 | }; 31 | 32 | Ok( 33 | Spider { 34 | species: "scary".to_string(), 35 | web: false, 36 | legs: fs, 37 | err_count: RefCell::new(0), 38 | } 39 | ) 40 | } 41 | 42 | pub fn main() { 43 | let spider = mk_spider().expect("Unable to create spider!"); 44 | println!("{:?}",spider); 45 | } 46 | -------------------------------------------------------------------------------- /basics/src/operators.rs: -------------------------------------------------------------------------------- 1 | // ch12 operator overloading 2 | 3 | #[derive(Clone,Copy,Debug)] 4 | struct Complex { 5 | re: T, 6 | im: T 7 | } 8 | 9 | // unary operators 10 | use std::ops::{Neg,Add}; 11 | 12 | impl Neg for Complex where T: Neg { 13 | type Output = Complex; 14 | fn neg(self) -> Self::Output { 15 | Complex { re: -self.re, im: -self.im } 16 | } 17 | } 18 | 19 | impl Add> for Complex 20 | where L: Add 21 | { 22 | type Output = Complex; 23 | fn add(self, rhs: Complex) -> Self::Output { 24 | Complex { re: self.re + rhs.re 25 | , im: self.im + rhs.im } 26 | } 27 | } 28 | 29 | // addition with mutable assignment? 30 | use std::ops::AddAssign; 31 | 32 | impl AddAssign for Complex where T: AddAssign 33 | { 34 | // x += y; 35 | fn add_assign(&mut self, rhs: Complex) { 36 | self.re += rhs.re; 37 | self.im += rhs.im; 38 | } 39 | 40 | } 41 | 42 | // equality 43 | impl PartialEq for Complex { 44 | fn eq(&self, other: &Complex) -> bool { 45 | self.re == other.re && self.im == other.im 46 | } 47 | /* use default ne */ 48 | } 49 | 50 | /* test */ 51 | pub fn main() { 52 | let x = Complex { re: 4, im: 2}; 53 | let y = -x; 54 | let z = -y; 55 | 56 | let mut o = Complex { re: 4, im: 16 }; 57 | o += z; 58 | 59 | println!("{:?}", y); 60 | println!("{:?}", z); 61 | println!("{:?}", z + z); 62 | println!("{:?}", o); 63 | 64 | } 65 | -------------------------------------------------------------------------------- /basics/src/ownership.rs: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | print_padovan(); 3 | let s = boxing(); 4 | println!("{}", s); 5 | let t = move_thing(); 6 | println!("{:?}", t); 7 | let t = move_thing1(); 8 | println!("{:?}", t); 9 | let t = move_thing2(); 10 | println!("{}",t); 11 | move_thing3(); 12 | move_thing4(); 13 | let t = move_thing5(); 14 | println!("{:?}",t); 15 | } 16 | 17 | fn print_padovan() { 18 | let a = vec![1, 1, 1]; // local var on stack, ptr to heap 19 | let mut b = a; // drops a 20 | for i in 3..10 { 21 | let next = b[i - 3] + b[i - 2]; 22 | b.push(next); 23 | } 24 | println!("P(1..10) = {:?}", b); // drop b and reclaim the heap 25 | } 26 | 27 | fn boxing() -> String { 28 | let point = Box::new((0.625, 0.5)); // ptr to heap alloc 29 | let label = format!("{:?}", point); // ptr to heap alloc str 30 | label 31 | } 32 | 33 | fn move_thing() -> (Vec, Vec) { 34 | let s = vec!["a".to_string(), "b".to_string()]; 35 | let t = s.clone(); 36 | // let u = s; // move 37 | let u = s.clone(); 38 | println!("{:?}", s); 39 | (t,u) 40 | } 41 | 42 | fn move_thing1() -> String { 43 | #[allow(unused_assignments)] 44 | let mut s = "Govinda".to_string(); 45 | s = "Siddhartha".to_string(); // re-assign drops 46 | s 47 | } 48 | 49 | fn move_thing2() -> String { 50 | #[derive(Debug)] 51 | struct Person { 52 | name: String, 53 | birth: i32, 54 | } 55 | 56 | let mut c = Vec::new(); // new empty vector 57 | c.push(Person { 58 | name: "Palestrina".to_string(), 59 | birth: 1525, 60 | }); 61 | 62 | format!("{:?}", c) 63 | } 64 | 65 | fn move_thing3() { 66 | let c = true; 67 | let x = vec![10, 20, 30]; 68 | if c { 69 | f(x); // owns x 70 | } else { 71 | g(x); // owns x 72 | } 73 | // h(x); // either path uses it 74 | 75 | fn f(_: Vec) {} 76 | fn g(_: Vec) {} 77 | // fn h() -> bool {true} 78 | 79 | // let x = vec![10, 20, 30]; 80 | // while h() { 81 | // g(x); // loop moves x 82 | // } 83 | 84 | let mut v = Vec::new(); 85 | for i in 101 .. 106 { 86 | v.push(i.to_string()); 87 | } 88 | // let third = v[2]; // move fragment of v 89 | let _fifth = &v[4]; // a ref is ok 90 | } 91 | 92 | fn move_thing4() { 93 | let mut v = Vec::new(); 94 | for i in 101i8 .. 106 { 95 | v.push(i.to_string()); 96 | } 97 | 98 | // pop value off the end 99 | let fifth = v.pop().unwrap(); 100 | assert_eq!(fifth, "105"); 101 | 102 | // remove a value out 103 | let second = v.swap_remove(1); 104 | assert_eq!(second, "102"); 105 | 106 | let third = std::mem::replace(&mut v[2], "substitute".to_string()); 107 | assert_eq!(third, "103"); // the value that is removed 108 | 109 | println!("{:?}", v); 110 | 111 | let v = vec!["a".to_string(), "b".to_string(), "c".to_string()]; 112 | 113 | for mut s in v { 114 | s.push('!'); // needs to be mut 115 | println!("{}", s); 116 | } 117 | } 118 | #[derive(Debug)] 119 | struct Person { 120 | name: Option, 121 | birth: i32, 122 | } 123 | 124 | fn move_thing5() -> (Option, Vec) { 125 | let mut c = Vec::new(); 126 | c.push(Person { 127 | name: Some("Palestrina".to_string()), 128 | birth: 1525, 129 | }); 130 | 131 | // let n = c[0].name; // move component 132 | let n = c[0].name.take(); // swaps for None 133 | 134 | (n, c) 135 | } 136 | -------------------------------------------------------------------------------- /basics/src/panic.rs: -------------------------------------------------------------------------------- 1 | // rustc -C panic=abbort panic.rs 2 | #[allow(unreachable_code)] 3 | pub fn main() { 4 | // unwinding 5 | { 6 | println!("{}", pirate_share(100, 15)); 7 | println!("{}", pirate_share(100, 1)); 8 | } 9 | 10 | panic!("{:?}", panic!()); // explicit panic. 11 | 12 | // interesting: 13 | fix(); 14 | 15 | { 16 | println!("{}", pirate_share(100, 0)); // panicked at 'attempt to divide by zero' 17 | } 18 | } 19 | 20 | fn fix() -> ! { 21 | loop {panic!()} 22 | } 23 | 24 | fn pirate_share(total: u64, crew_size: usize) -> u64 { 25 | (total / 2) / crew_size as u64 26 | } 27 | -------------------------------------------------------------------------------- /basics/src/pattern.rs: -------------------------------------------------------------------------------- 1 | // Pg 223. Patterns 2 | 3 | pub fn main() { 4 | 5 | // literals 6 | { 7 | let x = (100,"foo"); 8 | if let (100, "foo") = x {}; 9 | } 10 | 11 | // ranges 12 | { 13 | let x = 42; 14 | println!("{}" , match x { 15 | // warning: `...` range patterns are deprecated! 16 | // 40 ... 43 => "yes", 17 | 40 ..= 43 => "yes", 18 | _ => "no" 19 | }); 20 | } 21 | 22 | // variables. borrow a mutable variable to the pattern match 23 | { 24 | let x = 42; 25 | 26 | println!("{}" , match x { 27 | // 40 ... 43 => "yes", 28 | mut y@40 ..= 43 => { y*=2 ; format!("{}",y) }, 29 | _ => "no".to_string() 30 | }); 31 | 32 | println!("{}" , match x { 33 | ref y@40 ..= 43 => { format!("{}",*y) }, 34 | _ => "no".to_string() 35 | }); 36 | 37 | println!("{}", x); 38 | } 39 | 40 | // guards and structures 41 | { 42 | struct Color(u64,u64,u32); 43 | let v = Color(256,3,52); 44 | println!("{}", match v { 45 | Color(r,_,_) if r > 200 => r, 46 | _ => 0 47 | }); 48 | } 49 | 50 | // how far does the exhaustiveness checking go? 51 | { 52 | fn foo(n: u64) -> u64 { 53 | let mut i = n; 54 | loop { 55 | if i == 0 { 56 | return n; 57 | } else { 58 | i += 2; 59 | } 60 | } 61 | } 62 | 63 | let v = 0 /* diverges: 1 */; 64 | println!("{}", match v { 65 | #[allow(clippy::eq_op)] 66 | _ if true == true => "wat", 67 | _ if foo(v) == 0 => "yes", 68 | _ => "sigh", 69 | }); 70 | 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /basics/src/rc.rs: -------------------------------------------------------------------------------- 1 | // Rc and Arc 2 | // 3 | // Rc: Refefence Count 4 | // Arc: Atomic Reference Count 5 | // 6 | use std::rc::Rc; 7 | 8 | pub fn main() { 9 | // construct a reference counted pointer 10 | let s: Rc = Rc::new("foo".to_string()); 11 | let _t: Rc = s.clone(); 12 | #[allow(clippy::redundant_clone)] 13 | let _u: Rc = s.clone(); 14 | 15 | // 3 stack allocated pointers to a heap allocated ref-count box + string ref (unboxed) 16 | // all refer to the same block 17 | // can't be shared and mutable 18 | // s.push_str(" noodles"); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /basics/src/result.rs: -------------------------------------------------------------------------------- 1 | // Result is like all sorts of Maybe/Optional monad stuff 2 | // 3 | use std::io; 4 | 5 | // Error Handling: Result 6 | pub fn main() { 7 | let arr: &[u8] = &[6, 1, 2, 0, 1, 2, 3, 4, 5, 6]; 8 | 9 | println!("{:?}", find(&|x| { x / 3 == 2 }, arr)); 10 | println!("{:?}", find(&|x| { x == 9 }, arr)); 11 | println!("{:?}", find(&|x| { x == 6 }, arr)); 12 | 13 | let s = match get_weather() { 14 | Ok(v) => format!("bool : {}", v), 15 | Err(e) => format!("err : {}", e), 16 | }; 17 | println!("{}", s); 18 | 19 | if get_weather().is_ok() { 20 | println!("It's ok!"); 21 | } 22 | 23 | if get_weather().is_err() { 24 | println!("It is an error!"); 25 | } 26 | 27 | println!( 28 | "ok? {}", 29 | match get_weather().ok() { 30 | Some(true) => "true enough", 31 | _ => "not really true", 32 | } 33 | ); 34 | 35 | println!( 36 | "err? {}", 37 | match get_weather().err() { 38 | Some(e) => format!("{:?}", e), 39 | _ => "not really an error".to_string(), 40 | } 41 | ); 42 | 43 | println!("all good: {}", get_weather().unwrap_or(false)); 44 | println!( 45 | "all good: {}", 46 | get_weather().expect("well that's not success") 47 | ); 48 | 49 | if let Err(e) = wrapping() { 50 | println!("{:?}", e); 51 | std::process::exit(1); 52 | } 53 | 54 | match get_weather2() { 55 | Ok(_) => (), // std::process::exit(42), 56 | Err(MyError { problem }) => println!("{}", problem), 57 | }; 58 | } 59 | 60 | fn wrapping() -> Result<(), io::Error> { 61 | // unwrap 62 | let _v = get_weather()?; 63 | 64 | // equiv to 65 | let _v = match get_weather() { 66 | Ok(v) => v, 67 | Err(e) => return Err(e), 68 | }; 69 | 70 | Ok(()) 71 | } 72 | 73 | fn find(f: &dyn Fn(u8) -> bool, p: &[u8]) -> Option { 74 | match find_index(f, p) { 75 | Some(n) => Some(p[n]), 76 | _ => None, 77 | } 78 | } 79 | 80 | fn find_index(k: &dyn Fn(u8) -> bool, p: &[u8]) -> Option { 81 | // for n in 0..p.len() { 82 | for (n, i) in p.iter().enumerate() { 83 | if k(*i) { 84 | return Some(n); 85 | } 86 | } 87 | None 88 | } 89 | 90 | /* 91 | 92 | -- | /O(n)/ The 'find' function takes a predicate and a ByteString, 93 | -- and returns the first element in matching the predicate, or 'Nothing' 94 | -- if there is no such element. 95 | -- 96 | -- > find f p = case findIndex f p of Just n -> Just (p ! n) ; _ -> Nothing 97 | -- 98 | find :: (Word8 -> Bool) -> ByteString -> Maybe Word8 99 | find f p = case findIndex f p of 100 | Just n -> Just (p `unsafeIndex` n) 101 | _ -> Nothing 102 | {-# INLINE find #-} 103 | 104 | -- | The 'findIndex' function takes a predicate and a 'ByteString' and 105 | -- returns the index of the first element in the ByteString 106 | -- satisfying the predicate. 107 | findIndex :: (Word8 -> Bool) -> ByteString -> Maybe Int 108 | findIndex k (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \f -> go (f `plusPtr` s) 0 109 | where 110 | go !ptr !n | n >= l = return Nothing 111 | | otherwise = do w <- peek ptr 112 | if k w 113 | then return (Just n) 114 | else go (ptr `plusPtr` 1) (n+1) 115 | {-# INLINE findIndex #-} 116 | 117 | */ 118 | 119 | type MyResult = Result; 120 | type MyBoolResult = MyResult; 121 | 122 | fn get_weather() -> MyBoolResult { 123 | Ok(true) 124 | } 125 | 126 | fn get_weather2() -> Result { 127 | if 1 > 2 { 128 | Err(MyError { 129 | problem: "This cannot be".to_string(), 130 | }) 131 | } else { 132 | Ok(true) 133 | } 134 | } 135 | 136 | /* implement a custom error type */ 137 | #[derive(Debug, Clone)] 138 | pub struct MyError { 139 | pub problem: String, 140 | } 141 | -------------------------------------------------------------------------------- /basics/src/sharing.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Pages 114 - 122 3 | * Sharing and mutation 4 | */ 5 | pub fn main() { 6 | // 1. sharing versus mutation 7 | { 8 | // v: ptr to contiguous block of i32 on heap, with capacity 9 | let v: Vec = vec![4, 8, 19, 27, 34, 10]; 10 | { 11 | let r = &v; // borrow 12 | let x = r[0]; // read for its effect? 13 | println!("{}", x); 14 | // drop r 15 | } 16 | let aside = v; // we can still use 'v', move v to aside 17 | let r = &aside; 18 | let x = r[0]; 19 | println!("{}", x); 20 | } 21 | 22 | // 2. more sharing 23 | { 24 | fn extend_m(vec: &mut Vec, slice: &[f64]) { 25 | for e in slice { 26 | vec.push(*e); 27 | } 28 | } 29 | let mut a: Vec = vec![1.0, 2.0, 3.0]; 30 | let b = [4.0, 5.0]; 31 | extend_m(&mut a, &b); 32 | println!("{:?}", a); 33 | 34 | fn extend_pure(vec: &[f64], slice: &[f64]) -> Vec { 35 | let mut u = vec.to_owned(); 36 | for e in slice { 37 | u.push(*e); 38 | } 39 | u // stack return 40 | } 41 | let a: Vec = vec![1.0, 2.0, 3.0]; 42 | let b = [4.0, 5.0]; 43 | let c = extend_pure(&a, &b); 44 | println!("{:?}", a); 45 | println!("{:?}", c); 46 | 47 | let mut wave = Vec::new(); 48 | let head = vec![0.0, 1.0]; 49 | let tail = [0.0, -1.0]; 50 | extend_m(&mut wave, &head); 51 | extend_m(&mut wave, &tail); 52 | 53 | // this looks dubious. it might reallocate... 54 | // mutable and immutable lifetimes shouldn't overlap 55 | // extend_m(&mut wave, &wave); 56 | 57 | // this should be fine: 58 | let wave2 = extend_pure(&wave, &wave); 59 | println!("{:?}", wave2); 60 | } 61 | /* 62 | * shared references to values must be read-only in the lifetime of the shared ref. 63 | * mutable references mean those values are now exclusive to the lifetime of the reference 64 | */ 65 | 66 | // 3. mutable borrowing and sharing examples, and ownership changes 67 | // n.b. similar example: borrow checker is shrinking the lifetimes from the book, so you need 68 | // to extend them to make it work 69 | { 70 | let /*mut*/ x1 = 10; 71 | let r1 = &x1; 72 | let r2 = &x1; // shared ro borrow: ok 73 | // NO: x += 10; // an effect. but it should be immutable now 74 | // NO: let m = &mut x; // borrow a mutable ref, should invalidate 'x' for lifetime of m 75 | assert_eq!(r1, r2); // extend lifetime to make it work 76 | 77 | let mut y1 = 20; 78 | let _m1 = &mut y1; 79 | // NO: let m2 = &mut y1; // a second mutable borrow. inconsistent 80 | // assert_eq!(m1, m2); // extend lifetime to make it work 81 | 82 | let /*mut*/ w1 = (107, 109); // mutable tuple 83 | let r1 = &w1; 84 | let _r0 = &r1.0; // OK. more shared ref 85 | // let m1 = &mut r.1; // borrow shared mut ref to 2nd component. nope 86 | 87 | let mut v1 = (136, 139); 88 | let m1 = &mut v1; 89 | let m0 = &mut m1.0; // reborrow mutable from mutable is ok? 90 | *m0 = 137; // destructive assignment to first field of tuple. to de-ref 91 | let _r1 = &m1.1; 92 | // let x = v.1; // NO: use of borrowed value, still in scope 93 | assert_eq!(m0,m0); // extend lifetime 94 | let y1 = v1.0; // copy . this is ok because shorter scoep of the mutables 95 | println!("{:?}",y1); // fine 96 | 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /basics/src/struct.rs: -------------------------------------------------------------------------------- 1 | // pg. 193: structs 2 | // 3 | // types have CamelCase. fields and functions have snake case 4 | // 5 | 6 | #[derive(Clone)] 7 | struct GSM { // greyscale map 8 | pixels: Vec, 9 | size: (usize, usize), 10 | } 11 | 12 | // tuple-like struct. product type with a newtype and indexing 13 | #[derive(Debug)] 14 | struct P(usize, usize, usize); 15 | 16 | // hehey you can use them as newtypes 17 | #[allow(dead_code)] 18 | struct T(Vec); 19 | 20 | // empty data types, wohoo 21 | #[allow(dead_code)] 22 | struct U; 23 | 24 | fn mk_p(a: usize, b: usize, c: usize) -> P { 25 | P(a,b,c) 26 | } 27 | 28 | fn mk_gsm(w: usize, h: usize) -> GSM { 29 | GSM { 30 | pixels: vec![0; w*h], 31 | size: (w,h) 32 | } 33 | } 34 | 35 | pub fn main() { 36 | 37 | let w1 = 1024; 38 | let h1 = 576; 39 | 40 | let a1 = mk_gsm(w1,h1); 41 | let b1 = mk_gsm(w1/2, h1/2); 42 | 43 | let v1 = vec![0;0]; 44 | let c1 = GSM { pixels: v1, .. b1 }; 45 | 46 | // move pixels from 'a' , not copied! 47 | let d1 = GSM { pixels: a1.pixels.clone(), .. a1 }; 48 | 49 | println!("{}", a1.pixels.len()); 50 | println!("{}", b1.pixels.len()); 51 | println!("{}", c1.pixels.len()); 52 | println!("{}", d1.pixels.len()); 53 | 54 | let a1 = mk_p(1,2,3); 55 | println!("{:?}", a1); 56 | println!("{:?}", a1.1); 57 | } 58 | -------------------------------------------------------------------------------- /basics/src/trait.rs: -------------------------------------------------------------------------------- 1 | // pg 245, traits 2 | 3 | trait V { 4 | fn is_good(&self) -> bool { 5 | false // default impl 6 | } 7 | } 8 | 9 | extern crate num_traits; 10 | use num_traits::identities as I; 11 | 12 | /* whoo num class */ 13 | impl V for O { 14 | #[inline] 15 | fn is_good(&self) -> bool { 16 | *self > I::zero() 17 | } 18 | } 19 | 20 | /* 21 | #[inline] 22 | fn generic_gtz(v: T, zero: T) -> bool { 23 | v > zero 24 | } 25 | 26 | impl V for i128 { fn is_good(&self) -> bool { generic_gtz(*self, 0) } } 27 | impl V for i64 { fn is_good(&self) -> bool { generic_gtz(*self, 0) } } 28 | impl V for i32 { fn is_good(&self) -> bool { generic_gtz(*self, 0) } } 29 | impl V for i16 { fn is_good(&self) -> bool { generic_gtz(*self, 0) } } 30 | impl V for i8 { fn is_good(&self) -> bool { generic_gtz(*self, 0) } } 31 | */ 32 | 33 | pub fn main() { 34 | println!("{}",V::is_good(&1i8)); 35 | println!("{}",V::is_good(&0i16)); 36 | println!("{}",V::is_good(&1i64)); 37 | println!("{}",V::is_good(&0i128)); 38 | 39 | /* examples of method call syntax */ 40 | let v: i64 = 7; 41 | 42 | // "qualified method calls " 43 | if v.is_good() // OO method call 44 | && i64::is_good(&v) // type-based dispatch? 45 | && V::is_good(&v) // trait function call 46 | && ::is_good(&v) // type/trait dispatch, fully qualified 47 | { 48 | println!("this is a good one"); 49 | } else { 50 | panic!("much badness"); 51 | } 52 | 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /basics/src/types.rs: -------------------------------------------------------------------------------- 1 | const V_I8: i8 = 0; 2 | const V_I16: i16 = -5i16; 3 | const V_I32: i32 = 2*8; 4 | const V_I64: i64 = 20_922_789_888_000_000; 5 | 6 | const V_U8: u8 = b'*'; 7 | const V_U16: u16 = 5u16; 8 | const V_U32: u32 = 0; 9 | const V_U64: u64 = 0; 10 | #[allow(clippy::inconsistent_digit_grouping)] 11 | const V_U128_1: u128 = 0b0011____0011_1101_0011_0011_11010011_0011_1101_0011_1101_0011_0011_11010011_0011_1101; 12 | 13 | const V_ISIZE: isize = 137; 14 | const V_USIZE: usize = 0xffff_fc00usize; 15 | 16 | #[allow(clippy::excessive_precision)] 17 | const V_F32: f32 = 3.1415926536897832; 18 | #[allow(clippy::excessive_precision)] 19 | const V_F64: f64 = 3.141_592_653_689_783_2; 20 | 21 | const V_TRUE: bool = true; 22 | const V_FALSE: bool = false; 23 | 24 | const V_CHAR: char = '\u{CA0}'; 25 | 26 | const V_UNIT: () = (); 27 | 28 | const V_TUPLE: (char, u8, i32) = ('x', 42, 256); 29 | 30 | #[derive(Debug)] 31 | struct TyStruct { 32 | x: f32, 33 | y: f32, 34 | } // type definiton 35 | 36 | // named struct 37 | const V_STRUCT: TyStruct = TyStruct { x: 32., y: 64. }; 38 | 39 | // tuple-struct ... 40 | #[derive(Debug)] 41 | struct TyTupStruct(i32, char); 42 | 43 | const V_TUP_STRUCT: TyTupStruct = TyTupStruct(42, 'f'); 44 | 45 | // from https://doc.rust-lang.org/reference/items/constant-items.html 46 | const BIT1: u32 = 1 << 3; 47 | const BIT2: u32 = 1 << 1; 48 | 49 | const BITS: [u32; 2] = [BIT1, BIT2]; 50 | const STRING: &str = "bitstring"; 51 | 52 | #[derive(Debug)] 53 | struct BitsNStrings<'a> { 54 | mybits: [u32; 2], 55 | mystring: &'a str, 56 | } 57 | 58 | const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings { 59 | mybits: BITS, 60 | mystring: STRING, 61 | }; 62 | 63 | #[derive(Debug)] 64 | struct Z; // woo hoo 65 | 66 | const V_Z: Z = Z; 67 | 68 | #[allow(dead_code)] 69 | enum X {} // yeah boi 70 | 71 | #[allow(dead_code)] 72 | #[derive(Debug)] 73 | enum Y { 74 | Z, 75 | X, 76 | } 77 | 78 | #[allow(dead_code)] 79 | fn x() -> Y { 80 | Y::Z 81 | } 82 | 83 | // ok let's do it 84 | #[derive(Debug)] 85 | enum Expr { 86 | LAM(char, Box), 87 | EVAL(Box, Box), 88 | CONST(u32), 89 | VAR(char), 90 | PRIM(char, Box, Box), 91 | } 92 | 93 | const E_EXP_ONE: Expr = Expr::CONST(1); 94 | const E_EXP_TWO: Expr = Expr::CONST(2); 95 | const E_EXP_VAR_X: Expr = Expr::VAR('x'); 96 | 97 | fn mk_exp_op(op: char, e1: Expr, e2: Expr) -> Expr { 98 | let box1 = Box::new(e1); 99 | let box2 = Box::new(e2); 100 | Expr::PRIM(op, box1, box2) 101 | } 102 | 103 | fn mk_exp_eval(e1: Expr, e2: Expr) -> Expr { 104 | let box1 = Box::new(e1); 105 | let box2 = Box::new(e2); 106 | Expr::EVAL(box1, box2) 107 | } 108 | 109 | fn mk_exp_lam(sym: char, e: Expr) -> Expr { 110 | let box1 = Box::new(e); 111 | Expr::LAM(sym, box1) 112 | } 113 | 114 | const V_REF: &i32 = &V_I32; 115 | 116 | fn mk_suffix(x: char, s: &str) -> String { 117 | let mut t: String = (*s).to_string(); 118 | t.push(x); 119 | t 120 | } 121 | 122 | const V_ARR_0: [u8; 4] = [0x00,0xe0,0x4c,0x68]; 123 | 124 | // what does this do? 125 | fn mk_vec(vs: &[u8]) -> Vec { 126 | let us: Vec = vec!(vs[1]); // weird 127 | us 128 | } 129 | 130 | fn mk_3slice(vs: &[u8]) -> &[u8] { 131 | &vs[0..3] // 3 elements? 132 | 133 | } 134 | 135 | const V_FN_TY_0: fn() -> u32 = mk_u32_zero; 136 | const V_FN_TY_1: fn() -> u32 = || 1; 137 | const V_FN_TY_2: fn(u32,u32) -> u32 = |a,b| a*b; 138 | 139 | fn mk_u32_zero() -> u32 { 140 | 0 141 | } 142 | 143 | const V_U64_0: u64 = std::u64::MAX; // + 1; 144 | 145 | const S_1: &str = "test 1 2 3"; 146 | const S_2: &str = "there \n\ 147 | once \ 148 | was"; 149 | const S_3: &str = r##"this 150 | is a string 151 | in complete free form. 152 | "##; 153 | 154 | const S_4: [u8;3] = [b'A', b'B', b'C']; 155 | 156 | pub fn main() { 157 | println!("i8 = {}", V_I8); 158 | println!("i16 = {}", V_I16); 159 | println!("i32 = {}", V_I32); 160 | println!("i64 = {}", V_I64); 161 | 162 | println!("u8 = {}", V_U8); 163 | println!("u16 = {}", V_U16); 164 | println!("u32 = {}", V_U32); 165 | println!("u64 = {}", V_U64); 166 | 167 | println!("isize = {}", V_ISIZE); 168 | println!("usize = {}", V_USIZE); 169 | 170 | println!("f32 = {}", V_F32); 171 | println!("f64 = {}", V_F64); 172 | 173 | println!("bool = {}", V_TRUE); 174 | println!("bool = {}", V_FALSE); 175 | 176 | println!("char = {} {}", V_CHAR, V_CHAR); 177 | 178 | println!("unit = {:?}", V_UNIT); // n.b. not Display 179 | 180 | println!("tuple = {:?}", V_TUPLE); 181 | 182 | println!("struct = {:?}", V_STRUCT); 183 | println!("struct2 = {:?}", BITS_N_STRINGS); 184 | println!("struct3 = {:?}", V_TUP_STRUCT); 185 | println!("struct4 = {:?}", V_Z); 186 | println!("struct5 = {:?}", x()); 187 | 188 | println!("exp_1 = {:?}", E_EXP_ONE); 189 | println!("exp_2 = {:?}", E_EXP_TWO); 190 | println!("exp_3 = {:?}", mk_exp_op('*', E_EXP_ONE, E_EXP_TWO)); 191 | println!("exp_3 = {:?}", mk_exp_eval(E_EXP_ONE, E_EXP_TWO)); 192 | println!( 193 | "exp_4 = {:?}", 194 | mk_exp_lam('x', mk_exp_op('*', E_EXP_VAR_X, E_EXP_TWO)) 195 | ); 196 | 197 | println!("ref = {:?}", V_REF); 198 | let s = mk_suffix('#',"foo"); 199 | println!("String = {:?}", s); 200 | println!("String = {:?}", &s[0..3]); // n.b runtime indexing errors 201 | 202 | println!("arr0 = {:?}", V_ARR_0); 203 | println!("arr1 = {:?}", mk_vec(&V_ARR_0)); 204 | println!("arr2 = {:?}", mk_3slice(&V_ARR_0)); 205 | 206 | println!("fn0 = {:?}", V_FN_TY_0); 207 | println!("fn1 = {:?}", V_FN_TY_0()); // app 208 | println!("fn2 = {:?}", V_FN_TY_1()); // app 209 | println!("fn2 = {:?}", V_FN_TY_2(4,6)); 210 | 211 | println!("u64 = {:?}", V_U64_0); 212 | // println!("u64 = {:?}", V_U64_0 - V_U64_0 - 1); 213 | println!("u64 = {:?}", V_U64_0.wrapping_add(1)); 214 | println!("u64 = {:?}", V_U64_0.wrapping_add(2)); 215 | println!("u128 = {:?}", V_U128_1); 216 | 217 | assert_eq!( 10_i8 as u16, 10_u16); 218 | assert_eq!( 2525_u16 as i16, 2525_i16); 219 | assert_eq!( -1_i16 as i32, -1_i32); // sign extension 220 | assert_eq!( 65535_u16 as i32, 65535_i32); // zero extended 221 | 222 | // bit truncation 223 | assert_eq!(1000_i16 as u8, 232_u8); 224 | assert_eq!(-1_i8 as u8, 255_u8); 225 | 226 | assert_eq!(2u16.pow(4), 16); 227 | assert_eq!(2_u16.pow(4), 16); 228 | assert_eq!(u16::pow(2,4), 16); 229 | 230 | println!("pi = {:?}", std::f64::consts::PI); // 3.141_592_653_589_793_f64); 231 | 232 | let c = std::char::from_u32(V_U32 + 123456); 233 | println!("char = {:?}", c); 234 | 235 | println!("string = {:?}", S_1); 236 | println!("string = {:?}", S_2); 237 | println!("string = {:?}", S_3); 238 | println!("string = {:?}", S_4); 239 | 240 | } 241 | -------------------------------------------------------------------------------- /basics/src/unicode.rs: -------------------------------------------------------------------------------- 1 | extern crate regex; 2 | // ch17: pg 392 3 | 4 | pub fn main() { 5 | // latin1 6 | { 7 | fn latin1_to_char(c: u8) -> char { 8 | c as char 9 | } 10 | fn char_to_latin1(c: char) -> Option { 11 | if c as u32 <= 0xff { 12 | Some(c as u8) 13 | } else { 14 | None 15 | } 16 | } 17 | 18 | let cs = [92,102,103,42,43,44,45u8]; 19 | 20 | for i in cs.iter() { 21 | println!("{}", latin1_to_char(*i)); 22 | println!("{:?}", char_to_latin1(latin1_to_char(*i))); 23 | } 24 | } 25 | 26 | // unicode methods 27 | { 28 | assert_eq!(false, 'X'.is_numeric()); 29 | assert_eq!(true, 'X'.is_alphabetic()); 30 | assert_eq!(true, 'X'.is_alphanumeric()); 31 | assert_eq!(false, 'X'.is_whitespace()); 32 | } 33 | 34 | // String / str 35 | { 36 | let s = String::new(); 37 | assert_eq!(s.len(), 0); 38 | 39 | let s1: &str = "foo"; 40 | let s2: String = s1.to_string(); 41 | assert_eq!(s1.len(), 3); 42 | assert_eq!(s2.len(), 3); 43 | 44 | let s3 = "man hat tan"; 45 | let s4 :String = s3.chars().filter(|c| !c.is_whitespace()).collect(); 46 | assert_eq!(s4.len(), 9); 47 | 48 | let s5 = &s4[2..4]; 49 | println!("{}", s5); 50 | } 51 | 52 | // joins/appends 53 | { 54 | let mut s6 = String::new(); 55 | // s6.extend("foo".chars()); 56 | // s6.extend("bar".chars()); 57 | s6.push_str("foo"); 58 | s6.push_str("bar"); 59 | println!("{}", s6); 60 | } 61 | 62 | // writes 63 | { 64 | use std::fmt::Write; 65 | 66 | let mut l = String::new(); 67 | let e = writeln!(l, "This TODO is the string").ok(); 68 | println!("{:?}", e); 69 | println!("{}", l); 70 | } 71 | 72 | // searching 73 | { 74 | let s1 = "One fine day, in the middle of the night"; 75 | 76 | // find is very overloaded nice. 77 | assert_eq!(s1.find(','), Some(12)); 78 | assert_eq!(s1.find("night"), Some(35)); 79 | assert_eq!(s1.find(char::is_whitespace), Some(3)); 80 | } 81 | 82 | // matching 83 | { 84 | let code = "\t function noodle() {"; 85 | assert_eq!(code.trim_start_matches(&[' ', '\t'] as &[char]), "function noodle() {"); 86 | } 87 | 88 | // formatting types 89 | { 90 | // Display 91 | let x = (core::f64::consts::PI, "foo"); 92 | let y = (314159265, "foo"); 93 | println!("{}", x.0); 94 | println!("{:?}", x); 95 | 96 | // n.b. this a bug in the book 97 | // use std::fmt::Binary; 98 | println!("{:#b}", y.0); 99 | 100 | struct Complex { r: f64, i: f64}; 101 | 102 | use std::fmt; 103 | impl fmt::Display for Complex { 104 | fn fmt(&self, dest: &mut fmt::Formatter) -> fmt::Result { 105 | let i_sign = if self.i < 0. { '-' } else { '+' }; 106 | write!(dest, "{} {} {}i", self.r, i_sign, f64::abs(self.i)) 107 | } 108 | } 109 | println!("{}", Complex { r: 42.32, i: -1.23 }); 110 | } 111 | 112 | // regex package 113 | { 114 | use regex::{Regex}; 115 | 116 | let semver: Regex = 117 | Regex::new(r"(\d+)\.(\d+)\.(\d+)(-[-.[:alnum:]]*)?").unwrap(); 118 | 119 | let yes = r#"regex = "0.2.5""#; 120 | let yes1 = r#"regex = "0.2.5--Xfoo--YFoo""#; 121 | assert!(semver.is_match(yes)); 122 | assert!(semver.is_match(yes1)); 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /basics/src/unlines.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::io::prelude::*; 3 | 4 | pub fn main() { 5 | let f = io::stdin(); 6 | for l in f.lock().lines() { 7 | println!("{:?}", l); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /basics/src/utility.rs: -------------------------------------------------------------------------------- 1 | // ch 282 / utility traits 2 | 3 | struct A { 4 | name: String, 5 | nick: Vec 6 | } 7 | 8 | use std::ops::Drop; 9 | 10 | impl Drop for A { 11 | 12 | // run before dropping the associated memory 13 | fn drop(&mut self) { 14 | eprintln!("Dropping {}", self.name); 15 | if !self.nick.is_empty() { 16 | eprintln!("AKA ({})", self.nick.join(", ")); 17 | } 18 | } 19 | } 20 | 21 | pub fn main() { 22 | let mut a = A { name: "Zeus".to_string(), nick: vec!["cloud man".to_string()] }; 23 | println!("before"); 24 | a = A { name: "B".to_string(), nick: vec![] }; 25 | println!("after"); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /basics/src/vecdeque.rs: -------------------------------------------------------------------------------- 1 | // ch 16: pg 374: vecdeques 2 | // 3 | use std::collections::VecDeque; 4 | use std::collections::BinaryHeap; 5 | use std::collections::HashMap; 6 | use std::collections::BTreeMap; 7 | use std::collections::HashSet; 8 | use std::collections::BTreeSet; 9 | 10 | pub fn main() { 11 | // introduction 12 | { 13 | let mut x: VecDeque = VecDeque::new(); 14 | x.push_front(4); 15 | x.push_back(3); 16 | x.push_back(2); 17 | for i in x { 18 | println!("{}",i ); 19 | } 20 | } 21 | 22 | // binary heaps 23 | { 24 | let mut x: BinaryHeap = BinaryHeap::new(); 25 | x.push(7); 26 | x.push(3); 27 | x.push(1); 28 | println!("{}", x.pop().unwrap()); 29 | } 30 | 31 | // hashmaps and btrees 32 | { 33 | let mut h : HashMap = vec![("foo".to_string(), 7i64) 34 | ,("bar".to_string(), 8) 35 | ].into_iter().collect(); 36 | let mut b : BTreeMap = vec![("foo".to_string(), 7i64) 37 | ,("bar".to_string(), 8) 38 | ].into_iter().collect(); 39 | 40 | assert_eq!(h.is_empty(), false); 41 | assert_eq!(b.is_empty(), false); 42 | 43 | assert_eq!(h.contains_key("foo"), true ); 44 | assert_eq!(b.contains_key("foo"), true ); 45 | 46 | println!("{}", b.get("foo").unwrap() 47 | + h.get("foo").unwrap()); 48 | 49 | assert_eq!(b.insert("foo".to_string(),7), Some(7)); 50 | assert_eq!(h.insert("foo".to_string(),7), Some(7)); 51 | 52 | /* 53 | let mut i = HashMap::new(); 54 | i.append(&h); 55 | assert_eq!(h.is_empty(), true); 56 | assert_eq!(i.is_empty(), false); 57 | */ 58 | 59 | } 60 | 61 | // hashsets / btreesets 62 | { 63 | // membership 64 | let h : HashSet = vec!["foo".to_string() ,"bar".to_string()].into_iter().collect(); 65 | let b : BTreeSet = vec!["foo".to_string() ,"bar".to_string()].into_iter().collect(); 66 | let b2 : BTreeSet = vec!["baz".to_string() ,"bar".to_string()].into_iter().collect(); 67 | 68 | assert_eq!(h.contains("foo"), true ); 69 | assert_eq!(b.contains("foo"), true ); 70 | 71 | // "bar" is the intersection. shared ref to string in set. fast(!) 72 | let v : Vec<&String> = b.intersection(&b2).collect(); 73 | println!("{:?}", v); 74 | 75 | } 76 | 77 | // hash types : derivation 78 | { 79 | #[derive(PartialEq,Hash,Eq)] 80 | struct A { 81 | a: String, 82 | b: i64 83 | } 84 | let h : HashSet = vec![A{ a : "foo".to_string(), b: 32 }].into_iter().collect(); 85 | assert_eq!(h.contains(&A { a : "foo".to_string(), b: 33 } ), false ); 86 | assert_eq!(h.contains(&A { a : "foo".to_string(), b: 32 } ), true ); 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /difference-list/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "difference-list" 3 | version = "0.1.0" 4 | license = "BSD3" 5 | authors = ["Don Stewart "] 6 | repository = "" 7 | documentation = "" 8 | description = """ 9 | Difference lists are a list-like type supporting O(1) append. This is 10 | particularly useful for efficient logging and pretty printing, where list 11 | append quickly becomes too expensive. 12 | """ 13 | 14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 15 | 16 | [dependencies] 17 | -------------------------------------------------------------------------------- /difference-list/src/lib.rs: -------------------------------------------------------------------------------- 1 | /// 2 | /// This structure supports /O(1)/ append and snoc operations on lists, making it 3 | /// very useful for append-heavy uses (esp. left-nested uses of append operations), such as logging 4 | /// and pretty printing. 5 | /// 6 | pub mod dlist { 7 | 8 | use std::marker::PhantomData; 9 | 10 | /// The type of difference lists of A 11 | pub struct DList { 12 | phantom: PhantomData, 13 | } 14 | 15 | // pub struct DList { unDL: &(dyn Fn(&[A]) -> &[A]) } 16 | // 17 | /* 18 | impl DList { 19 | 20 | pub fn new() -> DList { 21 | empty() 22 | } 23 | 24 | } 25 | */ 26 | 27 | // free functional version 28 | pub fn empty() -> DList { 29 | DList { 30 | phantom: PhantomData, 31 | } 32 | } 33 | 34 | 35 | #[allow(dead_code)] 36 | fn id(a: A) -> A { 37 | a 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /difference-list/src/tests.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | use dlist::{id}; 4 | 5 | mod tests { 6 | #[test] 7 | fn test_id1() { 8 | /* 9 | assert_eq!(dlist::id(1), 1); 10 | assert_eq!(dlist::id(()), ()); 11 | assert_eq!(dlist::id(""), ""); 12 | assert_eq!(dlist::id([1,2,3]), [1,2,3]); 13 | */ 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /fern_sim/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fern_sim" 3 | version = "0.1.0" 4 | authors = ["Don Stewart "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /fern_sim/src/bin/efern.rs: -------------------------------------------------------------------------------- 1 | extern crate fern_sim; 2 | use fern_sim::{Fern, run_simulation}; 3 | 4 | fn main() { 5 | let mut fern = Fern { 6 | size: 1.0, 7 | growth_rate: 0.001 8 | }; 9 | run_simulation(&mut fern, 1000); 10 | println!("final fern size: {}", fern.size); 11 | } 12 | -------------------------------------------------------------------------------- /fern_sim/src/lib.rs: -------------------------------------------------------------------------------- 1 | // data is public 2 | pub struct Fern { 3 | pub size: f64, 4 | pub growth_rate: f64, 5 | } 6 | 7 | // methods "attached" to Fern 8 | impl Fern { 9 | // growth fun is public 10 | pub fn grow(&mut self) { 11 | self.size *= 1.0 + self.growth_rate; 12 | } 13 | } 14 | 15 | // functional style seems simpler?? 16 | pub fn grow_f(fern: &mut Fern) { 17 | fern.size *= 1.0 + fern.growth_rate; 18 | } 19 | 20 | pub fn run_simulation(fern: &mut Fern, days: usize) { 21 | for _ in 0 .. days { 22 | fern.grow(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /iron-gcd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iron-gcd" 3 | version = "0.1.0" 4 | authors = ["Don Stewart "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | iron = "0.5.1" 11 | mime = "0.2.3" 12 | router = "0.5.1" 13 | urlencoded = "0.5.0" 14 | 15 | -------------------------------------------------------------------------------- /iron-gcd/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate iron; 2 | extern crate router; 3 | extern crate urlencoded; 4 | #[macro_use] extern crate mime; 5 | 6 | use iron::prelude::*; 7 | use iron::status; 8 | use router::Router; 9 | use std::str::FromStr; 10 | use urlencoded::UrlEncodedBody; 11 | 12 | fn main() { 13 | let mut router = Router::new(); 14 | 15 | router.get("/", get_form, "root"); 16 | router.post("/gcd", post_gcd, "gcd"); 17 | 18 | println!("Serving on http://localhost:3000..."); 19 | Iron::new(router).http("localhost:3000").unwrap(); 20 | } 21 | 22 | fn get_form(_req: &mut Request) -> IronResult { 23 | let mut res = Response::new(); 24 | 25 | res.set_mut(status::Ok); 26 | res.set_mut(mime!(Text/Html; Charset=Utf8)); 27 | res.set_mut( 28 | r#" 29 | GCD Calc 30 |

31 | 32 | 33 | 34 | 35 | "#, 36 | ); 37 | 38 | Ok(res) 39 | } 40 | 41 | fn post_gcd(req: &mut Request) -> IronResult { 42 | let mut res = Response::new(); 43 | 44 | let form_data = match req.get_ref::() { 45 | Err(e) => { 46 | res.set_mut(status::BadRequest); 47 | res.set_mut(format!("Error parsing form data: {:?}\n", e)); 48 | return Ok(res); 49 | } 50 | Ok(map) => map 51 | }; 52 | 53 | let unparsed_numbers = match form_data.get("n") { 54 | None => { 55 | res.set_mut(status::BadRequest); 56 | res.set_mut("form data has no 'n' params\n".to_string()); 57 | return Ok(res); 58 | } 59 | Some(ns) => ns 60 | }; 61 | 62 | let mut nums = Vec::new(); 63 | for un in unparsed_numbers { 64 | match u64::from_str(&un) { 65 | Err(_) => { 66 | res.set_mut(status::BadRequest); 67 | res.set_mut( 68 | format!("Value for 'n' param not a number: {:?}\n", un)); 69 | return Ok(res); 70 | } 71 | Ok(n) => { nums.push(n); } 72 | } 73 | } 74 | 75 | let d = foldl1_gcd(&nums); 76 | 77 | res.set_mut(status::Ok); 78 | res.set_mut(mime!(Text/Html; Charset=Utf8)); 79 | res.set_mut(format!("The gcd of the numbers {:?} is {}\n", nums, d)); 80 | Ok(res) 81 | } 82 | 83 | // todo make this polymorphic 84 | fn foldl1_gcd(xs: &[u64]) -> u64 { 85 | let mut r = xs[0]; 86 | for p in &xs[1..] { 87 | r = gcd(r, *p) 88 | } 89 | r 90 | } 91 | 92 | // todo make this polymorphic 93 | fn gcd(mut n: u64, mut m: u64) -> u64 { 94 | assert!(n != 0 && m != 0); 95 | while m != 0 { 96 | if m < n { 97 | std::mem::swap(&mut m, &mut n); 98 | } 99 | m %= n; 100 | } 101 | n 102 | } 103 | -------------------------------------------------------------------------------- /mandelbrot/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mandelbrot" 3 | version = "0.1.0" 4 | authors = ["Don Stewart "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | num = "0.1.27" 11 | image = "0.13.0" 12 | crossbeam = "0.2.8" 13 | -------------------------------------------------------------------------------- /mandelbrot/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate crossbeam; 2 | extern crate image; 3 | extern crate num; 4 | 5 | use image::png::PNGEncoder; 6 | use image::ColorType; 7 | use num::Complex; 8 | use std::fs::File; 9 | use std::str::FromStr; 10 | 11 | fn main() { 12 | let args: Vec = std::env::args().collect(); 13 | 14 | if args.len() != 5 { 15 | eprintln!("Usage: mandelbrot FILE PIXELS UPPERLEFT LOWERRIGHT"); 16 | eprintln!( 17 | "Example: {} mandel.png 1000x750 -1.20,0.35 -1,0.20", 18 | args[0] 19 | ); 20 | std::process::exit(1); 21 | } 22 | 23 | let bounds = parse_pair(&args[2], 'x').expect("error parsing image dimensions"); 24 | let upper_left = parse_complex(&args[3]).expect("error parsing upper left corner point"); 25 | let lower_right = parse_complex(&args[4]).expect("error parsing lower right corner point"); 26 | 27 | let mut pixels = vec![0; bounds.0 * bounds.1]; 28 | 29 | // render(&mut pixels, bounds, upper_left, lower_right); 30 | let threads = 8; 31 | let rows_per_band = bounds.1 / threads + 1; 32 | 33 | { 34 | let bands: Vec<&mut [u8]> = pixels.chunks_mut(rows_per_band * bounds.0).collect(); 35 | crossbeam::scope(|spawner| { 36 | for (i, band) in bands.into_iter().enumerate() { 37 | let top = rows_per_band * i; 38 | let height = band.len() / bounds.0; 39 | let band_bounds = (bounds.0, height); 40 | let band_upper_left = pixel_to_point(bounds, (0, top), upper_left, lower_right); 41 | let band_lower_right = 42 | pixel_to_point(bounds, (bounds.0, top + height), upper_left, lower_right); 43 | 44 | spawner.spawn(move || { 45 | render(band, band_bounds, band_upper_left, band_lower_right); 46 | }); 47 | } 48 | }); 49 | } 50 | 51 | write_image(&args[1], &pixels, bounds).expect("error writing PNG file"); 52 | } 53 | 54 | #[allow(dead_code)] 55 | fn parse_pair(s: &str, sep: char) -> Option<(T, T)> { 56 | match s.find(sep) { 57 | None => None, 58 | Some(i) => match (T::from_str(&s[..i]), T::from_str(&s[i + 1..])) { 59 | (Ok(l), Ok(r)) => Some((l, r)), 60 | _ => None, 61 | }, 62 | } 63 | } 64 | 65 | #[allow(dead_code)] 66 | fn parse_complex(s: &str) -> Option> { 67 | match parse_pair(s, ',') { 68 | Some((re, im)) => Some(Complex { re, im }), 69 | None => None, 70 | } 71 | } 72 | 73 | #[test] 74 | fn test_parse_pair() { 75 | let sep = ','; 76 | assert_eq!(parse_pair::("", sep), None); 77 | assert_eq!(parse_pair::("10", sep), None); 78 | assert_eq!(parse_pair::(",10", sep), None); // no missing 79 | assert_eq!(parse_pair::("10,20", sep), Some((10, 20))); 80 | assert_ne!(parse_pair::("10,20", sep), Some((10, 10))); // equality 81 | assert_eq!(parse_pair::("10,20xy", sep), None); // no trailing 82 | } 83 | 84 | #[allow(dead_code)] 85 | fn escape_time(c: Complex, limit: u32) -> Option { 86 | let mut z = Complex { re: 0.0, im: 0.0 }; 87 | for i in 0..limit { 88 | z = z * z + c; 89 | if z.norm_sqr() > 4.0 { 90 | return Some(i); 91 | } 92 | } 93 | None 94 | } 95 | 96 | #[allow(dead_code)] 97 | fn complex_square_root(c: Complex) { 98 | let mut z = Complex { re: 0.0, im: 0.0 }; 99 | loop { 100 | z = z * z + c; 101 | } 102 | } 103 | 104 | #[allow(dead_code)] 105 | fn square_add_loop(c: f64) { 106 | let mut x = 0.; 107 | loop { 108 | x = x * x + c; 109 | } 110 | } 111 | 112 | #[allow(dead_code)] 113 | fn square_loop(mut x: f64) { 114 | loop { 115 | x = x * x; 116 | } 117 | } 118 | 119 | #[allow(dead_code)] 120 | fn pixel_to_point( 121 | bounds: (usize, usize), 122 | pixel: (usize, usize), 123 | upper_left: Complex, 124 | lower_right: Complex, 125 | ) -> Complex { 126 | let (w, h) = ( 127 | lower_right.re - upper_left.re, 128 | upper_left.im - lower_right.im, 129 | ); 130 | Complex { 131 | re: upper_left.re + pixel.0 as f64 * w / bounds.0 as f64, 132 | im: upper_left.im - pixel.1 as f64 * h / bounds.1 as f64, 133 | } 134 | } 135 | 136 | #[test] 137 | fn test_pixel_to_point() { 138 | assert_eq!( 139 | pixel_to_point( 140 | (100, 100), 141 | (25, 75), 142 | Complex { re: -1.0, im: 1.0 }, 143 | Complex { re: 1.0, im: -1.0 } 144 | ), 145 | Complex { re: -0.5, im: -0.5 } 146 | ); 147 | } 148 | 149 | fn render( 150 | pixels: &mut [u8], 151 | bounds: (usize, usize), 152 | upper_left: Complex, 153 | lower_right: Complex, 154 | ) { 155 | assert!(pixels.len() == bounds.0 * bounds.1); 156 | 157 | for row in 0..bounds.1 { 158 | for column in 0..bounds.0 { 159 | let point = pixel_to_point(bounds, (column, row), upper_left, lower_right); 160 | pixels[row * bounds.0 + column] = match escape_time(point, 255) { 161 | None => 0, 162 | Some(count) => 255 - count as u8, 163 | } 164 | } 165 | } 166 | } 167 | 168 | fn write_image( 169 | filename: &str, 170 | pixels: &[u8], 171 | bounds: (usize, usize), 172 | ) -> Result<(), std::io::Error> { 173 | let output = File::create(filename)?; 174 | 175 | let encoder = PNGEncoder::new(output); 176 | encoder.encode( 177 | &pixels, 178 | bounds.0 as u32, 179 | bounds.1 as u32, 180 | ColorType::Gray(8), 181 | )?; 182 | Ok(()) 183 | } 184 | -------------------------------------------------------------------------------- /stream-fusion/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stream-fusion" 3 | version = "0.1.0" 4 | authors = ["Don Stewart "] 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [lib] 9 | name = "stream_fusion" 10 | path = "src/lib.rs" 11 | 12 | [[bin]] 13 | name = "stream_test" 14 | path = "src/bin.rs" 15 | 16 | [dependencies] 17 | either = "*" 18 | num-traits = "*" 19 | 20 | [dev-dependencies] 21 | criterion = "0.3" 22 | 23 | [[bench]] 24 | name = "basics" 25 | harness = false 26 | 27 | -------------------------------------------------------------------------------- /stream-fusion/benches/basics.rs: -------------------------------------------------------------------------------- 1 | 2 | extern crate criterion; 3 | 4 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 5 | 6 | extern crate stream_fusion; 7 | use stream_fusion::{closure,r#trait}; 8 | 9 | fn criterion_benchmark(c: &mut Criterion) { 10 | let lim = 1_000_000; 11 | c.bench_function(&*format!("trait {}", lim), 12 | |b| b.iter(|| r#trait::basic_bench(black_box(lim)))); 13 | c.bench_function(&*format!("closure {}", lim), 14 | |b| b.iter(|| closure::basic_bench(black_box(lim)))); 15 | c.bench_function(&*format!("basic trait {}", lim), 16 | |b| b.iter(|| trait_bench1(black_box(lim)))); 17 | c.bench_function(&*format!("basic closure {}", lim), 18 | |b| b.iter(|| closure_bench1(black_box(lim)))); 19 | } 20 | 21 | criterion_group!(benches, criterion_benchmark); 22 | criterion_main!(benches); 23 | 24 | use r#trait::Stream; 25 | 26 | // arith seems to get optimized away 27 | pub fn trait_bench1(n: usize) -> i64 { 28 | r#trait::range(0, n as i64) 29 | .map(|n| n + 2) 30 | .foldl(|n, x| n + x, 0) 31 | } 32 | // arith seems to get optimized away 33 | pub fn closure_bench1(n: usize) -> i64 { 34 | let s0 = closure::range(0, n as i64); 35 | let s1 = closure::map(|n| n + 2, s0); 36 | closure::foldl(|n, x| n + x, 0, &s1) 37 | } 38 | -------------------------------------------------------------------------------- /stream-fusion/src/bin.rs: -------------------------------------------------------------------------------- 1 | mod r#trait; 2 | 3 | extern crate num_traits; 4 | 5 | fn main() { 6 | println!("{}", r#trait::basic_bench(1_000_000)); 7 | // println!("{}", iter_bench(1_000_000)); 8 | } 9 | 10 | /* 11 | * Same code generated as for Stream w/ Skip 12 | */ 13 | 14 | /* 15 | fn iter_bench(n: i64) -> i64 { 16 | (0 .. n) 17 | .filter(|n| n % 2 == 1) 18 | .map(|n| n * 3) 19 | .fold(0, |n, x| n + x) 20 | } 21 | */ 22 | -------------------------------------------------------------------------------- /stream-fusion/src/closure.rs: -------------------------------------------------------------------------------- 1 | // 2 | // Example of how to do stream fusion iterators in Rust 3 | // using pure functions/closure passing only 4 | // 5 | extern crate either; 6 | 7 | // Result of taking a single step in a stream 8 | pub enum Step { 9 | Yield(A, S), 10 | Skip(S), 11 | Done, 12 | } 13 | 14 | // data Stream a = forall s. Stream (s -> (Step s a)) s 15 | pub struct Stream<'s, S: Seed, A: Copy> { 16 | next: Box Step + 's>, 17 | seed: S 18 | } 19 | 20 | // 21 | // A class to hide specific seed implementations 22 | // 23 | pub trait Seed: Copy {} 24 | impl Seed for () {} 25 | impl Seed for bool {} 26 | impl Seed for usize {} 27 | impl Seed for i64 {} 28 | impl Seed for either::Either {} 29 | impl Seed for (S, T) {} 30 | 31 | // Check if a 'Stream' is empty 32 | pub fn is_empty_f<'s, A : Copy>(s: &Stream<'s, impl Seed, A>) -> bool { 33 | let mut st1 = s.seed; 34 | loop { 35 | let r = (s.next)(st1); 36 | match r { 37 | Step::Yield(..) => return false, 38 | Step::Skip(st2) => st1 = st2, 39 | Step::Done => return true, 40 | } 41 | } 42 | } 43 | 44 | // The empty stream 45 | pub fn empty_f<'s, A: Copy>() -> Stream<'s, impl Seed, A> { 46 | Stream { 47 | next: Box::new(|_| Step::Done), 48 | seed: (), 49 | } 50 | } 51 | 52 | // A stream with a single element 53 | pub fn singleton<'s, A: 's + Copy>(a: A) -> Stream<'s, impl Seed, A> { 54 | let step = move |b: bool| { 55 | if b { 56 | Step::Yield(a, false) 57 | } else { 58 | Step::Done 59 | } 60 | }; 61 | Stream { 62 | next: Box::new(step), 63 | seed: true, 64 | } 65 | } 66 | 67 | // Concatenate two streams 68 | pub fn append<'s, A: Copy + 's, S: Seed + 's, T: Seed + 's>( 69 | l: Stream<'s, S, A>, 70 | r: Stream<'s, T, A>, 71 | ) -> Stream<'s, impl Seed, A> 72 | { 73 | let x = l.seed; 74 | let step = move |a: either::Either| match a { 75 | either::Either::Left(sa) => { 76 | let v = (l.next)(sa); 77 | match v { 78 | Step::Yield(x, sa1) => Step::Yield(x, either::Either::Left(sa1)), 79 | Step::Skip(sa1) => Step::Skip(either::Either::Left(sa1)), 80 | Step::Done => Step::Skip(either::Either::Right(r.seed)), 81 | } 82 | } 83 | either::Either::Right(sb) => { 84 | let v = (r.next)(sb); 85 | match v { 86 | Step::Yield(x, sb1) => Step::Yield(x, either::Either::Right(sb1)), 87 | Step::Skip(sb1) => Step::Skip(either::Either::Right(sb1)), 88 | Step::Done => Step::Done, 89 | } 90 | } 91 | }; 92 | 93 | Stream { 94 | next: Box::new(step), 95 | seed: either::Either::Left(x), 96 | } 97 | } 98 | 99 | // Yield a 'Stream' of values obtained by running the generator a given number of times 100 | pub fn replicate<'s, A: 's + Copy>(n: usize, a: A) -> Stream<'s, impl Seed, A> { 101 | let step = move |i: usize| { 102 | if i == 0 { 103 | Step::Done 104 | } else { 105 | Step::Yield(a, i - 1) 106 | } 107 | }; 108 | Stream { 109 | next: Box::new(step), 110 | seed: n, 111 | } 112 | } 113 | 114 | use num_traits::int::PrimInt; 115 | 116 | // Yield a 'Stream' of values from A to B-1 117 | pub fn range<'s, A>(a: A, b : A) -> Stream<'s, impl Seed, A> 118 | where A: 's + Seed + Copy + std::ops::Add + PrimInt 119 | { 120 | let step = move |i: A| { 121 | if i >= b { 122 | Step::Done 123 | } else { 124 | Step::Yield(i, i + A::one()) 125 | } 126 | }; 127 | Stream { 128 | next: Box::new(step), 129 | seed: a, 130 | } 131 | } 132 | 133 | // Left fold with a accumulator and an operator 134 | #[inline(always)] 135 | pub fn foldl<'s, A: 's + Copy, B: 's + Copy>( 136 | f: fn(B, A) -> B, 137 | w: B, 138 | s: &Stream<'s, impl Seed, A>, 139 | ) -> B { 140 | let mut st = s.seed; 141 | let mut z = w; 142 | loop { 143 | let r = (s.next)(st); 144 | match r { 145 | Step::Yield(x, s1) => { 146 | z = f(z, x); 147 | st = s1 148 | } 149 | Step::Skip(s1) => st = s1, 150 | Step::Done => return z, 151 | } 152 | } 153 | } 154 | 155 | // Length of a stream 156 | pub fn length(s: &Stream) -> usize { 157 | foldl(|n, _| n + 1, 0, s) 158 | } 159 | 160 | // Map a function over a 'Stream' 161 | #[inline(always)] 162 | pub fn map<'s, A: 's + Copy, B: 's + Copy>( 163 | f: fn(A) -> B, 164 | s: Stream<'s, impl Seed +'s, A>, 165 | ) -> Stream<'s, impl Seed, B> { 166 | let x = s.seed; 167 | let step = move |st| { 168 | let r = (s.next)(st); 169 | match r { 170 | Step::Yield(x, st1) => { 171 | let y = f(x); 172 | Step::Yield(y, st1) 173 | } 174 | Step::Skip(st1) => Step::Skip(st1), 175 | Step::Done => Step::Done, 176 | } 177 | }; 178 | Stream { 179 | next: Box::new(step), 180 | seed: x, 181 | } 182 | } 183 | 184 | // Filter a 'Stream' with a predicate 185 | pub fn filter<'s, A: 's + Copy>( 186 | f: fn(&A) -> bool, 187 | s: Stream<'s, impl Seed +'s, A>, 188 | ) -> Stream<'s, impl Seed, A> { 189 | let x = s.seed; 190 | let step = move |st| { 191 | let r = (s.next)(st); 192 | match r { 193 | Step::Yield(x, st1) => { 194 | if f(&x) { 195 | Step::Yield(x, st1) 196 | } else { 197 | Step::Skip(st1) 198 | } 199 | } 200 | Step::Skip(st1) => Step::Skip(st1), 201 | Step::Done => Step::Done, 202 | } 203 | }; 204 | Stream { 205 | next: Box::new(step), 206 | seed: x, 207 | } 208 | } 209 | 210 | // First element of the 'Stream' or None if empty 211 | pub fn head<'s, A: 's + Copy>(s: &Stream<'s, impl Seed, A>) -> Option { 212 | let mut st1 = s.seed; 213 | loop { 214 | let r = (s.next)(st1); 215 | match r { 216 | Step::Yield(x, _) => return Some(x), 217 | Step::Skip(st2) => st1 = st2, 218 | Step::Done => return None, 219 | } 220 | } 221 | } 222 | 223 | // Last element of the 'Stream' or None if empty 224 | pub fn last<'s, A: 's + Copy>(s: &Stream<'s, impl Seed, A>) -> Option { 225 | let mut st1 = s.seed; 226 | // we do this as two loops. one that iterates until we find at least one value 227 | // the other that then holds the most recent seen one, until it returns 228 | let mut result: A; 229 | 230 | loop { 231 | let r = (s.next)(st1); 232 | match r { 233 | Step::Yield(x, st2) => { 234 | st1 = st2; 235 | result = x; 236 | break; 237 | } 238 | Step::Skip(st2) => st1 = st2, 239 | Step::Done => return None, 240 | } 241 | } 242 | // r is definitely initialized now with a possible result 243 | loop { 244 | let r = (s.next)(st1); 245 | match r { 246 | Step::Yield(y, st2) => { 247 | st1 = st2; 248 | result = y; 249 | } 250 | Step::Skip(st2) => st1 = st2, 251 | Step::Done => { 252 | return Some(result); 253 | } 254 | } 255 | } 256 | } 257 | 258 | // The first @n@ elements of a stream 259 | pub fn take<'s, A: Copy>(n: usize, s: &'s Stream<'s, impl Seed, A>) -> Stream<'s, impl Seed, A> { 260 | let step1 = move |(s0, i)| { 261 | if i < n { 262 | let r = (s.next)(s0); // run the first stream 263 | match r { 264 | Step::Yield(x, s1) => Step::Yield(x, (s1, i + 1)), 265 | Step::Skip(s1) => Step::Skip((s1, i)), 266 | Step::Done => Step::Done, 267 | } 268 | } else { 269 | Step::Done 270 | } 271 | }; 272 | Stream { 273 | next: Box::new(step1), 274 | seed: (s.seed, 0), 275 | } 276 | } 277 | 278 | /* 279 | * need trait or hiding for state 280 | */ 281 | pub fn cons<'s, A: 's + Copy>( 282 | a: A, 283 | s: Stream<'s, impl Seed + 's, A>, 284 | ) -> Stream<'s, impl Seed, A> { 285 | let s1 = singleton(a); 286 | append(s1, s) // consumes 287 | } 288 | 289 | pub fn basic_bench(n: usize) -> i64 { 290 | let s1 = range(0, n as i64); 291 | let s2 = filter(|n| n % 2 == 1, s1); 292 | let s3 = map(|n| n * 2, s2); 293 | foldl(|n, x| n + x, 0, &s3) 294 | } 295 | 296 | /* basic tests */ 297 | #[cfg(test)] 298 | mod tests { 299 | 300 | use super::*; 301 | 302 | #[test] 303 | fn test_empty_m() { 304 | let s1: Stream<_, i64> = empty_f(); 305 | assert_eq!(true, is_empty_f(&s1)); 306 | } 307 | 308 | /* functional calls */ 309 | 310 | #[test] 311 | fn test_empty() { 312 | let s1: Stream<_, i64> = empty_f(); 313 | assert_eq!(true, is_empty_f(&s1)); 314 | } 315 | 316 | #[test] 317 | fn test_singleton() { 318 | let s1 = singleton(42i64); 319 | assert_eq!(false, is_empty_f(&s1)); 320 | } 321 | 322 | #[test] 323 | fn test_append() { 324 | let s1 = singleton(42i64); 325 | let s2 = singleton(64i64); 326 | let s3 = append(s1, s2); 327 | 328 | assert_eq!(false, is_empty_f(&s3)); 329 | } 330 | 331 | #[test] 332 | fn test_replicate() { 333 | let s1 = replicate(10, 42i64); 334 | assert_eq!(false, is_empty_f(&s1)); 335 | } 336 | 337 | #[test] 338 | fn test_length() { 339 | let l = 10; 340 | let s1 = replicate(l, 42i64); 341 | let s2 = replicate(l, 42i64); 342 | let s3 = append(s1, s2); 343 | assert_eq!(length(&s3), 2 * l); 344 | } 345 | 346 | #[test] 347 | fn test_map() { 348 | let s1 = replicate(10, 42i64); 349 | let s2 = map(|x| x + 1, s1); 350 | let v = foldl(|n, i| n + i, 0, &s2); 351 | assert_eq!(v, 43 * 10) 352 | } 353 | 354 | #[test] 355 | fn test_head() { 356 | let s1 = replicate(10, 42i64); 357 | assert_eq!(Some(42), head(&s1)); 358 | let s1: Stream<_, i64> = empty_f(); 359 | assert_eq!(None, head(&s1)); 360 | } 361 | 362 | #[test] 363 | fn test_last() { 364 | let s1 = replicate(10, 42i64); 365 | assert_eq!(Some(42), last(&s1)); 366 | let s1: Stream<_, i64> = empty_f(); 367 | assert_eq!(None, last(&s1)); 368 | } 369 | 370 | #[test] 371 | fn test_take() { 372 | let s1 = replicate(10, 42i64); 373 | assert_eq!(2, length(&take(2, &s1))); 374 | let s1: Stream<_, i64> = empty_f(); 375 | assert_eq!(0, length(&take(10, &s1))); 376 | } 377 | 378 | #[test] 379 | fn test_cons() { 380 | let s2 = cons(3, cons(4, cons(6, empty_f()))); 381 | assert_eq!(3, length(&s2)); 382 | } 383 | 384 | #[test] 385 | fn test_perf_lazy() { // should be fast 386 | let lim = 10000000; 387 | let s1 = replicate(lim, 0); 388 | assert_eq!(1, length(&take(1,&s1))); 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /stream-fusion/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod r#trait; 2 | pub mod closure; 3 | pub mod traitnoskip; 4 | 5 | extern crate num_traits; 6 | 7 | #[cfg(test)] 8 | mod tests { 9 | use super::*; 10 | 11 | #[test] 12 | fn it_works() { 13 | assert_eq!(5000, r#trait::basic_bench(100)); 14 | assert_eq!(5000, closure::basic_bench(100)); 15 | assert_eq!(5000, traitnoskip::basic_bench(100)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /stream-fusion/src/trait.rs: -------------------------------------------------------------------------------- 1 | // Result of taking a single step in a stream 2 | // 3 | // Trait implementation: 4 | // - generators and transformers are data types 5 | // - impl Stream for each type 6 | // - consumers are trait methods 7 | // - seed of stream stored in trait types 8 | // 9 | pub enum Step { 10 | Yield(S::Item, S), 11 | Skip(S), 12 | Done, 13 | } 14 | 15 | pub trait Stream: Sized + Copy { 16 | type Item; 17 | 18 | fn next(&self) -> Step; 19 | 20 | fn is_empty(&self) -> bool { 21 | let mut stream = *self; 22 | loop { 23 | let v = stream.next(); 24 | match v { 25 | Step::Yield(..) => { return false } 26 | Step::Skip(s) => { stream = s } 27 | Step::Done => { return true } 28 | } 29 | } 30 | } 31 | 32 | fn foldl(self, f: F, w: B) -> B 33 | where F : Fn(B,Self::Item) -> B 34 | { 35 | let mut stream = self; 36 | let mut z = w; 37 | loop { 38 | let v = stream.next(); 39 | match v { 40 | Step::Yield(x, s) => { 41 | z = f(z, x); 42 | stream = s; 43 | } 44 | Step::Skip(s) => { stream = s } 45 | Step::Done => { return z } 46 | } 47 | } 48 | } 49 | 50 | // Length of a stream 51 | fn length(&self) -> usize { 52 | self.foldl(|n, _| n + 1, 0) 53 | } 54 | 55 | // Map a function over a 'Stream' 56 | fn map(self, f:F) -> Map 57 | where F: Fn(Self::Item) -> B 58 | { 59 | Map { stream: self, mapf: f } 60 | } 61 | 62 | // Filter a 'stream' with a predicate 63 | fn filter(self, f:F) -> Filter 64 | where F: Fn(&Self::Item) -> bool 65 | { 66 | Filter { stream: self, filterp: f } 67 | } 68 | 69 | } 70 | 71 | use std::marker::PhantomData; 72 | 73 | #[derive(Copy,Clone)] 74 | pub struct Empty { empty: PhantomData } 75 | 76 | impl Stream for Empty { 77 | type Item = A; 78 | 79 | fn next(&self) -> Step { 80 | Step::Done 81 | } 82 | } 83 | 84 | pub fn empty() -> Empty { 85 | Empty { empty: PhantomData } 86 | } 87 | 88 | #[derive(Copy,Clone)] 89 | pub struct Single { item: A, state: bool } 90 | 91 | impl Stream for Single { 92 | type Item = A; 93 | 94 | fn next(&self) -> Step { 95 | if self.state { 96 | Step::Yield(self.item, Single { 97 | item: self.item, 98 | state: false 99 | }) 100 | } else { 101 | Step::Done 102 | } 103 | } 104 | } 105 | 106 | pub fn single(a: A) -> Single { 107 | Single { item: a, state: true } 108 | } 109 | 110 | #[derive(Copy,Clone)] 111 | pub struct Replicate { item: A, state: usize } 112 | 113 | impl Stream for Replicate { 114 | type Item = A; 115 | 116 | fn next(&self) -> Step { 117 | if self.state == 0 { 118 | Step::Done 119 | } else { 120 | Step::Yield(self.item, Replicate { 121 | item: self.item, 122 | state: self.state - 1 123 | }) 124 | } 125 | } 126 | } 127 | 128 | pub fn replicate(a: A, n: usize) -> Replicate { 129 | Replicate { item: a, state: n } 130 | } 131 | 132 | #[derive(Copy,Clone)] 133 | pub struct Range { start: A, end: A } 134 | 135 | use num_traits::int::PrimInt; 136 | 137 | impl Stream for Range 138 | where A: Copy + std::ops::Add + PrimInt 139 | { 140 | type Item = A; 141 | 142 | fn next(&self) -> Step { 143 | if self.start >= self.end { 144 | Step::Done 145 | } else { 146 | Step::Yield(self.start, 147 | Range { 148 | start: self.start + A::one(), 149 | end: self.end 150 | } 151 | ) 152 | } 153 | } 154 | } 155 | 156 | pub fn range(a: A, b: A) -> Range { 157 | Range { start: a, end : b } 158 | } 159 | 160 | #[derive(Clone,Copy)] 161 | pub struct Map { stream: S, mapf: F } 162 | 163 | impl Stream for Map 164 | where F: Fn(S::Item) -> B 165 | { 166 | type Item = B; 167 | 168 | fn next(&self) -> Step { 169 | let f = self.mapf; 170 | match self.stream.next() { 171 | Step::Done => Step::Done, 172 | Step::Skip(s) => 173 | Step::Skip(Map { 174 | stream: s, 175 | mapf: f 176 | }), 177 | Step::Yield(x, s) => 178 | Step::Yield(f(x), Map { 179 | stream: s, 180 | mapf: f 181 | }), 182 | } 183 | } 184 | } 185 | 186 | #[derive(Clone,Copy)] 187 | pub struct Filter { stream: S, filterp: F } 188 | 189 | impl Stream for Filter 190 | where F: Fn(&S::Item) -> bool 191 | { 192 | type Item = S::Item; 193 | 194 | fn next(&self) -> Step { 195 | let p = self.filterp; 196 | match self.stream.next() { 197 | Step::Done => Step::Done, 198 | Step::Skip(s) => 199 | Step::Skip(Filter { 200 | stream: s, 201 | filterp: p 202 | }), 203 | Step::Yield(x, s) => { 204 | let s1 = Filter { stream: s, filterp: p }; 205 | if p(&x) { 206 | Step::Yield (x, s1) 207 | } else { 208 | Step::Skip(s1) 209 | } 210 | } 211 | } 212 | } 213 | } 214 | 215 | /* 216 | // todo : append, head, take, last, cons 217 | */ 218 | 219 | pub fn basic_bench(n: usize) -> i64 { 220 | range(0, n as i64) 221 | .filter(|n| n % 2 == 1) 222 | .map(|n| n * 2) 223 | .foldl(|n, x| n + x, 0) 224 | } 225 | 226 | #[cfg(test)] 227 | mod tests { 228 | 229 | use super::*; 230 | 231 | #[test] 232 | fn test_empty() { 233 | let s: Empty = empty(); 234 | assert_eq!(true, s.is_empty()); 235 | } 236 | 237 | #[test] 238 | fn test_single() { 239 | let s: Single = single(42); 240 | assert_eq!(false, s.is_empty()); 241 | } 242 | 243 | #[test] 244 | fn test_length() { 245 | let s: Empty = empty(); 246 | assert_eq!(0, s.length()); 247 | let s: Single = single(42); 248 | assert_eq!(1, s.length()); 249 | } 250 | 251 | #[test] 252 | fn test_replicate() { 253 | let s = replicate(42i64, 100); 254 | assert_eq!(false, s.is_empty()); 255 | assert_eq!(100, s.length()); 256 | } 257 | 258 | #[test] 259 | fn test_range() { 260 | let s = range(0, 10); 261 | assert_eq!(false, s.is_empty()); 262 | assert_eq!(10, s.length()); 263 | assert_eq!(45, s.foldl(|n,i| n + i, 0)); 264 | } 265 | 266 | #[test] 267 | fn test_range2() { 268 | let s = range(1, 3); 269 | assert_eq!(2, s.length()); 270 | assert_eq!(3, s.foldl(|n,i| n + i, 0)); 271 | } 272 | 273 | #[test] 274 | fn test_map() { 275 | let s1 = replicate(42i64, 10); 276 | let v = s1.map(|x| { x + 1 } ).foldl(|n, i| n + i, 0); 277 | assert_eq!(v, 43 * 10) 278 | } 279 | 280 | #[test] 281 | fn test_filter() { 282 | let v = replicate(42i64, 10) 283 | .map(|x| { x + 1 } ) 284 | .filter(|x| { x % 2 == 0 } ) 285 | .foldl(|n, i| n + i, 0); 286 | assert_eq!(v, 0) 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /stream-fusion/src/traitnoskip.rs: -------------------------------------------------------------------------------- 1 | // Result of taking a single step in a stream 2 | // 3 | // Trait implementation: 4 | // - generators and transformers are data types 5 | // - impl Stream for each type 6 | // - consumers are trait methods 7 | // - seed of stream stored in trait types 8 | // 9 | pub enum Step { 10 | Yield(S::Item, S), 11 | Done, 12 | } 13 | 14 | pub trait Stream: Sized + Copy { 15 | type Item; 16 | 17 | fn next(&self) -> Step; 18 | 19 | fn is_empty(&self) -> bool { 20 | let v = self.next(); 21 | match v { 22 | Step::Yield(..) => { false } 23 | Step::Done => { true } 24 | } 25 | } 26 | 27 | fn foldl(self, f: F, w: B) -> B 28 | where F : Fn(B,Self::Item) -> B 29 | { 30 | let mut stream = self; 31 | let mut z = w; 32 | loop { 33 | let v = stream.next(); 34 | match v { 35 | Step::Yield(x, s) => { 36 | z = f(z, x); 37 | stream = s; 38 | } 39 | Step::Done => { return z } 40 | } 41 | } 42 | } 43 | 44 | // Length of a stream 45 | fn length(&self) -> usize { 46 | self.foldl(|n, _| n + 1, 0) 47 | } 48 | 49 | // Map a function over a 'Stream' 50 | fn map(self, f:F) -> Map 51 | where F: Fn(Self::Item) -> B 52 | { 53 | Map { stream: self, mapf: f } 54 | } 55 | 56 | // Filter a 'stream' with a predicate 57 | fn filter(self, f:F) -> Filter 58 | where F: Fn(&Self::Item) -> bool 59 | { 60 | Filter { stream: self, filterp: f } 61 | } 62 | 63 | } 64 | 65 | use std::marker::PhantomData; 66 | 67 | #[derive(Copy,Clone)] 68 | pub struct Empty { empty: PhantomData } 69 | 70 | impl Stream for Empty { 71 | type Item = A; 72 | 73 | fn next(&self) -> Step { 74 | Step::Done 75 | } 76 | } 77 | 78 | pub fn empty() -> Empty { 79 | Empty { empty: PhantomData } 80 | } 81 | 82 | #[derive(Copy,Clone)] 83 | pub struct Single { item: A, state: bool } 84 | 85 | impl Stream for Single { 86 | type Item = A; 87 | 88 | fn next(&self) -> Step { 89 | if self.state { 90 | Step::Yield(self.item, Single { 91 | item: self.item, 92 | state: false 93 | }) 94 | } else { 95 | Step::Done 96 | } 97 | } 98 | } 99 | 100 | pub fn single(a: A) -> Single { 101 | Single { item: a, state: true } 102 | } 103 | 104 | #[derive(Copy,Clone)] 105 | pub struct Replicate { item: A, state: usize } 106 | 107 | impl Stream for Replicate { 108 | type Item = A; 109 | 110 | fn next(&self) -> Step { 111 | if self.state == 0 { 112 | Step::Done 113 | } else { 114 | Step::Yield(self.item, Replicate { 115 | item: self.item, 116 | state: self.state - 1 117 | }) 118 | } 119 | } 120 | } 121 | 122 | pub fn replicate(a: A, n: usize) -> Replicate { 123 | Replicate { item: a, state: n } 124 | } 125 | 126 | #[derive(Copy,Clone)] 127 | pub struct Range { start: A, end: A } 128 | 129 | use num_traits::int::PrimInt; 130 | 131 | impl Stream for Range 132 | where A: Copy + std::ops::Add + PrimInt 133 | { 134 | type Item = A; 135 | 136 | fn next(&self) -> Step { 137 | if self.start >= self.end { 138 | Step::Done 139 | } else { 140 | Step::Yield(self.start, 141 | Range { 142 | start: self.start + A::one(), 143 | end: self.end 144 | } 145 | ) 146 | } 147 | } 148 | } 149 | 150 | pub fn range(a: A, b: A) -> Range { 151 | Range { start: a, end : b } 152 | } 153 | 154 | #[derive(Clone,Copy)] 155 | pub struct Map { stream: S, mapf: F } 156 | 157 | impl Stream for Map 158 | where F: Fn(S::Item) -> B 159 | { 160 | type Item = B; 161 | 162 | fn next(&self) -> Step { 163 | let f = self.mapf; 164 | match self.stream.next() { 165 | Step::Done => Step::Done, 166 | Step::Yield(x, s) => 167 | Step::Yield(f(x), Map { 168 | stream: s, 169 | mapf: f 170 | }), 171 | } 172 | } 173 | } 174 | 175 | #[derive(Clone,Copy)] 176 | pub struct Filter { stream: S, filterp: F } 177 | 178 | impl Stream for Filter 179 | where F: Fn(&S::Item) -> bool 180 | { 181 | type Item = S::Item; 182 | 183 | fn next(&self) -> Step { 184 | let p = self.filterp; 185 | let mut stream1 = self.stream; 186 | loop { 187 | match stream1.next() { 188 | Step::Done => return Step::Done, 189 | Step::Yield(x, s) => { 190 | if p(&x) { 191 | let s1 = Filter { stream: s, filterp: p }; 192 | return Step::Yield (x, s1) 193 | } else { 194 | stream1 = s; 195 | // In the paper we would just Skip here, to keep it non-recursive. 196 | // Without skip, we need a nested loop 197 | // Step::Skip(s1), need to recurse. 198 | } 199 | } 200 | } 201 | } 202 | } 203 | } 204 | 205 | /* 206 | // todo : append, head, take, last, cons 207 | */ 208 | 209 | pub fn basic_bench(n: usize) -> i64 { 210 | range(0, n as i64) 211 | .filter(|n| n % 2 == 1) 212 | .map(|n| n * 2) 213 | .foldl(|n, x| n + x, 0) 214 | } 215 | 216 | #[cfg(test)] 217 | mod tests { 218 | 219 | use super::*; 220 | 221 | #[test] 222 | fn test_empty() { 223 | let s: Empty = empty(); 224 | assert_eq!(true, s.is_empty()); 225 | } 226 | 227 | #[test] 228 | fn test_single() { 229 | let s: Single = single(42); 230 | assert_eq!(false, s.is_empty()); 231 | } 232 | 233 | #[test] 234 | fn test_length() { 235 | let s: Empty = empty(); 236 | assert_eq!(0, s.length()); 237 | let s: Single = single(42); 238 | assert_eq!(1, s.length()); 239 | } 240 | 241 | #[test] 242 | fn test_replicate() { 243 | let s = replicate(42i64, 100); 244 | assert_eq!(false, s.is_empty()); 245 | assert_eq!(100, s.length()); 246 | } 247 | 248 | #[test] 249 | fn test_range() { 250 | let s = range(0, 10); 251 | assert_eq!(false, s.is_empty()); 252 | assert_eq!(10, s.length()); 253 | assert_eq!(45, s.foldl(|n,i| n + i, 0)); 254 | } 255 | 256 | #[test] 257 | fn test_range2() { 258 | let s = range(1, 3); 259 | assert_eq!(2, s.length()); 260 | assert_eq!(3, s.foldl(|n,i| n + i, 0)); 261 | } 262 | 263 | #[test] 264 | fn test_map() { 265 | let s1 = replicate(42i64, 10); 266 | let v = s1.map(|x| { x + 1 } ).foldl(|n, i| n + i, 0); 267 | assert_eq!(v, 43 * 10) 268 | } 269 | 270 | #[test] 271 | fn test_filter() { 272 | let v = replicate(42i64, 10) 273 | .map(|x| { x + 1 } ) 274 | .filter(|x| { x % 2 == 0 } ) 275 | .foldl(|n, i| n + i, 0); 276 | assert_eq!(v, 0) 277 | } 278 | } 279 | --------------------------------------------------------------------------------