remove workspace from the repository, instead generate a zipfile to upload
authorRalf Jung <post@ralfj.de>
Mon, 13 Jun 2016 18:18:26 +0000 (20:18 +0200)
committerRalf Jung <post@ralfj.de>
Mon, 13 Jun 2016 18:35:42 +0000 (20:35 +0200)
41 files changed:
Makefile
README.md
docs/.gitignore
src/main.rs
src/part00.rs
src/part01.rs
src/part02.rs
src/part03.rs
src/part04.rs
src/part05.rs
src/part06.rs
src/part07.rs
src/part08.rs
src/part09.rs
src/part10.rs
src/part11.rs
src/part12.rs
src/part13.rs
src/part14.rs
src/part15.rs
src/part16.rs
workspace/.gitignore
workspace/README.md [deleted file]
workspace/src/main.rs
workspace/src/part00.rs [deleted file]
workspace/src/part01.rs [deleted file]
workspace/src/part02.rs [deleted file]
workspace/src/part03.rs [deleted file]
workspace/src/part04.rs [deleted file]
workspace/src/part05.rs [deleted file]
workspace/src/part06.rs [deleted file]
workspace/src/part07.rs [deleted file]
workspace/src/part08.rs [deleted file]
workspace/src/part09.rs [deleted file]
workspace/src/part10.rs [deleted file]
workspace/src/part11.rs [deleted file]
workspace/src/part12.rs [deleted file]
workspace/src/part13.rs [deleted file]
workspace/src/part14.rs [deleted file]
workspace/src/part15.rs [deleted file]
workspace/src/part16.rs [deleted file]

index 1674606b61600ca772f9bc66368393e8af237640..c157dacd438510f9ca826f9cf0815e93f1b4b584 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -22,10 +22,10 @@ docs/%.html: .tmp/docs/%.rs
 # The generated files are shipped only for the benefit of Windows users, who
 # typically don't have the necessary tools for generating the workspace
 # available.
-workspace: $(WORKSPACEFILES)
+workspace: $(WORKSPACEFILES) docs/workspace.zip
 
 workspace/src/%.rs: src/%.rs Makefile dup-unimpl.sed
-       @mkdir -p .tmp/docs
+       @mkdir -p .tmp/docs workspace/src/
        @echo "$< -> $@"
        @# sed-fu: remove lines starting with "//@", and replace those ending in "/*@*/" or "/*@@*/" by "unimplemented!()".
        @# Also coalesce multiple adjacent such lines to one.
@@ -34,6 +34,10 @@ workspace/src/%.rs: src/%.rs Makefile dup-unimpl.sed
 workspace/src/main.rs:
        # Don't touch this file
 
+docs/workspace.zip: $(WORKSPACEFILES) workspace/Cargo.toml workspace/Cargo.lock
+       @rm -f $@
+       zip $@ $^
+
 ## Crates
 crates: $(WORKSPACEFILES)
        @cargo build
index 7895b8b94e5c6186e74b9a4f733db79f667e6dbe..acef159bb30851fc96687e04a634ce922b611ab8 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,9 +1,12 @@
 # Rust-101
 
 This documents Rust-101, a tutorial for the [Rust
-language](http://www.rust-lang.org/). You are probably looking for the
-[actual tutorial](https://www.ralfj.de/projects/rust-101/main.html).
+language](http://www.rust-lang.org/).
 
+## Online tutorial
+
+The easiest way to the toturial is to check out its
+[online version](https://www.ralfj.de/projects/rust-101/main.html).
 
 ## Usage
 
index fe099b809ba26649fe710a99b6f67970c0f104da..e48f428185aee31c81830d7f57c4b29e5e7210fe 100644 (file)
@@ -1,3 +1,4 @@
 fonts/
 *.html
+*.zip
 pycco.css
index 69d9ca7090a3812d66f88e12e2a42f82d40be17f..b4ee6ffee289c473a24e923efc9167936e884158 100644 (file)
 // [the second chapter of The Book](https://doc.rust-lang.org/stable/book/installing-rust.html).
 // This will also install `cargo`, the tool responsible for building rust projects (or *crates*).
 // 
-// Next, fetch the Rust-101 source code from the [git repository](https://www.ralfj.de/git/rust-101.git)
-// (also available [on GitHub](https://github.com/RalfJung/rust-101), and as a
-// [zip archive](https://github.com/RalfJung/rust-101/archive/master.zip) in case you don't have git installed).
+// Next, we have to prepare a workspace for you to conduct your Rust-101 work in, so that you don't
+// have to start with an empty file. The easiest way is to [download the workspace](https://www.ralfj.de/projects/rust-101/workspace.zip)
+// matching the online tutorial. Try `cargo build` in that new folder to check that compiling your workspace succeeds.
+// (You can also execute it with `cargo run`, but you'll need to do some work before this does anything useful.)
 // 
-// There is a workspace prepared for you in the `workspace` folder. I suggest you copy this
-// folder somewhere else. Try `cargo build` in that new folder to check that compiling your workspace succeeds.
-// (You can also execute it with `cargo run`, but you'll need to do some work before this will succeed.)
+// Alternatively, you can build the workspace from source by fetching the [git repository](https://www.ralfj.de/git/rust-101.git)
+// and running `make workspace`.
 
 // Course Content
 // --------------
index 00eb4d1dfe9e92a8c8ac35a986ca12d86569276d..d126a1795648dba7b6afabac70f1a5a17a43b823 100644 (file)
@@ -113,4 +113,4 @@ pub fn main() {
 //@ computed that ourselves, but that's beside the point. More importantly:
 //@ You completed the first part of the course.
 
-//@ [index](main.html) | previous | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part00.rs) | [next](part01.html)
+//@ [index](main.html) | previous | [raw source](workspace/src/part00.rs) | [next](part01.html)
index fa06a80cda682e60ebd44c70b61546c698336411..56272b2f68c294c879171bee569068cd482d2522 100644 (file)
@@ -106,4 +106,4 @@ pub fn main() {
 
 // **Exercise 01.2**: Write a function `vec_print` that takes a vector and prints all its elements.
 
-//@ [index](main.html) | [previous](part00.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part01.rs) | [next](part02.html)
+//@ [index](main.html) | [previous](part00.html) | [raw source](workspace/src/part01.rs) | [next](part02.html)
index 44a20d43408c92b15bd4ae675b71e16ca9eae2ef..6a0108766edb638f580207b00347d9d2ed9e7ece 100644 (file)
@@ -146,4 +146,4 @@ pub fn main() {
 // **Exercise 02.1**: Change your program such that it computes the minimum of a `Vec<f32>` (where `f32` is the type
 // of 32-bit floating-point numbers). You should not change `vec_min` in any way, obviously!
 
-//@ [index](main.html) | [previous](part01.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part02.rs) | [next](part03.html)
+//@ [index](main.html) | [previous](part01.html) | [raw source](workspace/src/part02.rs) | [next](part03.html)
index 3a35aa7057a40bdf496775aad6972996b37d4041..2e818d1413f730187d5327d0726fa3591707635f 100644 (file)
@@ -116,4 +116,4 @@ impl<T: Print> SomethingOrNothing<T> {
 // **Exercise 03.2**: Building on exercise 02.2, implement all the things you need on `f32` to make your
 // program work with floating-point numbers.
 
-//@ [index](main.html) | [previous](part02.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part03.rs) | [next](part04.html)
+//@ [index](main.html) | [previous](part02.html) | [raw source](workspace/src/part03.rs) | [next](part04.html)
index 31e80564fdbac017ee4e83fe61378f97b3a15fa5..cb101fe10fbed065e41a4bb9e1bdb0416db4f133 100644 (file)
@@ -143,4 +143,4 @@ fn mutable_ref_demo() {
 // As it turns out, combined with the abstraction facilities of Rust, this is a very powerful mechanism
 // to tackle many problems beyond basic memory safety. You will see some examples for this soon.
 
-//@ [index](main.html) | [previous](part03.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part04.rs) | [next](part05.html)
+//@ [index](main.html) | [previous](part03.html) | [raw source](workspace/src/part04.rs) | [next](part05.html)
index 8a2cd9060247a2010212d85bac47924a24153141..eaad9804aaad71226c1bf3332839d32c73bbd9ce 100644 (file)
@@ -147,4 +147,4 @@ fn work_on_variant(mut var: Variant, text: String) {
 //@ I hope this example clarifies why Rust has to rule out mutation in the presence of aliasing *in general*,
 //@ not just for the specific case of a buffer being reallocated, and old pointers becoming hence invalid.
 
-//@ [index](main.html) | [previous](part04.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part05.rs) | [next](part06.html)
+//@ [index](main.html) | [previous](part04.html) | [raw source](workspace/src/part05.rs) | [next](part06.html)
index 9552eb5316224fa15e27bc216286ceb8b2afb7d7..4c0e6cebaeda3ffdda5f6191749e5a804355a768 100644 (file)
@@ -148,4 +148,4 @@ fn rust_foo(mut v: Vec<i32>) -> i32 {
 //@ Most of the time, we don't have to explicitly add lifetimes to function types. This is thanks to *lifetime elision*,
 //@ where Rust will automatically insert lifetimes we did not specify, following some [simple, well-documented rules](https://doc.rust-lang.org/stable/book/lifetimes.html#lifetime-elision).
 
-//@ [index](main.html) | [previous](part05.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part06.rs) | [next](part07.html)
+//@ [index](main.html) | [previous](part05.html) | [raw source](workspace/src/part06.rs) | [next](part07.html)
index 2d88390c82f88956c91d2e3c3149288374bf7b29..e395ba622af9cb3a1dc46f66940c79d26bc3be9b 100644 (file)
@@ -147,4 +147,4 @@ fn test_vec_min() {
 // of course, need a `Display` bound on `T`.) Then you should be able to use them with `println!` just like you do
 // with numbers, and get rid of the inherent functions to print `SomethingOrNothing<i32>` and `SomethingOrNothing<f32>`.
 
-//@ [index](main.html) | [previous](part06.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part07.rs) | [next](part08.html)
+//@ [index](main.html) | [previous](part06.html) | [raw source](workspace/src/part07.rs) | [next](part08.html)
index 340de24a88e071f2e2ab68fd54ee646b85fd7e04..c18cbeb957e673a2d19bce1e01c0bee4c4213b54 100644 (file)
@@ -152,4 +152,4 @@ mod tests {
 // **Exercise 08.6**: Write a subtraction function, and testcases for it. Decide for yourself how you want to handle negative results.
 // For example, you may want to return an `Option`, to panic, or to return `0`.
 
-//@ [index](main.html) | [previous](part07.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part08.rs) | [next](part09.html)
+//@ [index](main.html) | [previous](part07.html) | [raw source](workspace/src/part08.rs) | [next](part09.html)
index ecb9ffaab1c801c9d7445937f9514d2bc411869f..5916258a3da7e4d830b705361cf147010cc64558 100644 (file)
@@ -146,4 +146,4 @@ impl<'a> IntoIterator for &'a BigInt {
 //@ then you will obtain ownership of the elements during the iteration - and destroy the vector in the process. We actually did that in
 //@ `part01::vec_min`, but we did not care. You can write `for e in &v` or `for e in v.iter()` to avoid this.
 
-//@ [index](main.html) | [previous](part08.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part09.rs) | [next](part10.html)
+//@ [index](main.html) | [previous](part08.html) | [raw source](workspace/src/part09.rs) | [next](part10.html)
index b586cd5057d3da50b4319dc207d324c589f2e4c0..6fa8f1e429f9e50ef21678e9ce9d16d1f582c825 100644 (file)
@@ -141,4 +141,4 @@ fn filter_vec_by_divisor(v: &Vec<i32>, divisor: i32) -> Vec<i32> {
 // product of those numbers that sit at odd positions? A function that checks whether a vector contains a certain number? Whether all numbers are
 // smaller than some threshold? Be creative!
 
-//@ [index](main.html) | [previous](part09.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part10.rs) | [next](part11.html)
+//@ [index](main.html) | [previous](part09.html) | [raw source](workspace/src/part10.rs) | [next](part11.html)
index a5cafa1ca6794419e1d29184b862ab0b1b0b98d7..9d931db73b41fc912c1885ab74075890ab8eb99b 100644 (file)
@@ -117,4 +117,4 @@ pub fn main() {
 // to work with an arbitrary type `T` that's passed to the callbacks. Since you need to call multiple callbacks with the
 // same `t: T`, you will either have to restrict `T` to `Copy` types, or pass a reference.
 
-//@ [index](main.html) | [previous](part10.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part11.rs) | [next](part12.html)
+//@ [index](main.html) | [previous](part10.html) | [raw source](workspace/src/part11.rs) | [next](part12.html)
index 7d03ca61c0d1a238618ff996835a1e783d5cd525..c2331eaf618b82aa2ee8e1308512c52b364401cd 100644 (file)
@@ -166,4 +166,4 @@ fn demo_mut(c: &mut CallbacksMut) {
 // **Exercise 12.1**: Write some piece of code using only the available, public interface of `CallbacksMut` such that a reentrant call to a closure
 // is happening, and the program panics because the `RefCell` refuses to hand out a second mutable borrow of the closure's environment.
 
-//@ [index](main.html) | [previous](part11.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part12.rs) | [next](part13.html)
+//@ [index](main.html) | [previous](part11.html) | [raw source](workspace/src/part12.rs) | [next](part13.html)
index 4fbc908cab5043b8eb486ce6f7d97eecded1d251..8edcc9912db61ce1ec85b0bab10382772788c61f 100644 (file)
@@ -189,4 +189,4 @@ pub fn main() {
 //@ So if the environment of your closure contains an `Rc`, it won't be `Send`, preventing it from causing trouble. If however every
 //@ captured variable *is* `Send`, then so is the entire environment, and you are good.
 
-//@ [index](main.html) | [previous](part12.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part13.rs) | [next](part14.html)
+//@ [index](main.html) | [previous](part12.html) | [raw source](workspace/src/part13.rs) | [next](part14.html)
index e16837ce352a6f10cde0595047c74c9898346b45..5c009059b527ea7b9659bd9c2af7d26b17da9230 100644 (file)
@@ -159,4 +159,4 @@ Options:
 // the pattern to regular-expression mode, and change `filter_lines` to honor this option. The documentation of regex is available from its crates.io site.
 // (You won't be able to use the `regex!` macro if you are on the stable or beta channel of Rust. But it wouldn't help for our use-case anyway.)
 
-//@ [index](main.html) | [previous](part13.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part14.rs) | [next](part15.html)
+//@ [index](main.html) | [previous](part13.html) | [raw source](workspace/src/part14.rs) | [next](part15.html)
index 6c99f4d726fe0f2a2e05b0e3cda17059f917587f..b1cab06d9b4bd91cc4fefc3ed24d033fa364b50e 100644 (file)
@@ -145,4 +145,4 @@ pub fn main() {
 //@ [Rust RFC](https://github.com/rust-lang/rfcs/blob/master/text/0458-send-improvements.md), which contains a type `RcMut` that would be `Sync` and not `Send`.
 //@ You may also be interested in [this blog post](https://huonw.github.io/blog/2015/02/some-notes-on-send-and-sync/) on the topic.
 
-//@ [index](main.html) | [previous](part14.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part15.rs) | [next](part16.html)
+//@ [index](main.html) | [previous](part14.html) | [raw source](workspace/src/part15.rs) | [next](part16.html)
index efa48a5f52d2376b3af1b04be2bb096477144906..f0707aac6466e15ce1696e3bbd6e7c8c041efe47 100644 (file)
@@ -197,4 +197,4 @@ impl<T> Drop for LinkedList<T> {
 //@ extensions here and there. The [index](main.html) contains some more links to additional resources you may find useful. 
 //@ With that, there's only one thing left to say: Happy Rust Hacking!
 
-//@ [index](main.html) | [previous](part15.html) | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part16.rs) | next
+//@ [index](main.html) | [previous](part15.html) | [raw source](workspace/src/part16.rs) | next
index 38ceaf9a7829c23d3bd66972d39e823b5545752d..7e94cdfc81aab2421fbb3dce41ff75088625bce3 100644 (file)
@@ -1,2 +1,2 @@
 target/
-.*
+src/part*.rs
diff --git a/workspace/README.md b/workspace/README.md
deleted file mode 100644 (file)
index ff4e1ee..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-## Workspace
-
-This folder contains your Rust-101 workspace. I suggest you copy this
-folder somewhere else. Try `cargo build` in that new folder to check that compiling your workspace succeeds.
-(You can also execute it with `cargo run`, but you'll need to do some work before this will succeed.)
-See the [main tutorial](https://www.ralfj.de/projects/rust-101/main.html) for more details.
-
-Please do *not* edit this folder inside a `git clone` of Rust-101. The files in here are auto-generated.
-You should edit the files in `src/` in the repository root instead.
index 77632d9427cf924f55a82580a5a82e78a541208f..d804cfba20e0599000ff8d669323a86336c099e8 100644 (file)
@@ -1,5 +1,10 @@
 #![allow(dead_code, unused_imports, unused_variables, unused_mut, unreachable_code)]
 
+// To get started with the course, open the file `part00.rs` in this workspace as well
+// as its [fully explained version](https://www.ralfj.de/projects/rust-101/part00.html).
+// The code below is mostly boilerplate to dispatch into the various parts of the
+// tutorial.
+
 // Only the files imported here will be compiled.
 mod part00;
 mod part01;
diff --git a/workspace/src/part00.rs b/workspace/src/part00.rs
deleted file mode 100644 (file)
index 9144eae..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-// Rust-101, Part 00: Algebraic datatypes
-// ======================================
-
-// As our first piece of Rust code, we want to write a function that computes the
-// minimum of a list.
-
-
-// An `enum` for "a number or nothing" could look as follows:
-enum NumberOrNothing {
-    Number(i32),
-    Nothing
-}
-
-// Observe how in Rust, the return type comes *after* the arguments.
-fn vec_min(vec: Vec<i32>) -> NumberOrNothing {
-    let mut min = NumberOrNothing::Nothing;
-
-    // Now we want to *iterate* over the list. Rust has some nice syntax for iterators:
-    for el in vec {
-        // So `el` is an element of the list. We need to update `min` accordingly, but how do we get the current
-        // number in there? This is what pattern matching can do:
-        match min {
-            // In this case (*arm*) of the `match`, `min` is currently nothing, so let's just make it the number `el`.
-            NumberOrNothing::Nothing => {
-                unimplemented!()
-            },
-            // In this arm, `min` is currently the number `n`, so let's compute the new minimum and store it.
-            NumberOrNothing::Number(n) => {
-                unimplemented!()
-            }
-        }
-    }
-    // Finally, we return the result of the computation.
-    return min;
-}
-
-// Now that we reduced the problem to computing the minimum of two integers, let's do that.
-fn min_i32(a: i32, b: i32) -> i32 {
-    if a < b {
-        unimplemented!()
-    } else {
-        unimplemented!()
-    }
-}
-
-// Phew. We wrote our first Rust function! But all this `NumberOrNothing::` is getting kind of
-// ugly. Can't we do that nicer?
-
-// Indeed, we can: The following line tells Rust to take
-// the constructors of `NumberOrNothing` into the local namespace.
-// Try moving that above the function, and removing all the occurrences of `NumberOrNothing::`.
-use self::NumberOrNothing::{Number,Nothing};
-
-// To call this function, we now just need a list. Of course, ultimately we want to ask the user for
-// a list of numbers, but for now, let's just hard-code something.
-
-fn read_vec() -> Vec<i32> {
-    unimplemented!()
-}
-
-// Of course, we would also like to actually see the result of the computation, so we need to print the result.
-
-fn print_number_or_nothing(n: NumberOrNothing) {
-    unimplemented!()
-}
-
-// Putting it all together:
-pub fn main() {
-    let vec = read_vec();
-    let min = vec_min(vec);
-    print_number_or_nothing(min);
-}
-
-// Finally, try `cargo run` on the console to run it.
-
-
diff --git a/workspace/src/part01.rs b/workspace/src/part01.rs
deleted file mode 100644 (file)
index be2c2d2..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-// Rust-101, Part 01: Expressions, Inherent methods
-// ================================================
-
-// For Rust to compile this file, make sure to enable the corresponding line
-// in `main.rs` before going on.
-
-
-// ## Expression-based programming
-fn sqr(i: i32) -> i32 { i * i }
-
-// Conditionals are also just expressions. This is comparable to the ternary `? :` operator
-// from languages like C.
-fn abs(i: i32) -> i32 { if i >= 0 { i } else { -i } }
-
-enum NumberOrNothing {
-    Number(i32),
-    Nothing
-}
-use self::NumberOrNothing::{Number,Nothing};
-fn number_or_default(n: NumberOrNothing, default: i32) -> i32 {
-    match n {
-        Nothing => default,
-        Number(n) => n,
-    }
-}
-
-// It is even the case that blocks are expressions, evaluating to the last expression they contain.
-fn compute_stuff(x: i32) -> i32 {
-    let y = { let z = x*x; z + 14 };
-    y*y
-}
-
-// Let us now refactor `vec_min`.
-fn vec_min(v: Vec<i32>) -> NumberOrNothing {
-    fn min_i32(a: i32, b: i32) -> i32 {
-        unimplemented!()
-    }
-
-    let mut min = Nothing;
-    for e in v {
-        unimplemented!()
-    }
-    min
-}
-
-// Now that's already much shorter! Make sure you can go over the code above and actually understand
-// every step of what's going on.
-
-// ## Inherent implementations
-impl NumberOrNothing {
-    fn print(self) {
-        match self {
-            Nothing => println!("The number is: <nothing>"),
-            Number(n) => println!("The number is: {}", n),
-        };
-    }
-}
-
-// With our refactored functions and methods, `main` now looks as follows:
-fn read_vec() -> Vec<i32> {
-    vec![18,5,7,2,9,27]
-}
-pub fn main() {
-    let vec = read_vec();
-    let min = vec_min(vec);
-    unimplemented!()
-}
-// You will have to replace `part00` by `part01` in the `main` function in
-// `main.rs` to run this code.
-
-// **Exercise 01.1**: Write a function `vec_sum` that computes the sum of all values of a `Vec<i32>`.
-
-// **Exercise 01.2**: Write a function `vec_print` that takes a vector and prints all its elements.
-
diff --git a/workspace/src/part02.rs b/workspace/src/part02.rs
deleted file mode 100644 (file)
index 357c5a0..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-// Rust-101, Part 02: Generic types, Traits
-// ========================================
-
-
-// ## Generic datatypes
-
-pub enum SomethingOrNothing<T>  {
-    Something(T),
-    Nothing,
-}
-// Instead of writing out all the variants, we can also just import them all at once.
-pub use self::SomethingOrNothing::*;
-type NumberOrNothing = SomethingOrNothing<i32>;
-
-// ## Generic `impl`, Static functions
-// Inside an `impl`, `Self` refers to the type we are implementing things for. Here, it is
-// an alias for `SomethingOrNothing<T>`.
-impl<T> SomethingOrNothing<T> {
-    fn new(o: Option<T>) -> Self {
-        unimplemented!()
-    }
-
-    fn to_option(self) -> Option<T> {
-        unimplemented!()
-    }
-}
-// You can call static functions, and in particular constructors, as demonstrated in `call_constructor`.
-fn call_constructor(x: i32) -> SomethingOrNothing<i32> {
-    SomethingOrNothing::new(Some(x))
-}
-
-// ## Traits
-
-pub trait Minimum : Copy {
-    fn min(self, b: Self) -> Self;
-}
-
-pub fn vec_min<T: Minimum>(v: Vec<T>) -> SomethingOrNothing<T> {
-    let mut min = Nothing;
-    for e in v {
-        min = Something(match min {
-            Nothing => e,
-            // Here, we can now call the `min` function of the trait.
-            Something(n) => {
-                unimplemented!()
-            }
-        });
-    }
-    min
-}
-
-// ## Trait implementations
-// To make `vec_min` usable with a `Vec<i32>`, we implement the `Minimum` trait for `i32`.
-impl Minimum for i32 {
-    fn min(self, b: Self) -> Self {
-        unimplemented!()
-    }
-}
-
-// We again provide a `print` function.
-impl NumberOrNothing {
-    pub fn print(self) {
-        match self {
-            Nothing => println!("The number is: <nothing>"),
-            Something(n) => println!("The number is: {}", n),
-        };
-    }
-}
-
-// Now we are ready to run our new code. Remember to change `main.rs` appropriately.
-fn read_vec() -> Vec<i32> {
-    vec![18,5,7,3,9,27]
-}
-pub fn main() {
-    let vec = read_vec();
-    let min = vec_min(vec);
-    min.print();
-}
-
-
-// **Exercise 02.1**: Change your program such that it computes the minimum of a `Vec<f32>` (where `f32` is the type
-// of 32-bit floating-point numbers). You should not change `vec_min` in any way, obviously!
-
diff --git a/workspace/src/part03.rs b/workspace/src/part03.rs
deleted file mode 100644 (file)
index 3840156..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-// Rust-101, Part 03: Input
-// ========================
-
-
-// I/O is provided by the module `std::io`, so we first have import that with `use`.
-// We also import the I/O *prelude*, which makes a bunch of commonly used I/O stuff
-// directly available.
-use std::io::prelude::*;
-use std::io;
-
-fn read_vec() -> Vec<i32> {
-    let mut vec: Vec<i32> = Vec::<i32>::new();
-    // The central handle to the standard input is made available by the function `io::stdin`.
-    let stdin = io::stdin();
-    println!("Enter a list of numbers, one per line. End with Ctrl-D (Linux) or Ctrl-Z (Windows).");
-    for line in stdin.lock().lines() {
-        // Rust's type for (dynamic, growable) strings is `String`. However, our variable `line`
-        // here is not yet of that type: It has type `io::Result<String>`.
-
-        // I chose the same name (`line`) for the new variable to ensure that I will never, accidentally,
-        // access the "old" `line` again.
-        let line = line.unwrap();
-        // Now that we have our `String`, we want to make it an `i32`.
-
-        match line.trim().parse::<i32>() {
-            Ok(num) => {
-                unimplemented!()
-            },
-            // We don't care about the particular error, so we ignore it with a `_`.
-            Err(_) => {
-                unimplemented!()
-            },
-        }
-    }
-
-    vec
-}
-
-
-// For the rest of the code, we just re-use part 02 by importing it with `use`.
-use part02::{SomethingOrNothing,Something,Nothing,vec_min};
-
-// If you update your `main.rs` to use part 03, `cargo run` should now ask you for some numbers,
-// and tell you the minimum. Neat, isn't it?
-pub fn main() {
-    let vec = read_vec();
-    unimplemented!()
-}
-
-// **Exercise 03.1**: Define a trait `Print` to write a generic version of `SomethingOrNothing::print`.
-// Implement that trait for `i32`, and change the code above to use it.
-// I will again provide a skeleton for this solution. It also shows how to attach bounds to generic
-// implementations (just compare it to the `impl` block from the previous exercise).
-// You can read this as "For all types `T` satisfying the `Print` trait, I provide an implementation
-// for `SomethingOrNothing<T>`".
-// 
-// Notice that I called the function on `SomethingOrNothing` `print2` to disambiguate from the `print` defined previously.
-// 
-// *Hint*: There is a macro `print!` for printing without appending a newline.
-pub trait Print {
-    /* Add things here */
-}
-impl<T: Print> SomethingOrNothing<T> {
-    fn print2(self) {
-        unimplemented!()
-    }
-}
-
-// **Exercise 03.2**: Building on exercise 02.2, implement all the things you need on `f32` to make your
-// program work with floating-point numbers.
-
diff --git a/workspace/src/part04.rs b/workspace/src/part04.rs
deleted file mode 100644 (file)
index e0d522e..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-// Rust-101, Part 04: Ownership, Borrowing, References
-// ===================================================
-
-/*
-  void foo(std::vector<int> v) {
-      int *first = &v[0];
-      v.push_back(42);
-      *first = 1337; // This is bad!
-  }
-*/
-
-// ## Ownership
-fn work_on_vector(v: Vec<i32>) { /* do something */ }
-fn ownership_demo() {
-    let v = vec![1,2,3,4];
-    work_on_vector(v);
-    /* println!("The first element is: {}", v[0]); */               /* BAD! */
-}
-
-// ## Borrowing a shared reference
-
-fn vec_min(v: &Vec<i32>) -> Option<i32> {
-    use std::cmp;
-
-    let mut min = None;
-    // This time, we explicitly request an iterator for the vector `v`. The method `iter` just borrows the vector
-    // it works on, and provides shared references to the elements.
-    for e in v.iter() {
-        // In the loop, `e` now has type `&i32`, so we have to dereference it to obtain an `i32`.
-        min = Some(match min {
-            None => *e,
-            Some(n) => cmp::min(n, *e)
-        });
-    }
-    min
-}
-
-// Now that `vec_min` does not acquire ownership of the vector anymore, we can call it multiple times on the same vector and also do things like
-fn shared_ref_demo() {
-    let v = vec![5,4,3,2,1];
-    let first = &v[0];
-    vec_min(&v);
-    vec_min(&v);
-    println!("The first element is: {}", *first);
-}
-
-// ## Unique, mutable references
-
-fn vec_inc(v: &mut Vec<i32>) {
-    for e in v.iter_mut() {
-        *e += 1;
-    }
-}
-// Here's an example of calling `vec_inc`.
-fn mutable_ref_demo() {
-    let mut v = vec![5,4,3,2,1];
-    /* let first = &v[0]; */
-    vec_inc(&mut v);
-    vec_inc(&mut v);
-    /* println!("The first element is: {}", *first); */             /* BAD! */
-}
-
-// ## Summary
-// The ownership and borrowing system of Rust enforces the following three rules:
-// 
-// * There is always exactly one owner of a piece of data
-// * If there is an active mutable reference, then nobody else can have active access to the data
-// * If there is an active shared reference, then every other active access to the data is also a shared reference
-// 
-// As it turns out, combined with the abstraction facilities of Rust, this is a very powerful mechanism
-// to tackle many problems beyond basic memory safety. You will see some examples for this soon.
-
diff --git a/workspace/src/part05.rs b/workspace/src/part05.rs
deleted file mode 100644 (file)
index 28c4030..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-// Rust-101, Part 05: Clone
-// ========================
-
-// ## Big Numbers
-
-pub struct BigInt {
-    pub data: Vec<u64>, // least significant digit first, no trailing zeros
-}
-
-// Now that we fixed the data representation, we can start implementing methods on it.
-impl BigInt {
-    pub fn new(x: u64) -> Self {
-        if x == 0 {
-            unimplemented!()
-        } else {
-            unimplemented!()
-        }
-    }
-
-    pub fn test_invariant(&self) -> bool {
-        if self.data.len() == 0 {
-            true
-        } else {
-            unimplemented!()
-        }
-    }
-
-    // We can convert any vector of digits into a number, by removing trailing zeros. The `mut`
-    // declaration for `v` here is just like the one in `let mut ...`: We completely own `v`, but Rust
-    // still asks us to make our intention of modifying it explicit. This `mut` is *not* part of the
-    // type of `from_vec` - the caller has to give up ownership of `v` anyway, so they don't care anymore
-    // what you do to it.
-    // 
-    // **Exercise 05.1**: Implement this function.
-    // 
-    // *Hint*: You can use `pop` to remove the last element of a vector.
-    pub fn from_vec(mut v: Vec<u64>) -> Self {
-        unimplemented!()
-    }
-}
-
-// ## Cloning
-fn clone_demo() {
-    let v = vec![0,1 << 16];
-    let b1 = BigInt::from_vec((&v).clone());
-    let b2 = BigInt::from_vec(v);
-}
-
-impl Clone for BigInt {
-    fn clone(&self) -> Self {
-        unimplemented!()
-    }
-}
-
-// We can also make the type `SomethingOrNothing<T>` implement `Clone`. 
-use part02::{SomethingOrNothing,Something,Nothing};
-impl<T: Clone> Clone for SomethingOrNothing<T> {
-    fn clone(&self) -> Self {
-        unimplemented!()
-    }
-}
-
-// **Exercise 05.2**: Write some more functions on `BigInt`. What about a function that returns the number of
-// digits? The number of non-zero digits? The smallest/largest digit? Of course, these should all take `self` as a shared reference (i.e., in borrowed form).
-
-// ## Mutation + aliasing considered harmful (part 2)
-enum Variant {
-    Number(i32),
-    Text(String),
-}
-fn work_on_variant(mut var: Variant, text: String) {
-    let mut ptr: &mut i32;
-    match var {
-        Variant::Number(ref mut n) => ptr = n,
-        Variant::Text(_) => return,
-    }
-    /* var = Variant::Text(text); */                                /* BAD! */
-    *ptr = 1337;
-}
-
diff --git a/workspace/src/part06.rs b/workspace/src/part06.rs
deleted file mode 100644 (file)
index 3bc7d08..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-// Rust-101, Part 06: Copy, Lifetimes
-// ==================================
-
-// We continue to work on our `BigInt`, so we start by importing what we already established.
-use part05::BigInt;
-
-// With `BigInt` being about numbers, we should be able to write a version of `vec_min`
-// that computes the minimum of a list of `BigInt`. First, we have to write `min` for `BigInt`.
-impl BigInt {
-    fn min_try1(self, other: Self) -> Self {
-        debug_assert!(self.test_invariant() && other.test_invariant());
-        // Now our assumption of having no trailing zeros comes in handy:
-        // If the lengths of the two numbers differ, we already know which is larger.
-        if self.data.len() < other.data.len() {
-            self
-        } else if self.data.len() > other.data.len() {
-            other
-        } else {
-            // **Exercise 06.1**: Fill in this code.
-            unimplemented!()
-        }
-    }
-}
-
-// Now we can write `vec_min`.
-fn vec_min(v: &Vec<BigInt>) -> Option<BigInt> {
-    let mut min: Option<BigInt> = None;
-    // If `v` is a shared reference to a vector, then the default for iterating over it is to call `iter`, the iterator that borrows the elements.
-    for e in v {
-        let e = e.clone();
-        unimplemented!()
-    }
-    min
-}
-
-// ## `Copy` types
-
-use part02::{SomethingOrNothing,Something,Nothing};
-impl<T: Copy> Copy for SomethingOrNothing<T> {}
-
-
-// ## Lifetimes
-
-fn head<T>(v: &Vec<T>) -> Option<&T> {
-    if v.len() > 0 {
-        unimplemented!()
-    } else {
-        None
-    }
-}
-// Technically, we are returning a pointer to the first element. But doesn't that mean that callers have to be
-// careful? Imagine `head` would be a C++ function, and we would write the following code.
-/*
-  int foo(std::vector<int> v) {
-    int *first = head(v);
-    v.push_back(42);
-    return *first;
-  }
-*/
-fn rust_foo(mut v: Vec<i32>) -> i32 {
-    let first: Option<&i32> = head(&v);
-    /* v.push(42); */
-    *first.unwrap()
-}
-
-
diff --git a/workspace/src/part07.rs b/workspace/src/part07.rs
deleted file mode 100644 (file)
index 916cb01..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// Rust-101, Part 07: Operator Overloading, Tests, Formatting
-// ==========================================================
-
-pub use part05::BigInt;
-
-// With our new knowledge of lifetimes, we are now able to write down the desired type of `min`:
-pub trait Minimum {
-    fn min<'a>(&'a self, other: &'a Self) -> &'a Self;
-}
-
-pub fn vec_min<T: Minimum>(v: &Vec<T>) -> Option<&T> {
-    let mut min: Option<&T> = None;
-    for e in v {
-        min = Some(match min {
-            None => e,
-            Some(n) => n.min(e)
-        });
-    }
-    min
-}
-
-// **Exercise 07.1**: For our `vec_min` to be usable with `BigInt`, you will have to provide an implementation of
-// `Minimum`. You should be able to pretty much copy the code you wrote for exercise 06.1. You should *not*
-// make any copies of `BigInt`!
-impl Minimum for BigInt {
-    fn min<'a>(&'a self, other: &'a Self) -> &'a Self {
-        unimplemented!()
-    }
-}
-
-// ## Operator Overloading
-
-impl PartialEq for BigInt {
-    #[inline]
-    fn eq(&self, other: &BigInt) -> bool {
-        debug_assert!(self.test_invariant() && other.test_invariant());
-        unimplemented!()
-    }
-}
-
-
-// Now we can compare `BigInt`s. Rust treats `PartialEq` special in that it is wired to the operator `==`:
-fn compare_big_ints() {
-    let b1 = BigInt::new(13);
-    let b2 = BigInt::new(37);
-    println!("b1 == b1: {} ; b1 == b2: {}; b1 != b2: {}", b1 == b1, b1 == b2, b1 != b2);
-}
-
-// ## Testing
-// With our equality test written, we are now ready to write our first testcase.
-// the `test` attribute. `assert!` is like `debug_assert!`, but does not get compiled away in a release build.
-#[test]
-fn test_min() {
-    let b1 = BigInt::new(1);
-    let b2 = BigInt::new(42);
-    let b3 = BigInt::from_vec(vec![0, 1]);
-
-    unimplemented!()
-}
-// Now run `cargo test` to execute the test. If you implemented `min` correctly, it should all work!
-
-// ## Formatting
-
-// All formating is handled by [`std::fmt`](https://doc.rust-lang.org/std/fmt/index.html). I won't explain
-// all the details, and refer you to the documentation instead.
-use std::fmt;
-
-impl fmt::Debug for BigInt {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.data.fmt(f)
-    }
-}
-
-// Now we are ready to use `assert_eq!` to test `vec_min`.
-/*#[test]*/
-fn test_vec_min() {
-    let b1 = BigInt::new(1);
-    let b2 = BigInt::new(42);
-    let b3 = BigInt::from_vec(vec![0, 1]);
-
-    let v1 = vec![b2.clone(), b1.clone(), b3.clone()];
-    let v2 = vec![b2.clone(), b3.clone()];
-    unimplemented!()
-}
-
-// **Exercise 07.1**: Add some more testcases. In particular, make sure you test the behavior of
-// `vec_min` on an empty vector. Also add tests for `BigInt::from_vec` (in particular, removing
-// trailing zeros). Finally, break one of your functions in a subtle way and watch the test fail.
-// 
-// **Exercise 07.2**: Go back to your good ol' `SomethingOrNothing`, and implement `Display` for it. (This will,
-// of course, need a `Display` bound on `T`.) Then you should be able to use them with `println!` just like you do
-// with numbers, and get rid of the inherent functions to print `SomethingOrNothing<i32>` and `SomethingOrNothing<f32>`.
-
diff --git a/workspace/src/part08.rs b/workspace/src/part08.rs
deleted file mode 100644 (file)
index 5ddcb33..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// Rust-101, Part 08: Associated Types, Modules
-// ============================================
-
-use std::{cmp,ops};
-use part05::BigInt;
-
-
-// So, let us write a function to "add with carry", and give it the appropriate type. Notice Rust's native support for pairs.
-fn overflowing_add(a: u64, b: u64, carry: bool) -> (u64, bool) {
-    let sum = a.wrapping_add(b);
-    // If an overflow happened, then the sum will be smaller than *both* summands. Without an overflow, of course, it will be
-    // at least as large as both of them. So, let's just pick one and check.
-    if sum >= a {
-        // The addition did not overflow. <br/>
-        // **Exercise 08.1**: Write the code to handle adding the carry in this case.
-        unimplemented!()
-    } else {
-        // Otherwise, the addition *did* overflow. It is impossible for the addition of the carry
-        // to overflow again, as we are just adding 0 or 1.
-        unimplemented!()
-    }
-}
-
-// `overflow_add` is a sufficiently intricate function that a test case is justified.
-// This should also help you to check your solution of the exercise.
-/*#[test]*/
-fn test_overflowing_add() {
-    assert_eq!(overflowing_add(10, 100, false), (110, false));
-    assert_eq!(overflowing_add(10, 100, true), (111, false));
-    assert_eq!(overflowing_add(1 << 63, 1 << 63, false), (0, true));
-    assert_eq!(overflowing_add(1 << 63, 1 << 63, true), (1, true));
-    assert_eq!(overflowing_add(1 << 63, (1 << 63) -1 , true), (0, true));
-}
-
-// ## Associated Types
-impl ops::Add<BigInt> for BigInt {
-
-    // Here, we choose the result type to be again `BigInt`.
-    type Output = BigInt;
-
-    // Now we can write the actual function performing the addition.
-    fn add(self, rhs: BigInt) -> Self::Output {
-        // We know that the result will be *at least* as long as the longer of the two operands,
-        // so we can create a vector with sufficient capacity to avoid expensive reallocations.
-        let max_len = cmp::max(self.data.len(), rhs.data.len());
-        let mut result_vec:Vec<u64> = Vec::with_capacity(max_len);
-        let mut carry = false; /* the current carry bit */
-        for i in 0..max_len {
-            let lhs_val = if i < self.data.len() { self.data[i] } else { 0 };
-            let rhs_val = if i < rhs.data.len() { rhs.data[i] } else { 0 };
-            // Compute next digit and carry. Then, store the digit for the result, and the carry for later.
-            unimplemented!()
-        }
-        // **Exercise 08.2**: Handle the final `carry`, and return the sum.
-        unimplemented!()
-    }
-}
-
-// ## Traits and reference types
-
-// Writing this out becomes a bit tedious, because trait implementations (unlike functions) require full explicit annotation
-// of lifetimes. Make sure you understand exactly what the following definition says. Notice that we can implement a trait for
-// a reference type!
-impl<'a, 'b> ops::Add<&'a BigInt> for &'b BigInt {
-    type Output = BigInt;
-    fn add(self, rhs: &'a BigInt) -> Self::Output {
-        // **Exercise 08.3**: Implement this function.
-        unimplemented!()
-    }
-}
-
-// **Exercise 08.4**: Implement the two missing combinations of arguments for `Add`. You should not have to duplicate the implementation.
-
-// ## Modules
-
-// Rust calls a bunch of definitions that are grouped together a *module*. You can put the tests in a submodule as follows.
-#[cfg(test)]
-mod tests {
-    use part05::BigInt;
-
-    /*#[test]*/
-    fn test_add() {
-        let b1 = BigInt::new(1 << 32);
-        let b2 = BigInt::from_vec(vec![0, 1]);
-
-        assert_eq!(&b1 + &b2, BigInt::from_vec(vec![1 << 32, 1]));
-        // **Exercise 08.5**: Add some more cases to this test.
-    }
-}
-
-// **Exercise 08.6**: Write a subtraction function, and testcases for it. Decide for yourself how you want to handle negative results.
-// For example, you may want to return an `Option`, to panic, or to return `0`.
-
diff --git a/workspace/src/part09.rs b/workspace/src/part09.rs
deleted file mode 100644 (file)
index 61cc70b..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-// Rust-101, Part 09: Iterators
-// ============================
-
-use part05::BigInt;
-
-
-pub struct Iter<'a> {
-    num: &'a BigInt,
-    idx: usize, // the index of the last number that was returned
-}
-
-// Now we are equipped to implement `Iterator` for `Iter`.
-impl<'a> Iterator for Iter<'a> {
-    // We choose the type of things that we iterate over to be the type of digits, i.e., `u64`.
-    type Item = u64;
-
-    fn next(&mut self) -> Option<u64> {
-        // First, check whether there's any more digits to return.
-        if self.idx == 0 {
-            // We already returned all the digits, nothing to do.
-            unimplemented!()
-        } else {
-            // Otherwise: Decrement, and return next digit.
-            unimplemented!()
-        }
-    }
-}
-
-// All we need now is a function that creates such an iterator for a given `BigInt`.
-impl BigInt {
-    fn iter(&self) -> Iter {
-        unimplemented!()
-    }
-}
-
-// We are finally ready to iterate! Remember to edit `main.rs` to run this function.
-pub fn main() {
-    let b = BigInt::new(1 << 63) + BigInt::new(1 << 16) + BigInt::new(1 << 63);
-    for digit in b.iter() {
-        println!("{}", digit);
-    }
-}
-
-// Of course, we don't have to use `for` to apply the iterator. We can also explicitly call `next`.
-fn print_digits_v1(b: &BigInt) {
-    let mut iter = b.iter();
-    loop {
-        // Each time we go through the loop, we analyze the next element presented by the iterator - until it stops.
-        unimplemented!()
-    }
-}
-
-fn print_digits_v2(b: &BigInt) {
-    let mut iter = b.iter();
-    while let Some(digit) = iter.next() {
-        println!("{}", digit)
-    }
-}
-
-// **Exercise 09.1**: Write a testcase for the iterator, making sure it yields the corrects numbers.
-// 
-// **Exercise 09.2**: Write a function `iter_ldf` that iterators over the digits with the least-significant
-// digits coming first. Write a testcase for it.
-
-// ## Iterator invalidation and lifetimes
-
-fn iter_invalidation_demo() {
-    let mut b = BigInt::new(1 << 63) + BigInt::new(1 << 16) + BigInt::new(1 << 63);
-    for digit in b.iter() {
-        println!("{}", digit);
-        /*b = b + BigInt::new(1);*/                                 /* BAD! */
-    }
-}
-
-// ## Iterator conversion trait
-
-impl<'a> IntoIterator for &'a BigInt {
-    type Item = u64;
-    type IntoIter = Iter<'a>;
-    fn into_iter(self) -> Iter<'a> {
-        self.iter()
-    }
-}
-// With this in place, you can now replace `b.iter()` in `main` by `&b`. Go ahead and try it! <br/>
-
diff --git a/workspace/src/part10.rs b/workspace/src/part10.rs
deleted file mode 100644 (file)
index 8fc650f..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-// Rust-101, Part 10: Closures
-// ===========================
-
-use std::fmt;
-use part05::BigInt;
-
-
-// So, let us define a trait that demands that the type provides some method `do_action` on digits.
-trait Action {
-    fn do_action(&mut self, digit: u64);
-}
-
-// Now we can write a function that takes some `a` of a type `A` such that we can call `do_action` on `a`, passing it every digit.
-impl BigInt {
-    fn act_v1<A: Action>(&self, mut a: A) {
-        for digit in self {
-            unimplemented!()
-        }
-    }
-}
-
-struct PrintWithString {
-    prefix: String,
-}
-
-impl Action for PrintWithString {
-    // Here we perform the actual printing of the prefix and the digit. We're not making use of our ability to
-    // change `self` here, but we could replace the prefix if we wanted.
-    fn do_action(&mut self, digit: u64) {
-        unimplemented!()
-    }
-}
-
-// Finally, this function takes a `BigInt` and a prefix, and prints the digits with the given prefix.
-fn print_with_prefix_v1(b: &BigInt, prefix: String) {
-    let my_action = PrintWithString { prefix: prefix };
-    b.act_v1(my_action);
-}
-
-// Here's a small main function, demonstrating the code above in action. Remember to edit `main.rs` to run it.
-pub fn main() {
-    let bignum = BigInt::new(1 << 63) + BigInt::new(1 << 16) + BigInt::new(1 << 63);
-    print_with_prefix_v1(&bignum, "Digit: ".to_string());
-}
-
-// ## Closures
-
-// This defines `act` very similar to above, but now we demand `A` to be the type of a closure that mutates its borrowed environment,
-// takes a digit, and returns nothing.
-impl BigInt {
-    fn act<A: FnMut(u64)>(&self, mut a: A) {
-        for digit in self {
-            // We can call closures as if they were functions - but really, what's happening here is translated to essentially what we wrote above, in `act_v1`.
-            unimplemented!()
-        }
-    }
-}
-
-// Now that we saw how to write a function that operates on closures, let's see how to write a closure.
-pub fn print_with_prefix(b: &BigInt, prefix: String) {
-    b.act(|digit| println!("{}{}", prefix, digit) );
-}
-// You can change `main` to call this function, and you should notice - nothing, no difference in behavior.
-// But we wrote much less boilerplate code!
-
-// Remember that we decided to use the `FnMut` trait above? This means our closure could actually mutate its environment.
-// For example, we can use that to count the digits as they are printed.
-pub fn print_and_count(b: &BigInt) {
-    let mut count: usize = 0;
-    b.act(|digit| { println!("{}: {}", count, digit); count = count +1; } );
-    println!("There are {} digits", count);
-}
-
-// ## Fun with iterators and closures
-
-// Let's say we want to write a function that increments every entry of a `Vec` by some number, then looks for numbers larger than some threshold, and prints them.
-fn inc_print_even(v: &Vec<i32>, offset: i32, threshold: i32) {
-    for i in v.iter().map(|n| *n + offset).filter(|n| *n > threshold) {
-        println!("{}", i);
-    }
-}
-
-// Sometimes it is useful to know both the position of some element in a list, and its value. That's where the `enumerate` function helps.
-fn print_enumerated<T: fmt::Display>(v: &Vec<T>) {
-    for (i, t) in v.iter().enumerate() {
-        println!("Position {}: {}", i, t);
-    }
-}
-
-// And as a final example, one can also collect all elements of an iterator, and put them, e.g., in a vector.
-fn filter_vec_by_divisor(v: &Vec<i32>, divisor: i32) -> Vec<i32> {
-    unimplemented!()
-}
-
-// **Exercise 10.1**: Look up the [documentation of `Iterator`](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html) to learn about more functions
-// that can act on iterators. Try using some of them. What about a function that sums the even numbers of an iterator? Or a function that computes the
-// product of those numbers that sit at odd positions? A function that checks whether a vector contains a certain number? Whether all numbers are
-// smaller than some threshold? Be creative!
-
diff --git a/workspace/src/part11.rs b/workspace/src/part11.rs
deleted file mode 100644 (file)
index a93ad07..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-// Rust-101, Part 11: Trait Objects, Box, Lifetime bounds
-// ======================================================
-
-
-// For now, we just decide that the callbacks have an argument of type `i32`.
-struct CallbacksV1<F: FnMut(i32)> {
-    callbacks: Vec<F>,
-}
-
-/* struct CallbacksV2 {
-    callbacks: Vec<FnMut(i32)>,
-} */
-
-pub struct Callbacks {
-    callbacks: Vec<Box<FnMut(i32)>>,
-}
-
-impl Callbacks {
-    // Now we can provide some functions. The constructor should be straight-forward.
-    pub fn new() -> Self {
-        unimplemented!()
-    }
-
-    // Registration simply stores the callback.
-    pub fn register(&mut self, callback: Box<FnMut(i32)>) {
-        self.callbacks.push(callback);
-    }
-
-    // We can also write a generic version of `register`, such that it will be instantiated with some concrete closure type `F`
-    // and do the creation of the `Box` and the conversion from `F` to `FnMut(i32)` itself.
-    
-    pub fn register_generic<F: FnMut(i32)+'static>(&mut self, callback: F) {
-        unimplemented!()
-    }
-
-    // And here we call all the stored callbacks.
-    pub fn call(&mut self, val: i32) {
-        // Since they are of type `FnMut`, we need to mutably iterate.
-        for callback in self.callbacks.iter_mut() {
-            unimplemented!()
-        }
-    }
-}
-
-// Now we are ready for the demo. Remember to edit `main.rs` to run it.
-pub fn main() {
-    let mut c = Callbacks::new();
-    c.register(Box::new(|val| println!("Callback 1: {}", val)));
-    c.call(0);
-
-    {
-        let mut count: usize = 0;
-        c.register_generic(move |val| {
-            count = count+1;
-            println!("Callback 2: {} ({}. time)", val, count);
-        } );
-    }
-    c.call(1); c.call(2);
-}
-
-
-// **Exercise 11.1**: We made the arbitrary choice of using `i32` for the arguments. Generalize the data structures above
-// to work with an arbitrary type `T` that's passed to the callbacks. Since you need to call multiple callbacks with the
-// same `t: T`, you will either have to restrict `T` to `Copy` types, or pass a reference.
-
diff --git a/workspace/src/part12.rs b/workspace/src/part12.rs
deleted file mode 100644 (file)
index 1593e8a..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-// Rust-101, Part 12: Rc, Interior Mutability, Cell, RefCell
-// =========================================================
-
-use std::rc::Rc;
-use std::cell::{Cell, RefCell};
-
-
-
-#[derive(Clone)]
-struct Callbacks {
-    callbacks: Vec<Rc<Fn(i32)>>,
-}
-
-impl Callbacks {
-    pub fn new() -> Self {
-        Callbacks { callbacks: Vec::new() }
-    }
-
-    // Registration works just like last time, except that we are creating an `Rc` now.
-    pub fn register<F: Fn(i32)+'static>(&mut self, callback: F) {
-        unimplemented!()
-    }
-
-    pub fn call(&self, val: i32) {
-        // We only need a shared iterator here. Since `Rc` is a smart pointer, we can directly call the callback.
-        for callback in self.callbacks.iter() {
-            unimplemented!()
-        }
-    }
-}
-
-// Time for a demo!
-fn demo(c: &mut Callbacks) {
-    c.register(|val| println!("Callback 1: {}", val));
-    c.call(0); c.clone().call(1);
-}
-
-pub fn main() {
-    let mut c = Callbacks::new();
-    demo(&mut c);
-}
-
-// ## Interior Mutability
-
-// So, let us put our counter in a `Cell`, and replicate the example from the previous part.
-fn demo_cell(c: &mut Callbacks) {
-    {
-        let count = Cell::new(0);
-        // Again, we have to move ownership of the `count` into the environment closure.
-        c.register(move |val| {
-            // In here, all we have is a shared reference of our environment. But that's good enough for the `get` and `set` of the cell!
-            let new_count = count.get()+1;
-            count.set(new_count);
-            println!("Callback 2: {} ({}. time)", val, new_count);
-        } );
-    }
-
-    c.call(2); c.clone().call(3);
-}
-
-
-// ## `RefCell`
-
-// Our final version of `Callbacks` puts the closure environment into a `RefCell`.
-#[derive(Clone)]
-struct CallbacksMut {
-    callbacks: Vec<Rc<RefCell<FnMut(i32)>>>,
-}
-
-impl CallbacksMut {
-    pub fn new() -> Self {
-        CallbacksMut { callbacks: Vec::new() }
-    }
-
-    pub fn register<F: FnMut(i32)+'static>(&mut self, callback: F) {
-        unimplemented!()
-    }
-
-    pub fn call(&mut self, val: i32) {
-        for callback in self.callbacks.iter() {
-            // We have to *explicitly* borrow the contents of a `RefCell` by calling `borrow` or `borrow_mut`.
-            let mut closure = callback.borrow_mut();
-            // Unfortunately, Rust's auto-dereference of pointers is not clever enough here. We thus have to explicitly
-            // dereference the smart pointer and obtain a mutable reference to the content.
-            (&mut *closure)(val);
-        }
-    }
-}
-
-// Now we can repeat the demo from the previous part - but this time, our `CallbacksMut` type
-// can be cloned.
-fn demo_mut(c: &mut CallbacksMut) {
-    c.register(|val| println!("Callback 1: {}", val));
-    c.call(0);
-
-    {
-        let mut count: usize = 0;
-        c.register(move |val| {
-            count = count+1;
-            println!("Callback 2: {} ({}. time)", val, count);
-        } );
-    }
-    c.call(1); c.clone().call(2);
-}
-
-// **Exercise 12.1**: Write some piece of code using only the available, public interface of `CallbacksMut` such that a reentrant call to a closure
-// is happening, and the program panics because the `RefCell` refuses to hand out a second mutable borrow of the closure's environment.
-
diff --git a/workspace/src/part13.rs b/workspace/src/part13.rs
deleted file mode 100644 (file)
index ae12cd1..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-// Rust-101, Part 13: Concurrency, Arc, Send
-// =========================================
-
-use std::io::prelude::*;
-use std::{io, fs, thread};
-use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
-use std::sync::Arc;
-
-
-// Before we come to the actual code, we define a data-structure `Options` to store all the information we need
-// to complete the job: Which files to work on, which pattern to look for, and how to output. <br/>
-#[derive(Clone,Copy)]
-pub enum OutputMode {
-    Print,
-    SortAndPrint,
-    Count,
-}
-use self::OutputMode::*;
-
-pub struct Options {
-    pub files: Vec<String>,
-    pub pattern: String,
-    pub output_mode: OutputMode,
-}
-
-
-// The first function reads the files, and sends every line over the `out_channel`.
-fn read_files(options: Arc<Options>, out_channel: SyncSender<String>) {
-    for file in options.files.iter() {
-        // First, we open the file, ignoring any errors.
-        let file = fs::File::open(file).unwrap();
-        // Then we obtain a `BufReader` for it, which provides the `lines` function.
-        let file = io::BufReader::new(file);
-        for line in file.lines() {
-            let line = line.unwrap();
-            // Now we send the line over the channel, ignoring the possibility of `send` failing.
-            out_channel.send(line).unwrap();
-        }
-    }
-    // When we drop the `out_channel`, it will be closed, which the other end can notice.
-}
-
-// The second function filters the lines it receives through `in_channel` with the pattern, and sends
-// matches via `out_channel`.
-fn filter_lines(options: Arc<Options>,
-                in_channel: Receiver<String>,
-                out_channel: SyncSender<String>) {
-    // We can simply iterate over the channel, which will stop when the channel is closed.
-    for line in in_channel.iter() {
-        // `contains` works on lots of types of patterns, but in particular, we can use it to test whether
-        // one string is contained in another. This is another example of Rust using traits as substitute for overloading.
-        if line.contains(&options.pattern) {
-            unimplemented!()
-        }
-    }
-}
-
-// The third function performs the output operations, receiving the relevant lines on its `in_channel`.
-fn output_lines(options: Arc<Options>, in_channel: Receiver<String>) {
-    match options.output_mode {
-        Print => {
-            // Here, we just print every line we see.
-            for line in in_channel.iter() {
-                unimplemented!()
-            }
-        },
-        Count => {
-            // We are supposed to count the number of matching lines. There's a convenient iterator adapter that
-            // we can use for this job.
-            unimplemented!()
-        },
-        SortAndPrint => {
-            // We are asked to sort the matching lines before printing. So let's collect them all in a local vector...
-            let mut data: Vec<String> = in_channel.iter().collect();
-            // ...and implement the actual sorting later.
-            unimplemented!()
-        }
-    }
-}
-
-// With the operations of the three threads defined, we can now implement a function that performs grepping according
-// to some given options.
-pub fn run(options: Options) {
-    // We move the `options` into an `Arc`, as that's what the thread workers expect.
-    let options = Arc::new(options);
-
-    // This sets up the channels. We use a `sync_channel` with buffer-size of 16 to avoid needlessly filling RAM.
-    let (line_sender, line_receiver) = sync_channel(16);
-    let (filtered_sender, filtered_receiver) = sync_channel(16);
-
-    // Spawn the read thread: `thread::spawn` takes a closure that is run in a new thread.
-    let options1 = options.clone();
-    let handle1 = thread::spawn(move || read_files(options1, line_sender));
-
-    // Same with the filter thread.
-    let options2 = options.clone();
-    let handle2 = thread::spawn(move || {
-        filter_lines(options2, line_receiver, filtered_sender)
-    });
-
-    // And the output thread.
-    let options3 = options.clone();
-    let handle3 = thread::spawn(move || output_lines(options3, filtered_receiver));
-
-    // Finally, wait until all three threads did their job.
-    handle1.join().unwrap();
-    handle2.join().unwrap();
-    handle3.join().unwrap();
-}
-
-// Now we have all the pieces together for testing our rgrep with some hard-coded options.
-pub fn main() {
-    let options = Options {
-        files: vec!["src/part10.rs".to_string(),
-                    "src/part11.rs".to_string(),
-                    "src/part12.rs".to_string()],
-        pattern: "let".to_string(),
-        output_mode: Print
-    };
-    run(options);
-}
-
-// **Exercise 13.1**: Change rgrep such that it prints not only the matching lines, but also the name of the file
-// and the number of the line in the file. You will have to change the type of the channels from `String` to something
-// that records this extra information.
-
-
-
diff --git a/workspace/src/part14.rs b/workspace/src/part14.rs
deleted file mode 100644 (file)
index 5906acf..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-// Rust-101, Part 14: Slices, Arrays, External Dependencies
-// ========================================================
-
-
-// ## Slices
-
-pub fn sort<T: PartialOrd>(data: &mut [T]) {
-    if data.len() < 2 { return; }
-
-    // We decide that the element at 0 is our pivot, and then we move our cursors through the rest of the slice,
-    // making sure that everything on the left is no larger than the pivot, and everything on the right is no smaller.
-    let mut lpos = 1;
-    let mut rpos = data.len();
-    /* Invariant: pivot is data[0]; everything with index (0,lpos) is <= pivot;
-       [rpos,len) is >= pivot; lpos < rpos */
-    loop {
-        // **Exercise 14.1**: Complete this Quicksort loop. You can use `swap` on slices to swap two elements. Write a
-        // test function for `sort`.
-        unimplemented!()
-    }
-
-    // Once our cursors met, we need to put the pivot in the right place.
-    data.swap(0, lpos-1);
-
-    // Finally, we split our slice to sort the two halves. The nice part about slices is that splitting them is cheap:
-    let (part1, part2) = data.split_at_mut(lpos);
-    unimplemented!()
-}
-
-// **Exercise 14.2**: Since `String` implements `PartialEq`, you can now change the function `output_lines` in the previous part
-// to call the sort function above. If you did exercise 13.1, you will have slightly more work. Make sure you sort by the matched line
-// only, not by filename or line number!
-
-// Now, we can sort, e.g., an vector of numbers.
-fn sort_nums(data: &mut Vec<i32>) {
-    sort(&mut data[..]);
-}
-
-// ## Arrays
-fn sort_array() {
-    let mut array_of_data: [f64; 5] = [1.0, 3.4, 12.7, -9.12, 0.1];
-    sort(&mut array_of_data);
-}
-
-// ## External Dependencies
-
-
-// I disabled the following module (using a rather bad hack), because it only compiles if `docopt` is linked.
-// Remove the attribute of the `rgrep` module to enable compilation.
-#[cfg(feature = "disabled")]
-pub mod rgrep {
-    // Now that `docopt` is linked, we can first add it to the namespace with `extern crate` and then import shorter names with `use`.
-    // We also import some other pieces that we will need.
-    extern crate docopt;
-    use self::docopt::Docopt;
-    use part13::{run, Options, OutputMode};
-    use std::process;
-
-    // The `USAGE` string documents how the program is to be called. It's written in a format that `docopt` can parse.
-    static USAGE: &'static str = "
-Usage: rgrep [-c] [-s] <pattern> <file>...
-
-Options:
-    -c, --count  Count number of matching lines (rather than printing them).
-    -s, --sort   Sort the lines before printing.
-";
-
-    // This function extracts the rgrep options from the command-line arguments.
-    fn get_options() -> Options {
-        // This parses `argv` and exit the program with an error message if it fails. The code is taken from the [`docopt` documentation](http://burntsushi.net/rustdoc/docopt/). <br/>
-        let args = Docopt::new(USAGE).and_then(|d| d.parse()).unwrap_or_else(|e| e.exit());
-        // Now we can get all the values out.
-        let count = args.get_bool("-c");
-        let sort = args.get_bool("-s");
-        let pattern = args.get_str("<pattern>");
-        let files = args.get_vec("<file>");
-        if count && sort {
-            println!("Setting both '-c' and '-s' at the same time does not make any sense.");
-            process::exit(1);
-        }
-
-        // We need to make the strings owned to construct the `Options` instance.
-        let mode = if count {
-            OutputMode::Count
-        } else if sort {
-            OutputMode::SortAndPrint
-        } else {
-            OutputMode::Print
-        };
-        Options {
-            files: files.iter().map(|file| file.to_string()).collect(),
-            pattern: pattern.to_string(),
-            output_mode: mode,
-        }
-    }
-
-    // Finally, we can call the `run` function from the previous part on the options extracted using `get_options`. Edit `main.rs` to call this function.
-    // You can now use `cargo run -- <pattern> <files>` to call your program, and see the argument parser and the threads we wrote previously in action!
-    pub fn main() {
-        unimplemented!()
-    }
-}
-
-// **Exercise 14.3**: Wouldn't it be nice if rgrep supported regular expressions? There's already a crate that does all the parsing and matching on regular
-// expression, it's called [regex](https://crates.io/crates/regex). Add this crate to the dependencies of your workspace, add an option ("-r") to switch
-// the pattern to regular-expression mode, and change `filter_lines` to honor this option. The documentation of regex is available from its crates.io site.
-// (You won't be able to use the `regex!` macro if you are on the stable or beta channel of Rust. But it wouldn't help for our use-case anyway.)
-
diff --git a/workspace/src/part15.rs b/workspace/src/part15.rs
deleted file mode 100644 (file)
index 148f648..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-// Rust-101, Part 15: Mutex, Interior Mutability (cont.), RwLock, Sync
-// ===================================================================
-
-use std::sync::{Arc, Mutex};
-use std::thread;
-use std::time::Duration;
-
-
-// The derived `Clone` implementation will clone the `Arc`, so all clones will actually talk about the same counter.
-#[derive(Clone)]
-struct ConcurrentCounter(Arc<Mutex<usize>>);
-
-impl ConcurrentCounter {
-    // The constructor just wraps the constructors of `Arc` and `Mutex`.
-    pub fn new(val: usize) -> Self {
-        unimplemented!()
-    }
-
-    // The core operation is, of course, `increment`.
-    pub fn increment(&self, by: usize) {
-        // `lock` on a mutex returns a guard, very much like `RefCell`. The guard gives access to the data contained in the mutex.
-        let mut counter = self.0.lock().unwrap();
-        *counter = *counter + by;
-    }
-
-    // The function `get` returns the current value of the counter.
-    pub fn get(&self) -> usize {
-        unimplemented!()
-    }
-}
-
-// Now our counter is ready for action.
-pub fn main() {
-    let counter = ConcurrentCounter::new(0);
-
-    // We clone the counter for the first thread, which increments it by 2 every 15ms.
-    let counter1 = counter.clone();
-    let handle1 = thread::spawn(move || {
-        for _ in 0..10 {
-            thread::sleep(Duration::from_millis(15));
-            counter1.increment(2);
-        }
-    });
-
-    // The second thread increments the counter by 3 every 20ms.
-    let counter2 = counter.clone();
-    let handle2 = thread::spawn(move || {
-        for _ in 0..10 {
-            thread::sleep(Duration::from_millis(20));
-            counter2.increment(3);
-        }
-    });
-
-    // Now we watch the threads working on the counter.
-    for _ in 0..50 {
-        thread::sleep(Duration::from_millis(5));
-        println!("Current value: {}", counter.get());
-    }
-
-    // Finally, we wait for all the threads to finish to be sure we can catch the counter's final value.
-    handle1.join().unwrap();
-    handle2.join().unwrap();
-    println!("Final value: {}", counter.get());
-}
-
-// **Exercise 15.1**: Add an operation `compare_and_inc(&self, test: usize, by: usize)` that increments the counter by
-// `by` *only if* the current value is `test`.
-// 
-// **Exercise 15.2**: Rather than panicking in case the lock is poisoned, we can use `into_inner` on the error to recover
-// the data inside the lock. Change the code above to do that. Try using `unwrap_or_else` for this job.
-
-
-// **Exercise 15.3**:  Change the code above to use `RwLock`, such that multiple calls to `get` can be executed at the same time.
-
-
diff --git a/workspace/src/part16.rs b/workspace/src/part16.rs
deleted file mode 100644 (file)
index fa5b184..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-// Rust-101, Part 16: Unsafe Rust, Drop
-// ====================================
-
-use std::ptr;
-use std::mem;
-use std::marker::PhantomData;
-
-
-// A node of the list consists of the data, and two node pointers for the predecessor and successor.
-struct Node<T> {
-    next: NodePtr<T>,
-    prev: NodePtr<T>,
-    data: T,
-}
-// A node pointer is a *mutable raw pointer* to a node.
-type NodePtr<T> = *mut Node<T>;
-
-// The linked list itself stores pointers to the first and the last node. In addition, we tell Rust that this type
-// will own data of type `T`.
-pub struct LinkedList<T> {
-    first: NodePtr<T>,
-    last:  NodePtr<T>,
-    _marker: PhantomData<T>,
-}
-
-
-unsafe fn raw_into_box<T>(r: *mut T) -> Box<T> {
-    mem::transmute(r)
-}
-fn box_into_raw<T>(b: Box<T>) -> *mut T {
-    unsafe { mem::transmute(b) }
-}
-
-impl<T> LinkedList<T> {
-    // A new linked list just contains null pointers. `PhantomData` is how we construct any `PhantomData<T>`.
-    pub fn new() -> Self {
-        LinkedList { first: ptr::null_mut(), last: ptr::null_mut(), _marker: PhantomData }
-    }
-
-    // This function adds a new node to the end of the list.
-    pub fn push_back(&mut self, t: T) {
-        // Create the new node, and make it a raw pointer.
-        let new = Box::new( Node { data: t, next: ptr::null_mut(), prev: self.last } );
-        let new = box_into_raw(new);
-        // Update other pointers to this node.
-        if self.last.is_null() {
-            debug_assert!(self.first.is_null());
-            // The list is currently empty, so we have to update the head pointer.
-            unimplemented!()
-        } else {
-            debug_assert!(!self.first.is_null());
-            // We have to update the `next` pointer of the tail node.
-            unimplemented!()
-        }
-        // Make this the last node.
-        self.last = new;
-    }
-
-    // **Exercise 16.1**: Add some more operations to `LinkedList`: `pop_back`, `push_front` and `pop_front`.
-    // Add testcases for `push_back` and all of your functions. The `pop` functions should take `&mut self`
-    // and return `Option<T>`.
-
-    // Next, we are going to provide an iterator.
-    pub fn iter_mut(&mut self) -> IterMut<T> {
-        IterMut { next: self.first, _marker: PhantomData  }
-    }
-}
-
-
-pub struct IterMut<'a, T> where T: 'a {
-    next: NodePtr<T>,
-    _marker: PhantomData<&'a mut LinkedList<T>>,
-}
-
-impl<'a, T> Iterator for IterMut<'a, T> {
-    type Item = &'a mut T;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        // The actual iteration is straight-forward: Once we reached a null pointer, we are done.
-        if self.next.is_null() {
-            None
-        } else {
-            // Otherwise, we can convert the next pointer to a reference, get a reference to the data
-            // and update the iterator.
-            let next = unsafe { &mut *self.next };
-            let ret = &mut next.data;
-            unimplemented!()
-        }
-    }
-}
-
-
-// **Exercise 16.2**: Add a method `iter` and a type `Iter` providing iteration for shared references.
-// Add testcases for both kinds of iterators.
-
-// ## `Drop`
-
-impl<T> Drop for LinkedList<T> {
-    // The destructor itself is a method which takes `self` in mutably borrowed form. It cannot own `self`, because then
-    // the destructor of `self` would be called at the end of the function, resulting in endless recursion.
-    fn drop(&mut self) {
-        let mut cur_ptr = self.first;
-        while !cur_ptr.is_null() {
-            // In the destructor, we just iterate over the entire list, successively obtaining ownership
-            // (`Box`) of every node. When the box is dropped, it will call the destructor on `data` if
-            // necessary, and subsequently free the node on the heap.
-            let cur = unsafe { raw_into_box(cur_ptr) };
-            cur_ptr = cur.next;
-            drop(cur);
-        }
-    }
-}
-
-// ## The End
-