diff --git a/.all-contributorsrc b/.all-contributorsrc index d4a0857d..fe18385f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -454,11 +454,577 @@ "code", "content" ] + }, + { + "login": "uce", + "name": "Ufuk Celebi", + "avatar_url": "https://avatars3.githubusercontent.com/u/1756620?v=4", + "profile": "https://github.com/uce", + "contributions": [ + "code" + ] + }, + { + "login": "lebedevsergey", + "name": "lebedevsergey", + "avatar_url": "https://avatars2.githubusercontent.com/u/7325764?v=4", + "profile": "https://github.com/lebedevsergey", + "contributions": [ + "doc" + ] + }, + { + "login": "avrong", + "name": "Aleksei Trifonov", + "avatar_url": "https://avatars2.githubusercontent.com/u/6342851?v=4", + "profile": "https://github.com/avrong", + "contributions": [ + "content" + ] + }, + { + "login": "Darrenmeehan", + "name": "Darren Meehan", + "avatar_url": "https://avatars2.githubusercontent.com/u/411136?v=4", + "profile": "https://drn.ie", + "contributions": [ + "content" + ] + }, + { + "login": "jihchi", + "name": "Jihchi Lee", + "avatar_url": "https://avatars1.githubusercontent.com/u/87983?v=4", + "profile": "https://github.com/jihchi", + "contributions": [ + "content" + ] + }, + { + "login": "bertonha", + "name": "Christofer Bertonha", + "avatar_url": "https://avatars3.githubusercontent.com/u/1225902?v=4", + "profile": "https://github.com/bertonha", + "contributions": [ + "content" + ] + }, + { + "login": "apatniv", + "name": "Vivek Bharath Akupatni", + "avatar_url": "https://avatars2.githubusercontent.com/u/22565917?v=4", + "profile": "https://github.com/apatniv", + "contributions": [ + "code", + "test" + ] + }, + { + "login": "DiD92", + "name": "DΓ­dac SementΓ© FernΓ‘ndez", + "avatar_url": "https://avatars3.githubusercontent.com/u/6002416?v=4", + "profile": "https://github.com/DiD92", + "contributions": [ + "code", + "content" + ] + }, + { + "login": "wrobstory", + "name": "Rob Story", + "avatar_url": "https://avatars3.githubusercontent.com/u/2601457?v=4", + "profile": "https://github.com/wrobstory", + "contributions": [ + "code" + ] + }, + { + "login": "siobhanjacobson", + "name": "Siobhan Jacobson", + "avatar_url": "https://avatars2.githubusercontent.com/u/28983835?v=4", + "profile": "https://github.com/siobhanjacobson", + "contributions": [ + "code" + ] + }, + { + "login": "EvanCarroll", + "name": "Evan Carroll", + "avatar_url": "https://avatars2.githubusercontent.com/u/19922?v=4", + "profile": "https://www.linkedin.com/in/evancarroll/", + "contributions": [ + "content" + ] + }, + { + "login": "jmahmood", + "name": "Jawaad Mahmood", + "avatar_url": "https://avatars3.githubusercontent.com/u/95606?v=4", + "profile": "http://www.jawaadmahmood.com", + "contributions": [ + "content" + ] + }, + { + "login": "GaurangTandon", + "name": "Gaurang Tandon", + "avatar_url": "https://avatars1.githubusercontent.com/u/6308683?v=4", + "profile": "https://github.com/GaurangTandon", + "contributions": [ + "content" + ] + }, + { + "login": "dev-cyprium", + "name": "Stefan Kupresak", + "avatar_url": "https://avatars1.githubusercontent.com/u/6002628?v=4", + "profile": "https://github.com/dev-cyprium", + "contributions": [ + "content" + ] + }, + { + "login": "greg-el", + "name": "Greg Leonard", + "avatar_url": "https://avatars3.githubusercontent.com/u/45019882?v=4", + "profile": "https://github.com/greg-el", + "contributions": [ + "content" + ] + }, + { + "login": "ryanpcmcquen", + "name": "Ryan McQuen", + "avatar_url": "https://avatars3.githubusercontent.com/u/772937?v=4", + "profile": "https://ryanpcmcquen.org", + "contributions": [ + "code" + ] + }, + { + "login": "AnnikaCodes", + "name": "Annika", + "avatar_url": "https://avatars3.githubusercontent.com/u/56906084?v=4", + "profile": "https://github.com/AnnikaCodes", + "contributions": [ + "review" + ] + }, + { + "login": "darnuria", + "name": "Axel Viala", + "avatar_url": "https://avatars1.githubusercontent.com/u/2827553?v=4", + "profile": "https://darnuria.eu", + "contributions": [ + "code" + ] + }, + { + "login": "sazid", + "name": "Mohammed Sazid Al Rashid", + "avatar_url": "https://avatars1.githubusercontent.com/u/2370167?v=4", + "profile": "https://sazid.github.io", + "contributions": [ + "content", + "code" + ] + }, + { + "login": "seeplusplus", + "name": "Caleb Webber", + "avatar_url": "https://avatars1.githubusercontent.com/u/17479099?v=4", + "profile": "https://codingthemsoftly.com", + "contributions": [ + "maintenance" + ] + }, + { + "login": "pcn", + "name": "Peter N", + "avatar_url": "https://avatars2.githubusercontent.com/u/1056756?v=4", + "profile": "https://github.com/pcn", + "contributions": [ + "maintenance" + ] + }, + { + "login": "seancad", + "name": "seancad", + "avatar_url": "https://avatars1.githubusercontent.com/u/47405611?v=4", + "profile": "https://github.com/seancad", + "contributions": [ + "maintenance" + ] + }, + { + "login": "wsh", + "name": "Will Hayworth", + "avatar_url": "https://avatars3.githubusercontent.com/u/181174?v=4", + "profile": "http://willhayworth.com", + "contributions": [ + "content" + ] + }, + { + "login": "chrizel", + "name": "Christian Zeller", + "avatar_url": "https://avatars3.githubusercontent.com/u/20802?v=4", + "profile": "https://github.com/chrizel", + "contributions": [ + "content" + ] + }, + { + "login": "jfchevrette", + "name": "Jean-Francois Chevrette", + "avatar_url": "https://avatars.githubusercontent.com/u/3001?v=4", + "profile": "https://github.com/jfchevrette", + "contributions": [ + "content", + "code" + ] + }, + { + "login": "jbaber", + "name": "John Baber-Lucero", + "avatar_url": "https://avatars.githubusercontent.com/u/1908117?v=4", + "profile": "https://github.com/jbaber", + "contributions": [ + "content" + ] + }, + { + "login": "tal-zvon", + "name": "Tal", + "avatar_url": "https://avatars.githubusercontent.com/u/3195851?v=4", + "profile": "https://github.com/tal-zvon", + "contributions": [ + "content" + ] + }, + { + "login": "apogeeoak", + "name": "apogeeoak", + "avatar_url": "https://avatars.githubusercontent.com/u/59737221?v=4", + "profile": "https://github.com/apogeeoak", + "contributions": [ + "content", + "code" + ] + }, + { + "login": "Crell", + "name": "Larry Garfield", + "avatar_url": "https://avatars.githubusercontent.com/u/254863?v=4", + "profile": "http://www.garfieldtech.com/", + "contributions": [ + "content" + ] + }, + { + "login": "circumspect", + "name": "circumspect", + "avatar_url": "https://avatars.githubusercontent.com/u/40770208?v=4", + "profile": "https://github.com/circumspect", + "contributions": [ + "content" + ] + }, + { + "login": "cjwyett", + "name": "Cyrus Wyett", + "avatar_url": "https://avatars.githubusercontent.com/u/34195737?v=4", + "profile": "https://github.com/cjwyett", + "contributions": [ + "content" + ] + }, + { + "login": "cadolphs", + "name": "cadolphs", + "avatar_url": "https://avatars.githubusercontent.com/u/13894820?v=4", + "profile": "https://github.com/cadolphs", + "contributions": [ + "code" + ] + }, + { + "login": "hpwxf", + "name": "Pascal H.", + "avatar_url": "https://avatars.githubusercontent.com/u/26146722?v=4", + "profile": "https://www.haveneer.com", + "contributions": [ + "content" + ] + }, + { + "login": "chapeupreto", + "name": "Rod Elias", + "avatar_url": "https://avatars.githubusercontent.com/u/834048?v=4", + "profile": "https://twitter.com/chapeupreto", + "contributions": [ + "content" + ] + }, + { + "login": "blerchy", + "name": "Matt Lebl", + "avatar_url": "https://avatars.githubusercontent.com/u/2555355?v=4", + "profile": "https://github.com/blerchy", + "contributions": [ + "code" + ] + }, + { + "login": "flakolefluk", + "name": "Ignacio Le Fluk", + "avatar_url": "https://avatars.githubusercontent.com/u/11986564?v=4", + "profile": "http://flakolefluk.dev", + "contributions": [ + "content" + ] + }, + { + "login": "tlyu", + "name": "Taylor Yu", + "avatar_url": "https://avatars.githubusercontent.com/u/431873?v=4", + "profile": "https://github.com/tlyu", + "contributions": [ + "code", + "content" + ] + }, + { + "login": "Zerotask", + "name": "Patrick Hintermayer", + "avatar_url": "https://avatars.githubusercontent.com/u/20150243?v=4", + "profile": "https://zerotask.github.io", + "contributions": [ + "code" + ] + }, + { + "login": "arthas168", + "name": "Pete Pavlovski", + "avatar_url": "https://avatars.githubusercontent.com/u/32264020?v=4", + "profile": "https://petkopavlovski.com/", + "contributions": [ + "content" + ] + }, + { + "login": "k12ish", + "name": "k12ish", + "avatar_url": "https://avatars.githubusercontent.com/u/45272873?v=4", + "profile": "https://github.com/k12ish", + "contributions": [ + "content" + ] + }, + { + "login": "hongshaoyang", + "name": "Shao Yang Hong", + "avatar_url": "https://avatars.githubusercontent.com/u/19281800?v=4", + "profile": "https://github.com/hongshaoyang", + "contributions": [ + "content" + ] + }, + { + "login": "bmacer", + "name": "Brandon Macer", + "avatar_url": "https://avatars.githubusercontent.com/u/13931806?v=4", + "profile": "https://github.com/bmacer", + "contributions": [ + "content" + ] + }, + { + "login": "stoiandan", + "name": "Stoian Dan", + "avatar_url": "https://avatars.githubusercontent.com/u/10388612?v=4", + "profile": "https://github.com/stoiandan", + "contributions": [ + "content" + ] + }, + { + "login": "PiDelport", + "name": "Pi Delport", + "avatar_url": "https://avatars.githubusercontent.com/u/630271?v=4", + "profile": "https://about.me/pjdelport", + "contributions": [ + "content" + ] + }, + { + "login": "sateeshkumarb", + "name": "Sateesh ", + "avatar_url": "https://avatars.githubusercontent.com/u/429263?v=4", + "profile": "https://github.com/sateeshkumarb", + "contributions": [ + "code", + "content" + ] + }, + { + "login": "kayuapi", + "name": "ZC", + "avatar_url": "https://avatars.githubusercontent.com/u/10304328?v=4", + "profile": "https://github.com/kayuapi", + "contributions": [ + "content" + ] + }, + { + "login": "hyperparabolic", + "name": "hyperparabolic", + "avatar_url": "https://avatars.githubusercontent.com/u/12348474?v=4", + "profile": "https://github.com/hyperparabolic", + "contributions": [ + "code" + ] + }, + { + "login": "kolbma", + "name": "arlecchino", + "avatar_url": "https://avatars.githubusercontent.com/u/5228369?v=4", + "profile": "https://www.net4visions.at", + "contributions": [ + "doc" + ] + }, + { + "login": "jazzplato", + "name": "Richthofen", + "avatar_url": "https://avatars.githubusercontent.com/u/7576730?v=4", + "profile": "https://richthofen.io/", + "contributions": [ + "code" + ] + }, + { + "login": "cseltol", + "name": "Ivan Nerazumov", + "avatar_url": "https://avatars.githubusercontent.com/u/64264529?v=4", + "profile": "https://github.com/cseltol", + "contributions": [ + "doc" + ] + }, + { + "login": "lauralindzey", + "name": "lauralindzey", + "avatar_url": "https://avatars.githubusercontent.com/u/65185744?v=4", + "profile": "https://github.com/lauralindzey", + "contributions": [ + "doc" + ] + }, + { + "login": "sinharaksh1t", + "name": "Rakshit Sinha", + "avatar_url": "https://avatars.githubusercontent.com/u/28585848?v=4", + "profile": "https://github.com/sinharaksh1t", + "contributions": [ + "content" + ] + }, + { + "login": "dbednar230", + "name": "Damian", + "avatar_url": "https://avatars.githubusercontent.com/u/54457902?v=4", + "profile": "https://github.com/dbednar230", + "contributions": [ + "content" + ] + }, + { + "login": "benarmstead", + "name": "Ben Armstead", + "avatar_url": "https://avatars.githubusercontent.com/u/70973680?v=4", + "profile": "https://benarmstead.co.uk", + "contributions": [ + "code" + ] + }, + { + "login": "anuk909", + "name": "anuk909", + "avatar_url": "https://avatars.githubusercontent.com/u/34924662?v=4", + "profile": "https://github.com/anuk909", + "contributions": [ + "content", + "code" + ] + }, + { + "login": "granddaifuku", + "name": "granddaifuku", + "avatar_url": "https://avatars.githubusercontent.com/u/49578068?v=4", + "profile": "https://granddaifuku.com/", + "contributions": [ + "content" + ] + }, + { + "login": "Weilet", + "name": "Weilet", + "avatar_url": "https://avatars.githubusercontent.com/u/32561597?v=4", + "profile": "https://weilet.me", + "contributions": [ + "content" + ] + }, + { + "login": "Millione", + "name": "LIU JIE", + "avatar_url": "https://avatars.githubusercontent.com/u/38575932?v=4", + "profile": "https://github.com/Millione", + "contributions": [ + "content" + ] + }, + { + "login": "abusch", + "name": "Antoine BΓΌsch", + "avatar_url": "https://avatars.githubusercontent.com/u/506344?v=4", + "profile": "https://github.com/abusch", + "contributions": [ + "code" + ] + }, + { + "login": "frogtd", + "name": "frogtd", + "avatar_url": "https://avatars.githubusercontent.com/u/31412003?v=4", + "profile": "https://frogtd.com/", + "contributions": [ + "content" + ] + }, + { + "login": "EmisonLu", + "name": "Zhenghao Lu", + "avatar_url": "https://avatars.githubusercontent.com/u/54395432?v=4", + "profile": "https://github.com/EmisonLu", + "contributions": [ + "content" + ] + }, + { + "login": "fredr", + "name": "Fredrik Enestad", + "avatar_url": "https://avatars.githubusercontent.com/u/762956?v=4", + "profile": "https://soundtrackyourbrand.com", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, "projectName": "rustlings", - "projectOwner": "fmoko", + "projectOwner": "rust-lang", "repoType": "github", "repoHost": "https://github.com", "skipCi": true diff --git a/.gitignore b/.gitignore index 6094e5c1..253f8f33 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ target/ exercises/clippy/Cargo.toml exercises/clippy/Cargo.lock .idea +.vscode +*.iml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000..46b1a6a8 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,7 @@ +tasks: + - init: /workspace/rustlings/install.sh + command: /workspace/.cargo/bin/rustlings watch + +vscode: + extensions: + - rust-lang.rust@0.7.8:CvNqMTgDdt3UXt+6BCDTVg== diff --git a/.replit b/.replit new file mode 100644 index 00000000..8462a6fc --- /dev/null +++ b/.replit @@ -0,0 +1,2 @@ +language = "rust" +run = "[ -x ~/.cargo/bin/rustlings ] && ~/.cargo/bin/rustlings watch || ./install.sh" diff --git a/CHANGELOG.md b/CHANGELOG.md index f72c9607..fcc39e42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,207 @@ + +## 4.6.0 (2021-09-25) + + +#### Features + +* add advanced_errs2 ([abd6b70c](https://github.com/rust-lang/rustlings/commit/abd6b70c72dc6426752ff41f09160b839e5c449e)) +* add advanced_errs1 ([882d535b](https://github.com/rust-lang/rustlings/commit/882d535ba8628d5e0b37e8664b3e2f26260b2671)) +* Add a farewell message when quitting `watch` ([1caef0b4](https://github.com/rust-lang/rustlings/commit/1caef0b43494c8b8cdd6c9260147e70d510f1aca)) +* add more watch commands ([a7dc080b](https://github.com/rust-lang/rustlings/commit/a7dc080b95e49146fbaafe6922a6de2f8cb1582a), closes [#842](https://github.com/rust-lang/rustlings/issues/842)) +* **modules:** update exercises, add modules3 (#822) ([dfd2fab4](https://github.com/rust-lang/rustlings/commit/dfd2fab4f33d1bf59e2e5ee03123c0c9a67a9481)) +* **quiz1:** add default function name in comment (#838) ([0a11bad7](https://github.com/rust-lang/rustlings/commit/0a11bad71402b5403143d642f439f57931278c07)) + +#### Bug Fixes + +* Correct small typo in exercises/conversions/from_str.rs ([86cc8529](https://github.com/rust-lang/rustlings/commit/86cc85295ae36948963ae52882e285d7e3e29323)) +* **cli:** typo in exercise.rs (#848) ([06d5c097](https://github.com/rust-lang/rustlings/commit/06d5c0973a3dffa3c6c6f70acb775d4c6630323c)) +* **from_str, try_from_into:** custom error types ([2dc93cad](https://github.com/rust-lang/rustlings/commit/2dc93caddad43821743e4903d89b355df58d7a49)) +* **modules2:** fix typo (#835) ([1c3beb0a](https://github.com/rust-lang/rustlings/commit/1c3beb0a59178c950dc05fe8ee2346b017429ae0)) +* **move_semantics5:** + * change &mut *y to &mut x (#814) ([d75759e8](https://github.com/rust-lang/rustlings/commit/d75759e829fdcd64ef071cf4b6eae2a011a7718b)) + * Clarify instructions ([df25684c](https://github.com/rust-lang/rustlings/commit/df25684cb79f8413915e00b5efef29369849cef1)) +* **quiz1:** Fix inconsistent wording (#826) ([03131a3d](https://github.com/rust-lang/rustlings/commit/03131a3d35d9842598150f9da817f7cc26e2669a)) + + + + +## 4.5.0 (2021-07-07) + + +#### Features + +* Add move_semantics5 exercise. (#746) ([399ab328](https://github.com/rust-lang/rustlings/commit/399ab328d8d407265c09563aa4ef4534b2503ff2)) +* **cli:** Add "next" to run the next unsolved exercise. (#785) ([d20e413a](https://github.com/rust-lang/rustlings/commit/d20e413a68772cd493561f2651cf244e822b7ca5)) + +#### Bug Fixes + +* rename result1 to errors4 ([50ab289d](https://github.com/rust-lang/rustlings/commit/50ab289da6b9eb19a7486c341b00048c516b88c0)) +* move_semantics5 hints ([1b858285](https://github.com/rust-lang/rustlings/commit/1b85828548f46f58b622b5e0c00f8c989f928807)) +* remove trailing whitespaces from iterators1 ([4d4fa774](https://github.com/rust-lang/rustlings/commit/4d4fa77459392acd3581c6068aa8be9a02de12fc)) +* add hints to generics1 and generics2 exercises ([31457940](https://github.com/rust-lang/rustlings/commit/31457940846b3844d78d4a4d2b074bc8d6aaf1eb)) +* remove trailing whitespace ([d9b69bd1](https://github.com/rust-lang/rustlings/commit/d9b69bd1a0a7a99f2c0d80933ad2eea44c8c71b2)) +* **installation:** first PowerShell command ([aa9a943d](https://github.com/rust-lang/rustlings/commit/aa9a943ddf3ae260782e73c26bcc9db60e5894b6)) +* **iterators5:** derive Clone, Copy ([91fc9e31](https://github.com/rust-lang/rustlings/commit/91fc9e3118f4af603c9911698cc2a234725cb032)) +* **quiz1:** Updated question description (#794) ([d8766496](https://github.com/rust-lang/rustlings/commit/d876649616cc8a8dd5f539f8bc1a5434b960b1e9)) +* **try_from_into, from_str:** hints for dyn Error ([11d2cf0d](https://github.com/rust-lang/rustlings/commit/11d2cf0d604dee3f5023c17802d69438e69fa50e)) +* **variables5:** confine the answer further ([48ffcbd2](https://github.com/rust-lang/rustlings/commit/48ffcbd2c4cc4d936c2c7480019190f179813cc5)) + + + + +## 4.4.0 (2021-04-24) + + +#### Bug Fixes + +* Fix spelling error in main.rs ([91ee27f2](https://github.com/rust-lang/rustlings/commit/91ee27f22bd3797a9db57e5fd430801c170c5db8)) +* typo in default out text ([644c49f1](https://github.com/rust-lang/rustlings/commit/644c49f1e04cbb24e95872b3a52b07d692ae3bc8)) +* **collections:** Naming exercises for vectors and hashmap ([bef39b12](https://github.com/rust-lang/rustlings/commit/bef39b125961310b34b34871e480a82e82af4678)) +* **from_str:** + * Correct typos ([5f7c89f8](https://github.com/rust-lang/rustlings/commit/5f7c89f85db1f33da01911eaa479c3a2d4721678)) + * test for error instead of unwrap/should_panic ([15e71535](https://github.com/rust-lang/rustlings/commit/15e71535f37cfaed36e22eb778728d186e2104ab)) + * use trait objects for from_str ([c3e7b831](https://github.com/rust-lang/rustlings/commit/c3e7b831786c9172ed8bd5d150f3c432f242fba9)) +* **functions3:** improve function argument type (#687) ([a6509cc4](https://github.com/rust-lang/rustlings/commit/a6509cc4d545d8825f01ddf7ee37823b372154dd)) +* **hashmap2:** Update incorrect assertion (#660) ([72aaa15e](https://github.com/rust-lang/rustlings/commit/72aaa15e6ab4b72b3422f1c6356396e20a2a2bb8)) +* **info:** Fix typo (#635) ([cddc1e86](https://github.com/rust-lang/rustlings/commit/cddc1e86e7ec744ee644cc774a4887b1a0ded3e8)) +* **iterators2:** Moved errors out of tests. ([baf4ba17](https://github.com/rust-lang/rustlings/commit/baf4ba175ba6eb92989e3dd54ecbec4bedc9a863), closes [#359](https://github.com/rust-lang/rustlings/issues/359)) +* **iterators3:** Enabled iterators3.rs to run without commented out tests. ([c6712dfc](https://github.com/rust-lang/rustlings/commit/c6712dfccd1a093e590ad22bbc4f49edc417dac0)) +* **main:** Let find_exercise work with borrows ([347f30bd](https://github.com/rust-lang/rustlings/commit/347f30bd867343c5ace1097e085a1f7e356553f7)) +* **move_semantics4:** + * Remove redundant "instead" (#640) ([cc266d7d](https://github.com/rust-lang/rustlings/commit/cc266d7d80b91e79df3f61984f231b7f1587218e)) + * Small readbility improvement (#617) ([10965920](https://github.com/rust-lang/rustlings/commit/10965920fbdf8a1efc85bed869e55a1787006404)) +* **option2:** Rename uninformative variables (#675) ([b4de6594](https://github.com/rust-lang/rustlings/commit/b4de6594380636817d13c2677ec6f472a964cf43)) +* **quiz3:** Force an answer to Q2 (#672) ([0d894e6f](https://github.com/rust-lang/rustlings/commit/0d894e6ff739943901e1ae8c904582e5c2f843bd)) +* **structs:** Add 5.3 to structs/README (#652) ([6bd791f2](https://github.com/rust-lang/rustlings/commit/6bd791f2f44aa7f0ad926df767f6b1fa8f12a9a9)) +* **structs2:** correct grammar in hint (#663) ([ebdb66c7](https://github.com/rust-lang/rustlings/commit/ebdb66c7bfb6d687a14cc511a559a222e6fc5de4)) +* **structs3:** + * reword heading comment (#664) ([9f3e8c2d](https://github.com/rust-lang/rustlings/commit/9f3e8c2dde645e5264c2d2200e68842b5f47bfa3)) + * add check to prevent naive implementation of is_international ([05a753fe](https://github.com/rust-lang/rustlings/commit/05a753fe6333d36dbee5f68c21dec04eacdc75df)) +* **threads1:** line number correction ([7857b0a6](https://github.com/rust-lang/rustlings/commit/7857b0a689b0847f48d8c14cbd1865e3b812d5ca)) +* **try_from_into:** use trait objects ([2e93a588](https://github.com/rust-lang/rustlings/commit/2e93a588e0abe8badb7eafafb9e7d073c2be5df8)) + +#### Features + +* Replace clap with argh ([7928122f](https://github.com/rust-lang/rustlings/commit/7928122fcef9ca7834d988b1ec8ca0687478beeb)) +* Replace emojis when NO_EMOJI env variable present ([8d62a996](https://github.com/rust-lang/rustlings/commit/8d62a9963708dbecd9312e8bcc4b47049c72d155)) +* Added iterators5.rs exercise. ([b29ea17e](https://github.com/rust-lang/rustlings/commit/b29ea17ea94d1862114af2cf5ced0e09c197dc35)) +* **arc1:** Add more details to description and hint (#710) ([81be4044](https://github.com/rust-lang/rustlings/commit/81be40448777fa338ebced3b0bfc1b32d6370313)) +* **cli:** Improve the list command with options, and then some ([8bbe4ff1](https://github.com/rust-lang/rustlings/commit/8bbe4ff1385c5c169c90cd3ff9253f9a91daaf8e)) +* **list:** + * updated progress percentage ([1c6f7e4b](https://github.com/rust-lang/rustlings/commit/1c6f7e4b7b9b3bd36f4da2bb2b69c549cc8bd913)) + * added progress info ([c0e3daac](https://github.com/rust-lang/rustlings/commit/c0e3daacaf6850811df5bc57fa43e0f249d5cfa4)) + + + + +## 4.3.0 (2020-12-29) + +#### Features + +* Rewrite default out text ([44d39112](https://github.com/rust-lang/rustlings/commit/44d39112ff122b29c9793fe52e605df1612c6490)) +* match exercise order to book chapters (#541) ([033bf119](https://github.com/rust-lang/rustlings/commit/033bf1198fc8bfce1b570e49da7cde010aa552e3)) +* Crab? (#586) ([fa9f522b](https://github.com/rust-lang/rustlings/commit/fa9f522b7f043d7ef73a39f003a9272dfe72c4f4)) +* add "rustlings list" command ([838f9f30](https://github.com/rust-lang/rustlings/commit/838f9f30083d0b23fd67503dcf0fbeca498e6647)) +* **try_from_into:** remove duplicate annotation ([04f1d079](https://github.com/rust-lang/rustlings/commit/04f1d079aa42a2f49af694bc92c67d731d31a53f)) + +#### Bug Fixes + +* update structs README ([bcf14cf6](https://github.com/rust-lang/rustlings/commit/bcf14cf677adb3a38a3ac3ca53f3c69f61153025)) +* added missing exercises to info.toml ([90cfb6ff](https://github.com/rust-lang/rustlings/commit/90cfb6ff28377531bfc34acb70547bdb13374f6b)) +* gives a bit more context to magic number ([30644c9a](https://github.com/rust-lang/rustlings/commit/30644c9a062b825c0ea89435dc59f0cad86b110e)) +* **functions2:** Change signature to trigger precise error message: (#605) ([0ef95947](https://github.com/rust-lang/rustlings/commit/0ef95947cc30482e63a7045be6cc2fb6f6dcb4cc)) +* **structs1:** Adjust wording (#573) ([9334783d](https://github.com/rust-lang/rustlings/commit/9334783da31d821cc59174fbe8320df95828926c)) +* **try_from_into:** + * type error ([4f4cfcf3](https://github.com/rust-lang/rustlings/commit/4f4cfcf3c36c8718c7c170c9c3a6935e6ef0618c)) + * Update description (#584) ([96347df9](https://github.com/rust-lang/rustlings/commit/96347df9df294f01153b29d9ad4ba361f665c755)) +* **vec1:** Have test compare every element in a and v ([9b6c6293](https://github.com/rust-lang/rustlings/commit/9b6c629397b24b944f484f5b2bbd8144266b5695)) + + +## 4.2.0 (2020-11-07) + +#### Features + +* Add HashMap exercises ([633c00cf](https://github.com/rust-lang/rustlings/commit/633c00cf8071e1e82959a3010452a32f34f29fc9)) +* Add Vec exercises ([0c12fa31](https://github.com/rust-lang/rustlings/commit/0c12fa31c57c03c6287458a0a8aca7afd057baf6)) +* **primitive_types6:** Add a test (#548) ([2b1fb2b7](https://github.com/rust-lang/rustlings/commit/2b1fb2b739bf9ad8d6b7b12af25fee173011bfc4)) +* **try_from_into:** Add tests (#571) ([95ccd926](https://github.com/rust-lang/rustlings/commit/95ccd92616ae79ba287cce221101e0bbe4f68cdc)) + +#### Bug Fixes + +* log error output when inotify limit is exceeded ([d61b4e5a](https://github.com/rust-lang/rustlings/commit/d61b4e5a13b44d72d004082f523fa1b6b24c1aca)) +* more unique temp_file ([5643ef05](https://github.com/rust-lang/rustlings/commit/5643ef05bc81e4a840e9456f4406a769abbe1392)) +* **installation:** Update the MinRustVersion ([21bfb2d4](https://github.com/rust-lang/rustlings/commit/21bfb2d4777429c87d8d3b5fbf0ce66006dcd034)) +* **iterators2:** Update description (#578) ([197d3a3d](https://github.com/rust-lang/rustlings/commit/197d3a3d8961b2465579218a6749b2b2cefa8ddd)) +* **primitive_types6:** + * remove 'unused doc comment' warning ([472d8592](https://github.com/rust-lang/rustlings/commit/472d8592d65c8275332a20dfc269e7ac0d41bc88)) + * missing comma in test ([4fb230da](https://github.com/rust-lang/rustlings/commit/4fb230daf1251444fcf29e085cee222a91f8a37e)) +* **quiz3:** Second test is for odd numbers, not even. (#553) ([18e0bfef](https://github.com/rust-lang/rustlings/commit/18e0bfef1de53071e353ba1ec5837002ff7290e6)) + + +## 4.1.0 (2020-10-05) + +#### Bug Fixes + +* Update rustlings version in Cargo.lock ([1cc40bc9](https://github.com/rust-lang/rustlings/commit/1cc40bc9ce95c23d56f6d91fa1c4deb646231fef)) +* **arc1:** index mod should equal thread count ([b4062ef6](https://github.com/rust-lang/rustlings/commit/b4062ef6993e80dac107c4093ea85166ad3ee0fa)) +* **enums3:** Update Message::ChangeColor to take a tuple. (#457) ([4b6540c7](https://github.com/rust-lang/rustlings/commit/4b6540c71adabad647de8a09e57295e7c7c7d794)) +* **exercises:** adding question mark to quiz2 ([101072ab](https://github.com/rust-lang/rustlings/commit/101072ab9f8c80b40b8b88cb06cbe38aca2481c5)) +* **generics3:** clarify grade change ([47f7672c](https://github.com/rust-lang/rustlings/commit/47f7672c0307732056e7426e81d351f0dd7e22e5)) +* **structs3:** Small adjustment of variable name ([114b54cb](https://github.com/rust-lang/rustlings/commit/114b54cbdb977234b39e5f180d937c14c78bb8b2)) +* **using_as:** Add test so that proper type is returned. (#512) ([3286c5ec](https://github.com/rust-lang/rustlings/commit/3286c5ec19ea5fb7ded81d047da5f8594108a490)) + +#### Features + +* Added iterators1.rs exercise ([9642f5a3](https://github.com/rust-lang/rustlings/commit/9642f5a3f686270a4f8f6ba969919ddbbc4f7fdd)) +* Add ability to run rustlings on repl.it (#471) ([8f7b5bd0](https://github.com/rust-lang/rustlings/commit/8f7b5bd00eb83542b959830ef55192d2d76db90a)) +* Add gitpod support (#473) ([4821a8be](https://github.com/rust-lang/rustlings/commit/4821a8be94af4f669042a06ab917934cfacd032f)) +* Remind the user of the hint option (#425) ([816b1f5e](https://github.com/rust-lang/rustlings/commit/816b1f5e85d6cc6e72673813a85d0ada2a8f84af)) +* Remind the user of the hint option (#425) ([9f61db5d](https://github.com/rust-lang/rustlings/commit/9f61db5dbe38538cf06571fcdd5f806e7901e83a)) +* **cli:** Added 'cls' command to 'watch' mode (#474) ([4f2468e1](https://github.com/rust-lang/rustlings/commit/4f2468e14f574a93a2e9b688367b5752ed96ae7b)) +* **try_from_into:** Add insufficient length test (#469) ([523d18b8](https://github.com/rust-lang/rustlings/commit/523d18b873a319f7c09262f44bd40e2fab1830e5)) + + +## 4.0.0 (2020-07-08) + +#### Breaking Changes + +* Add a --nocapture option to display test harnesses' outputs ([8ad5f9bf](https://github.com/rust-lang/rustlings/commit/8ad5f9bf531a4848b1104b7b389a20171624c82f)) +* Rename test to quiz, fixes #244 ([010a0456](https://github.com/rust-lang/rustlings/commit/010a04569282149cea7f7a76fc4d7f4c9f0f08dd)) + +#### Features + +* Add traits README ([173bb141](https://github.com/rust-lang/rustlings/commit/173bb14140c5530cbdb59e53ace3991a99d804af)) +* Add box1.rs exercise ([7479a473](https://github.com/rust-lang/rustlings/commit/7479a4737bdcac347322ad0883ca528c8675e720)) +* Rewrite try_from_into (#393) ([763aa6e3](https://github.com/rust-lang/rustlings/commit/763aa6e378a586caae2d8d63755a85eeba227933)) +* Add if2 exercise ([1da84b5f](https://github.com/rust-lang/rustlings/commit/1da84b5f7c489f65bd683c244f13c7d1ee812df0)) +* Added exercise structs3.rs ([b66e2e09](https://github.com/rust-lang/rustlings/commit/b66e2e09622243e086a0f1258dd27e1a2d61c891)) +* Add exercise variables6 covering const (#352) ([5999acd2](https://github.com/rust-lang/rustlings/commit/5999acd24a4f203292be36e0fd18d385887ec481)) + +#### Bug Fixes + +* Change then to than ([ddd98ad7](https://github.com/rust-lang/rustlings/commit/ddd98ad75d3668fbb10eff74374148aa5ed2344d)) +* rename quiz1 to tests1 in info (#420) ([0dd1c6ca](https://github.com/rust-lang/rustlings/commit/0dd1c6ca6b389789e0972aa955fe17aa15c95f29)) +* fix quiz naming inconsistency (#421) ([5563adbb](https://github.com/rust-lang/rustlings/commit/5563adbb890587fc48fbbc9c4028642687f1e85b)) +* confine the user further in variable exercises ([06ef4cc6](https://github.com/rust-lang/rustlings/commit/06ef4cc654e75d22a526812919ee49b8956280bf)) +* update iterator and macro text for typos and clarity ([95900828](https://github.com/rust-lang/rustlings/commit/959008284834bece0196a01e17ac69a7e3590116)) +* update generics2 closes #362 ([964c974a](https://github.com/rust-lang/rustlings/commit/964c974a0274199d755073b917c2bc5da0c9b4f1)) +* confusing comment in conversions/try_from_into.rs ([c9e4f2cf](https://github.com/rust-lang/rustlings/commit/c9e4f2cfb4c48d0b7451263cfb43b9426438122d)) +* **arc1:** Passively introduce attributes (#429) ([113cdae2](https://github.com/rust-lang/rustlings/commit/113cdae2d4e4c55905e8056ad326ede7fd7de356)) +* **box1:** fix comment typo (#426) ([bb2ca251](https://github.com/rust-lang/rustlings/commit/bb2ca251106b27a7272d9a30872904dd1376654c)) +* **errorsn:** Try harder to confine the user. (#388) ([2b20c8a0](https://github.com/rust-lang/rustlings/commit/2b20c8a0f5774d07c58d110d75879f33fc6273b5)) +* **from_into.rs:** typo ([a901499e](https://github.com/rust-lang/rustlings/commit/a901499ededd3ce1995164700514fe4e9a0373ea)) +* **generics2:** Guide students to the answer (#430) ([e6bd8021](https://github.com/rust-lang/rustlings/commit/e6bd8021d9a7dd06feebc30c9d5f953901d7b419)) +* **installation:** + * Provide a backup git reference when tag can't be curl ([9e4fb100](https://github.com/rust-lang/rustlings/commit/9e4fb1009f1c9e3433915c03e22c2af422e5c5fe)) + * Check if python is available while checking for git,rustc and cargo ([9cfb617d](https://github.com/rust-lang/rustlings/commit/9cfb617d5b0451b4b51644a1298965390cda9884)) +* **option1:** + * Don't add only zeros to the numbers array ([cce6a442](https://github.com/rust-lang/rustlings/commit/cce6a4427718724a9096800754cd3abeca6a1580)) + * Add cast to usize, as it is confusing in the context of an exercise about Option ([f6cffc7e](https://github.com/rust-lang/rustlings/commit/f6cffc7e487b42f15a6f958e49704c93a8d4465b)) +* **option2:** Add TODO to comments (#400) ([10967bce](https://github.com/rust-lang/rustlings/commit/10967bce57682812dc0891a9f9757da1a9d87404)) +* **options1:** Add hint about Array Initialization (#389) ([9f75554f](https://github.com/rust-lang/rustlings/commit/9f75554f2a30295996f03f0160b98c0458305502)) +* **test2:** name of type String and &str (#394) ([d6c0a688](https://github.com/rust-lang/rustlings/commit/d6c0a688e6a96f93ad60d540d4b326f342fc0d45)) +* **variables6:** minor typo (#419) ([524e17df](https://github.com/rust-lang/rustlings/commit/524e17df10db95f7b90a0f75cc8997182a8a4094)) + ## 3.0.0 (2020-04-11) @@ -41,14 +245,14 @@ * Update deps to version compatable with aarch64-pc-windows (#263) ([19a93428](https://github.com/rust-lang/rustlings/commit/19a93428b3c73d994292671f829bdc8e5b7b3401)) * **docs:** * Added a necessary step to Windows installation process (#242) ([3906efcd](https://github.com/rust-lang/rustlings/commit/3906efcd52a004047b460ed548037093de3f523f)) - * Fixed mangled sentence from book; edited for clarity (#266) ([ade52ff](https://github.com/rust-lang/rustlings/commit/ade52ffb739987287ddd5705944c8777705faed9)) + * Fixed mangled sentence from book; edited for clarity (#266) ([ade52ff](https://github.com/rust-lang/rustlings/commit/ade52ffb739987287ddd5705944c8777705faed9)) * Updated iterators readme to account for iterators4 exercise (#273) ([bec8e3a](https://github.com/rust-lang/rustlings/commit/bec8e3a644cbd88db1c73ea5f1d8a364f4a34016)) * **installation:** make fatal errors more obvious (#272) ([17d0951e](https://github.com/rust-lang/rustlings/commit/17d0951e66fda8e11b204d5c4c41a0d5e22e78f7)) * **iterators2:** * Remove reference to missing iterators2.rs (#245) ([419f7797](https://github.com/rust-lang/rustlings/commit/419f7797f294e4ce6a2b883199731b5bde77d262)) * **as_ref_mut:** Enable a test and improve per clippy's suggestion (#256) ([dfdf809](https://github.com/rust-lang/rustlings/commit/dfdf8093ebbd4145864995627b812780de52f902)) * **tests1:** - * Change test command ([fe10e06c](https://github.com/rust-lang/rustlings/commit/fe10e06c3733ddb4a21e90d09bf79bfe618e97ce) + * Change test command ([fe10e06c](https://github.com/rust-lang/rustlings/commit/fe10e06c3733ddb4a21e90d09bf79bfe618e97ce) * Correct test command in tests1.rs comment (#263) ([39fa7ae](https://github.com/rust-lang/rustlings/commit/39fa7ae8b70ad468da49b06f11b2383135a63bcf)) #### Features diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d566df08..2ca0e341 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,12 +26,12 @@ isn't really that complicated since the bulk of the work is done by `rustc`. ### Adding an exercise -First step is to add the exercise! Call it `exercises/yourTopic/yourTopicN.rs`, make sure to +The first step is to add the exercise! Name the file `exercises/yourTopic/yourTopicN.rs`, make sure to put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`. -Next you want to make sure it runs when using `rustlings`. All exercises are stored in `info.toml`, under the `exercises` array. They're ordered by the order they're ran when using `rustlings verify`. +Next make sure it runs with `rustlings`. The exercise metadata is stored in `info.toml`, under the `exercises` array. The order of the `exercises` array determines the order the exercises are run by `rustlings verify`. -You want to make sure where in the file you add your exercise. If you're not sure, add it at the bottom and ask in your pull request. To add an exercise, edit the file like this: +Add the metadata for your exercise in the correct order in the `exercises` array. If you are unsure of the correct ordering, add it at the bottom and ask in your pull request. The exercise metadata should contain the following: ```diff ... + [[exercises]] diff --git a/Cargo.lock b/Cargo.lock index 52c8ed45..e536d1b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,920 +1,747 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" -version = "0.7.3" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] -name = "ansi_term" -version = "0.11.0" +name = "argh" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7317a549bc17c5278d9e72bb6e62c6aa801ac2567048e39ebc1c194249323e" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "argh_derive", + "argh_shared", ] +[[package]] +name = "argh_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60949c42375351e9442e354434b0cba2ac402c1237edf673cac3a4bf983b8d3c" +dependencies = [ + "argh_shared", + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "argh_shared" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a61eb019cb8f415d162cb9f12130ee6bbe9168b7d953c17f4ad049e4051ca00" + [[package]] name = "assert_cmd" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc477793bd82ec39799b6f6b3df64938532fdf2ab0d49ef817eac65856a5a1e" dependencies = [ - "escargot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "predicates 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "escargot", + "predicates", + "predicates-core", + "predicates-tree", ] [[package]] name = "atty" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi 0.3.9", ] [[package]] name = "autocfg" -version = "0.1.4" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" -version = "1.0.4" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] -name = "clap" -version = "2.33.0" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clicolors-control" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "lazy_static", + "libc", + "winapi 0.3.9", ] [[package]] name = "console" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628" dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "clicolors-control", + "encode_unicode", + "lazy_static", + "libc", + "parking_lot", + "regex", + "termios", + "unicode-width", + "winapi 0.3.9", ] [[package]] name = "console" -version = "0.8.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" dependencies = [ - "clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "encode_unicode", + "lazy_static", + "libc", + "regex", + "terminal_size", + "unicode-width", + "winapi 0.3.9", ] [[package]] name = "difference" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" [[package]] name = "encode_unicode" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "escargot" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceb9adbf9874d5d028b5e4c5739d22b71988252b25c9c98fe7cf9738bee84597" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "log", + "serde", + "serde_json", ] [[package]] name = "filetime" -version = "0.2.5" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "winapi 0.3.9", ] [[package]] name = "float-cmp" -version = "0.4.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" dependencies = [ - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits", ] [[package]] name = "fsevent" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "fsevent-sys", ] [[package]] name = "fsevent-sys" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "fuchsia-zircon-sys", ] [[package]] name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] [[package]] name = "indicatif" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd1e2ee08e6c255ce890f5a99d17000850e664e7acf119fb03b25b0575bfe" dependencies = [ - "console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "console 0.14.1", + "lazy_static", + "number_prefix", + "parking_lot", + "regex", ] [[package]] name = "inotify" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "inotify-sys", + "libc", ] [[package]] name = "inotify-sys" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", +] + +[[package]] +name = "instant" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +dependencies = [ + "cfg-if 1.0.0", ] [[package]] name = "iovec" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "itoa" -version = "0.4.4" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "lazy_static" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.58" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5" [[package]] name = "lock_api" -version = "0.2.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" dependencies = [ - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard", ] [[package]] name = "log" -version = "0.4.6" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "memchr" -version = "2.2.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "mio" -version = "0.6.19" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", ] [[package]] name = "mio-extras" -version = "2.0.5" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" dependencies = [ - "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell", + "log", + "mio", + "slab", ] [[package]] name = "miow" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", ] [[package]] name = "net2" -version = "0.2.33" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", ] [[package]] name = "normalize-line-endings" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "notify" -version = "4.0.15" +version = "4.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "filetime", + "fsevent", + "fsevent-sys", + "inotify", + "libc", + "mio", + "mio-extras", + "walkdir", + "winapi 0.3.9", ] [[package]] name = "num-traits" -version = "0.2.8" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] name = "number_prefix" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" dependencies = [ - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits", ] -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "parking_lot" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ - "lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "instant", + "lock_api", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.5.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.9", ] [[package]] name = "predicates" -version = "1.0.1" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df" dependencies = [ - "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "normalize-line-endings 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "difference", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", ] [[package]] name = "predicates-core" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451" [[package]] name = "predicates-tree" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dd0fd014130206c9352efbdc92be592751b2b9274dff685348341082c6ea3d" dependencies = [ - "predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "predicates-core", + "treeline", ] [[package]] name = "proc-macro2" -version = "0.4.30" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "quote" -version = "0.6.12" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", ] [[package]] name = "regex" -version = "1.1.6" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ - "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.6" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rustlings" -version = "3.0.0" +version = "4.6.0" dependencies = [ - "assert_cmd 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "predicates 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "argh", + "assert_cmd", + "console 0.7.7", + "glob", + "indicatif", + "notify", + "predicates", + "regex", + "serde", + "toml", ] [[package]] name = "ryu" -version = "0.2.8" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "same-file" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "scopeguard" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.92" +version = "1.0.129" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1" dependencies = [ - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.92" +version = "1.0.129" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57ae87ad533d9a56427558b516d0adac283614e347abf85b0dc0cbbf0a249f3" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" -version = "1.0.39" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "slab" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" [[package]] name = "smallvec" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "strsim" -version = "0.8.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "0.15.34" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] -name = "termion" -version = "1.5.2" +name = "terminal_size" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi 0.3.9", ] [[package]] name = "termios" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "treeline" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" [[package]] -name = "ucd-util" -version = "0.1.3" +name = "unicode-segmentation" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "utf8-ranges" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "vec_map" -version = "0.8.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "walkdir" -version = "2.2.7" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ - "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file", + "winapi 0.3.9", + "winapi-util", ] [[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] - -[metadata] -"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum assert_cmd 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2dc477793bd82ec39799b6f6b3df64938532fdf2ab0d49ef817eac65856a5a1e" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" -"checksum clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73abfd4c73d003a674ce5d2933fca6ce6c42480ea84a5ffe0a2dc39ed56300f9" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628" -"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242" -"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" -"checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd" -"checksum escargot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ceb9adbf9874d5d028b5e4c5739d22b71988252b25c9c98fe7cf9738bee84597" -"checksum filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2f8c63033fcba1f51ef744505b3cad42510432b904c062afa67ad7ece008429d" -"checksum float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "134a8fa843d80a51a5b77d36d42bc2def9edcb0262c914861d08129fd1926600" -"checksum fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" -"checksum fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -"checksum indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "40ecd1e2ee08e6c255ce890f5a99d17000850e664e7acf119fb03b25b0575bfe" -"checksum inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8" -"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" -"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" -"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" -"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" -"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum normalize-line-endings 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2e0a1a39eab95caf4f5556da9289b9e68f0aafac901b2ce80daaf020d3b733a8" -"checksum notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" -"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" -"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" -"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" -"checksum predicates 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "53e09015b0d3f5a0ec2d4428f7559bb7b3fff341b4e159fedd1d57fac8b939ff" -"checksum predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178" -"checksum predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" -"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" -"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" -"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" -"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" -"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" -"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" -"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -"checksum treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" -"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/Cargo.toml b/Cargo.toml index 3481a886..3b2a85a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "rustlings" -version = "3.0.0" -authors = ["Marisa ", "Carol (Nichols || Goulding) "] +version = "4.6.0" +authors = ["anastasie ", "Carol (Nichols || Goulding) "] edition = "2018" [dependencies] -clap = "2.32.0" +argh = "0.1.4" indicatif = "0.10.3" console = "0.7.7" notify = "4.0.15" diff --git a/README.md b/README.md index 6724f05a..6e5ce3f6 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,14 @@ -![crab pet](https://i.imgur.com/LbZJgmm.gif) -[![All Contributors](https://img.shields.io/badge/all_contributors-48-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-110-orange.svg?style=flat-square)](#contributors-) -# rustlings πŸ¦€β€οΈ [![Build status](https://badge.buildkite.com/7af93d81dc522c67a1ec8e33ff5705861b1cb36360b774807f.svg)](https://buildkite.com/mokou/rustlings) +# rustlings πŸ¦€β€οΈ Greetings and welcome to `rustlings`. This project contains small exercises to get you used to reading and writing Rust code. This includes reading and responding to compiler messages! _...looking for the old, web-based version of Rustlings? Try [here](https://github.com/rust-lang/rustlings/tree/rustlings-1)_ -Alternatively, for a first-time Rust learner, there's several other resources: +Alternatively, for a first-time Rust learner, there are several other resources: - [The Book](https://doc.rust-lang.org/book/index.html) - The most comprehensive resource for learning Rust, but a bit theoretical sometimes. You will be using this along with Rustlings! - [Rust By Example](https://doc.rust-lang.org/rust-by-example/index.html) - Learn Rust by solving little exercises! It's almost like `rustlings`, but online @@ -25,37 +24,45 @@ You will need to have Rust installed. You can get it by visiting https://rustup. Just run: ```bash -curl -L https://git.io/rustlings | bash +curl -L https://git.io/install-rustlings | bash # Or if you want it to be installed to a different path: -curl -L https://git.io/rustlings | bash -s mypath/ +curl -L https://git.io/install-rustlings | bash -s mypath/ ``` This will install Rustlings and give you access to the `rustlings` command. Run it to get started! ## Windows -In PowerShell, set `ExecutionPolicy` to `RemoteSigned`: +In PowerShell (Run as Administrator), set `ExecutionPolicy` to `RemoteSigned`: ```ps -Set-ExecutionPolicy RemoteSigned +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser ``` Then, you can run: ```ps -Start-BitsTransfer -Source https://git.io/rustlings-win -Destination $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1 +Start-BitsTransfer -Source https://git.io/JTL5v -Destination $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1 ``` To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it. +When you get a permission denied message then you have to exclude the directory where you placed the rustlings in your virus-scanner + +## Browser: + +[Run on Repl.it](https://repl.it/github/rust-lang/rustlings) + +[Open in Gitpod](https://gitpod.io/#https://github.com/rust-lang/rustlings) + ## Manually -Basically: Clone the repository, checkout to the latest tag, run `cargo install`. +Basically: Clone the repository at the latest tag, run `cargo install`. ```bash -git clone https://github.com/rust-lang/rustlings +# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 4.6.0) +git clone -b 4.6.0 --depth 1 https://github.com/rust-lang/rustlings cd rustlings -git checkout tags/3.0.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest) cargo install --force --path . ``` @@ -70,7 +77,7 @@ Then, same as above, run `rustlings` to get started. The exercises are sorted by topic and can be found in the subdirectory `rustlings/exercises/`. For every topic there is an additional README file with some resources to get you started on the topic. We really recommend that you have a look at them before you start. -The task is simple. Most exercises contain an error that keep it from compiling, and it's up to you to fix it! Some exercises are also run as tests, but rustlings handles them all the same. To run the exercises in the recommended order, execute: +The task is simple. Most exercises contain an error that keeps them from compiling, and it's up to you to fix it! Some exercises are also run as tests, but rustlings handles them all the same. To run the exercises in the recommended order, execute: ```bash rustlings watch @@ -90,6 +97,12 @@ In case you want to go by your own order, or want to only verify a single exerci rustlings run myExercise1 ``` +Or simply use the following command to run the next unsolved exercise in the course: + +```bash +rustlings run next +``` + In case you get stuck, you can run the following command to get a hint for your exercise: @@ -97,10 +110,43 @@ exercise: rustlings hint myExercise1 ``` +You can also get the hint for the next unsolved exercise with the following command: + +``` bash +rustlings hint next +``` + +To check your progress, you can run the following command: +```bash +rustlings list +``` + ## Testing yourself After every couple of sections, there will be a quiz that'll test your knowledge on a bunch of sections at once. These quizzes are found in `exercises/quizN.rs`. +## Continuing On + +Once you've completed Rustlings, put your new knowledge to good use! Continue practicing your Rust skills by building your own projects, contributing to Rustlings, or finding other open-source projects to contribute to. + +## Uninstalling Rustlings + +If you want to remove Rustlings from your system, there's two steps. First, you'll need to remove the exercises folder that the install script created +for you: + +``` bash +rm -rf rustlings # or your custom folder name, if you chose and or renamed it +``` + +Second, since Rustlings got installed via `cargo install`, it's only reasonable to assume that you can also remove it using Cargo, and +exactly that is the case. Run `cargo uninstall` to remove the `rustlings` binary: + +``` bash +cargo uninstall rustlings +``` + +Now you should be done! + ## Completion Rustlings isn't done; there are a couple of sections that are very experimental and don't have proper documentation. These include: @@ -132,69 +178,148 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Carol (Nichols || Goulding)

πŸ’» πŸ–‹

QuietMisdreavus

πŸ’» πŸ–‹

Robert M Lugg

πŸ–‹

Hynek Schlawack

πŸ’»

Katharina Fey

πŸ’»

lukabavdaz

πŸ’» πŸ–‹

Erik Vesteraas

πŸ’»

delet0r

πŸ’»

Carol (Nichols || Goulding)

πŸ’» πŸ–‹

QuietMisdreavus

πŸ’» πŸ–‹

Robert M Lugg

πŸ–‹

Hynek Schlawack

πŸ’»

Katharina Fey

πŸ’»

lukabavdaz

πŸ’» πŸ–‹

Erik Vesteraas

πŸ’»

delet0r

πŸ’»

Shaun Bennett

πŸ’»

Andrew Bagshaw

πŸ’»

Kyle Isom

πŸ’»

Colin Pitrat

πŸ’»

Zac Anger

πŸ’»

Matthias Geier

πŸ’»

Chris Pearce

πŸ’»

Yvan Sraka

πŸ’»

Shaun Bennett

πŸ’»

Andrew Bagshaw

πŸ’»

Kyle Isom

πŸ’»

Colin Pitrat

πŸ’»

Zac Anger

πŸ’»

Matthias Geier

πŸ’»

Chris Pearce

πŸ’»

Yvan Sraka

πŸ’»

Denys Smirnov

πŸ’»

eddyp

πŸ’»

Brian Kung

πŸ’» πŸ–‹

Russell

πŸ’»

Dan Wilhelm

πŸ“–

Jesse

πŸ’» πŸ–‹

Fredrik JambrΓ©n

πŸ’»

Pete McFarlane

πŸ–‹

Denys Smirnov

πŸ’»

eddyp

πŸ’»

Brian Kung

πŸ’» πŸ–‹

Russell

πŸ’»

Dan Wilhelm

πŸ“–

Jesse

πŸ’» πŸ–‹

Fredrik JambrΓ©n

πŸ’»

Pete McFarlane

πŸ–‹

nkanderson

πŸ’» πŸ–‹

Ajax M

πŸ“–

Dylan Nugent

πŸ–‹

vyaslav

πŸ’» πŸ–‹

George

πŸ’»

Thomas Holloway

πŸ’» πŸ–‹

Jubilee

πŸ’»

WofWca

πŸ’»

nkanderson

πŸ’» πŸ–‹

Ajax M

πŸ“–

Dylan Nugent

πŸ–‹

vyaslav

πŸ’» πŸ–‹

George

πŸ’»

Thomas Holloway

πŸ’» πŸ–‹

Jubilee

πŸ’»

WofWca

πŸ’»

Roberto Vidal

πŸ’» πŸ“– πŸ€” 🚧

Jens

πŸ“–

Rahat Ahmed

πŸ“–

Abdou Seck

πŸ’» πŸ–‹ πŸ‘€

Katie

πŸ’»

Socrates

πŸ“–

gnodarse

πŸ–‹

Harrison Metzger

πŸ’»

Roberto Vidal

πŸ’» πŸ“– πŸ€” 🚧

Jens

πŸ“–

Rahat Ahmed

πŸ“–

Abdou Seck

πŸ’» πŸ–‹ πŸ‘€

Katie

πŸ’»

Socrates

πŸ“–

gnodarse

πŸ–‹

Harrison Metzger

πŸ’»

Torben Jonas

πŸ’» πŸ–‹

Paul Bissex

πŸ“–

Steven Mann

πŸ’» πŸ–‹

Mario Reder

πŸ’» πŸ–‹

skim

πŸ’»

Sanjay K

πŸ’» πŸ–‹

Rohan Jain

πŸ’»

Said Aspen

πŸ’» πŸ–‹

Torben Jonas

πŸ’» πŸ–‹

Paul Bissex

πŸ“–

Steven Mann

πŸ’» πŸ–‹

Mario Reder

πŸ’» πŸ–‹

skim

πŸ’»

Sanjay K

πŸ’» πŸ–‹

Rohan Jain

πŸ’»

Said Aspen

πŸ’» πŸ–‹

Ufuk Celebi

πŸ’»

lebedevsergey

πŸ“–

Aleksei Trifonov

πŸ–‹

Darren Meehan

πŸ–‹

Jihchi Lee

πŸ–‹

Christofer Bertonha

πŸ–‹

Vivek Bharath Akupatni

πŸ’» ⚠️

DΓ­dac SementΓ© FernΓ‘ndez

πŸ’» πŸ–‹

Rob Story

πŸ’»

Siobhan Jacobson

πŸ’»

Evan Carroll

πŸ–‹

Jawaad Mahmood

πŸ–‹

Gaurang Tandon

πŸ–‹

Stefan Kupresak

πŸ–‹

Greg Leonard

πŸ–‹

Ryan McQuen

πŸ’»

Annika

πŸ‘€

Axel Viala

πŸ’»

Mohammed Sazid Al Rashid

πŸ–‹ πŸ’»

Caleb Webber

🚧

Peter N

🚧

seancad

🚧

Will Hayworth

πŸ–‹

Christian Zeller

πŸ–‹

Jean-Francois Chevrette

πŸ–‹ πŸ’»

John Baber-Lucero

πŸ–‹

Tal

πŸ–‹

apogeeoak

πŸ–‹ πŸ’»

Larry Garfield

πŸ–‹

circumspect

πŸ–‹

Cyrus Wyett

πŸ–‹

cadolphs

πŸ’»

Pascal H.

πŸ–‹

Rod Elias

πŸ–‹

Matt Lebl

πŸ’»

Ignacio Le Fluk

πŸ–‹

Taylor Yu

πŸ’» πŸ–‹

Patrick Hintermayer

πŸ’»

Pete Pavlovski

πŸ–‹

k12ish

πŸ–‹

Shao Yang Hong

πŸ–‹

Brandon Macer

πŸ–‹

Stoian Dan

πŸ–‹

Pi Delport

πŸ–‹

Sateesh

πŸ’» πŸ–‹

ZC

πŸ–‹

hyperparabolic

πŸ’»

arlecchino

πŸ“–

Richthofen

πŸ’»

Ivan Nerazumov

πŸ“–

lauralindzey

πŸ“–

Rakshit Sinha

πŸ–‹

Damian

πŸ–‹

Ben Armstead

πŸ’»

anuk909

πŸ–‹ πŸ’»

granddaifuku

πŸ–‹

Weilet

πŸ–‹

LIU JIE

πŸ–‹

Antoine BΓΌsch

πŸ’»

frogtd

πŸ–‹

Zhenghao Lu

πŸ–‹

Fredrik Enestad

πŸ–‹
- + + This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/buildkite.yml b/buildkite.yml deleted file mode 100644 index 91a0753c..00000000 --- a/buildkite.yml +++ /dev/null @@ -1,5 +0,0 @@ -steps: - - label: "Test with stable" - command: rustup run stable cargo test - - label: "Test with beta" - command: rustup run beta cargo test diff --git a/default_out.txt b/default_out.txt index 05267591..b90d1e3a 100644 --- a/default_out.txt +++ b/default_out.txt @@ -1,19 +1,25 @@ Thanks for installing Rustlings! -Is this your first time? +Is this your first time? Don't worry, Rustlings was made for beginners! We are +going to teach you a lot of things about Rust, but before we can get +started, here's a couple of notes about how Rustlings operates: -Let's make sure you're up to speed: -- You have Rust installed, preferably via `rustup` -- You have `~/.cargo/bin` added to your PATH variable -- You have cloned this repository (https://github.com/rust-lang/rustlings) -- You have installed Rust language support for your editor -- You have locally installed the `rustlings` command by running an - installation script or manually executing: +1. The central concept behind Rustlings is that you solve exercises. These + exercises usually have some sort of syntax error in them, which will cause + them to fail compilation or testing. Sometimes there's a logic error instead + of a syntax error. No matter what error, it's your job to find it and fix it! + You'll know when you fixed it because then, the exercise will compile and + Rustlings will be able to move on to the next exercise. +2. If you run Rustlings in watch mode (which we recommend), it'll automatically + start with the first exercise. Don't get confused by an error message popping + up as soon as you run Rustlings! This is part of the exercise that you're + supposed to solve, so open the exercise file in an editor and start your + detective work! +3. If you're stuck on an exercise, there is a helpful hint you can view by typing + 'hint' (in watch mode), or running `rustlings hint myexercise`. +4. If an exercise doesn't make sense to you, feel free to open an issue on GitHub! + (https://github.com/rust-lang/rustlings/issues/new). We look at every issue, + and sometimes, other learners do too so you can help each other out! -cargo install --force --path . - -If you've done all of this (or even most of it), congrats! You're ready -to start working with Rust. - -To get started, run `rustlings watch` in order to get the first exercise. -Make sure to have your editor open! +Got all that? Great! To get started, run `rustlings watch` in order to get the first +exercise. Make sure to have your editor open! diff --git a/exercises/README.md b/exercises/README.md new file mode 100644 index 00000000..73754db5 --- /dev/null +++ b/exercises/README.md @@ -0,0 +1,24 @@ +# Exercise to Book Chapter mapping + +| Exercise | Book Chapter | +|------------------------|--------------| +| variables | Β§3.1 | +| functions | Β§3.3 | +| if | Β§3.5 | +| move_semantics | Β§4.1 | +| primitive_types | Β§4.3 | +| structs | Β§5.1 | +| enums | Β§6 | +| modules | Β§7 | +| collections | Β§8.1, Β§8.3 | +| strings | Β§8.2 | +| error_handling | Β§9 | +| generics | Β§10 | +| option | Β§10.1 | +| traits | Β§10.2 | +| tests | Β§11.1 | +| standard_library_types | Β§13.2 | +| threads | Β§16.1 | +| macros | Β§19.6 | +| clippy | n/a | +| conversions | n/a | diff --git a/exercises/advanced_errors/advanced_errs1.rs b/exercises/advanced_errors/advanced_errs1.rs new file mode 100644 index 00000000..4bc7b635 --- /dev/null +++ b/exercises/advanced_errors/advanced_errs1.rs @@ -0,0 +1,98 @@ +// advanced_errs1.rs + +// Remember back in errors6, we had multiple mapping functions so that we +// could translate lower-level errors into our custom error type using +// `map_err()`? What if we could use the `?` operator directly instead? + +// Make this code compile! Execute `rustlings hint advanced_errs1` for +// hints :) + +// I AM NOT DONE + +use std::num::ParseIntError; +use std::str::FromStr; + +// This is a custom error type that we will be using in the `FromStr` +// implementation. +#[derive(PartialEq, Debug)] +enum ParsePosNonzeroError { + Creation(CreationError), + ParseInt(ParseIntError), +} + +impl From for ParsePosNonzeroError { + fn from(e: CreationError) -> Self { + // TODO: complete this implementation so that the `?` operator will + // work for `CreationError` + } +} + +// TODO: implement another instance of the `From` trait here so that the +// `?` operator will work in the other place in the `FromStr` +// implementation below. + +// Don't change anything below this line. + +impl FromStr for PositiveNonzeroInteger { + type Err = ParsePosNonzeroError; + fn from_str(s: &str) -> Result { + let x: i64 = s.parse()?; + Ok(PositiveNonzeroInteger::new(x)?) + } +} + +#[derive(PartialEq, Debug)] +struct PositiveNonzeroInteger(u64); + +#[derive(PartialEq, Debug)] +enum CreationError { + Negative, + Zero, +} + +impl PositiveNonzeroInteger { + fn new(value: i64) -> Result { + match value { + x if x < 0 => Err(CreationError::Negative), + x if x == 0 => Err(CreationError::Zero), + x => Ok(PositiveNonzeroInteger(x as u64)), + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_parse_error() { + // We can't construct a ParseIntError, so we have to pattern match. + assert!(matches!( + PositiveNonzeroInteger::from_str("not a number"), + Err(ParsePosNonzeroError::ParseInt(_)) + )); + } + + #[test] + fn test_negative() { + assert_eq!( + PositiveNonzeroInteger::from_str("-555"), + Err(ParsePosNonzeroError::Creation(CreationError::Negative)) + ); + } + + #[test] + fn test_zero() { + assert_eq!( + PositiveNonzeroInteger::from_str("0"), + Err(ParsePosNonzeroError::Creation(CreationError::Zero)) + ); + } + + #[test] + fn test_positive() { + let x = PositiveNonzeroInteger::new(42); + assert!(x.is_ok()); + assert_eq!(PositiveNonzeroInteger::from_str("42"), Ok(x.unwrap())); + } +} diff --git a/exercises/advanced_errors/advanced_errs2.rs b/exercises/advanced_errors/advanced_errs2.rs new file mode 100644 index 00000000..d9d44d06 --- /dev/null +++ b/exercises/advanced_errors/advanced_errs2.rs @@ -0,0 +1,203 @@ +// advanced_errs2.rs + +// This exercise demonstrates a few traits that are useful for custom error +// types to implement, especially so that other code can consume the custom +// error type more usefully. + +// Make this compile, and make the tests pass! +// Execute `rustlings hint advanced_errs2` for hints. + +// Steps: +// 1. Implement a missing trait so that `main()` will compile. +// 2. Complete the partial implementation of `From` for +// `ParseClimateError`. +// 3. Handle the missing error cases in the `FromStr` implementation for +// `Climate`. +// 4. Complete the partial implementation of `Display` for +// `ParseClimateError`. + +// I AM NOT DONE + +use std::error::Error; +use std::fmt::{self, Display, Formatter}; +use std::num::{ParseFloatError, ParseIntError}; +use std::str::FromStr; + +// This is the custom error type that we will be using for the parser for +// `Climate`. +#[derive(Debug, PartialEq)] +enum ParseClimateError { + Empty, + BadLen, + NoCity, + ParseInt(ParseIntError), + ParseFloat(ParseFloatError), +} + +// This `From` implementation allows the `?` operator to work on +// `ParseIntError` values. +impl From for ParseClimateError { + fn from(e: ParseIntError) -> Self { + Self::ParseInt(e) + } +} + +// This `From` implementation allows the `?` operator to work on +// `ParseFloatError` values. +impl From for ParseClimateError { + fn from(e: ParseFloatError) -> Self { + // TODO: Complete this function + } +} + +// TODO: Implement a missing trait so that `main()` below will compile. It +// is not necessary to implement any methods inside the missing trait. + +// The `Display` trait allows for other code to obtain the error formatted +// as a user-visible string. +impl Display for ParseClimateError { + // TODO: Complete this function so that it produces the correct strings + // for each error variant. + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + // Imports the variants to make the following code more compact. + use ParseClimateError::*; + match self { + NoCity => write!(f, "no city name"), + ParseFloat(e) => write!(f, "error parsing temperature: {}", e), + _ => write!(f, "unhandled error!"), + } + } +} + +#[derive(Debug, PartialEq)] +struct Climate { + city: String, + year: u32, + temp: f32, +} + +// Parser for `Climate`. +// 1. Split the input string into 3 fields: city, year, temp. +// 2. Return an error if the string is empty or has the wrong number of +// fields. +// 3. Return an error if the city name is empty. +// 4. Parse the year as a `u32` and return an error if that fails. +// 5. Parse the temp as a `f32` and return an error if that fails. +// 6. Return an `Ok` value containing the completed `Climate` value. +impl FromStr for Climate { + type Err = ParseClimateError; + // TODO: Complete this function by making it handle the missing error + // cases. + fn from_str(s: &str) -> Result { + let v: Vec<_> = s.split(',').collect(); + let (city, year, temp) = match &v[..] { + [city, year, temp] => (city.to_string(), year, temp), + _ => return Err(ParseClimateError::BadLen), + }; + let year: u32 = year.parse()?; + let temp: f32 = temp.parse()?; + Ok(Climate { city, year, temp }) + } +} + +// Don't change anything below this line (other than to enable ignored +// tests). + +fn main() -> Result<(), Box> { + println!("{:?}", "Hong Kong,1999,25.7".parse::()?); + println!("{:?}", "".parse::()?); + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn test_empty() { + let res = "".parse::(); + assert_eq!(res, Err(ParseClimateError::Empty)); + assert_eq!(res.unwrap_err().to_string(), "empty input"); + } + #[test] + fn test_short() { + let res = "Boston,1991".parse::(); + assert_eq!(res, Err(ParseClimateError::BadLen)); + assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields"); + } + #[test] + fn test_long() { + let res = "Paris,1920,17.2,extra".parse::(); + assert_eq!(res, Err(ParseClimateError::BadLen)); + assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields"); + } + #[test] + fn test_no_city() { + let res = ",1997,20.5".parse::(); + assert_eq!(res, Err(ParseClimateError::NoCity)); + assert_eq!(res.unwrap_err().to_string(), "no city name"); + } + #[test] + fn test_parse_int_neg() { + let res = "Barcelona,-25,22.3".parse::(); + assert!(matches!(res, Err(ParseClimateError::ParseInt(_)))); + let err = res.unwrap_err(); + if let ParseClimateError::ParseInt(ref inner) = err { + assert_eq!( + err.to_string(), + format!("error parsing year: {}", inner.to_string()) + ); + } else { + unreachable!(); + }; + } + #[test] + fn test_parse_int_bad() { + let res = "Beijing,foo,15.0".parse::(); + assert!(matches!(res, Err(ParseClimateError::ParseInt(_)))); + let err = res.unwrap_err(); + if let ParseClimateError::ParseInt(ref inner) = err { + assert_eq!( + err.to_string(), + format!("error parsing year: {}", inner.to_string()) + ); + } else { + unreachable!(); + }; + } + #[test] + fn test_parse_float() { + let res = "Manila,2001,bar".parse::(); + assert!(matches!(res, Err(ParseClimateError::ParseFloat(_)))); + let err = res.unwrap_err(); + if let ParseClimateError::ParseFloat(ref inner) = err { + assert_eq!( + err.to_string(), + format!("error parsing temperature: {}", inner.to_string()) + ); + } else { + unreachable!(); + }; + } + #[test] + fn test_parse_good() { + let res = "Munich,2015,23.1".parse::(); + assert_eq!( + res, + Ok(Climate { + city: "Munich".to_string(), + year: 2015, + temp: 23.1, + }) + ); + } + #[test] + #[ignore] + fn test_downcast() { + let res = "SΓ£o Paulo,-21,28.5".parse::(); + assert!(matches!(res, Err(ParseClimateError::ParseInt(_)))); + let err = res.unwrap_err(); + let inner: Option<&(dyn Error + 'static)> = err.source(); + assert!(inner.is_some()); + assert!(inner.unwrap().is::()); + } +} diff --git a/exercises/clippy/README.md b/exercises/clippy/README.md index 60a12fe5..55438af6 100644 --- a/exercises/clippy/README.md +++ b/exercises/clippy/README.md @@ -1,8 +1,10 @@ -### Clippy +# Clippy The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code. If you used the installation script for Rustlings, Clippy should be already installed. If not you can install it manually via `rustup component add clippy`. -For more information about Clippy lints, please see [their documentation page](https://rust-lang.github.io/rust-clippy/master/). +## Further information + +- [GitHub Repository](https://github.com/rust-lang/rust-clippy). diff --git a/exercises/collections/README.md b/exercises/collections/README.md new file mode 100644 index 00000000..b6d62acb --- /dev/null +++ b/exercises/collections/README.md @@ -0,0 +1,23 @@ +# Collections + +Rust’s standard library includes a number of very useful data +structures called collections. Most other data types represent one +specific value, but collections can contain multiple values. Unlike +the built-in array and tuple types, the data these collections point +to is stored on the heap, which means the amount of data does not need +to be known at compile time and can grow or shrink as the program +runs. + +This exercise will get you familiar with two fundamental data +structures that are used very often in Rust programs: + +* A *vector* allows you to store a variable number of values next to + each other. +* A *hash map* allows you to associate a value with a particular key. + You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map), + [*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages. + +## Further information + +- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html) +- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html) diff --git a/exercises/collections/hashmap1.rs b/exercises/collections/hashmap1.rs new file mode 100644 index 00000000..64b5a7f3 --- /dev/null +++ b/exercises/collections/hashmap1.rs @@ -0,0 +1,44 @@ +// hashmap1.rs +// A basket of fruits in the form of a hash map needs to be defined. +// The key represents the name of the fruit and the value represents +// how many of that particular fruit is in the basket. You have to put +// at least three different types of fruits (e.g apple, banana, mango) +// in the basket and the total count of all the fruits should be at +// least five. +// +// Make me compile and pass the tests! +// +// Execute the command `rustlings hint hashmap1` if you need +// hints. + +// I AM NOT DONE + +use std::collections::HashMap; + +fn fruit_basket() -> HashMap { + let mut basket = // TODO: declare your hash map here. + + // Two bananas are already given for you :) + basket.insert(String::from("banana"), 2); + + // TODO: Put more fruits in your basket here. + + basket +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn at_least_three_types_of_fruits() { + let basket = fruit_basket(); + assert!(basket.len() >= 3); + } + + #[test] + fn at_least_five_fruits() { + let basket = fruit_basket(); + assert!(basket.values().sum::() >= 5); + } +} diff --git a/exercises/collections/hashmap2.rs b/exercises/collections/hashmap2.rs new file mode 100644 index 00000000..0abe19ab --- /dev/null +++ b/exercises/collections/hashmap2.rs @@ -0,0 +1,81 @@ +// hashmap2.rs + +// A basket of fruits in the form of a hash map is given. The key +// represents the name of the fruit and the value represents how many +// of that particular fruit is in the basket. You have to put *MORE +// THAN 11* fruits in the basket. Three types of fruits - Apple (4), +// Mango (2) and Lychee (5) are already given in the basket. You are +// not allowed to insert any more of these fruits! +// +// Make me pass the tests! +// +// Execute the command `rustlings hint hashmap2` if you need +// hints. + +// I AM NOT DONE + +use std::collections::HashMap; + +#[derive(Hash, PartialEq, Eq)] +enum Fruit { + Apple, + Banana, + Mango, + Lychee, + Pineapple, +} + +fn fruit_basket(basket: &mut HashMap) { + let fruit_kinds = vec![ + Fruit::Apple, + Fruit::Banana, + Fruit::Mango, + Fruit::Lychee, + Fruit::Pineapple, + ]; + + for fruit in fruit_kinds { + // TODO: Put new fruits if not already present. Note that you + // are not allowed to put any type of fruit that's already + // present! + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn get_fruit_basket() -> HashMap { + let mut basket = HashMap::::new(); + basket.insert(Fruit::Apple, 4); + basket.insert(Fruit::Mango, 2); + basket.insert(Fruit::Lychee, 5); + + basket + } + + #[test] + fn test_given_fruits_are_not_modified() { + let mut basket = get_fruit_basket(); + fruit_basket(&mut basket); + assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4); + assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2); + assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5); + } + + #[test] + fn at_least_five_types_of_fruits() { + let mut basket = get_fruit_basket(); + fruit_basket(&mut basket); + let count_fruit_kinds = basket.len(); + assert!(count_fruit_kinds >= 5); + } + + #[test] + fn greater_than_eleven_fruits() { + let mut basket = get_fruit_basket(); + fruit_basket(&mut basket); + let count = basket.values().sum::(); + assert!(count > 11); + } +} diff --git a/exercises/collections/vec1.rs b/exercises/collections/vec1.rs new file mode 100644 index 00000000..b144fb94 --- /dev/null +++ b/exercises/collections/vec1.rs @@ -0,0 +1,25 @@ +// vec1.rs +// Your task is to create a `Vec` which holds the exact same elements +// as in the array `a`. +// Make me compile and pass the test! +// Execute the command `rustlings hint vec1` if you need hints. + +// I AM NOT DONE + +fn array_and_vec() -> ([i32; 4], Vec) { + let a = [10, 20, 30, 40]; // a plain array + let v = // TODO: declare your vector here with the macro for vectors + + (a, v) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_array_and_vec_similarity() { + let (a, v) = array_and_vec(); + assert_eq!(a, v[..]); + } +} diff --git a/exercises/collections/vec2.rs b/exercises/collections/vec2.rs new file mode 100644 index 00000000..6595e401 --- /dev/null +++ b/exercises/collections/vec2.rs @@ -0,0 +1,33 @@ +// vec2.rs +// A Vec of even numbers is given. Your task is to complete the loop +// so that each number in the Vec is multiplied by 2. +// +// Make me pass the test! +// +// Execute the command `rustlings hint vec2` if you need +// hints. + +// I AM NOT DONE + +fn vec_loop(mut v: Vec) -> Vec { + for i in v.iter_mut() { + // TODO: Fill this up so that each element in the Vec `v` is + // multiplied by 2. + } + + // At this point, `v` should be equal to [4, 8, 12, 16, 20]. + v +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_vec_loop() { + let v: Vec = (1..).filter(|x| x % 2 == 0).take(5).collect(); + let ans = vec_loop(v.clone()); + + assert_eq!(ans, v.iter().map(|x| x * 2).collect::>()); + } +} diff --git a/exercises/conversions/README.md b/exercises/conversions/README.md index 114bd428..8d7da93e 100644 --- a/exercises/conversions/README.md +++ b/exercises/conversions/README.md @@ -1,5 +1,4 @@ -### Type conversions - +# Type conversions Rust offers a multitude of ways to convert a value of a given type into another type. @@ -15,6 +14,8 @@ Furthermore, the `std::str` module offers a trait called [`FromStr`](https://doc These should be the main ways ***within the standard library*** to convert data into your desired types. -#### Book Sections +## Further information -These are not directly covered in the book, but the standard library has great documentation for [conversions here](https://doc.rust-lang.org/std/convert/index.html). The `FromStr` trait is also covered [here](https://doc.rust-lang.org/std/str/trait.FromStr.html). \ No newline at end of file +These are not directly covered in the book, but the standard library has a great documentation for it. +- [conversions](https://doc.rust-lang.org/std/convert/index.html) +- [`FromStr` trait](https://doc.rust-lang.org/std/str/trait.FromStr.html) \ No newline at end of file diff --git a/exercises/conversions/as_ref_mut.rs b/exercises/conversions/as_ref_mut.rs index 963c0f2d..84f4a60c 100644 --- a/exercises/conversions/as_ref_mut.rs +++ b/exercises/conversions/as_ref_mut.rs @@ -3,6 +3,7 @@ // and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively. // I AM NOT DONE + // Obtain the number of bytes (not characters) in the given argument // Add the AsRef trait appropriately as a trait bound fn byte_counter(arg: T) -> usize { diff --git a/exercises/conversions/from_into.rs b/exercises/conversions/from_into.rs index 8fb9eb05..9d84174d 100644 --- a/exercises/conversions/from_into.rs +++ b/exercises/conversions/from_into.rs @@ -18,7 +18,6 @@ impl Default for Person { } } -// I AM NOT DONE // Your task is to complete this implementation // in order for the line `let p = Person::from("Mark,20")` to compile // Please note that you'll need to parse the age component into a `usize` @@ -33,6 +32,9 @@ impl Default for Person { // 5. Extract the other element from the split operation and parse it into a `usize` as the age // If while parsing the age, something goes wrong, then return the default of Person // Otherwise, then return an instantiated Person object with the results + +// I AM NOT DONE + impl From<&str> for Person { fn from(s: &str) -> Person { } @@ -73,7 +75,7 @@ mod tests { } #[test] fn test_bad_age() { - // Test that "Mark.twenty" will return the default person due to an error in parsing age + // Test that "Mark,twenty" will return the default person due to an error in parsing age let p = Person::from("Mark,twenty"); assert_eq!(p.name, "John"); assert_eq!(p.age, 30); @@ -113,4 +115,18 @@ mod tests { assert_eq!(p.name, "John"); assert_eq!(p.age, 30); } + + #[test] + fn test_trailing_comma() { + let p: Person = Person::from("Mike,32,"); + assert_eq!(p.name, "John"); + assert_eq!(p.age, 30); + } + + #[test] + fn test_trailing_comma_and_some_string() { + let p: Person = Person::from("Mike,32,man"); + assert_eq!(p.name, "John"); + assert_eq!(p.age, 30); + } } diff --git a/exercises/conversions/from_str.rs b/exercises/conversions/from_str.rs index 014d0549..ece0b3cf 100644 --- a/exercises/conversions/from_str.rs +++ b/exercises/conversions/from_str.rs @@ -1,27 +1,45 @@ -// This does practically the same thing that TryFrom<&str> does. +// from_str.rs +// This is similar to from_into.rs, but this time we'll implement `FromStr` +// and return errors instead of falling back to a default value. // Additionally, upon implementing FromStr, you can use the `parse` method // on strings to generate an object of the implementor type. // You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html +use std::num::ParseIntError; use std::str::FromStr; -#[derive(Debug)] +#[derive(Debug, PartialEq)] struct Person { name: String, age: usize, } +// We will use this error type for the `FromStr` implementation. +#[derive(Debug, PartialEq)] +enum ParsePersonError { + // Empty input string + Empty, + // Incorrect number of fields + BadLen, + // Empty name field + NoName, + // Wrapped error from parse::() + ParseInt(ParseIntError), +} + // I AM NOT DONE + // Steps: -// 1. If the length of the provided string is 0, then return an error +// 1. If the length of the provided string is 0, an error should be returned // 2. Split the given string on the commas present in it -// 3. Extract the first element from the split operation and use it as the name -// 4. If the name is empty, then return an error +// 3. Only 2 elements should be returned from the split, otherwise return an error +// 4. Extract the first element from the split operation and use it as the name // 5. Extract the other element from the split operation and parse it into a `usize` as the age -// with something like `"4".parse::()`. -// If while parsing the age, something goes wrong, then return an error -// Otherwise, then return a Result of a Person object +// with something like `"4".parse::()` +// 6. If while extracting the name and the age something goes wrong, an error should be returned +// If everything goes well, then return a Result of a Person object + impl FromStr for Person { - type Err = String; + type Err = ParsePersonError; fn from_str(s: &str) -> Result { } } @@ -37,7 +55,7 @@ mod tests { #[test] fn empty_input() { - assert!("".parse::().is_err()); + assert_eq!("".parse::(), Err(ParsePersonError::Empty)); } #[test] fn good_input() { @@ -48,39 +66,57 @@ mod tests { assert_eq!(p.age, 32); } #[test] - #[should_panic] fn missing_age() { - "John,".parse::().unwrap(); + assert!(matches!( + "John,".parse::(), + Err(ParsePersonError::ParseInt(_)) + )); } #[test] - #[should_panic] fn invalid_age() { - "John,twenty".parse::().unwrap(); + assert!(matches!( + "John,twenty".parse::(), + Err(ParsePersonError::ParseInt(_)) + )); } #[test] - #[should_panic] fn missing_comma_and_age() { - "John".parse::().unwrap(); + assert_eq!("John".parse::(), Err(ParsePersonError::BadLen)); } #[test] - #[should_panic] fn missing_name() { - ",1".parse::().unwrap(); + assert_eq!(",1".parse::(), Err(ParsePersonError::NoName)); } #[test] - #[should_panic] fn missing_name_and_age() { - ",".parse::().unwrap(); + assert!(matches!( + ",".parse::(), + Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_)) + )); } #[test] - #[should_panic] fn missing_name_and_invalid_age() { - ",one".parse::().unwrap(); + assert!(matches!( + ",one".parse::(), + Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_)) + )); } + #[test] + fn trailing_comma() { + assert_eq!("John,32,".parse::(), Err(ParsePersonError::BadLen)); + } + + #[test] + fn trailing_comma_and_some_string() { + assert_eq!( + "John,32,man".parse::(), + Err(ParsePersonError::BadLen) + ); + } } diff --git a/exercises/conversions/try_from_into.rs b/exercises/conversions/try_from_into.rs index dbdbe00e..b8ec4455 100644 --- a/exercises/conversions/try_from_into.rs +++ b/exercises/conversions/try_from_into.rs @@ -1,44 +1,54 @@ +// try_from_into.rs // TryFrom is a simple and safe type conversion that may fail in a controlled way under some circumstances. // Basically, this is the same as From. The main difference is that this should return a Result type // instead of the target type itself. // You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html -use std::convert::{TryInto, TryFrom}; +use std::convert::{TryFrom, TryInto}; -#[derive(Debug)] +#[derive(Debug, PartialEq)] struct Color { red: u8, green: u8, blue: u8, } +// We will use this error type for these `TryFrom` conversions. +#[derive(Debug, PartialEq)] +enum IntoColorError { + // Incorrect length of slice + BadLen, + // Integer conversion error + IntConversion, +} + // I AM NOT DONE // Your task is to complete this implementation // and return an Ok result of inner type Color. -// You need create implementation for a tuple of three integer, -// an array of three integer and slice of integer. +// You need to create an implementation for a tuple of three integers, +// an array of three integers, and a slice of integers. // -// Note, that implementation for tuple and array will be checked at compile-time, -// but slice implementation need check slice length! -// Also note, that chunk of correct rgb color must be integer in range 0..=255. +// Note that the implementation for tuple and array will be checked at compile time, +// but the slice implementation needs to check the slice length! +// Also note that correct RGB color values must be integers in the 0..=255 range. // Tuple implementation impl TryFrom<(i16, i16, i16)> for Color { - type Error = String; + type Error = IntoColorError; fn try_from(tuple: (i16, i16, i16)) -> Result { } } // Array implementation impl TryFrom<[i16; 3]> for Color { - type Error = String; + type Error = IntoColorError; fn try_from(arr: [i16; 3]) -> Result { } } // Slice implementation impl TryFrom<&[i16]> for Color { - type Error = String; + type Error = IntoColorError; fn try_from(slice: &[i16]) -> Result { } } @@ -48,15 +58,15 @@ fn main() { let c1 = Color::try_from((183, 65, 14)); println!("{:?}", c1); - // Since From is implemented for Color, we should be able to use Into + // Since TryFrom is implemented for Color, we should be able to use TryInto let c2: Result = [183, 65, 14].try_into(); println!("{:?}", c2); let v = vec![183, 65, 14]; - // With slice we should use `from` function + // With slice we should use `try_from` function let c3 = Color::try_from(&v[..]); println!("{:?}", c3); - // or take slice within round brackets and use Into + // or take slice within round brackets and use TryInto let c4: Result = (&v[..]).try_into(); println!("{:?}", c4); } @@ -66,65 +76,113 @@ mod tests { use super::*; #[test] - #[should_panic] fn test_tuple_out_of_range_positive() { - let _ = Color::try_from((256, 1000, 10000)).unwrap(); + assert_eq!( + Color::try_from((256, 1000, 10000)), + Err(IntoColorError::IntConversion) + ); } #[test] - #[should_panic] fn test_tuple_out_of_range_negative() { - let _ = Color::try_from((-1, -10, -256)).unwrap(); + assert_eq!( + Color::try_from((-1, -10, -256)), + Err(IntoColorError::IntConversion) + ); + } + #[test] + fn test_tuple_sum() { + assert_eq!( + Color::try_from((-1, 255, 255)), + Err(IntoColorError::IntConversion) + ); } #[test] fn test_tuple_correct() { - let c: Color = (183, 65, 14).try_into().unwrap(); - assert_eq!(c.red, 183); - assert_eq!(c.green, 65); - assert_eq!(c.blue, 14); + let c: Result = (183, 65, 14).try_into(); + assert!(c.is_ok()); + assert_eq!( + c.unwrap(), + Color { + red: 183, + green: 65, + blue: 14 + } + ); } - #[test] - #[should_panic] fn test_array_out_of_range_positive() { - let _: Color = [1000, 10000, 256].try_into().unwrap(); + let c: Result = [1000, 10000, 256].try_into(); + assert_eq!(c, Err(IntoColorError::IntConversion)); } #[test] - #[should_panic] fn test_array_out_of_range_negative() { - let _: Color = [-10, -256, -1].try_into().unwrap(); + let c: Result = [-10, -256, -1].try_into(); + assert_eq!(c, Err(IntoColorError::IntConversion)); + } + #[test] + fn test_array_sum() { + let c: Result = [-1, 255, 255].try_into(); + assert_eq!(c, Err(IntoColorError::IntConversion)); } #[test] fn test_array_correct() { - let c: Color = [183, 65, 14].try_into().unwrap(); - assert_eq!(c.red, 183); - assert_eq!(c.green, 65); - assert_eq!(c.blue, 14); + let c: Result = [183, 65, 14].try_into(); + assert!(c.is_ok()); + assert_eq!( + c.unwrap(), + Color { + red: 183, + green: 65, + blue: 14 + } + ); } - #[test] - #[should_panic] fn test_slice_out_of_range_positive() { let arr = [10000, 256, 1000]; - let _ = Color::try_from(&arr[..]).unwrap(); + assert_eq!( + Color::try_from(&arr[..]), + Err(IntoColorError::IntConversion) + ); } #[test] - #[should_panic] fn test_slice_out_of_range_negative() { let arr = [-256, -1, -10]; - let _ = Color::try_from(&arr[..]).unwrap(); + assert_eq!( + Color::try_from(&arr[..]), + Err(IntoColorError::IntConversion) + ); + } + #[test] + fn test_slice_sum() { + let arr = [-1, 255, 255]; + assert_eq!( + Color::try_from(&arr[..]), + Err(IntoColorError::IntConversion) + ); } #[test] fn test_slice_correct() { let v = vec![183, 65, 14]; - let c = Color::try_from(&v[..]).unwrap(); - assert_eq!(c.red, 183); - assert_eq!(c.green, 65); - assert_eq!(c.blue, 14); + let c: Result = Color::try_from(&v[..]); + assert!(c.is_ok()); + assert_eq!( + c.unwrap(), + Color { + red: 183, + green: 65, + blue: 14 + } + ); } #[test] - #[should_panic] fn test_slice_excess_length() { let v = vec![0, 0, 0, 0]; - let _ = Color::try_from(&v[..]).unwrap(); + assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen)); + } + #[test] + fn test_slice_insufficient_length() { + let v = vec![0, 0]; + assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen)); } } diff --git a/exercises/conversions/using_as.rs b/exercises/conversions/using_as.rs index 54f96515..821309ec 100644 --- a/exercises/conversions/using_as.rs +++ b/exercises/conversions/using_as.rs @@ -1,17 +1,28 @@ // Type casting in Rust is done via the usage of the `as` operator. // Please note that the `as` operator is not only used when type casting. // It also helps with renaming imports. +// +// The goal is to make sure that the division does not fail to compile +// and returns the proper type. // I AM NOT DONE -// The goal is to make sure that the division does not fail to compile + fn average(values: &[f64]) -> f64 { - let total = values - .iter() - .fold(0.0, |a, b| a + b); + let total = values.iter().fold(0.0, |a, b| a + b); total / values.len() } fn main() { let values = [3.5, 0.3, 13.0, 11.7]; println!("{}", average(&values)); -} \ No newline at end of file +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn returns_proper_type_and_value() { + assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125); + } +} diff --git a/exercises/enums/README.md b/exercises/enums/README.md index a090a43e..30d4d91d 100644 --- a/exercises/enums/README.md +++ b/exercises/enums/README.md @@ -1,10 +1,10 @@ -### Enums +# Enums -Rust allows you to define types called "enums" which enumerate possible values. +Rust allows you to define types called "enums" which enumerate possible values. Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell. -Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration. +Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration. -#### Book Sections +## Further information - [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html) - [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html) diff --git a/exercises/enums/enums2.rs b/exercises/enums/enums2.rs index 52ccb221..ec32d952 100644 --- a/exercises/enums/enums2.rs +++ b/exercises/enums/enums2.rs @@ -16,10 +16,10 @@ impl Message { fn main() { let messages = [ - Message::Move{ x: 10, y: 30 }, + Message::Move { x: 10, y: 30 }, Message::Echo(String::from("hello world")), Message::ChangeColor(200, 255, 255), - Message::Quit + Message::Quit, ]; for message in &messages { diff --git a/exercises/enums/enums3.rs b/exercises/enums/enums3.rs index 4b0be975..178b40c4 100644 --- a/exercises/enums/enums3.rs +++ b/exercises/enums/enums3.rs @@ -9,13 +9,13 @@ enum Message { struct Point { x: u8, - y: u8 + y: u8, } struct State { color: (u8, u8, u8), position: Point, - quit: bool + quit: bool, } impl State { @@ -46,14 +46,14 @@ mod tests { #[test] fn test_match_message_call() { - let mut state = State{ + let mut state = State { quit: false, - position: Point{ x: 0, y: 0 }, - color: (0, 0, 0) + position: Point { x: 0, y: 0 }, + color: (0, 0, 0), }; - state.process(Message::ChangeColor(255, 0, 255)); + state.process(Message::ChangeColor((255, 0, 255))); state.process(Message::Echo(String::from("hello world"))); - state.process(Message::Move(Point{ x: 10, y: 15 })); + state.process(Message::Move(Point { x: 10, y: 15 })); state.process(Message::Quit); assert_eq!(state.color, (255, 0, 255)); @@ -61,5 +61,4 @@ mod tests { assert_eq!(state.position.y, 15); assert_eq!(state.quit, true); } - } diff --git a/exercises/error_handling/README.md b/exercises/error_handling/README.md index cf66c2be..5255ace9 100644 --- a/exercises/error_handling/README.md +++ b/exercises/error_handling/README.md @@ -1,5 +1,11 @@ -For this exercise check out the sections: -- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html) -- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html) +# Error handling +Most errors aren’t serious enough to require the program to stop entirely. +Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to. +For example, if you try to open a file and that operation fails because the file doesn’t exist, you might want to create the file instead of terminating the process. -of the Rust Book. +## Further information + +- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html) +- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html) +- [Result](https://doc.rust-lang.org/rust-by-example/error/result.html) +- [Boxing errors](https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html) diff --git a/exercises/error_handling/result1.rs b/exercises/error_handling/errors4.rs similarity index 88% rename from exercises/error_handling/result1.rs rename to exercises/error_handling/errors4.rs index b978001b..0685c374 100644 --- a/exercises/error_handling/result1.rs +++ b/exercises/error_handling/errors4.rs @@ -1,5 +1,5 @@ -// result1.rs -// Make this test pass! Execute `rustlings hint result1` for hints :) +// errors4.rs +// Make this test pass! Execute `rustlings hint errors4` for hints :) // I AM NOT DONE diff --git a/exercises/error_handling/errors5.rs b/exercises/error_handling/errors5.rs new file mode 100644 index 00000000..365a8691 --- /dev/null +++ b/exercises/error_handling/errors5.rs @@ -0,0 +1,53 @@ +// errors5.rs + +// This program uses a completed version of the code from errors4. +// It won't compile right now! Why? +// Execute `rustlings hint errors5` for hints! + +// I AM NOT DONE + +use std::error; +use std::fmt; +use std::num::ParseIntError; + +// TODO: update the return type of `main()` to make this compile. +fn main() -> Result<(), ParseIntError> { + let pretend_user_input = "42"; + let x: i64 = pretend_user_input.parse()?; + println!("output={:?}", PositiveNonzeroInteger::new(x)?); + Ok(()) +} + +// Don't change anything below this line. + +#[derive(PartialEq, Debug)] +struct PositiveNonzeroInteger(u64); + +#[derive(PartialEq, Debug)] +enum CreationError { + Negative, + Zero, +} + +impl PositiveNonzeroInteger { + fn new(value: i64) -> Result { + match value { + x if x < 0 => Err(CreationError::Negative), + x if x == 0 => Err(CreationError::Zero), + x => Ok(PositiveNonzeroInteger(x as u64)) + } + } +} + +// This is required so that `CreationError` can implement `error::Error`. +impl fmt::Display for CreationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let description = match *self { + CreationError::Negative => "number is negative", + CreationError::Zero => "number is zero", + }; + f.write_str(description) + } +} + +impl error::Error for CreationError {} diff --git a/exercises/error_handling/errors6.rs b/exercises/error_handling/errors6.rs new file mode 100644 index 00000000..0f6b27a6 --- /dev/null +++ b/exercises/error_handling/errors6.rs @@ -0,0 +1,95 @@ +// errors6.rs + +// Using catch-all error types like `Box` isn't recommended +// for library code, where callers might want to make decisions based on the +// error content, instead of printing it out or propagating it further. Here, +// we define a custom error type to make it possible for callers to decide +// what to do next when our function returns an error. + +// Make these tests pass! Execute `rustlings hint errors6` for hints :) + +// I AM NOT DONE + +use std::num::ParseIntError; + +// This is a custom error type that we will be using in `parse_pos_nonzero()`. +#[derive(PartialEq, Debug)] +enum ParsePosNonzeroError { + Creation(CreationError), + ParseInt(ParseIntError) +} + +impl ParsePosNonzeroError { + fn from_creation(err: CreationError) -> ParsePosNonzeroError { + ParsePosNonzeroError::Creation(err) + } + // TODO: add another error conversion function here. +} + +fn parse_pos_nonzero(s: &str) + -> Result +{ + // TODO: change this to return an appropriate error instead of panicking + // when `parse()` returns an error. + let x: i64 = s.parse().unwrap(); + PositiveNonzeroInteger::new(x) + .map_err(ParsePosNonzeroError::from_creation) +} + +// Don't change anything below this line. + +#[derive(PartialEq, Debug)] +struct PositiveNonzeroInteger(u64); + +#[derive(PartialEq, Debug)] +enum CreationError { + Negative, + Zero, +} + +impl PositiveNonzeroInteger { + fn new(value: i64) -> Result { + match value { + x if x < 0 => Err(CreationError::Negative), + x if x == 0 => Err(CreationError::Zero), + x => Ok(PositiveNonzeroInteger(x as u64)) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_parse_error() { + // We can't construct a ParseIntError, so we have to pattern match. + assert!(matches!( + parse_pos_nonzero("not a number"), + Err(ParsePosNonzeroError::ParseInt(_)) + )); + } + + #[test] + fn test_negative() { + assert_eq!( + parse_pos_nonzero("-555"), + Err(ParsePosNonzeroError::Creation(CreationError::Negative)) + ); + } + + #[test] + fn test_zero() { + assert_eq!( + parse_pos_nonzero("0"), + Err(ParsePosNonzeroError::Creation(CreationError::Zero)) + ); + } + + #[test] + fn test_positive() { + let x = PositiveNonzeroInteger::new(42); + assert!(x.is_ok()); + assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap())); + } +} diff --git a/exercises/error_handling/errorsn.rs b/exercises/error_handling/errorsn.rs deleted file mode 100644 index 5fe212bf..00000000 --- a/exercises/error_handling/errorsn.rs +++ /dev/null @@ -1,117 +0,0 @@ -// errorsn.rs -// This is a bigger error exercise than the previous ones! -// You can do it! :) -// -// Edit the `read_and_validate` function ONLY. Don't create any Errors -// that do not already exist. -// -// So many things could go wrong! -// -// - Reading from stdin could produce an io::Error -// - Parsing the input could produce a num::ParseIntError -// - Validating the input could produce a CreationError (defined below) -// -// How can we lump these errors into one general error? That is, what -// type goes where the question marks are, and how do we return -// that type from the body of read_and_validate? -// -// Execute `rustlings hint errorsn` for hints :) - -// I AM NOT DONE - -use std::error; -use std::fmt; -use std::io; - -// PositiveNonzeroInteger is a struct defined below the tests. -fn read_and_validate(b: &mut dyn io::BufRead) -> Result { - let mut line = String::new(); - b.read_line(&mut line); - let num: i64 = line.trim().parse(); - let answer = PositiveNonzeroInteger::new(num); - answer -} - -// -// Nothing below this needs to be modified -// - -// This is a test helper function that turns a &str into a BufReader. -fn test_with_str(s: &str) -> Result> { - let mut b = io::BufReader::new(s.as_bytes()); - read_and_validate(&mut b) -} - -#[test] -fn test_success() { - let x = test_with_str("42\n"); - assert_eq!(PositiveNonzeroInteger(42), x.unwrap()); -} - -#[test] -fn test_not_num() { - let x = test_with_str("eleven billion\n"); - assert!(x.is_err()); -} - -#[test] -fn test_non_positive() { - let x = test_with_str("-40\n"); - assert!(x.is_err()); -} - -#[test] -fn test_ioerror() { - struct Broken; - impl io::Read for Broken { - fn read(&mut self, _buf: &mut [u8]) -> io::Result { - Err(io::Error::new(io::ErrorKind::BrokenPipe, "uh-oh!")) - } - } - let mut b = io::BufReader::new(Broken); - assert!(read_and_validate(&mut b).is_err()); - assert_eq!("uh-oh!", read_and_validate(&mut b).unwrap_err().to_string()); -} - -#[derive(PartialEq, Debug)] -struct PositiveNonzeroInteger(u64); - -impl PositiveNonzeroInteger { - fn new(value: i64) -> Result { - if value == 0 { - Err(CreationError::Zero) - } else if value < 0 { - Err(CreationError::Negative) - } else { - Ok(PositiveNonzeroInteger(value as u64)) - } - } -} - -#[test] -fn test_positive_nonzero_integer_creation() { - assert!(PositiveNonzeroInteger::new(10).is_ok()); - assert_eq!( - Err(CreationError::Negative), - PositiveNonzeroInteger::new(-10) - ); - assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0)); -} - -#[derive(PartialEq, Debug)] -enum CreationError { - Negative, - Zero, -} - -impl fmt::Display for CreationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let description = match *self { - CreationError::Negative => "Number is negative", - CreationError::Zero => "Number is zero", - }; - f.write_str(description) - } -} - -impl error::Error for CreationError {} diff --git a/exercises/functions/README.md b/exercises/functions/README.md index 351ae023..66547bd4 100644 --- a/exercises/functions/README.md +++ b/exercises/functions/README.md @@ -1,7 +1,7 @@ -### Functions +# Functions Here, you'll learn how to write functions and how Rust's compiler can trace things way back. -#### Book Sections +## Further information - [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html) diff --git a/exercises/functions/functions2.rs b/exercises/functions/functions2.rs index 108ba38b..5721a172 100644 --- a/exercises/functions/functions2.rs +++ b/exercises/functions/functions2.rs @@ -7,7 +7,7 @@ fn main() { call_me(3); } -fn call_me(num) { +fn call_me(num:) { for i in 0..num { println!("Ring! Call number {}", i + 1); } diff --git a/exercises/functions/functions3.rs b/exercises/functions/functions3.rs index e3c1bf73..ed5f839f 100644 --- a/exercises/functions/functions3.rs +++ b/exercises/functions/functions3.rs @@ -7,7 +7,7 @@ fn main() { call_me(); } -fn call_me(num: i32) { +fn call_me(num: u32) { for i in 0..num { println!("Ring! Call number {}", i + 1); } diff --git a/exercises/generics/README.md b/exercises/generics/README.md index 7105f06f..de46d503 100644 --- a/exercises/generics/README.md +++ b/exercises/generics/README.md @@ -1,7 +1,11 @@ -### Generics +# Generics -In this section you'll learn about saving yourself many lines of code with generics! +Generics is the topic of generalizing types and functionalities to broader cases. +This is extremely useful for reducing code duplication in many ways, but can call for rather involving syntax. +Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid. +The simplest and most common use of generics is for type parameters. -### Book Sections +## Further information -- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html) \ No newline at end of file +- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html) +- [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html) diff --git a/exercises/generics/generics1.rs b/exercises/generics/generics1.rs index d075a4d2..f93e64a0 100644 --- a/exercises/generics/generics1.rs +++ b/exercises/generics/generics1.rs @@ -1,10 +1,11 @@ -// This shopping list program isn't compiling! +// This shopping list program isn't compiling! // Use your knowledge of generics to fix it. +// Execute `rustlings hint generics1` for hints! + // I AM NOT DONE fn main() { let mut shopping_list: Vec = Vec::new(); shopping_list.push("milk"); } - diff --git a/exercises/generics/generics2.rs b/exercises/generics/generics2.rs index 23025aaa..1501529c 100644 --- a/exercises/generics/generics2.rs +++ b/exercises/generics/generics2.rs @@ -1,9 +1,12 @@ // This powerful wrapper provides the ability to store a positive integer value. // Rewrite it using generics so that it supports wrapping ANY type. +// Execute `rustlings hint generics2` for hints! + // I AM NOT DONE + struct Wrapper { - value: u32 + value: u32, } impl Wrapper { @@ -18,11 +21,11 @@ mod tests { #[test] fn store_u32_in_wrapper() { - assert_eq!(Wrapper::new(42).value, 42); + assert_eq!(Wrapper::new(42).value, 42); } #[test] fn store_str_in_wrapper() { assert_eq!(Wrapper::new("Foo").value, "Foo"); } -} \ No newline at end of file +} diff --git a/exercises/generics/generics3.rs b/exercises/generics/generics3.rs index c76425c3..64dd9bc1 100644 --- a/exercises/generics/generics3.rs +++ b/exercises/generics/generics3.rs @@ -1,13 +1,17 @@ // An imaginary magical school has a new report card generation system written in Rust! -// Currently the system only supports creating report cards where the student's grade -// is represented numerically (e.g. 1.0 -> 5.5). -// However, the school also issues alphabetical grades (A+ -> F-) and needs +// Currently the system only supports creating report cards where the student's grade +// is represented numerically (e.g. 1.0 -> 5.5). +// However, the school also issues alphabetical grades (A+ -> F-) and needs // to be able to print both types of report card! -// Make the necessary code changes to support alphabetical report cards, thereby making -// the second test pass. +// Make the necessary code changes in the struct ReportCard and the impl block +// to support alphabetical report cards. Change the Grade in the second test to "A+" +// to show that your changes allow alphabetical grades. + +// Execute 'rustlings hint generics3' for hints! // I AM NOT DONE + pub struct ReportCard { pub grade: f32, pub student_name: String, @@ -16,7 +20,7 @@ pub struct ReportCard { impl ReportCard { pub fn print(&self) -> String { - format!("{} ({}) - achieved a grade of {}", + format!("{} ({}) - achieved a grade of {}", &self.student_name, &self.student_age, &self.grade) } } @@ -28,21 +32,27 @@ mod tests { #[test] fn generate_numeric_report_card() { let report_card = ReportCard { - grade: 2.1, - student_name: "Tom Wriggle".to_string(), + grade: 2.1, + student_name: "Tom Wriggle".to_string(), student_age: 12, }; - assert_eq!(report_card.print(), "Tom Wriggle (12) - achieved a grade of 2.1"); + assert_eq!( + report_card.print(), + "Tom Wriggle (12) - achieved a grade of 2.1" + ); } #[test] fn generate_alphabetic_report_card() { // TODO: Make sure to change the grade here after you finish the exercise. let report_card = ReportCard { - grade: 2.1, - student_name: "Gary Plotter".to_string(), + grade: 2.1, + student_name: "Gary Plotter".to_string(), student_age: 11, }; - assert_eq!(report_card.print(), "Gary Plotter (11) - achieved a grade of A+"); + assert_eq!( + report_card.print(), + "Gary Plotter (11) - achieved a grade of A+" + ); } -} \ No newline at end of file +} diff --git a/exercises/if/README.md b/exercises/if/README.md index b1157218..528d9886 100644 --- a/exercises/if/README.md +++ b/exercises/if/README.md @@ -1,7 +1,7 @@ -### If +# If `if`, the most basic type of control flow, is what you'll learn here. -#### Book Sections +## Further information - [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions) diff --git a/exercises/macros/README.md b/exercises/macros/README.md index b48b880a..319d8408 100644 --- a/exercises/macros/README.md +++ b/exercises/macros/README.md @@ -1,10 +1,10 @@ -### Macros +# Macros Rust's macro system is very powerful, but also kind of difficult to wrap your head around. We're not going to teach you how to write your own fully-featured macros. Instead, we'll show you how to use and create them. -#### Book Sections +## Further information - [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html) - [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html) diff --git a/exercises/modules/README.md b/exercises/modules/README.md index bb765106..3dc8a482 100644 --- a/exercises/modules/README.md +++ b/exercises/modules/README.md @@ -1,7 +1,7 @@ -### Modules +# Modules In this section we'll give you an introduction to Rust's module system. -#### Book Sections +## Further information -- [The Module System](https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html) +- [The Module System](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html) diff --git a/exercises/modules/modules1.rs b/exercises/modules/modules1.rs index 812dfeef..1a2bd0dd 100644 --- a/exercises/modules/modules1.rs +++ b/exercises/modules/modules1.rs @@ -4,7 +4,13 @@ // I AM NOT DONE mod sausage_factory { + // Don't let anybody outside of this module see this! + fn get_secret_recipe() -> String { + String::from("Ginger") + } + fn make_sausage() { + get_secret_recipe(); println!("sausage!"); } } diff --git a/exercises/modules/modules2.rs b/exercises/modules/modules2.rs index fde439d1..87f0c458 100644 --- a/exercises/modules/modules2.rs +++ b/exercises/modules/modules2.rs @@ -1,11 +1,15 @@ // modules2.rs +// You can bring module paths into scopes and provide new names for them with the +// 'use' and 'as' keywords. Fix these 'use' statements to make the code compile. // Make me compile! Execute `rustlings hint modules2` for hints :) // I AM NOT DONE mod delicious_snacks { - use self::fruits::PEAR as fruit; - use self::veggies::CUCUMBER as veggie; + + // TODO: Fix these use statements + use self::fruits::PEAR as ??? + use self::veggies::CUCUMBER as ??? mod fruits { pub const PEAR: &'static str = "Pear"; diff --git a/exercises/modules/modules3.rs b/exercises/modules/modules3.rs new file mode 100644 index 00000000..8eed77df --- /dev/null +++ b/exercises/modules/modules3.rs @@ -0,0 +1,18 @@ +// modules3.rs +// You can use the 'use' keyword to bring module paths from modules from anywhere +// and especially from the Rust standard library into your scope. +// Bring SystemTime and UNIX_EPOCH +// from the std::time module. Bonus style points if you can do it with one line! +// Make me compile! Execute `rustlings hint modules3` for hints :) + +// I AM NOT DONE + +// TODO: Complete this use statement +use ??? + +fn main() { + match SystemTime::now().duration_since(UNIX_EPOCH) { + Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), + Err(_) => panic!("SystemTime before UNIX EPOCH!"), + } +} diff --git a/exercises/move_semantics/README.md b/exercises/move_semantics/README.md index 6842af7c..54ddd8e6 100644 --- a/exercises/move_semantics/README.md +++ b/exercises/move_semantics/README.md @@ -1,8 +1,8 @@ -### Move Semantics +# Move Semantics These exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- Thank you Felix!!! -#### Book Sections +## Further information For this section, the book links are especially important. diff --git a/exercises/move_semantics/move_semantics4.rs b/exercises/move_semantics/move_semantics4.rs index a1c4a413..2a23c710 100644 --- a/exercises/move_semantics/move_semantics4.rs +++ b/exercises/move_semantics/move_semantics4.rs @@ -1,6 +1,6 @@ // move_semantics4.rs // Refactor this code so that instead of having `vec0` and creating the vector -// in `fn main`, we instead create it within `fn fill_vec` and transfer the +// in `fn main`, we create it within `fn fill_vec` and transfer the // freshly created vector from fill_vec to its caller. // Execute `rustlings hint move_semantics4` for hints! @@ -18,7 +18,7 @@ fn main() { println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); } -// `fill_vec()` no longer take `vec: Vec` as argument +// `fill_vec()` no longer takes `vec: Vec` as argument fn fill_vec() -> Vec { let mut vec = vec; diff --git a/exercises/move_semantics/move_semantics5.rs b/exercises/move_semantics/move_semantics5.rs new file mode 100644 index 00000000..c4704f9e --- /dev/null +++ b/exercises/move_semantics/move_semantics5.rs @@ -0,0 +1,15 @@ +// move_semantics5.rs +// Make me compile only by reordering the lines in `main()`, but without +// adding, changing or removing any of them. +// Execute `rustlings hint move_semantics5` for hints :) + +// I AM NOT DONE + +fn main() { + let mut x = 100; + let y = &mut x; + let z = &mut x; + *y += 100; + *z += 1000; + assert_eq!(x, 1200); +} diff --git a/exercises/option/README.md b/exercises/option/README.md index d17b79cc..a304bb44 100644 --- a/exercises/option/README.md +++ b/exercises/option/README.md @@ -1,8 +1,17 @@ -### Option +# Option -#### Book Sections +Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not. +Option types are very common in Rust code, as they have a number of uses: +- Initial values +- Return values for functions that are not defined over their entire input range (partial functions) +- Return value for otherwise reporting simple errors, where None is returned on error +- Optional struct fields +- Struct fields that can be loaned or "taken" +- Optional function arguments +- Nullable pointers +- Swapping things out of difficult situations -To learn about Option, check out these links: +## Further Information - [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions) - [Option Module Documentation](https://doc.rust-lang.org/std/option/) diff --git a/exercises/option/option2.rs b/exercises/option/option2.rs index a1517d7c..c6b83ece 100644 --- a/exercises/option/option2.rs +++ b/exercises/option/option2.rs @@ -4,22 +4,22 @@ // I AM NOT DONE fn main() { - let optional_value = Some(String::from("rustlings")); + let optional_word = Some(String::from("rustlings")); // TODO: Make this an if let statement whose value is "Some" type - value = optional_value { - println!("the value of optional value is: {}", value); + word = optional_word { + println!("The word is: {}", word); } else { - println!("The optional value doesn't contain anything!"); + println!("The optional word doesn't contain anything"); } - let mut optional_values_vec: Vec> = Vec::new(); + let mut optional_integers_vec: Vec> = Vec::new(); for x in 1..10 { - optional_values_vec.push(Some(x)); + optional_integers_vec.push(Some(x)); } // TODO: make this a while let statement - remember that vector.pop also adds another layer of Option // You can stack `Option`'s into while let and if let - value = optional_values_vec.pop() { - println!("current value: {}", value); + integer = optional_integers_vec.pop() { + println!("current value: {}", integer); } } diff --git a/exercises/option/option3.rs b/exercises/option/option3.rs new file mode 100644 index 00000000..045d2acb --- /dev/null +++ b/exercises/option/option3.rs @@ -0,0 +1,19 @@ +// option3.rs +// Make me compile! Execute `rustlings hint option3` for hints + +// I AM NOT DONE + +struct Point { + x: i32, + y: i32, +} + +fn main() { + let y: Option = Some(Point { x: 100, y: 200 }); + + match y { + Some(p) => println!("Co-ordinates are {},{} ", p.x, p.y), + _ => println!("no match"), + } + y; // Fix without deleting this line. +} diff --git a/exercises/primitive_types/README.md b/exercises/primitive_types/README.md index daa70eea..cea69b02 100644 --- a/exercises/primitive_types/README.md +++ b/exercises/primitive_types/README.md @@ -1,9 +1,9 @@ -### Primitive Types +# Primitive Types Rust has a couple of basic types that are directly implemented into the compiler. In this section, we'll go through the most important ones. -#### Book Sections +## Further information - [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html) - [The Slice Type](https://doc.rust-lang.org/stable/book/ch04-03-slices.html) diff --git a/exercises/primitive_types/primitive_types3.rs b/exercises/primitive_types/primitive_types3.rs index dfd6351c..aaa518be 100644 --- a/exercises/primitive_types/primitive_types3.rs +++ b/exercises/primitive_types/primitive_types3.rs @@ -1,5 +1,5 @@ // primitive_types3.rs -// Create an array with at least 100 elements in it where the ??? is. +// Create an array with at least 100 elements in it where the ??? is. // Execute `rustlings hint primitive_types3` for hints! // I AM NOT DONE diff --git a/exercises/primitive_types/primitive_types6.rs b/exercises/primitive_types/primitive_types6.rs index 2bc817e9..b8c9b82b 100644 --- a/exercises/primitive_types/primitive_types6.rs +++ b/exercises/primitive_types/primitive_types6.rs @@ -1,11 +1,16 @@ // primitive_types6.rs // Use a tuple index to access the second element of `numbers`. -// You can put this right into the `println!` where the ??? is. +// You can put the expression for the second element where ??? is so that the test passes. // Execute `rustlings hint primitive_types6` for hints! // I AM NOT DONE -fn main() { +#[test] +fn indexing_tuple() { let numbers = (1, 2, 3); - println!("The second number is {}", ???); + // Replace below ??? with the tuple indexing syntax. + let second = ???; + + assert_eq!(2, second, + "This is not the 2nd number in the tuple!") } diff --git a/exercises/quiz1.rs b/exercises/quiz1.rs index 5c5c355d..b13b9284 100644 --- a/exercises/quiz1.rs +++ b/exercises/quiz1.rs @@ -5,19 +5,21 @@ // Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy // more than 40 at once, each apple only costs 1! Write a function that calculates -// the price of an order of apples given the order amount. No hints this time! +// the price of an order of apples given the quantity bought. No hints this time! // I AM NOT DONE // Put your function here! -// fn ..... { +// fn calculate_apple_price { // Don't modify this function! #[test] fn verify_test() { let price1 = calculate_apple_price(35); - let price2 = calculate_apple_price(65); + let price2 = calculate_apple_price(40); + let price3 = calculate_apple_price(65); assert_eq!(70, price1); - assert_eq!(65, price2); + assert_eq!(80, price2); + assert_eq!(65, price3); } diff --git a/exercises/quiz2.rs b/exercises/quiz2.rs index 8caeaa99..de0dce95 100644 --- a/exercises/quiz2.rs +++ b/exercises/quiz2.rs @@ -17,14 +17,14 @@ fn string(arg: String) { } fn main() { - ("blue"); - ("red".to_string()); - (String::from("hi")); - ("rust is fun!".to_owned()); - ("nice weather".into()); - (format!("Interpolation {}", "Station")); - (&String::from("abc")[0..1]); - (" hello there ".trim()); - ("Happy Monday!".to_string().replace("Mon", "Tues")); - ("mY sHiFt KeY iS sTiCkY".to_lowercase()); + ???("blue"); + ???("red".to_string()); + ???(String::from("hi")); + ???("rust is fun!".to_owned()); + ???("nice weather".into()); + ???(format!("Interpolation {}", "Station")); + ???(&String::from("abc")[0..1]); + ???(" hello there ".trim()); + ???("Happy Monday!".to_string().replace("Mon", "Tues")); + ???("mY sHiFt KeY iS sTiCkY".to_lowercase()); } diff --git a/exercises/quiz3.rs b/exercises/quiz3.rs index a0cd3712..fae0eedb 100644 --- a/exercises/quiz3.rs +++ b/exercises/quiz3.rs @@ -24,6 +24,7 @@ mod tests { #[test] fn returns_twice_of_negative_numbers() { - // TODO write an assert for `times_two(-4)` + // TODO replace unimplemented!() with an assert for `times_two(-4)` + unimplemented!() } } diff --git a/exercises/standard_library_types/README.md b/exercises/standard_library_types/README.md index 36b30c1f..809d61fe 100644 --- a/exercises/standard_library_types/README.md +++ b/exercises/standard_library_types/README.md @@ -1,7 +1,10 @@ -For the Box exercise check out the chapter [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html). +# Standard library types -For the Arc exercise check out the chapter [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html) of the Rust Book. +This section will teach you about Box, Shared-State Concurrency and Iterators. -For the Iterator exercise check out the chapters [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html) of the Rust Book and the [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/). -Do not adjust your monitors-- iterators1.rs is indeed missing. Iterators is a challenging topic, so we're leaving space for a simpler exercise! +## Further information +- [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html) +- [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html) +- [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html) +- [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/) diff --git a/exercises/standard_library_types/arc1.rs b/exercises/standard_library_types/arc1.rs index 07932c63..d167380c 100644 --- a/exercises/standard_library_types/arc1.rs +++ b/exercises/standard_library_types/arc1.rs @@ -1,7 +1,21 @@ // arc1.rs +// In this exercise, we are given a Vec of u32 called "numbers" with values ranging +// from 0 to 99 -- [ 0, 1, 2, ..., 98, 99 ] +// We would like to use this set of numbers within 8 different threads simultaneously. +// Each thread is going to get the sum of every eighth value, with an offset. +// The first thread (offset 0), will sum 0, 8, 16, ... +// The second thread (offset 1), will sum 1, 9, 17, ... +// The third thread (offset 2), will sum 2, 10, 18, ... +// ... +// The eighth thread (offset 7), will sum 7, 15, 23, ... + +// Because we are using threads, our values need to be thread-safe. Therefore, +// we are using Arc. We need to make a change in each of the two TODOs. + + // Make this code compile by filling in a value for `shared_numbers` where the -// TODO comment is and create an initial binding for `child_numbers` -// somewhere. Try not to create any copies of the `numbers` Vec! +// first TODO comment is, and create an initial binding for `child_numbers` +// where the second TODO comment is. Try not to create any copies of the `numbers` Vec! // Execute `rustlings hint arc1` for hints :) // I AM NOT DONE @@ -16,12 +30,13 @@ fn main() { let mut joinhandles = Vec::new(); for offset in 0..8 { + let child_numbers = // TODO joinhandles.push(thread::spawn(move || { let mut i = offset; let mut sum = 0; while i < child_numbers.len() { sum += child_numbers[i]; - i += 5; + i += 8; } println!("Sum of offset {} is {}", offset, sum); })); diff --git a/exercises/standard_library_types/box1.rs b/exercises/standard_library_types/box1.rs index f2654ce2..f312f3d6 100644 --- a/exercises/standard_library_types/box1.rs +++ b/exercises/standard_library_types/box1.rs @@ -26,7 +26,10 @@ pub enum List { fn main() { println!("This is an empty cons list: {:?}", create_empty_list()); - println!("This is a non-empty cons list: {:?}", create_non_empty_list()); + println!( + "This is a non-empty cons list: {:?}", + create_non_empty_list() + ); } pub fn create_empty_list() -> List { diff --git a/exercises/standard_library_types/iterators1.rs b/exercises/standard_library_types/iterators1.rs new file mode 100644 index 00000000..4606ad35 --- /dev/null +++ b/exercises/standard_library_types/iterators1.rs @@ -0,0 +1,24 @@ +// iterators1.rs +// +// Make me compile by filling in the `???`s +// +// When performing operations on elements within a collection, iterators are essential. +// This module helps you get familiar with the structure of using an iterator and +// how to go through elements within an iterable collection. +// +// Execute `rustlings hint iterators1` for hints :D + +// I AM NOT DONE + +fn main () { + let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"]; + + let mut my_iterable_fav_fruits = ???; // TODO: Step 1 + + assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana")); + assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2 + assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado")); + assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2.1 + assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry")); + assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 3 +} diff --git a/exercises/standard_library_types/iterators2.rs b/exercises/standard_library_types/iterators2.rs index 837725f0..87b4eaa1 100644 --- a/exercises/standard_library_types/iterators2.rs +++ b/exercises/standard_library_types/iterators2.rs @@ -1,28 +1,41 @@ // iterators2.rs -// In this module, you'll learn some of unique advantages that iterators can offer. -// Step 1. Complete the `capitalize_first` function to pass the first two cases. -// Step 2. Apply the `capitalize_first` function to a vector of strings. -// Ensure that it returns a vector of strings as well. -// Step 3. Apply the `capitalize_first` function again to a list. -// Try to ensure it returns a single string. +// In this exercise, you'll learn some of the unique advantages that iterators +// can offer. Follow the steps to complete the exercise. // As always, there are hints if you execute `rustlings hint iterators2`! // I AM NOT DONE +// Step 1. +// Complete the `capitalize_first` function. +// "hello" -> "Hello" pub fn capitalize_first(input: &str) -> String { let mut c = input.chars(); match c.next() { None => String::new(), - Some(first) => first.collect::() + c.as_str(), + Some(first) => ???, } } +// Step 2. +// Apply the `capitalize_first` function to a slice of string slices. +// Return a vector of strings. +// ["hello", "world"] -> ["Hello", "World"] +pub fn capitalize_words_vector(words: &[&str]) -> Vec { + vec![] +} + +// Step 3. +// Apply the `capitalize_first` function again to a slice of string slices. +// Return a single string. +// ["hello", " ", "world"] -> "Hello World" +pub fn capitalize_words_string(words: &[&str]) -> String { + String::new() +} + #[cfg(test)] mod tests { use super::*; - // Step 1. - // Tests that verify your `capitalize_first` function implementation #[test] fn test_success() { assert_eq!(capitalize_first("hello"), "Hello"); @@ -33,18 +46,15 @@ mod tests { assert_eq!(capitalize_first(""), ""); } - // Step 2. #[test] fn test_iterate_string_vec() { let words = vec!["hello", "world"]; - let capitalized_words: Vec = // TODO - assert_eq!(capitalized_words, ["Hello", "World"]); + assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]); } #[test] fn test_iterate_into_string() { let words = vec!["hello", " ", "world"]; - let capitalized_words = // TODO - assert_eq!(capitalized_words, "Hello World"); + assert_eq!(capitalize_words_string(&words), "Hello World"); } } diff --git a/exercises/standard_library_types/iterators3.rs b/exercises/standard_library_types/iterators3.rs index 353cea62..8c66c05b 100644 --- a/exercises/standard_library_types/iterators3.rs +++ b/exercises/standard_library_types/iterators3.rs @@ -1,11 +1,10 @@ // iterators3.rs // This is a bigger exercise than most of the others! You can do it! // Here is your mission, should you choose to accept it: -// 1. Complete the divide function to get the first four tests to pass -// 2. Uncomment the last two tests and get them to pass by filling in -// values for `x` using `division_results`. +// 1. Complete the divide function to get the first four tests to pass. +// 2. Get the remaining tests to pass by completing the result_with_list and +// list_of_results functions. // Execute `rustlings hint iterators3` to get some hints! -// Have fun :-) // I AM NOT DONE @@ -21,16 +20,28 @@ pub struct NotDivisibleError { divisor: i32, } -// This function should calculate `a` divided by `b` if `a` is -// evenly divisible by b. -// Otherwise, it should return a suitable error. +// Calculate `a` divided by `b` if `a` is evenly divisible by `b`. +// Otherwise, return a suitable error. pub fn divide(a: i32, b: i32) -> Result {} +// Complete the function and return a value of the correct type so the test passes. +// Desired output: Ok([1, 11, 1426, 3]) +fn result_with_list() -> () { + let numbers = vec![27, 297, 38502, 81]; + let division_results = numbers.into_iter().map(|n| divide(n, 27)); +} + +// Complete the function and return a value of the correct type so the test passes. +// Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)] +fn list_of_results() -> () { + let numbers = vec![27, 297, 38502, 81]; + let division_results = numbers.into_iter().map(|n| divide(n, 27)); +} + #[cfg(test)] mod tests { use super::*; - // Tests that verify your `divide` function implementation #[test] fn test_success() { assert_eq!(divide(81, 9), Ok(9)); @@ -57,22 +68,16 @@ mod tests { assert_eq!(divide(0, 81), Ok(0)); } - // Iterator exercises using your `divide` function - /* #[test] - fn result_with_list() { - let numbers = vec![27, 297, 38502, 81]; - let division_results = numbers.into_iter().map(|n| divide(n, 27)); - let x //... Fill in here! - assert_eq!(format!("{:?}", x), "Ok([1, 11, 1426, 3])"); + fn test_result_with_list() { + assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])"); } #[test] - fn list_of_results() { - let numbers = vec![27, 297, 38502, 81]; - let division_results = numbers.into_iter().map(|n| divide(n, 27)); - let x //... Fill in here! - assert_eq!(format!("{:?}", x), "[Ok(1), Ok(11), Ok(1426), Ok(3)]"); + fn test_list_of_results() { + assert_eq!( + format!("{:?}", list_of_results()), + "[Ok(1), Ok(11), Ok(1426), Ok(3)]" + ); } - */ } diff --git a/exercises/standard_library_types/iterators5.rs b/exercises/standard_library_types/iterators5.rs new file mode 100644 index 00000000..93f3ae11 --- /dev/null +++ b/exercises/standard_library_types/iterators5.rs @@ -0,0 +1,122 @@ +// iterators5.rs +// Let's define a simple model to track Rustlings exercise progress. Progress +// will be modelled using a hash map. The name of the exercise is the key and +// the progress is the value. Two counting functions were created to count the +// number of exercises with a given progress. These counting functions use +// imperative style for loops. Recreate this counting functionality using +// iterators. Only the two iterator methods (count_iterator and +// count_collection_iterator) need to be modified. +// Execute `rustlings hint iterators5` for hints. +// +// Make the code compile and the tests pass. + +// I AM NOT DONE + +use std::collections::HashMap; + +#[derive(Clone, Copy, PartialEq, Eq)] +enum Progress { + None, + Some, + Complete, +} + +fn count_for(map: &HashMap, value: Progress) -> usize { + let mut count = 0; + for val in map.values() { + if val == &value { + count += 1; + } + } + count +} + +fn count_iterator(map: &HashMap, value: Progress) -> usize { + // map is a hashmap with String keys and Progress values. + // map = { "variables1": Complete, "from_str": None, ... } +} + +fn count_collection_for(collection: &[HashMap], value: Progress) -> usize { + let mut count = 0; + for map in collection { + for val in map.values() { + if val == &value { + count += 1; + } + } + } + count +} + +fn count_collection_iterator(collection: &[HashMap], value: Progress) -> usize { + // collection is a slice of hashmaps. + // collection = [{ "variables1": Complete, "from_str": None, ... }, + // { "variables2": Complete, ... }, ... ] +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn count_complete() { + let map = get_map(); + assert_eq!(3, count_iterator(&map, Progress::Complete)); + } + + #[test] + fn count_equals_for() { + let map = get_map(); + assert_eq!( + count_for(&map, Progress::Complete), + count_iterator(&map, Progress::Complete) + ); + } + + #[test] + fn count_collection_complete() { + let collection = get_vec_map(); + assert_eq!( + 6, + count_collection_iterator(&collection, Progress::Complete) + ); + } + + #[test] + fn count_collection_equals_for() { + let collection = get_vec_map(); + assert_eq!( + count_collection_for(&collection, Progress::Complete), + count_collection_iterator(&collection, Progress::Complete) + ); + } + + fn get_map() -> HashMap { + use Progress::*; + + let mut map = HashMap::new(); + map.insert(String::from("variables1"), Complete); + map.insert(String::from("functions1"), Complete); + map.insert(String::from("hashmap1"), Complete); + map.insert(String::from("arc1"), Some); + map.insert(String::from("as_ref_mut"), None); + map.insert(String::from("from_str"), None); + + map + } + + fn get_vec_map() -> Vec> { + use Progress::*; + + let map = get_map(); + + let mut other = HashMap::new(); + other.insert(String::from("variables2"), Complete); + other.insert(String::from("functions2"), Complete); + other.insert(String::from("if1"), Complete); + other.insert(String::from("from_into"), None); + other.insert(String::from("try_from_into"), None); + + vec![map, other] + } +} diff --git a/exercises/strings/README.md b/exercises/strings/README.md index 38d24c84..fa2104cc 100644 --- a/exercises/strings/README.md +++ b/exercises/strings/README.md @@ -1,9 +1,9 @@ -### Strings +# Strings Rust has two string types, a string slice (`&str`) and an owned string (`String`). We're not going to dictate when you should use which one, but we'll show you how to identify and create them, as well as use them. -#### Book Sections +## Further information - [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html) diff --git a/exercises/structs/README.md b/exercises/structs/README.md index afbc72c8..3fc1fdc9 100644 --- a/exercises/structs/README.md +++ b/exercises/structs/README.md @@ -1,7 +1,8 @@ -### Structs +# Structs -Rust has three struct types: a classic c struct, a tuple struct, and a unit struct. +Rust has three struct types: a classic C struct, a tuple struct, and a unit struct. -#### Book Sections +## Further information -- [Structures](https://doc.rust-lang.org/rust-by-example/custom_types/structs.html) +- [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html) +- [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html) diff --git a/exercises/structs/structs3.rs b/exercises/structs/structs3.rs index 5503ce15..b3aa2825 100644 --- a/exercises/structs/structs3.rs +++ b/exercises/structs/structs3.rs @@ -1,7 +1,8 @@ // structs3.rs -// Structs contain more than simply some data, they can also have logic, in this -// exercise we have defined the Package struct and we want to test some logic attached to it, -// make the code compile and the tests pass! If you have issues execute `rustlings hint structs3` +// Structs contain data, but can also have logic. In this exercise we have +// defined the Package struct and we want to test some logic attached to it. +// Make the code compile and the tests pass! +// If you have issues execute `rustlings hint structs3` // I AM NOT DONE @@ -17,7 +18,11 @@ impl Package { if weight_in_grams <= 0 { // Something goes here... } else { - return Package {sender_country, recipient_country, weight_in_grams}; + Package { + sender_country, + recipient_country, + weight_in_grams, + } } } @@ -25,8 +30,8 @@ impl Package { // Something goes here... } - fn get_fees(&self, cents_per_kg: i32) -> ??? { - // Something goes here... (beware of grams to kg conversion) + fn get_fees(&self, cents_per_gram: i32) -> ??? { + // Something goes here... } } @@ -47,21 +52,31 @@ mod tests { fn create_international_package() { let sender_country = String::from("Spain"); let recipient_country = String::from("Russia"); - + let package = Package::new(sender_country, recipient_country, 1200); assert!(package.is_international()); } + #[test] + fn create_local_package() { + let sender_country = String::from("Canada"); + let recipient_country = sender_country.clone(); + + let package = Package::new(sender_country, recipient_country, 1200); + + assert!(!package.is_international()); + } + #[test] fn calculate_transport_fees() { let sender_country = String::from("Spain"); let recipient_country = String::from("Spain"); - let cents_per_kg = ???; - + let cents_per_gram = ???; + let package = Package::new(sender_country, recipient_country, 1500); - - assert_eq!(package.get_fees(cents_per_kg), 4500); + + assert_eq!(package.get_fees(cents_per_gram), 4500); } } diff --git a/exercises/tests/README.md b/exercises/tests/README.md index dbb14a83..27c6818d 100644 --- a/exercises/tests/README.md +++ b/exercises/tests/README.md @@ -1,7 +1,7 @@ -### Tests +# Tests Going out of order from the book to cover tests -- many of the following exercises will ask you to make tests pass! -#### Book Sections +## Further information - [Writing Tests](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) diff --git a/exercises/tests/tests3.rs b/exercises/tests/tests3.rs index 693b8aa5..3424f940 100644 --- a/exercises/tests/tests3.rs +++ b/exercises/tests/tests3.rs @@ -18,4 +18,9 @@ mod tests { fn is_true_when_even() { assert!(); } + + #[test] + fn is_false_when_odd() { + assert!(); + } } diff --git a/exercises/threads/README.md b/exercises/threads/README.md index 2024292f..d0866947 100644 --- a/exercises/threads/README.md +++ b/exercises/threads/README.md @@ -1 +1,9 @@ -For this exercise check out the [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) and the chapter [Concurrency](https://doc.rust-lang.org/book/ch16-01-threads.html) of the Rust Book. \ No newline at end of file +# Threads + +In most current operating systems, an executed program’s code is run in a process, and the operating system manages multiple processes at once. +Within your program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads. + +## Further information + +- [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) +- [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html) diff --git a/exercises/threads/threads1.rs b/exercises/threads/threads1.rs index 1785e8ce..f31b317e 100644 --- a/exercises/threads/threads1.rs +++ b/exercises/threads/threads1.rs @@ -1,7 +1,8 @@ // threads1.rs // Make this compile! Execute `rustlings hint threads1` for hints :) -// The idea is the thread spawned on line 21 is completing jobs while the main thread is -// monitoring progress until 10 jobs are completed. If you see 6 lines +// The idea is the thread spawned on line 22 is completing jobs while the main thread is +// monitoring progress until 10 jobs are completed. Because of the difference between the +// spawned threads' sleep time, and the waiting threads sleep time, when you see 6 lines // of "waiting..." and the program ends without timing out when running, // you've got it :) diff --git a/exercises/traits/README.md b/exercises/traits/README.md index 1ce46fe0..de67acd0 100644 --- a/exercises/traits/README.md +++ b/exercises/traits/README.md @@ -1,20 +1,19 @@ -### Traits +# Traits -A trait is a collection of methods. +A trait is a collection of methods. Data types can implement traits. To do so, the methods making up the trait are defined for the data type. For example, the `String` data type implements the `From<&str>` trait. This allows a user to write `String::from("hello")`. In this way, traits are somewhat similar to Java interfaces and C++ abstract classes. Some additional common Rust traits include: - -+ `Clone` (the `clone` method), -+ `Display` (which allows formatted display via `{}`), and -+ `Debug` (which allows formatted display via `{:?}`). +- `Clone` (the `clone` method) +- `Display` (which allows formatted display via `{}`) +- `Debug` (which allows formatted display via `{:?}`) Because traits indicate shared behavior between data types, they are useful when writing generics. -#### Book Sections +## Further information -- [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html) \ No newline at end of file +- [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html) diff --git a/exercises/traits/traits1.rs b/exercises/traits/traits1.rs index 8253ef80..2ef9e11b 100644 --- a/exercises/traits/traits1.rs +++ b/exercises/traits/traits1.rs @@ -1,21 +1,21 @@ // traits1.rs // Time to implement some traits! -// +// // Your task is to implement the trait // `AppendBar' for the type `String'. -// +// // The trait AppendBar has only one function, // which appends "Bar" to any object // implementing this trait. // I AM NOT DONE + trait AppendBar { fn append_bar(self) -> Self; } impl AppendBar for String { //Add your code here - } fn main() { @@ -40,5 +40,4 @@ mod tests { String::from("BarBar") ); } - -} \ No newline at end of file +} diff --git a/exercises/traits/traits2.rs b/exercises/traits/traits2.rs index 7f5014d0..916c3c4b 100644 --- a/exercises/traits/traits2.rs +++ b/exercises/traits/traits2.rs @@ -1,12 +1,12 @@ // traits2.rs -// +// // Your task is to implement the trait // `AppendBar' for a vector of strings. -// +// // To implement this trait, consider for // a moment what it means to 'append "Bar"' // to a vector of strings. -// +// // No boiler plate code this time, // you can do this! @@ -18,9 +18,6 @@ trait AppendBar { //TODO: Add your code here - - - #[cfg(test)] mod tests { use super::*; @@ -31,5 +28,4 @@ mod tests { assert_eq!(foo.pop().unwrap(), String::from("Bar")); assert_eq!(foo.pop().unwrap(), String::from("Foo")); } - } diff --git a/exercises/variables/README.md b/exercises/variables/README.md index 1e2eb596..11a7a78a 100644 --- a/exercises/variables/README.md +++ b/exercises/variables/README.md @@ -1,7 +1,9 @@ -### Variables +# Variables -Here you'll learn about simple variables. +In Rust, variables are immutable by default. +When a variable is immutable, once a value is bound to a name, you can’t change that value. +You can make them mutable by adding mut in front of the variable name. -#### Book Sections +## Further information - [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html) diff --git a/info.toml b/info.toml index ee4ab2f6..5eece6d7 100644 --- a/info.toml +++ b/info.toml @@ -52,7 +52,7 @@ because we want to assign a different typed value to an existing variable. Somet you may also like to reuse existing variable names because you are just converting values to different types like in this exercise. Fortunately Rust has a powerful solution to this problem: 'Shadowing'! -You can read more about 'Shadowing' in the book's section 'Variables and Mutability': +You can read more about 'Shadowing' in the book's section 'Variables and Mutability': https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing Try to solve this exercise afterwards using this technique.""" @@ -61,41 +61,16 @@ name = "variables6" path = "exercises/variables/variables6.rs" mode = "compile" hint = """ -We know about variables and mutability, but there is another important type of -variable available; constants. -Constants are always immutable and they are declared with keyword 'const' rather -then keyword 'let'. +We know about variables and mutability, but there is another important type of +variable available; constants. +Constants are always immutable and they are declared with keyword 'const' rather +than keyword 'let'. Constants types must also always be annotated. -Read more about constants under 'Differences Between Variables and Constants' in the book's section 'Variables and Mutability': +Read more about constants under 'Differences Between Variables and Constants' in the book's section 'Variables and Mutability': https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants """ -# IF - -[[exercises]] -name = "if1" -path = "exercises/if/if1.rs" -mode = "test" -hint = """ -It's possible to do this in one line if you would like! -Some similar examples from other languages: -- In C(++) this would be: `a > b ? a : b` -- In Python this would be: `a if a > b else b` -Remember in Rust that: -- the `if` condition does not need to be surrounded by parentheses -- `if`/`else` conditionals are expressions -- Each condition is followed by a `{}` block.""" - -[[exercises]] -name = "if2" -path = "exercises/if/if2.rs" -mode = "test" -hint = """ -For that first compiler error, it's important in Rust that each conditional -block return the same type! To get the tests passing, you will need a couple -conditions checking different input values.""" - # FUNCTIONS [[exercises]] @@ -146,6 +121,31 @@ They are not the same. There are two solutions: 1. Add a `return` ahead of `num * num;` 2. remove `;`, make it to be `num * num`""" +# IF + +[[exercises]] +name = "if1" +path = "exercises/if/if1.rs" +mode = "test" +hint = """ +It's possible to do this in one line if you would like! +Some similar examples from other languages: +- In C(++) this would be: `a > b ? a : b` +- In Python this would be: `a if a > b else b` +Remember in Rust that: +- the `if` condition does not need to be surrounded by parentheses +- `if`/`else` conditionals are expressions +- Each condition is followed by a `{}` block.""" + +[[exercises]] +name = "if2" +path = "exercises/if/if2.rs" +mode = "test" +hint = """ +For that first compiler error, it's important in Rust that each conditional +block return the same type! To get the tests passing, you will need a couple +conditions checking different input values.""" + # TEST 1 [[exercises]] @@ -154,271 +154,6 @@ path = "exercises/quiz1.rs" mode = "test" hint = "No hints this time ;)" -# PRIMITIVE TYPES - -[[exercises]] -name = "primitive_types1" -path = "exercises/primitive_types/primitive_types1.rs" -mode = "compile" -hint = "No hints this time ;)" - -[[exercises]] -name = "primitive_types2" -path = "exercises/primitive_types/primitive_types2.rs" -mode = "compile" -hint = "No hints this time ;)" - -[[exercises]] -name = "primitive_types3" -path = "exercises/primitive_types/primitive_types3.rs" -mode = "compile" -hint = """ -There's a shorthand to initialize Arrays with a certain size that does not -require you to type in 100 items (but you certainly can if you want!). -For example, you can do: -let array = ["Are we there yet?"; 10]; - -Bonus: what are some other things you could have that would return true -for `a.len() >= 100`?""" - -[[exercises]] -name = "primitive_types4" -path = "exercises/primitive_types/primitive_types4.rs" -mode = "test" -hint = """ -Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book: -https://doc.rust-lang.org/book/ch04-03-slices.html -and use the starting and ending indices of the items in the Array -that you want to end up in the slice. - -If you're curious why the first argument of `assert_eq!` does not -have an ampersand for a reference since the second argument is a -reference, take a look at the Deref coercions section of the book: -https://doc.rust-lang.org/book/ch15-02-deref.html""" - -[[exercises]] -name = "primitive_types5" -path = "exercises/primitive_types/primitive_types5.rs" -mode = "compile" -hint = """ -Take a look at the Data Types -> The Tuple Type section of the book: -https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type -Particularly the part about destructuring (second to last example in the section). -You'll need to make a pattern to bind `name` and `age` to the appropriate parts -of the tuple. You can do it!!""" - -[[exercises]] -name = "primitive_types6" -path = "exercises/primitive_types/primitive_types6.rs" -mode = "compile" -hint = """ -While you could use a destructuring `let` for the tuple here, try -indexing into it instead, as explained in the last example of the -Data Types -> The Tuple Type section of the book: -https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type -Now you have another tool in your toolbox!""" - -# STRUCTS - -[[exercises]] -name = "structs1" -path = "exercises/structs/structs1.rs" -mode = "test" -hint = """ -Rust has more than one type of struct. Both variants are used to package related data together. -On the one hand, there are normal, or classic, structs. These are named collections of related data stored in fields. -The other variant is tuple structs. Basically just named tuples. -In this exercise you need to implement one of each kind. - -Read more about structs in The Book: https://doc.rust-lang.org/stable/book/ch05-00-structs.html""" - -[[exercises]] -name = "structs2" -path = "exercises/structs/structs2.rs" -mode = "test" -hint = """ -Creating instances of structs is easy, all you need to do is assign some values to its fields. -There is however some shortcuts that can be taken when instantiating structs. -Have a look in The Book, to find out more: https://doc.rust-lang.org/stable/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax""" - -[[exercises]] -name = "structs3" -path = "exercises/structs/structs3.rs" -mode = "test" -hint = """ -The new method needs to panic if the weight is physically impossible :), how do we do that in Rust? - -For is_international: What makes a package international? Seems related to the places it goes through right? - -For calculate_transport_fees: Bigger is more expensive usually, we don't have size, but something may fit the bill here :) - -Have a look in The Book, to find out more about method implementations: https://doc.rust-lang.org/book/ch05-03-method-syntax.html""" - -# STRINGS - -[[exercises]] -name = "strings1" -path = "exercises/strings/strings1.rs" -mode = "compile" -hint = """ -The `current_favorite_color` function is currently returning a string slice with the `'static` -lifetime. We know this because the data of the string lives in our code itself -- it doesn't -come from a file or user input or another program -- so it will live as long as our program -lives. But it is still a string slice. There's one way to create a `String` by converting a -string slice covered in the Strings chapter of the book, and another way that uses the `From` -trait.""" - -[[exercises]] -name = "strings2" -path = "exercises/strings/strings2.rs" -mode = "compile" -hint = """ -Yes, it would be really easy to fix this by just changing the value bound to `word` to be a -string slice instead of a `String`, wouldn't it?? There is a way to add one character to line -9, though, that will coerce the `String` into a string slice.""" - -# TEST 2 - -[[exercises]] -name = "quiz2" -path = "exercises/quiz2.rs" -mode = "compile" -hint = "No hints this time ;)" - -# ENUMS - -[[exercises]] -name = "enums1" -path = "exercises/enums/enums1.rs" -mode = "compile" -hint = """ -Hint: The declaration of the enumeration type has not been defined yet.""" - -[[exercises]] -name = "enums2" -path = "exercises/enums/enums2.rs" -mode = "compile" -hint = """ -Hint: you can create enumerations that have different variants with different types -such as no data, anonymous structs, a single string, tuples, ...etc""" - -[[exercises]] -name = "enums3" -path = "exercises/enums/enums3.rs" -mode = "test" -hint = "No hints this time ;)" - -# TESTS - -[[exercises]] -name = "tests1" -path = "exercises/tests/tests1.rs" -mode = "test" -hint = """ -You don't even need to write any code to test -- you can just test values and run that, even -though you wouldn't do that in real life :) `assert!` is a macro that needs an argument. -Depending on the value of the argument, `assert!` will do nothing (in which case the test will -pass) or `assert!` will panic (in which case the test will fail). So try giving different values -to `assert!` and see which ones compile, which ones pass, and which ones fail :)""" - -[[exercises]] -name = "tests2" -path = "exercises/tests/tests2.rs" -mode = "test" -hint = """ -Like the previous exercise, you don't need to write any code to get this test to compile and -run. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it two -values that are equal! Try giving it two arguments that are different! Try giving it two values -that are of different types! Try switching which argument comes first and which comes second!""" - -[[exercises]] -name = "tests3" -path = "exercises/tests/tests3.rs" -mode = "test" -hint = """ -You can call a function right where you're passing arguments to `assert!` -- so you could do -something like `assert!(having_fun())`. If you want to check that you indeed get false, you -can negate the result of what you're doing using `!`, like `assert!(!having_fun())`.""" - -# TEST 3 - -[[exercises]] -name = "quiz3" -path = "exercises/quiz3.rs" -mode = "test" -hint = "No hints this time ;)" - -# MODULES - -[[exercises]] -name = "modules1" -path = "exercises/modules/modules1.rs" -mode = "compile" -hint = """ -Everything is private in Rust by default-- but there's a keyword we can use -to make something public! The compiler error should point to the thing that -needs to be public.""" - -[[exercises]] -name = "modules2" -path = "exercises/modules/modules2.rs" -mode = "compile" -hint = """ -The delicious_snacks module is trying to present an external -interface (the `fruit` and `veggie` constants) that is different than -its internal structure (the `fruits` and `veggies` modules and -associated constants). It's almost there except for one keyword missing for -each constant.""" - -# MACROS - -[[exercises]] -name = "macros1" -path = "exercises/macros/macros1.rs" -mode = "compile" -hint = """ -When you call a macro, you need to add something special compared to a -regular function call. If you're stuck, take a look at what's inside -`my_macro`.""" - -[[exercises]] -name = "macros2" -path = "exercises/macros/macros2.rs" -mode = "compile" -hint = """ -Macros don't quite play by the same rules as the rest of Rust, in terms of -what's available where. - -Unlike other things in Rust, the order of "where you define a macro" versus -"where you use it" actually matters.""" - -[[exercises]] -name = "macros3" -path = "exercises/macros/macros3.rs" -mode = "compile" -hint = """ -In order to use a macro outside of its module, you need to do something -special to the module to lift the macro out into its parent. - -The same trick also works on "extern crate" statements for crates that have -exported macros, if you've seen any of those around.""" - -[[exercises]] -name = "macros4" -path = "exercises/macros/macros4.rs" -mode = "compile" -hint = """ -You only need to add a single character to make this compile. -The way macros are written, it wants to see something between each -"macro arm", so it can separate them.""" -# TEST 4 - -[[exercises]] -name = "quiz4" -path = "exercises/quiz4.rs" -mode = "test" -hint = "No hints this time ;)" - # MOVE SEMANTICS [[exercises]] @@ -475,6 +210,249 @@ So the end goal is to: - since we're not creating a new vec in `main` anymore, we need to create a new vec in `fill_vec`, similarly to the way we did in `main`""" +[[exercises]] +name = "move_semantics5" +path = "exercises/move_semantics/move_semantics5.rs" +mode = "compile" +hint = """ +Carefully reason about the range in which each mutable reference is in +vogue. Does it help to update the value of referent (x) immediately after +the mutable reference is taken? Read more about 'Mutable References' +in the book's section References and Borrowing': +https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#mutable-references. +""" + +# PRIMITIVE TYPES + +[[exercises]] +name = "primitive_types1" +path = "exercises/primitive_types/primitive_types1.rs" +mode = "compile" +hint = "No hints this time ;)" + +[[exercises]] +name = "primitive_types2" +path = "exercises/primitive_types/primitive_types2.rs" +mode = "compile" +hint = "No hints this time ;)" + +[[exercises]] +name = "primitive_types3" +path = "exercises/primitive_types/primitive_types3.rs" +mode = "compile" +hint = """ +There's a shorthand to initialize Arrays with a certain size that does not +require you to type in 100 items (but you certainly can if you want!). +For example, you can do: +let array = ["Are we there yet?"; 10]; + +Bonus: what are some other things you could have that would return true +for `a.len() >= 100`?""" + +[[exercises]] +name = "primitive_types4" +path = "exercises/primitive_types/primitive_types4.rs" +mode = "test" +hint = """ +Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book: +https://doc.rust-lang.org/book/ch04-03-slices.html +and use the starting and ending indices of the items in the Array +that you want to end up in the slice. + +If you're curious why the first argument of `assert_eq!` does not +have an ampersand for a reference since the second argument is a +reference, take a look at the Deref coercions section of the book: +https://doc.rust-lang.org/book/ch15-02-deref.html""" + +[[exercises]] +name = "primitive_types5" +path = "exercises/primitive_types/primitive_types5.rs" +mode = "compile" +hint = """ +Take a look at the Data Types -> The Tuple Type section of the book: +https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type +Particularly the part about destructuring (second to last example in the section). +You'll need to make a pattern to bind `name` and `age` to the appropriate parts +of the tuple. You can do it!!""" + +[[exercises]] +name = "primitive_types6" +path = "exercises/primitive_types/primitive_types6.rs" +mode = "test" +hint = """ +While you could use a destructuring `let` for the tuple here, try +indexing into it instead, as explained in the last example of the +Data Types -> The Tuple Type section of the book: +https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type +Now you have another tool in your toolbox!""" + +# STRUCTS + +[[exercises]] +name = "structs1" +path = "exercises/structs/structs1.rs" +mode = "test" +hint = """ +Rust has more than one type of struct. Three actually, all variants are used to package related data together. +There are normal (or classic) structs. These are named collections of related data stored in fields. +Tuple structs are basically just named tuples. +Finally, Unit structs. These don't have any fields and are useful for generics. + +In this exercise you need to complete and implement one of each kind. +Read more about structs in The Book: https://doc.rust-lang.org/book/ch05-01-defining-structs.html""" + +[[exercises]] +name = "structs2" +path = "exercises/structs/structs2.rs" +mode = "test" +hint = """ +Creating instances of structs is easy, all you need to do is assign some values to its fields. +There are however some shortcuts that can be taken when instantiating structs. +Have a look in The Book, to find out more: https://doc.rust-lang.org/stable/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax""" + +[[exercises]] +name = "structs3" +path = "exercises/structs/structs3.rs" +mode = "test" +hint = """ +The new method needs to panic if the weight is physically impossible :), how do we do that in Rust? + +For is_international: What makes a package international? Seems related to the places it goes through right? + +For calculate_transport_fees: Bigger is more expensive usually, we don't have size, but something may fit the bill here :) + +Have a look in The Book, to find out more about method implementations: https://doc.rust-lang.org/book/ch05-03-method-syntax.html""" + +# ENUMS + +[[exercises]] +name = "enums1" +path = "exercises/enums/enums1.rs" +mode = "compile" +hint = """ +Hint: The declaration of the enumeration type has not been defined yet.""" + +[[exercises]] +name = "enums2" +path = "exercises/enums/enums2.rs" +mode = "compile" +hint = """ +Hint: you can create enumerations that have different variants with different types +such as no data, anonymous structs, a single string, tuples, ...etc""" + +[[exercises]] +name = "enums3" +path = "exercises/enums/enums3.rs" +mode = "test" +hint = "No hints this time ;)" + +# MODULES + +[[exercises]] +name = "modules1" +path = "exercises/modules/modules1.rs" +mode = "compile" +hint = """ +Everything is private in Rust by default-- but there's a keyword we can use +to make something public! The compiler error should point to the thing that +needs to be public.""" + +[[exercises]] +name = "modules2" +path = "exercises/modules/modules2.rs" +mode = "compile" +hint = """ +The delicious_snacks module is trying to present an external interface that is +different than its internal structure (the `fruits` and `veggies` modules and +associated constants). Complete the `use` statements to fit the uses in main and +find the one keyword missing for both constants.""" + +[[exercises]] +name = "modules3" +path = "exercises/modules/modules3.rs" +mode = "compile" +hint = """ +UNIX_EPOCH and SystemTime are declared in the std::time module. Add a use statement +for these two to bring them into scope. You can use nested paths or the glob +operator to bring these two in using only one line.""" + +# COLLECTIONS + +[[exercises]] +name = "vec1" +path = "exercises/collections/vec1.rs" +mode = "test" +hint = """ +In Rust, there are two ways to define a Vector. +1. One way is to use the `Vec::new()` function to create a new vector + and fill it with the `push()` method. +2. The second way, which is simpler is to use the `vec![]` macro and + define your elements inside the square brackets. +Check this chapter: https://doc.rust-lang.org/stable/book/ch08-01-vectors.html +of the Rust book to learn more. +""" + +[[exercises]] +name = "vec2" +path = "exercises/collections/vec2.rs" +mode = "test" +hint = """ +Hint 1: `i` is each element from the Vec as they are being iterated. + Can you try multiplying this? +Hint 2: Check the suggestion from the compiler error ;) +""" + +[[exercises]] +name = "hashmap1" +path = "exercises/collections/hashmap1.rs" +mode = "test" +hint = """ +Hint 1: Take a look at the return type of the function to figure out + the type for the `basket`. +Hint 2: Number of fruits should be at least 5. And you have to put + at least three different types of fruits. +""" + +[[exercises]] +name = "hashmap2" +path = "exercises/collections/hashmap2.rs" +mode = "test" +hint = """ +Use the `entry()` and `or_insert()` methods of `HashMap` to achieve this. +Learn more at https://doc.rust-lang.org/stable/book/ch08-03-hash-maps.html#only-inserting-a-value-if-the-key-has-no-value +""" + +# STRINGS + +[[exercises]] +name = "strings1" +path = "exercises/strings/strings1.rs" +mode = "compile" +hint = """ +The `current_favorite_color` function is currently returning a string slice with the `'static` +lifetime. We know this because the data of the string lives in our code itself -- it doesn't +come from a file or user input or another program -- so it will live as long as our program +lives. But it is still a string slice. There's one way to create a `String` by converting a +string slice covered in the Strings chapter of the book, and another way that uses the `From` +trait.""" + +[[exercises]] +name = "strings2" +path = "exercises/strings/strings2.rs" +mode = "compile" +hint = """ +Yes, it would be really easy to fix this by just changing the value bound to `word` to be a +string slice instead of a `String`, wouldn't it?? There is a way to add one character to line +9, though, that will coerce the `String` into a string slice.""" + +# TEST 2 + +[[exercises]] +name = "quiz2" +path = "exercises/quiz2.rs" +mode = "compile" +hint = "No hints this time ;)" + # ERROR HANDLING [[exercises]] @@ -512,49 +490,102 @@ and give it a try!""" [[exercises]] name = "errors3" path = "exercises/error_handling/errors3.rs" -mode = "test" +mode = "compile" hint = """ If other functions can return a `Result`, why shouldn't `main`?""" [[exercises]] -name = "errorsn" -path = "exercises/error_handling/errorsn.rs" +name = "errors4" +path = "exercises/error_handling/errors4.rs" mode = "test" hint = """ -First hint: To figure out what type should go where the ??? is, take a look -at the test helper function `test_with_str`, since it returns whatever -`read_and_validate` returns and `test_with_str` has its signature fully -specified. - - -Next hint: There are three places in `read_and_validate` that we call a -function that returns a `Result` (that is, the functions might fail). -Apply the `?` operator on those calls so that we return immediately from -`read_and_validate` if those function calls fail. +`PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result. +It should be doing some checking, returning an `Err` result if those checks fail, and only +returning an `Ok` result if those checks determine that everything is... okay :)""" +[[exercises]] +name = "errors5" +path = "exercises/error_handling/errors5.rs" +mode = "compile" +hint = """ +Hint: There are two different possible `Result` types produced within +`main()`, which are propagated using `?` operators. How do we declare a +return type from `main()` that allows both? Another hint: under the hood, the `?` operator calls `From::from` -on the error value to convert it to a boxed trait object, a Box, -which is polymorphic-- that means that lots of different kinds of errors -can be returned from the same function because all errors act the same -since they all implement the `error::Error` trait. +on the error value to convert it to a boxed trait object, a +`Box`, which is polymorphic-- that means that lots of +different kinds of errors can be returned from the same function because +all errors act the same since they all implement the `error::Error` trait. Check out this section of the book: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator +This exercise uses some concepts that we won't get to until later in the +course, like `Box` and the `From` trait. It's not important to understand +them in detail right now, but you can read ahead if you like. -Another another hint: Note that because the `?` operator returns -the *unwrapped* value in the `Ok` case, if we want to return a `Result` from -`read_and_validate` for *its* success case, we'll have to rewrap a value -that we got from the return value of a `?`ed call in an `Ok`-- this will -look like `Ok(something)`. +Read more about boxing errors: +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/boxing_errors.html +Read more about using the `?` operator with boxed errors: +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html +""" -Another another another hint: `Result`s must be "used", that is, you'll -get a warning if you don't handle a `Result` that you get in your -function. Read more about that in the `std::result` module docs: -https://doc.rust-lang.org/std/result/#results-must-be-used""" +[[exercises]] +name = "errors6" +path = "exercises/error_handling/errors6.rs" +mode = "test" +hint = """ +This exercise uses a completed version of `PositiveNonzeroInteger` from +errors4. -# OPTIONS / RESULTS +Below the line that TODO asks you to change, there is an example of using +the `map_err()` method on a `Result` to transform one type of error into +another. Try using something similar on the `Result` from `parse()`. You +might use the `?` operator to return early from the function, or you might +use a `match` expression, or maybe there's another way! + +You can create another function inside `impl ParsePosNonzeroError` to use +with `map_err()`. + +Read more about `map_err()` in the `std::result` documentation: +https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err""" + +# Generics + +[[exercises]] +name = "generics1" +path = "exercises/generics/generics1.rs" +mode = "compile" +hint = """ +Vectors in rust make use of generics to create dynamically sized arrays of any type. +You need to tell the compiler what type we are pushing onto this vector.""" + +[[exercises]] +name = "generics2" +path = "exercises/generics/generics2.rs" +mode = "test" +hint = """ +Currently we are wrapping only values of type 'u32'. +Maybe we could update the explicit references to this data type somehow? + +If you are still stuck https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-method-definitions +""" + +[[exercises]] +name = "generics3" +path = "exercises/generics/generics3.rs" +mode = "test" +hint = """ +To find the best solution to this challenge you're going to need to think back to your +knowledge of traits, specifically Trait Bound Syntax - you may also need this: "use std::fmt::Display;" + +This is definitely harder than the last two exercises! You need to think about not only making the +ReportCard struct generic, but also the correct property - you will need to change the implementation +of the struct slightly too...you can do it! +""" + +# OPTIONS [[exercises]] name = "option1" @@ -583,34 +614,80 @@ https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html Remember that Options can be stacked in if let and while let. For example: Some(Some(variable)) = variable2 - - +Also see Option::flatten """ [[exercises]] -name = "result1" -path = "exercises/error_handling/result1.rs" +name = "option3" +path = "exercises/option/option3.rs" +mode = "compile" +hint = """ +The compiler says a partial move happened in the `match` +statement. How can this be avoided? The compiler shows the correction +needed. After making the correction as suggested by the compiler, do +read: https://doc.rust-lang.org/std/keyword.ref.html""" + +# TRAITS + +[[exercises]] +name = "traits1" +path = "exercises/traits/traits1.rs" mode = "test" hint = """ -`PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result. -It should be doing some checking, returning an `Err` result if those checks fail, and only -returning an `Ok` result if those checks determine that everything is... okay :)""" - -# CLIPPY +A discussion about Traits in Rust can be found at: +https://doc.rust-lang.org/book/ch10-02-traits.html +""" [[exercises]] -name = "clippy1" -path = "exercises/clippy/clippy1.rs" -mode = "clippy" +name = "traits2" +path = "exercises/traits/traits2.rs" +mode = "test" hint = """ -Floating point calculations are usually imprecise, so asking if two values are exactly equal is asking for trouble""" +Notice how the trait takes ownership of 'self',and returns `Self'. +Try mutating the incoming string vector. + +Vectors provide suitable methods for adding an element at the end. See +the documentation at: https://doc.rust-lang.org/std/vec/struct.Vec.html""" + +# TESTS [[exercises]] -name = "clippy2" -path = "exercises/clippy/clippy2.rs" -mode = "clippy" +name = "tests1" +path = "exercises/tests/tests1.rs" +mode = "test" hint = """ -`for` loops over Option values are more clearly expressed as an `if let`""" +You don't even need to write any code to test -- you can just test values and run that, even +though you wouldn't do that in real life :) `assert!` is a macro that needs an argument. +Depending on the value of the argument, `assert!` will do nothing (in which case the test will +pass) or `assert!` will panic (in which case the test will fail). So try giving different values +to `assert!` and see which ones compile, which ones pass, and which ones fail :)""" + +[[exercises]] +name = "tests2" +path = "exercises/tests/tests2.rs" +mode = "test" +hint = """ +Like the previous exercise, you don't need to write any code to get this test to compile and +run. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it two +values that are equal! Try giving it two arguments that are different! Try giving it two values +that are of different types! Try switching which argument comes first and which comes second!""" + +[[exercises]] +name = "tests3" +path = "exercises/tests/tests3.rs" +mode = "test" +hint = """ +You can call a function right where you're passing arguments to `assert!` -- so you could do +something like `assert!(having_fun())`. If you want to check that you indeed get false, you +can negate the result of what you're doing using `!`, like `assert!(!having_fun())`.""" + +# TEST 3 + +[[exercises]] +name = "quiz3" +path = "exercises/quiz3.rs" +mode = "test" +hint = "No hints this time ;)" # STANDARD LIBRARY TYPES @@ -642,7 +719,29 @@ to avoid creating a copy of `numbers`, you'll need to create `child_numbers` inside the loop but still in the main thread. `child_numbers` should be a clone of the Arc of the numbers instead of a -thread-local copy of the numbers.""" +thread-local copy of the numbers. + +This is a simple exercise if you understand the underlying concepts, but if this +is too much of a struggle, consider reading through all of Chapter 16 in the book: +https://doc.rust-lang.org/stable/book/ch16-00-concurrency.html +""" + +[[exercises]] +name = "iterators1" +path = "exercises/standard_library_types/iterators1.rs" +mode = "compile" +hint = """ +Step 1: +We need to apply something to the collection `my_fav_fruits` before we start to go through +it. What could that be? Take a look at the struct definition for a vector for inspiration: +https://doc.rust-lang.org/std/vec/struct.Vec.html. +Step 2 & step 2.1: +Very similar to the lines above and below. You've got this! +Step 3: +An iterator goes through all elements in a collection, but what if we've run out of +elements? What should we expect here? If you're stuck, take a look at +https://doc.rust-lang.org/std/iter/trait.Iterator.html for some ideas. +""" [[exercises]] name = "iterators2" @@ -650,98 +749,67 @@ path = "exercises/standard_library_types/iterators2.rs" mode = "test" hint = """ Step 1 -You need to call something on `first` before it can be collected -Currently its type is `char`. Have a look at the methods that are available on that type: +The variable `first` is a `char`. It needs to be capitalized and added to the +remaining characters in `c` in order to return the correct `String`. +The remaining characters in `c` can be viewed as a string slice using the +`as_str` method. +The documentation for `char` contains many useful methods. https://doc.rust-lang.org/std/primitive.char.html - Step 2 -First you'll need to turn the Vec into an iterator -Then you'll need to apply your function unto each item in the vector -P.s. Don't forget to collect() at the end! - +Create an iterator from the slice. Transform the iterated values by applying +the `capitalize_first` function. Remember to collect the iterator. Step 3. -This is very similar to the previous test. The only real change is that you will need to -alter the type that collect is coerced into. For a bonus you could try doing this with a -turbofish""" +This is surprising similar to the previous solution. Collect is very powerful +and very general. Rust just needs to know the desired type.""" [[exercises]] name = "iterators3" path = "exercises/standard_library_types/iterators3.rs" mode = "test" hint = """ -Minor hint: In each of the two cases in the match in main, you can create x with either -a 'turbofish' or by hinting the type of x to the compiler. You may try both. +The divide function needs to return the correct error when even division is not +possible. -Major hint: Have a look at the Iter trait and at the explanation of its collect function. -Especially the part about Result is interesting.""" +The division_results variable needs to be collected into a collection type. + +The result_with_list function needs to return a single Result where the success +case is a vector of integers and the failure case is a DivisionError. + +The list_of_results function needs to return a vector of results. + +See https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect for how +the `FromIterator` trait is used in `collect()`.""" [[exercises]] name = "iterators4" path = "exercises/standard_library_types/iterators4.rs" mode = "test" hint = """ -In an imperative language, you might write a for loop that updates -a mutable variable. Or, you might write code utilizing recursion +In an imperative language, you might write a for loop that updates +a mutable variable. Or, you might write code utilizing recursion and a match clause. In Rust you can take another functional approach, computing the factorial elegantly with ranges and iterators.""" -# TRAITS - [[exercises]] -name = "traits1" -path = "exercises/traits/traits1.rs" +name = "iterators5" +path = "exercises/standard_library_types/iterators5.rs" mode = "test" hint = """ -A discussion about Traits in Rust can be found at: -https://doc.rust-lang.org/book/ch10-02-traits.html -""" +The documentation for the std::iter::Iterator trait contains numerous methods +that would be helpful here. -[[exercises]] -name = "traits2" -path = "exercises/traits/traits2.rs" -mode = "test" -hint = """ -Notice how the trait takes ownership of 'self',and returns `Self'. -Try mutating the incoming string vector. +Return 0 from count_collection_iterator to make the code compile in order to +test count_iterator. -Vectors provide suitable methods for adding an element at the end. See -the documentation at: https://doc.rust-lang.org/std/vec/struct.Vec.html""" +The collection variable in count_collection_iterator is a slice of HashMaps. It +needs to be converted into an iterator in order to use the iterator methods. -# Generics +The fold method can be useful in the count_collection_iterator function. -[[exercises]] -name = "generics1" -path = "exercises/generics/generics1.rs" -mode = "compile" -hint = """ -Vectors in rust make use of generics to create dynamically sized arrays of any type. -You need to tell the compiler what type we are pushing onto this vector.""" - -[[exercises]] -name = "generics2" -path = "exercises/generics/generics2.rs" -mode = "test" -hint = """ -Currently we are wrapping only values of type 'u32'. -Maybe we could update the explicit references to this data type somehow? - -If you are still stuck https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-method-definitions -""" - -[[exercises]] -name = "generics3" -path = "exercises/generics/generics3.rs" -mode = "test" -hint = """ -To find the best solution to this challenge you're going to need to think back to your -knowledge of traits, specifically Trait Bound Syntax - you may also need this: "use std::fmt::Display;" - -This is definitely harder than the last two exercises! You need to think about not only making the -ReportCard struct generic, but also the correct property - you will need to change the implementation -of the struct slightly too...you can do it! -""" +For a further challenge, consult the documentation for Iterator to find +a different method that could make your code more compact than using fold.""" # THREADS @@ -782,12 +850,86 @@ If you've learned from the sample solutions, I encourage you to come back to this exercise and try it again in a few days to reinforce what you've learned :)""" +# MACROS + +[[exercises]] +name = "macros1" +path = "exercises/macros/macros1.rs" +mode = "compile" +hint = """ +When you call a macro, you need to add something special compared to a +regular function call. If you're stuck, take a look at what's inside +`my_macro`.""" + +[[exercises]] +name = "macros2" +path = "exercises/macros/macros2.rs" +mode = "compile" +hint = """ +Macros don't quite play by the same rules as the rest of Rust, in terms of +what's available where. + +Unlike other things in Rust, the order of "where you define a macro" versus +"where you use it" actually matters.""" + +[[exercises]] +name = "macros3" +path = "exercises/macros/macros3.rs" +mode = "compile" +hint = """ +In order to use a macro outside of its module, you need to do something +special to the module to lift the macro out into its parent. + +The same trick also works on "extern crate" statements for crates that have +exported macros, if you've seen any of those around.""" + +[[exercises]] +name = "macros4" +path = "exercises/macros/macros4.rs" +mode = "compile" +hint = """ +You only need to add a single character to make this compile. +The way macros are written, it wants to see something between each +"macro arm", so it can separate them.""" + +# TEST 4 + +[[exercises]] +name = "quiz4" +path = "exercises/quiz4.rs" +mode = "test" +hint = "No hints this time ;)" + +# CLIPPY + +[[exercises]] +name = "clippy1" +path = "exercises/clippy/clippy1.rs" +mode = "clippy" +hint = """ +Not every floating point value can be represented exactly in binary values in +memory. Take a look at the description of +https://doc.rust-lang.org/stable/std/primitive.f32.html +When using the binary compare operators with floating points you won't compare +the floating point values but the binary representation in memory. This is +usually not what you would like to do. +See the suggestions of the clippy warning in compile output and use the +machine epsilon value... +https://doc.rust-lang.org/stable/std/primitive.f32.html#associatedconstant.EPSILON""" + +[[exercises]] +name = "clippy2" +path = "exercises/clippy/clippy2.rs" +mode = "clippy" +hint = """ +`for` loops over Option values are more clearly expressed as an `if let`""" + # TYPE CONVERSIONS [[exercises]] name = "using_as" path = "exercises/conversions/using_as.rs" -mode = "compile" +mode = "test" hint = """ Use the `as` operator to cast one of the operands in the last line of the `average` function into the expected return type.""" @@ -799,13 +941,48 @@ mode = "test" hint = """ Follow the steps provided right before the `From` implementation""" +[[exercises]] +name = "from_str" +path = "exercises/conversions/from_str.rs" +mode = "test" +hint = """ +The implementation of FromStr should return an Ok with a Person object, +or an Err with an error if the string is not valid. + +This is almost like the `from_into` exercise, but returning errors instead +of falling back to a default value. + +Hint: Look at the test cases to see which error variants to return. + +Another hint: You can use the `map_err` method of `Result` with a function +or a closure to wrap the error from `parse::`. + +Yet another hint: If you would like to propagate errors by using the `?` +operator in your solution, you might want to look at +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html +""" + [[exercises]] name = "try_from_into" path = "exercises/conversions/try_from_into.rs" mode = "test" hint = """ Follow the steps provided right before the `TryFrom` implementation. -You can also use the example at https://doc.rust-lang.org/std/convert/trait.TryFrom.html""" +You can also use the example at https://doc.rust-lang.org/std/convert/trait.TryFrom.html + +Hint: Is there an implementation of `TryFrom` in the standard library that +can both do the required integer conversion and check the range of the input? + +Another hint: Look at the test cases to see which error variants to return. + +Yet another hint: You can use the `map_err` or `or` methods of `Result` to +convert errors. + +Yet another hint: If you would like to propagate errors by using the `?` +operator in your solution, you might want to look at +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html + +Challenge: Can you make the `TryFrom` implementations generic over many integer types?""" [[exercises]] name = "as_ref_mut" @@ -814,11 +991,54 @@ mode = "test" hint = """ Add AsRef as a trait bound to the functions.""" +# ADVANCED ERRORS + [[exercises]] -name = "from_str" -path = "exercises/conversions/from_str.rs" +name = "advanced_errs1" +path = "exercises/advanced_errors/advanced_errs1.rs" mode = "test" hint = """ -The implementation of FromStr should return an Ok with a Person object, -or an Err with a string if the string is not valid. -This is almost like the `try_from_into` exercise.""" +This exercise uses an updated version of the code in errors6. The parsing +code is now in an implementation of the `FromStr` trait. Note that the +parsing code uses `?` directly, without any calls to `map_err()`. There is +one partial implementation of the `From` trait example that you should +complete. + +Details: The `?` operator calls `From::from()` on the error type to convert +it to the error type of the return type of the surrounding function. + +Hint: You will need to write another implementation of `From` that has a +different input type. +""" + +[[exercises]] +name = "advanced_errs2" +path = "exercises/advanced_errors/advanced_errs2.rs" +mode = "test" +hint = """ +This exercise demonstrates a few traits that are useful for custom error +types to implement. These traits make it easier for other code to consume +the custom error type. + +Follow the steps in the comment near the top of the file. You will have to +supply a missing trait implementation, and complete a few incomplete ones. + +You may find these pages to be helpful references: +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/define_error_type.html +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/boxing_errors.html +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/wrap_error.html + +Hint: What trait must our error type have for `main()` to return the return +type that it returns? + +Another hint: It's not necessary to implement any methods inside the missing +trait. (Some methods have default implementations that are supplied by the +trait.) + +Another hint: Consult the tests to determine which error variants (and which +error message text) to produce for certain error conditions. + +Challenge: There is one test that is marked `#[ignore]`. Can you supply the +missing code that will make it pass? You may want to consult the standard +library documentation for a certain trait for more hints. +""" diff --git a/install.ps1 b/install.ps1 index 6504e69e..32167f06 100644 --- a/install.ps1 +++ b/install.ps1 @@ -35,7 +35,7 @@ if (Get-Command cargo -ErrorAction SilentlyContinue) { function vercomp($v1, $v2) { if ($v1 -eq $v2) { return 0 - } + } $v1 = $v1.Replace(".", "0") $v2 = $v2.Replace(".", "0") @@ -53,7 +53,7 @@ function vercomp($v1, $v2) { } $rustVersion = $(rustc --version).Split(" ")[1] -$minRustVersion = "1.31" +$minRustVersion = "1.39" if ((vercomp $rustVersion $minRustVersion) -eq 2) { Write-Host "WARNING: Rust version is too old: $rustVersion - needs at least $minRustVersion" Write-Host "Please update Rust with 'rustup update'" diff --git a/install.sh b/install.sh index c32f5126..e986e741 100755 --- a/install.sh +++ b/install.sh @@ -87,7 +87,7 @@ function vercomp() { } RustVersion=$(rustc --version | cut -d " " -f 2) -MinRustVersion=1.31 +MinRustVersion=1.39 vercomp $RustVersion $MinRustVersion if [ $? -eq 2 ] then @@ -115,8 +115,8 @@ then if [[ -z ${Version} ]] then echo "No valid tag version found" - echo "Rustlings will be installed using the master branch" - Version="master" + echo "Rustlings will be installed using the main branch" + Version="main" else Version="tags/${Version}" fi diff --git a/src/exercise.rs b/src/exercise.rs index 177b7f38..ec694df9 100644 --- a/src/exercise.rs +++ b/src/exercise.rs @@ -1,5 +1,6 @@ use regex::Regex; use serde::Deserialize; +use std::env; use std::fmt::{self, Display, Formatter}; use std::fs::{self, remove_file, File}; use std::io::Read; @@ -11,14 +12,19 @@ const I_AM_DONE_REGEX: &str = r"(?m)^\s*///?\s*I\s+AM\s+NOT\s+DONE"; const CONTEXT: usize = 2; const CLIPPY_CARGO_TOML_PATH: &str = "./exercises/clippy/Cargo.toml"; -// Get a temporary file name that is hopefully unique to this process +// Get a temporary file name that is hopefully unique #[inline] fn temp_file() -> String { - format!("./temp_{}", process::id()) + let thread_id: String = format!("{:?}", std::thread::current().id()) + .chars() + .filter(|c| c.is_alphanumeric()) + .collect(); + + format!("./temp_{}_{}", process::id(), thread_id) } // The mode of the exercise. -#[derive(Deserialize, Copy, Clone)] +#[derive(Deserialize, Copy, Clone, Debug)] #[serde(rename_all = "lowercase")] pub enum Mode { // Indicates that the exercise should be compiled as a binary @@ -36,7 +42,7 @@ pub struct ExerciseList { // A representation of a rustlings exercise. // This is deserialized from the accompanying info.toml file -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] pub struct Exercise { // Name of the exercise pub name: String, @@ -121,9 +127,13 @@ name = "{}" path = "{}.rs""#, self.name, self.name, self.name ); - fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml) - .expect("Failed to write πŸ“Ž Clippy πŸ“Ž Cargo.toml file."); - // To support the ability to run the clipy exercises, build + let cargo_toml_error_msg = if env::var("NO_EMOJI").is_ok() { + "Failed to write Clippy Cargo.toml file." + } else { + "Failed to write πŸ“Ž Clippy πŸ“Ž Cargo.toml file." + }; + fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml).expect(cargo_toml_error_msg); + // To support the ability to run the clippy exercises, build // an executable, in addition to running clippy. With a // compilation failure, this would silently fail. But we expect // clippy to reflect the same failure while compiling later. @@ -134,7 +144,7 @@ path = "{}.rs""#, .expect("Failed to compile!"); // Due to an issue with Clippy, a cargo clean is required to catch all lints. // See https://github.com/rust-lang/rust-clippy/issues/2604 - // This is already fixed on master branch. See this issue to track merging into Cargo: + // This is already fixed on Clippy's master branch. See this issue to track merging into Cargo: // https://github.com/rust-lang/rust-clippy/issues/3837 Command::new("cargo") .args(&["clean", "--manifest-path", CLIPPY_CARGO_TOML_PATH]) @@ -152,7 +162,7 @@ path = "{}.rs""#, if cmd.status.success() { Ok(CompiledExercise { - exercise: &self, + exercise: self, _handle: FileHandle, }) } else { @@ -167,9 +177,10 @@ path = "{}.rs""#, fn run(&self) -> Result { let arg = match self.mode { Mode::Test => "--show-output", - _ => "" + _ => "", }; - let cmd = Command::new(&temp_file()).arg(arg) + let cmd = Command::new(&temp_file()) + .arg(arg) .output() .expect("Failed to run 'run' command"); @@ -226,6 +237,16 @@ path = "{}.rs""#, State::Pending(context) } + + // Check that the exercise looks to be solved using self.state() + // This is not the best way to check since + // the user can just remove the "I AM NOT DONE" string from the file + // without actually having solved anything. + // The only other way to truly check this would to compile and run + // the exercise; which would be both costly and counterintuitive + pub fn looks_done(&self) -> bool { + self.state() == State::Done + } } impl Display for Exercise { @@ -314,7 +335,7 @@ mod test { #[test] fn test_exercise_with_output() { let exercise = Exercise { - name: "finished_exercise".into(), + name: "exercise_with_output".into(), path: PathBuf::from("tests/fixture/success/testSuccess.rs"), mode: Mode::Test, hint: String::new(), diff --git a/src/main.rs b/src/main.rs index 9c64de2b..32e7bba2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,17 @@ use crate::exercise::{Exercise, ExerciseList}; use crate::run::run; use crate::verify::verify; -use clap::{crate_version, App, Arg, SubCommand}; +use argh::FromArgs; use console::Emoji; use notify::DebouncedEvent; use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use std::ffi::OsStr; use std::fs; -use std::io; +use std::io::{self, prelude::*}; use std::path::Path; use std::process::{Command, Stdio}; -use std::sync::mpsc::channel; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{channel, RecvTimeoutError}; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; @@ -22,41 +23,91 @@ mod exercise; mod run; mod verify; -fn main() { - let matches = App::new("rustlings") - .version(crate_version!()) - .author("Olivia Hugger, Carol Nichols") - .about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code") - .arg( - Arg::with_name("nocapture") - .long("nocapture") - .help("Show outputs from the test exercises") - ) - .subcommand( - SubCommand::with_name("verify") - .alias("v") - .about("Verifies all exercises according to the recommended order") - ) - .subcommand( - SubCommand::with_name("watch") - .alias("w") - .about("Reruns `verify` when files were edited") - ) - .subcommand( - SubCommand::with_name("run") - .alias("r") - .about("Runs/Tests a single exercise") - .arg(Arg::with_name("name").required(true).index(1)), - ) - .subcommand( - SubCommand::with_name("hint") - .alias("h") - .about("Returns a hint for the current exercise") - .arg(Arg::with_name("name").required(true).index(1)), - ) - .get_matches(); +// In sync with crate version +const VERSION: &str = "4.6.0"; - if matches.subcommand_name().is_none() { +#[derive(FromArgs, PartialEq, Debug)] +/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code +struct Args { + /// show outputs from the test exercises + #[argh(switch)] + nocapture: bool, + /// show the executable version + #[argh(switch, short = 'v')] + version: bool, + #[argh(subcommand)] + nested: Option, +} + +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand)] +enum Subcommands { + Verify(VerifyArgs), + Watch(WatchArgs), + Run(RunArgs), + Hint(HintArgs), + List(ListArgs), +} + +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "verify")] +/// Verifies all exercises according to the recommended order +struct VerifyArgs {} + +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "watch")] +/// Reruns `verify` when files were edited +struct WatchArgs {} + +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "run")] +/// Runs/Tests a single exercise +struct RunArgs { + #[argh(positional)] + /// the name of the exercise + name: String, +} + +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "hint")] +/// Returns a hint for the given exercise +struct HintArgs { + #[argh(positional)] + /// the name of the exercise + name: String, +} + +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "list")] +/// Lists the exercises available in Rustlings +struct ListArgs { + #[argh(switch, short = 'p')] + /// show only the paths of the exercises + paths: bool, + #[argh(switch, short = 'n')] + /// show only the names of the exercises + names: bool, + #[argh(option, short = 'f')] + /// provide a string to match exercise names + /// comma separated patterns are acceptable + filter: Option, + #[argh(switch, short = 'u')] + /// display only exercises not yet solved + unsolved: bool, + #[argh(switch, short = 's')] + /// display only exercises that have been solved + solved: bool, +} + +fn main() { + let args: Args = argh::from_env(); + + if args.version { + println!("v{}", VERSION); + std::process::exit(0); + } + + if args.nested.is_none() { println!(); println!(r#" welcome to... "#); println!(r#" _ _ _ "#); @@ -86,72 +137,169 @@ fn main() { let toml_str = &fs::read_to_string("info.toml").unwrap(); let exercises = toml::from_str::(toml_str).unwrap().exercises; - let verbose = matches.is_present("nocapture"); + let verbose = args.nocapture; - if let Some(ref matches) = matches.subcommand_matches("run") { - let name = matches.value_of("name").unwrap(); - - let matching_exercise = |e: &&Exercise| name == e.name; - - let exercise = exercises.iter().find(matching_exercise).unwrap_or_else(|| { - println!("No exercise found for your given name!"); - std::process::exit(1) - }); - - run(&exercise, verbose).unwrap_or_else(|_| std::process::exit(1)); - } - - if let Some(ref matches) = matches.subcommand_matches("hint") { - let name = matches.value_of("name").unwrap(); - - let exercise = exercises - .iter() - .find(|e| name == e.name) - .unwrap_or_else(|| { - println!("No exercise found for your given name!"); - std::process::exit(1) - }); - - println!("{}", exercise.hint); - } - - if matches.subcommand_matches("verify").is_some() { - verify(&exercises, verbose).unwrap_or_else(|_| std::process::exit(1)); - } - - if matches.subcommand_matches("watch").is_some() && watch(&exercises, verbose).is_ok() { - println!( - "{emoji} All exercises completed! {emoji}", - emoji = Emoji("πŸŽ‰", "β˜…") - ); - println!(); - println!("We hope you enjoyed learning about the various aspects of Rust!"); - println!( - "If you noticed any issues, please don't hesitate to report them to our repo." - ); - println!("You can also contribute your own exercises to help the greater community!"); - println!(); - println!("Before reporting an issue or contributing, please read our guidelines:"); - println!("https://github.com/rust-lang/rustlings/blob/master/CONTRIBUTING.md"); - } - - if matches.subcommand_name().is_none() { + let command = args.nested.unwrap_or_else(|| { let text = fs::read_to_string("default_out.txt").unwrap(); println!("{}", text); + std::process::exit(0); + }); + match command { + Subcommands::List(subargs) => { + if !subargs.paths && !subargs.names { + println!("{:<17}\t{:<46}\t{:<7}", "Name", "Path", "Status"); + } + let mut exercises_done: u16 = 0; + let filters = subargs.filter.clone().unwrap_or_default().to_lowercase(); + exercises.iter().for_each(|e| { + let fname = format!("{}", e.path.display()); + let filter_cond = filters + .split(',') + .filter(|f| !f.trim().is_empty()) + .any(|f| e.name.contains(&f) || fname.contains(&f)); + let status = if e.looks_done() { + exercises_done += 1; + "Done" + } else { + "Pending" + }; + let solve_cond = { + (e.looks_done() && subargs.solved) + || (!e.looks_done() && subargs.unsolved) + || (!subargs.solved && !subargs.unsolved) + }; + if solve_cond && (filter_cond || subargs.filter.is_none()) { + let line = if subargs.paths { + format!("{}\n", fname) + } else if subargs.names { + format!("{}\n", e.name) + } else { + format!("{:<17}\t{:<46}\t{:<7}\n", e.name, fname, status) + }; + // Somehow using println! leads to the binary panicking + // when its output is piped. + // So, we're handling a Broken Pipe error and exiting with 0 anyway + let stdout = std::io::stdout(); + { + let mut handle = stdout.lock(); + handle.write_all(line.as_bytes()).unwrap_or_else(|e| { + match e.kind() { + std::io::ErrorKind::BrokenPipe => std::process::exit(0), + _ => std::process::exit(1), + }; + }); + } + } + }); + let percentage_progress = exercises_done as f32 / exercises.len() as f32 * 100.0; + println!( + "Progress: You completed {} / {} exercises ({:.2} %).", + exercises_done, + exercises.len(), + percentage_progress + ); + std::process::exit(0); + } + + Subcommands::Run(subargs) => { + let exercise = find_exercise(&subargs.name, &exercises); + + run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1)); + } + + Subcommands::Hint(subargs) => { + let exercise = find_exercise(&subargs.name, &exercises); + + println!("{}", exercise.hint); + } + + Subcommands::Verify(_subargs) => { + verify(&exercises, verbose).unwrap_or_else(|_| std::process::exit(1)); + } + + Subcommands::Watch(_subargs) => match watch(&exercises, verbose) { + Err(e) => { + println!( + "Error: Could not watch your progress. Error message was {:?}.", + e + ); + println!("Most likely you've run out of disk space or your 'inotify limit' has been reached."); + std::process::exit(1); + } + Ok(WatchStatus::Finished) => { + println!( + "{emoji} All exercises completed! {emoji}", + emoji = Emoji("πŸŽ‰", "β˜…") + ); + println!(); + println!("+----------------------------------------------------+"); + println!("| You made it to the Fe-nish line! |"); + println!("+-------------------------- ------------------------+"); + println!(" \\/ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–’β–’ "); + println!(" β–’β–’β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–’β–’ "); + println!(" β–‘β–‘β–’β–’β–’β–’β–‘β–‘β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’β–‘β–‘β–’β–’β–’β–’ "); + println!(" β–“β–“β–“β–“β–“β–“β–“β–“ β–“β–“ β–“β–“β–ˆβ–ˆ β–“β–“ β–“β–“β–ˆβ–ˆ β–“β–“ β–“β–“β–“β–“β–“β–“β–“β–“ "); + println!(" β–’β–’β–’β–’ β–’β–’ β–ˆβ–ˆβ–ˆβ–ˆ β–’β–’ β–ˆβ–ˆβ–ˆβ–ˆ β–’β–’β–‘β–‘ β–’β–’β–’β–’ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–“β–“β–“β–“β–“β–“β–’β–’β–’β–’β–’β–’β–’β–’β–“β–“β–’β–’β–“β–“β–’β–’β–’β–’β–’β–’β–’β–’ "); + println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ "); + println!(" β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’ β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’ β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ β–’β–’ "); + println!(" β–’β–’ β–’β–’ β–’β–’ β–’β–’ "); + println!(); + println!("We hope you enjoyed learning about the various aspects of Rust!"); + println!( + "If you noticed any issues, please don't hesitate to report them to our repo." + ); + println!( + "You can also contribute your own exercises to help the greater community!" + ); + println!(); + println!("Before reporting an issue or contributing, please read our guidelines:"); + println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md"); + } + Ok(WatchStatus::Unfinished) => { + println!("We hope you're enjoying learning about Rust!"); + println!("If you want to continue working on the exercises at a later point, you can simply run `rustlings watch` again"); + } + }, } } -fn spawn_watch_shell(failed_exercise_hint: &Arc>>) { +fn spawn_watch_shell( + failed_exercise_hint: &Arc>>, + should_quit: Arc, +) { let failed_exercise_hint = Arc::clone(failed_exercise_hint); - println!("Type 'hint' to get help"); + println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here."); thread::spawn(move || loop { let mut input = String::new(); match io::stdin().read_line(&mut input) { Ok(_) => { - if input.trim().eq("hint") { + let input = input.trim(); + if input == "hint" { if let Some(hint) = &*failed_exercise_hint.lock().unwrap() { println!("{}", hint); } + } else if input == "clear" { + println!("\x1B[2J\x1B[1;1H"); + } else if input.eq("quit") { + should_quit.store(true, Ordering::SeqCst); + println!("Bye!"); + } else if input.eq("help") { + println!("Commands available to you in watch mode:"); + println!(" hint - prints the current exercise's hint"); + println!(" clear - clears the screen"); + println!(" quit - quits watch mode"); + println!(" help - displays this help message"); + println!(); + println!("Watch mode automatically re-evaluates the current exercise"); + println!("when you edit a file's contents.") } else { println!("unknown command: {}", input); } @@ -161,7 +309,33 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc>>) { }); } -fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> { +fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise { + if name.eq("next") { + exercises + .iter() + .find(|e| !e.looks_done()) + .unwrap_or_else(|| { + println!("πŸŽ‰ Congratulations! You have done all the exercises!"); + println!("πŸ”š There are no more exercises to do next!"); + std::process::exit(1) + }) + } else { + exercises + .iter() + .find(|e| e.name == name) + .unwrap_or_else(|| { + println!("No exercise found for '{}'!", name); + std::process::exit(1) + }) + } +} + +enum WatchStatus { + Finished, + Unfinished, +} + +fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result { /* Clears the terminal with an ANSI escape code. Works in UNIX and newer Windows terminals. */ fn clear_screen() { @@ -169,6 +343,7 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> { } let (tx, rx) = channel(); + let should_quit = Arc::new(AtomicBool::new(false)); let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?; watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?; @@ -177,22 +352,28 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> { let to_owned_hint = |t: &Exercise| t.hint.to_owned(); let failed_exercise_hint = match verify(exercises.iter(), verbose) { - Ok(_) => return Ok(()), + Ok(_) => return Ok(WatchStatus::Finished), Err(exercise) => Arc::new(Mutex::new(Some(to_owned_hint(exercise)))), }; - spawn_watch_shell(&failed_exercise_hint); + spawn_watch_shell(&failed_exercise_hint, Arc::clone(&should_quit)); loop { - match rx.recv() { + match rx.recv_timeout(Duration::from_secs(1)) { Ok(event) => match event { DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => { if b.extension() == Some(OsStr::new("rs")) && b.exists() { let filepath = b.as_path().canonicalize().unwrap(); let pending_exercises = exercises .iter() - .skip_while(|e| !filepath.ends_with(&e.path)); + .skip_while(|e| !filepath.ends_with(&e.path)) + // .filter(|e| filepath.ends_with(&e.path)) + .chain( + exercises + .iter() + .filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)), + ); clear_screen(); match verify(pending_exercises, verbose) { - Ok(_) => return Ok(()), + Ok(_) => return Ok(WatchStatus::Finished), Err(exercise) => { let mut failed_exercise_hint = failed_exercise_hint.lock().unwrap(); *failed_exercise_hint = Some(to_owned_hint(exercise)); @@ -202,8 +383,15 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> { } _ => {} }, + Err(RecvTimeoutError::Timeout) => { + // the timeout expired, just check the `should_quit` variable below then loop again + } Err(e) => println!("watch error: {:?}", e), } + // Check if we need to exit + if should_quit.load(Ordering::SeqCst) { + return Ok(WatchStatus::Unfinished); + } } } diff --git a/src/ui.rs b/src/ui.rs index 38cbaa40..1ee46316 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,23 +1,33 @@ macro_rules! warn { ($fmt:literal, $ex:expr) => {{ use console::{style, Emoji}; + use std::env; let formatstr = format!($fmt, $ex); - println!( - "{} {}", - style(Emoji("⚠️ ", "!")).red(), - style(formatstr).red() - ); + if env::var("NO_EMOJI").is_ok() { + println!("{} {}", style("!").red(), style(formatstr).red()); + } else { + println!( + "{} {}", + style(Emoji("⚠️ ", "!")).red(), + style(formatstr).red() + ); + } }}; } macro_rules! success { ($fmt:literal, $ex:expr) => {{ use console::{style, Emoji}; + use std::env; let formatstr = format!($fmt, $ex); - println!( - "{} {}", - style(Emoji("βœ…", "βœ“")).green(), - style(formatstr).green() - ); + if env::var("NO_EMOJI").is_ok() { + println!("{} {}", style("βœ“").green(), style(formatstr).green()); + } else { + println!( + "{} {}", + style(Emoji("βœ…", "βœ“")).green(), + style(formatstr).green() + ); + } }}; } diff --git a/src/verify.rs b/src/verify.rs index 807bea9e..fd59fa51 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -1,6 +1,7 @@ use crate::exercise::{CompiledExercise, Exercise, Mode, State}; use console::style; use indicatif::ProgressBar; +use std::env; // Verify that the provided container of Exercise objects // can be compiled and run without any failures. @@ -9,13 +10,13 @@ use indicatif::ProgressBar; // determines whether or not the test harness outputs are displayed. pub fn verify<'a>( start_at: impl IntoIterator, - verbose: bool + verbose: bool, ) -> Result<(), &'a Exercise> { for exercise in start_at { let compile_result = match exercise.mode { - Mode::Test => compile_and_test(&exercise, RunMode::Interactive, verbose), - Mode::Compile => compile_and_run_interactively(&exercise), - Mode::Clippy => compile_only(&exercise), + Mode::Test => compile_and_test(exercise, RunMode::Interactive, verbose), + Mode::Compile => compile_and_run_interactively(exercise), + Mode::Clippy => compile_only(exercise), }; if !compile_result.unwrap_or(false) { return Err(exercise); @@ -41,11 +42,11 @@ fn compile_only(exercise: &Exercise) -> Result { progress_bar.set_message(format!("Compiling {}...", exercise).as_str()); progress_bar.enable_steady_tick(100); - let _ = compile(&exercise, &progress_bar)?; + let _ = compile(exercise, &progress_bar)?; progress_bar.finish_and_clear(); success!("Successfully compiled {}!", exercise); - Ok(prompt_for_completion(&exercise, None)) + Ok(prompt_for_completion(exercise, None)) } // Compile the given Exercise and run the resulting binary in an interactive mode @@ -54,7 +55,7 @@ fn compile_and_run_interactively(exercise: &Exercise) -> Result { progress_bar.set_message(format!("Compiling {}...", exercise).as_str()); progress_bar.enable_steady_tick(100); - let compilation = compile(&exercise, &progress_bar)?; + let compilation = compile(exercise, &progress_bar)?; progress_bar.set_message(format!("Running {}...", exercise).as_str()); let result = compilation.run(); @@ -72,14 +73,12 @@ fn compile_and_run_interactively(exercise: &Exercise) -> Result { success!("Successfully ran {}!", exercise); - Ok(prompt_for_completion(&exercise, Some(output.stdout))) + Ok(prompt_for_completion(exercise, Some(output.stdout))) } // Compile the given Exercise as a test harness and display // the output if verbose is set to true -fn compile_and_test( - exercise: &Exercise, run_mode: RunMode, verbose: bool -) -> Result { +fn compile_and_test(exercise: &Exercise, run_mode: RunMode, verbose: bool) -> Result { let progress_bar = ProgressBar::new_spinner(); progress_bar.set_message(format!("Testing {}...", exercise).as_str()); progress_bar.enable_steady_tick(100); @@ -95,7 +94,7 @@ fn compile_and_test( } success!("Successfully tested {}", &exercise); if let RunMode::Interactive = run_mode { - Ok(prompt_for_completion(&exercise, None)) + Ok(prompt_for_completion(exercise, None)) } else { Ok(true) } @@ -139,14 +138,26 @@ fn prompt_for_completion(exercise: &Exercise, prompt_output: Option) -> State::Pending(context) => context, }; + let no_emoji = env::var("NO_EMOJI").is_ok(); + + let clippy_success_msg = if no_emoji { + "The code is compiling, and Clippy is happy!" + } else { + "The code is compiling, and πŸ“Ž Clippy πŸ“Ž is happy!" + }; + let success_msg = match exercise.mode { Mode::Compile => "The code is compiling!", Mode::Test => "The code is compiling, and the tests pass!", - Mode::Clippy => "The code is compiling, and πŸ“Ž Clippy πŸ“Ž is happy!", + Mode::Clippy => clippy_success_msg, }; println!(); - println!("πŸŽ‰ πŸŽ‰ {} πŸŽ‰ πŸŽ‰", success_msg); + if no_emoji { + println!("~*~ {} ~*~", success_msg) + } else { + println!("πŸŽ‰ πŸŽ‰ {} πŸŽ‰ πŸŽ‰", success_msg) + } println!(); if let Some(output) = prompt_output { diff --git a/tests/fixture/state/info.toml b/tests/fixture/state/info.toml index 7bfc697e..547b3a48 100644 --- a/tests/fixture/state/info.toml +++ b/tests/fixture/state/info.toml @@ -9,3 +9,10 @@ name = "pending_test_exercise" path = "pending_test_exercise.rs" mode = "test" hint = """""" + +[[exercises]] +name = "finished_exercise" +path = "finished_exercise.rs" +mode = "compile" +hint = """""" + diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 0f49b5a8..be9af965 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -24,7 +24,7 @@ fn fails_when_in_wrong_dir() { fn verify_all_success() { Command::cargo_bin("rustlings") .unwrap() - .arg("v") + .arg("verify") .current_dir("tests/fixture/success") .assert() .success(); @@ -34,7 +34,7 @@ fn verify_all_success() { fn verify_fails_if_some_fails() { Command::cargo_bin("rustlings") .unwrap() - .arg("v") + .arg("verify") .current_dir("tests/fixture/failure") .assert() .code(1); @@ -44,7 +44,7 @@ fn verify_fails_if_some_fails() { fn run_single_compile_success() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "compSuccess"]) + .args(&["run", "compSuccess"]) .current_dir("tests/fixture/success/") .assert() .success(); @@ -54,7 +54,7 @@ fn run_single_compile_success() { fn run_single_compile_failure() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "compFailure"]) + .args(&["run", "compFailure"]) .current_dir("tests/fixture/failure/") .assert() .code(1); @@ -64,7 +64,7 @@ fn run_single_compile_failure() { fn run_single_test_success() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "testSuccess"]) + .args(&["run", "testSuccess"]) .current_dir("tests/fixture/success/") .assert() .success(); @@ -74,7 +74,7 @@ fn run_single_test_success() { fn run_single_test_failure() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "testFailure"]) + .args(&["run", "testFailure"]) .current_dir("tests/fixture/failure/") .assert() .code(1); @@ -84,7 +84,7 @@ fn run_single_test_failure() { fn run_single_test_not_passed() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "testNotPassed.rs"]) + .args(&["run", "testNotPassed.rs"]) .current_dir("tests/fixture/failure/") .assert() .code(1); @@ -94,7 +94,7 @@ fn run_single_test_not_passed() { fn run_single_test_no_filename() { Command::cargo_bin("rustlings") .unwrap() - .arg("r") + .arg("run") .current_dir("tests/fixture/") .assert() .code(1); @@ -104,7 +104,7 @@ fn run_single_test_no_filename() { fn run_single_test_no_exercise() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "compNoExercise.rs"]) + .args(&["run", "compNoExercise.rs"]) .current_dir("tests/fixture/failure") .assert() .code(1); @@ -114,7 +114,7 @@ fn run_single_test_no_exercise() { fn get_hint_for_single_test() { Command::cargo_bin("rustlings") .unwrap() - .args(&["h", "testFailure"]) + .args(&["hint", "testFailure"]) .current_dir("tests/fixture/failure") .assert() .code(0) @@ -131,10 +131,15 @@ fn all_exercises_require_confirmation() { file.read_to_string(&mut s).unwrap(); s }; - source.matches("// I AM NOT DONE").next().expect(&format!( - "There should be an `I AM NOT DONE` annotation in {:?}", - path - )); + source + .matches("// I AM NOT DONE") + .next() + .unwrap_or_else(|| { + panic!( + "There should be an `I AM NOT DONE` annotation in {:?}", + path + ) + }); } } @@ -142,7 +147,7 @@ fn all_exercises_require_confirmation() { fn run_compile_exercise_does_not_prompt() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "pending_exercise"]) + .args(&["run", "pending_exercise"]) .current_dir("tests/fixture/state") .assert() .code(0) @@ -153,7 +158,7 @@ fn run_compile_exercise_does_not_prompt() { fn run_test_exercise_does_not_prompt() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "pending_test_exercise"]) + .args(&["run", "pending_test_exercise"]) .current_dir("tests/fixture/state") .assert() .code(0) @@ -164,7 +169,7 @@ fn run_test_exercise_does_not_prompt() { fn run_single_test_success_with_output() { Command::cargo_bin("rustlings") .unwrap() - .args(&["--nocapture", "r", "testSuccess"]) + .args(&["--nocapture", "run", "testSuccess"]) .current_dir("tests/fixture/success/") .assert() .code(0) @@ -175,9 +180,63 @@ fn run_single_test_success_with_output() { fn run_single_test_success_without_output() { Command::cargo_bin("rustlings") .unwrap() - .args(&["r", "testSuccess"]) + .args(&["run", "testSuccess"]) .current_dir("tests/fixture/success/") .assert() .code(0) .stdout(predicates::str::contains("THIS TEST TOO SHALL PAS").not()); -} \ No newline at end of file +} + +#[test] +fn run_rustlings_list() { + Command::cargo_bin("rustlings") + .unwrap() + .args(&["list"]) + .current_dir("tests/fixture/success") + .assert() + .success(); +} + +#[test] +fn run_rustlings_list_no_pending() { + Command::cargo_bin("rustlings") + .unwrap() + .args(&["list"]) + .current_dir("tests/fixture/success") + .assert() + .success() + .stdout(predicates::str::contains("Pending").not()); +} + +#[test] +fn run_rustlings_list_both_done_and_pending() { + Command::cargo_bin("rustlings") + .unwrap() + .args(&["list"]) + .current_dir("tests/fixture/state") + .assert() + .success() + .stdout(predicates::str::contains("Done").and(predicates::str::contains("Pending"))); +} + +#[test] +fn run_rustlings_list_without_pending() { + Command::cargo_bin("rustlings") + .unwrap() + .args(&["list", "--solved"]) + .current_dir("tests/fixture/state") + .assert() + .success() + .stdout(predicates::str::contains("Pending").not()); +} + +#[test] +fn run_rustlings_list_without_done() { + Command::cargo_bin("rustlings") + .unwrap() + .args(&["list", "--unsolved"]) + .current_dir("tests/fixture/state") + .assert() + .success() + .stdout(predicates::str::contains("Done").not()); +}