commit 5ed2507bd32112beed3d5c87735edab106f8ad45 Author: Timothy Warren Date: Tue Mar 12 14:53:46 2019 -0400 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4be2a60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,128 @@ +# Created by https://www.gitignore.io/api/rust,macos,jetbrains+all +# Edit at https://www.gitignore.io/?templates=rust,macos,jetbrains+all + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin + .idea/sonarlint + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# End of https://www.gitignore.io/api/rust,macos,jetbrains+all diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8f49850 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "lists" +version = "0.1.0" +authors = ["Timothy Warren "] +edition = "2018" + +[dependencies] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c126997 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +# Learning Rust With Entirely Too Many Linked Lists + + +Code examples from the online [book](https://cglab.ca/~abeinges/blah/too-many-lists/book/README.html) diff --git a/src/first.rs b/src/first.rs new file mode 100644 index 0000000..9e3fb27 --- /dev/null +++ b/src/first.rs @@ -0,0 +1,88 @@ +use std::mem; + +pub struct List { + head: Link, +} + +enum Link { + Empty, + More(Box), +} + +struct Node { + elem: i32, + next: Link, +} + +impl List { + pub fn new() -> Self { + List { head: Link::Empty } + } + + pub fn push(&mut self, elem: i32) { + let new_node = Box::new(Node { + elem, + next: mem::replace(&mut self.head, Link::Empty), + }); + + self.head = Link::More(new_node) + } + + pub fn pop(&mut self) -> Option { + match mem::replace(&mut self.head, Link::Empty) { + Link::Empty => None, + Link::More(boxed_node) => { + let node = *boxed_node; + self.head = node.next; + Some(node.elem) + } + } + } +} + +impl Drop for List { + fn drop(&mut self) { + let mut cur_link = mem::replace(&mut self.head, Link::Empty); + + while let Link::More(mut boxed_node) = cur_link { + cur_link = mem::replace(&mut boxed_node.next, Link::Empty); + // boxed_node goes out of scope and gets dropped here; + // but its Node's `next` field has been set to Link::Empty + // so no unbounded recursion occurs. + } + } +} + +#[cfg(test)] +mod test { + use super::List; + + #[test] + fn basics() { + let mut list = List::new(); + + // Check empty list behaves right + assert_eq!(list.pop(), None); + + // Populate list + list.push(1); + list.push(2); + list.push(3); + + // Check normal removal + assert_eq!(list.pop(), Some(3)); + assert_eq!(list.pop(), Some(2)); + + // Push some more just to make sure nothing's corrupted + list.push(4); + list.push(5); + + // Check normal removal + assert_eq!(list.pop(), Some(5)); + assert_eq!(list.pop(), Some(4)); + + // Check exhaustion + assert_eq!(list.pop(), Some(1)); + assert_eq!(list.pop(), None); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a592e79 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod first;