Chapter 3 to 6
authorGreg Burri <greg.burri@gmail.com>
Sat, 19 Oct 2024 21:48:23 +0000 (23:48 +0200)
committerGreg Burri <greg.burri@gmail.com>
Sat, 19 Oct 2024 21:48:23 +0000 (23:48 +0200)
71 files changed:
Cargo.lock
exercises/03_ticket_v1/00_intro/src/lib.rs
exercises/03_ticket_v1/01_struct/src/lib.rs
exercises/03_ticket_v1/02_validation/src/lib.rs
exercises/03_ticket_v1/03_modules/src/lib.rs
exercises/03_ticket_v1/04_visibility/src/lib.rs
exercises/03_ticket_v1/05_encapsulation/src/lib.rs
exercises/03_ticket_v1/06_ownership/src/lib.rs
exercises/03_ticket_v1/07_setters/src/lib.rs
exercises/03_ticket_v1/08_stack/src/lib.rs
exercises/03_ticket_v1/09_heap/src/lib.rs
exercises/03_ticket_v1/10_references_in_memory/src/lib.rs
exercises/03_ticket_v1/11_destructor/src/lib.rs
exercises/03_ticket_v1/12_outro/src/lib.rs
exercises/04_traits/00_intro/src/lib.rs
exercises/04_traits/01_trait/src/lib.rs
exercises/04_traits/02_orphan_rule/src/lib.rs
exercises/04_traits/03_operator_overloading/src/lib.rs
exercises/04_traits/04_derive/src/lib.rs
exercises/04_traits/05_trait_bounds/src/lib.rs
exercises/04_traits/06_str_slice/src/lib.rs
exercises/04_traits/07_deref/src/lib.rs
exercises/04_traits/08_sized/src/lib.rs
exercises/04_traits/09_from/src/lib.rs
exercises/04_traits/10_assoc_vs_generic/src/lib.rs
exercises/04_traits/11_clone/src/lib.rs
exercises/04_traits/12_copy/src/lib.rs
exercises/04_traits/13_drop/src/lib.rs
exercises/04_traits/14_outro/src/lib.rs
exercises/05_ticket_v2/00_intro/src/lib.rs
exercises/05_ticket_v2/01_enum/src/lib.rs
exercises/05_ticket_v2/02_match/src/lib.rs
exercises/05_ticket_v2/03_variants_with_data/src/lib.rs
exercises/05_ticket_v2/04_if_let/src/lib.rs
exercises/05_ticket_v2/05_nullability/src/lib.rs
exercises/05_ticket_v2/06_fallibility/src/lib.rs
exercises/05_ticket_v2/07_unwrap/src/lib.rs
exercises/05_ticket_v2/08_error_enums/src/lib.rs
exercises/05_ticket_v2/09_error_trait/src/lib.rs
exercises/05_ticket_v2/10_packages/src/lib.rs [new file with mode: 0644]
exercises/05_ticket_v2/11_dependencies/Cargo.toml
exercises/05_ticket_v2/12_thiserror/Cargo.toml
exercises/05_ticket_v2/12_thiserror/src/lib.rs
exercises/05_ticket_v2/13_try_from/src/lib.rs
exercises/05_ticket_v2/14_source/src/lib.rs
exercises/05_ticket_v2/15_outro/Cargo.toml
exercises/05_ticket_v2/15_outro/src/description.rs
exercises/05_ticket_v2/15_outro/src/status.rs
exercises/05_ticket_v2/15_outro/src/title.rs
exercises/06_ticket_management/00_intro/src/lib.rs
exercises/06_ticket_management/01_arrays/src/lib.rs
exercises/06_ticket_management/02_vec/Cargo.toml
exercises/06_ticket_management/02_vec/src/lib.rs
exercises/06_ticket_management/03_resizing/src/lib.rs
exercises/06_ticket_management/04_iterators/src/lib.rs
exercises/06_ticket_management/05_iter/src/lib.rs
exercises/06_ticket_management/06_lifetimes/src/lib.rs
exercises/06_ticket_management/07_combinators/src/lib.rs
exercises/06_ticket_management/08_impl_trait/src/lib.rs
exercises/06_ticket_management/09_impl_trait_2/src/lib.rs
exercises/06_ticket_management/10_slices/src/lib.rs
exercises/06_ticket_management/11_mutable_slices/src/lib.rs
exercises/06_ticket_management/12_two_states/src/lib.rs
exercises/06_ticket_management/13_index/src/lib.rs
exercises/06_ticket_management/14_index_mut/src/lib.rs
exercises/06_ticket_management/15_hashmap/src/lib.rs
exercises/06_ticket_management/16_btreemap/src/lib.rs
exercises/07_threads/00_intro/src/lib.rs
exercises/07_threads/01_threads/src/lib.rs
exercises/07_threads/02_static/src/lib.rs
exercises/07_threads/03_leak/src/lib.rs

index d560369..0dc0878 100644 (file)
@@ -4,18 +4,18 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.22.0"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
 dependencies = [
  "gimli",
 ]
 
 [[package]]
-name = "adler"
-version = "1.0.2"
+name = "adler2"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
 
 [[package]]
 name = "aho-corasick"
@@ -105,9 +105,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.86"
+version = "1.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
 
 [[package]]
 name = "arrays"
@@ -138,23 +138,23 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "backtrace"
-version = "0.3.73"
+version = "0.3.74"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
 dependencies = [
  "addr2line",
- "cc",
  "cfg-if",
  "libc",
  "miniz_oxide",
  "object",
  "rustc-demangle",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -240,9 +240,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
-version = "1.7.1"
+version = "1.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
+checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
 
 [[package]]
 name = "cancellation"
@@ -253,9 +253,12 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.1.7"
+version = "1.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
+checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
+dependencies = [
+ "shlex",
+]
 
 [[package]]
 name = "cfg-if"
@@ -284,9 +287,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.13"
+version = "4.5.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
+checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -294,9 +297,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.13"
+version = "4.5.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99"
+checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
 dependencies = [
  "anstream",
  "anstyle",
@@ -307,18 +310,18 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.12"
+version = "4.5.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8670053e87c316345e384ca1f3eba3006fc6355ed8b8a1140d104e109e3df34"
+checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb"
 dependencies = [
  "clap",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.5.13"
+version = "4.5.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -366,15 +369,15 @@ version = "0.1.0"
 
 [[package]]
 name = "core-foundation-sys"
-version = "0.8.6"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.12"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
+checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
 dependencies = [
  "libc",
 ]
@@ -443,6 +446,9 @@ dependencies = [
 [[package]]
 name = "deps"
 version = "0.1.0"
+dependencies = [
+ "anyhow",
+]
 
 [[package]]
 name = "deref"
@@ -566,20 +572,20 @@ dependencies = [
 
 [[package]]
 name = "fastrand"
-version = "2.1.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
+checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
 
 [[package]]
 name = "filetime"
-version = "0.2.23"
+version = "0.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
+checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall 0.4.1",
- "windows-sys 0.52.0",
+ "libredox",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -633,9 +639,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -643,15 +649,15 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -660,21 +666,21 @@ dependencies = [
 
 [[package]]
 name = "futures-sink"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
 
 [[package]]
 name = "futures-task"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
 
 [[package]]
 name = "futures-util"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
 dependencies = [
  "futures-core",
  "futures-macro",
@@ -717,15 +723,15 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.29.0"
+version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
 
 [[package]]
 name = "globset"
-version = "0.4.14"
+version = "0.4.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
+checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19"
 dependencies = [
  "aho-corasick",
  "bstr",
@@ -769,9 +775,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.14.5"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
 
 [[package]]
 name = "hashmap"
@@ -869,9 +875,9 @@ dependencies = [
 
 [[package]]
 name = "httparse"
-version = "1.9.4"
+version = "1.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
+checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
 
 [[package]]
 name = "httpdate"
@@ -887,9 +893,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
 name = "hyper"
-version = "0.14.30"
+version = "0.14.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9"
+checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -911,9 +917,9 @@ dependencies = [
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.60"
+version = "0.1.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
+checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -952,9 +958,9 @@ version = "0.1.0"
 
 [[package]]
 name = "ignore"
-version = "0.4.22"
+version = "0.4.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
+checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
 dependencies = [
  "crossbeam-deque",
  "globset",
@@ -996,9 +1002,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.3.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -1097,9 +1103,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "js-sys"
-version = "0.3.69"
+version = "0.3.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
+checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -1124,15 +1130,21 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
 [[package]]
 name = "leaking"
 version = "0.1.0"
 
 [[package]]
 name = "libc"
-version = "0.2.155"
+version = "0.2.159"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
 
 [[package]]
 name = "libdbus-sys"
@@ -1144,6 +1156,17 @@ dependencies = [
  "pkg-config",
 ]
 
+[[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags 2.6.0",
+ "libc",
+ "redox_syscall",
+]
+
 [[package]]
 name = "lifetime"
 version = "0.1.0"
@@ -1267,7 +1290,7 @@ dependencies = [
  "clap",
  "itertools",
  "mdbook",
- "pulldown-cmark 0.11.0",
+ "pulldown-cmark 0.11.3",
  "pulldown-cmark-to-cmark",
  "semver",
  "serde_json",
@@ -1297,11 +1320,11 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.4"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
+checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
 dependencies = [
- "adler",
+ "adler2",
 ]
 
 [[package]]
@@ -1318,9 +1341,9 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
+checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
 dependencies = [
  "hermit-abi",
  "libc",
@@ -1399,29 +1422,29 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.36.2"
+version = "0.36.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
+checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.19.0"
+version = "1.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
 [[package]]
 name = "opener"
-version = "0.7.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8df34be653210fbe9ffaff41d3b92721c56ce82dfee58ee684f9afb5e3a90c0"
+checksum = "d0812e5e4df08da354c851a3376fead46db31c2214f849d3de356d774d057681"
 dependencies = [
  "bstr",
  "dbus",
  "normpath",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1439,6 +1462,9 @@ version = "0.1.0"
 [[package]]
 name = "outro_04"
 version = "0.1.0"
+dependencies = [
+ "thiserror",
+]
 
 [[package]]
 name = "outro_08"
@@ -1485,7 +1511,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall 0.5.3",
+ "redox_syscall",
  "smallvec",
  "windows-targets 0.52.6",
 ]
@@ -1500,9 +1526,9 @@ dependencies = [
 
 [[package]]
 name = "pathdiff"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361"
 
 [[package]]
 name = "percent-encoding"
@@ -1512,9 +1538,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pest"
-version = "2.7.11"
+version = "2.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95"
+checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
 dependencies = [
  "memchr",
  "thiserror",
@@ -1523,9 +1549,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.7.11"
+version = "2.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a"
+checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd"
 dependencies = [
  "pest",
  "pest_generator",
@@ -1533,9 +1559,9 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.7.11"
+version = "2.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183"
+checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e"
 dependencies = [
  "pest",
  "pest_meta",
@@ -1546,9 +1572,9 @@ dependencies = [
 
 [[package]]
 name = "pest_meta"
-version = "2.7.11"
+version = "2.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f"
+checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d"
 dependencies = [
  "once_cell",
  "pest",
@@ -1614,18 +1640,18 @@ dependencies = [
 
 [[package]]
 name = "pin-project"
-version = "1.1.5"
+version = "1.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
+checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec"
 dependencies = [
  "pin-project-internal",
 ]
 
 [[package]]
 name = "pin-project-internal"
-version = "1.1.5"
+version = "1.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
+checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1646,9 +1672,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
 name = "pkg-config"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
 
 [[package]]
 name = "ppv-lite86"
@@ -1667,9 +1693,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
 dependencies = [
  "unicode-ident",
 ]
@@ -1688,9 +1714,9 @@ dependencies = [
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.11.0"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8746739f11d39ce5ad5c2520a9b75285310dbfe78c541ccf832d38615765aec0"
+checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
 dependencies = [
  "bitflags 2.6.0",
  "getopts",
@@ -1717,14 +1743,14 @@ version = "15.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b9c77db841443d89a57ae94f22d29c022f6d9f41b00bddbf1f4024dbaf4bdce1"
 dependencies = [
- "pulldown-cmark 0.11.0",
+ "pulldown-cmark 0.11.3",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.36"
+version = "1.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
 dependencies = [
  "proc-macro2",
 ]
@@ -1761,18 +1787,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
-dependencies = [
- "bitflags 1.3.2",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.5.3"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
+checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
 dependencies = [
  "bitflags 2.6.0",
 ]
@@ -1783,9 +1800,9 @@ version = "0.1.0"
 
 [[package]]
 name = "regex"
-version = "1.10.6"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
+checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1795,9 +1812,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.7"
+version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1806,9 +1823,9 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "resizing"
@@ -1837,9 +1854,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustix"
-version = "0.38.34"
+version = "0.38.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
 dependencies = [
  "bitflags 2.6.0",
  "errno",
@@ -1899,18 +1916,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 
 [[package]]
 name = "serde"
-version = "1.0.204"
+version = "1.0.210"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.204"
+version = "1.0.210"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1919,9 +1936,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.122"
+version = "1.0.128"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
+checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
 dependencies = [
  "itoa",
  "memchr",
@@ -2099,9 +2116,9 @@ version = "0.1.0"
 
 [[package]]
 name = "syn"
-version = "2.0.72"
+version = "2.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2118,15 +2135,15 @@ version = "0.1.0"
 
 [[package]]
 name = "tempfile"
-version = "3.11.0"
+version = "3.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
+checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
 dependencies = [
  "cfg-if",
  "fastrand",
  "once_cell",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -2142,28 +2159,28 @@ dependencies = [
 
 [[package]]
 name = "terminal_size"
-version = "0.3.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
+checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef"
 dependencies = [
  "rustix",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.63"
+version = "1.0.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
+checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.63"
+version = "1.0.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
+checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2175,6 +2192,7 @@ name = "thiserror_"
 version = "0.1.0"
 dependencies = [
  "common",
+ "thiserror",
 ]
 
 [[package]]
@@ -2206,14 +2224,14 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.39.2"
+version = "1.40.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
+checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
 dependencies = [
  "backtrace",
  "bytes",
  "libc",
- "mio 1.0.1",
+ "mio 1.0.2",
  "parking_lot",
  "pin-project-lite",
  "signal-hook-registry",
@@ -2247,9 +2265,9 @@ dependencies = [
 
 [[package]]
 name = "tokio-util"
-version = "0.7.11"
+version = "0.7.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
+checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
 dependencies = [
  "bytes",
  "futures-core",
@@ -2275,9 +2293,9 @@ checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
 
 [[package]]
 name = "tower-service"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
 
 [[package]]
 name = "tracing"
@@ -2351,9 +2369,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
 name = "ucd-trie"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
+checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
 
 [[package]]
 name = "unicase"
@@ -2366,30 +2384,30 @@ dependencies = [
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.15"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
 
 [[package]]
 name = "unicode-normalization"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
+checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
 dependencies = [
  "tinyvec",
 ]
 
 [[package]]
 name = "unicode-width"
-version = "0.1.13"
+version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
 
 [[package]]
 name = "unwrap"
@@ -2442,6 +2460,9 @@ dependencies = [
 [[package]]
 name = "vec"
 version = "0.1.0"
+dependencies = [
+ "lazy_static",
+]
 
 [[package]]
 name = "version_check"
@@ -2508,19 +2529,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.92"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
+checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
 dependencies = [
  "cfg-if",
+ "once_cell",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.92"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
+checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
 dependencies = [
  "bumpalo",
  "log",
@@ -2533,9 +2555,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.92"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
+checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -2543,9 +2565,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.92"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
+checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2556,9 +2578,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.92"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
 
 [[package]]
 name = "welcome_00"
index f7afa47..c52e3ac 100644 (file)
@@ -1,6 +1,6 @@
 fn intro() -> &'static str {
     // TODO: fix me ðŸ‘‡
-    "I'm ready to __!"
+    "I'm ready to start modelling a software ticket!"
 }
 
 #[cfg(test)]
index 1119e33..df71eb4 100644 (file)
@@ -5,6 +5,17 @@
 // It should also have a method named `is_available` that returns a `true` if the quantity is
 // greater than 0, otherwise `false`.
 
+struct Order {
+    price: u32,
+    quantity: u32,
+}
+
+impl Order {
+    pub fn is_available(&self) -> bool {
+        self.quantity > 0
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index 7eaa5e5..6456a17 100644 (file)
@@ -1,3 +1,13 @@
+// enum Status {
+//     Todo,
+//     InProgress,
+//     Done,
+// }
+
+// impl From<String> for Status {
+//     fn from(str: String) -> Self {}
+// }
+
 struct Ticket {
     title: String,
     description: String,
@@ -18,7 +28,27 @@ impl Ticket {
     // as well as some `String` methods. Use the documentation of Rust's standard library
     // to find the most appropriate options -> https://doc.rust-lang.org/std/string/struct.String.html
     fn new(title: String, description: String, status: String) -> Self {
-        todo!();
+        match status.as_str() {
+            "To-Do" | "In Progress" | "Done" => {}
+            _ => panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed"),
+        }
+
+        if title.is_empty() {
+            panic!("Title cannot be empty")
+        }
+
+        if title.len() > 50 {
+            panic!("Title cannot be longer than 50 bytes");
+        }
+
+        if description.is_empty() {
+            panic!("Description cannot be empty");
+        }
+
+        if description.len() > 500 {
+            panic!("Description cannot be longer than 500 bytes");
+        }
+
         Self {
             title,
             description,
index df07620..f93112b 100644 (file)
@@ -1,6 +1,7 @@
 mod helpers {
     // TODO: Make this code compile, either by adding a `use` statement or by using
     //  the appropriate path to refer to the `Ticket` struct.
+    use super::Ticket;
 
     fn create_todo_ticket(title: String, description: String) -> Ticket {
         Ticket::new(title, description, "To-Do".into())
index b494fc9..65a1593 100644 (file)
@@ -1,12 +1,12 @@
 mod ticket {
-    struct Ticket {
+    pub struct Ticket {
         title: String,
         description: String,
         status: String,
     }
 
     impl Ticket {
-        fn new(title: String, description: String, status: String) -> Ticket {
+        pub fn new(title: String, description: String, status: String) -> Ticket {
             if title.is_empty() {
                 panic!("Title cannot be empty");
             }
@@ -55,7 +55,7 @@ mod tests {
         //
         // TODO: Once you have verified that the below does not compile,
         //   comment the line out to move on to the next exercise!
-        assert_eq!(ticket.description, "A description");
+        // assert_eq!(ticket.description, "A description");
     }
 
     fn encapsulation_cannot_be_violated() {
@@ -68,10 +68,10 @@ mod tests {
         //
         // TODO: Once you have verified that the below does not compile,
         //   comment the lines out to move on to the next exercise!
-        let ticket = Ticket {
-            title: "A title".into(),
-            description: "A description".into(),
-            status: "To-Do".into(),
-        };
+        // let ticket = Ticket {
+        //     title: "A title".into(),
+        //     description: "A description".into(),
+        //     status: "To-Do".into(),
+        // };
     }
 }
index 91e06eb..44ebdd3 100644 (file)
@@ -30,6 +30,18 @@ pub mod ticket {
             }
         }
 
+        pub fn title(self) -> String {
+            self.title
+        }
+
+        pub fn description(self) -> String {
+            self.description
+        }
+
+        pub fn status(self) -> String {
+            self.status
+        }
+
         // TODO: Add three public methods to the `Ticket` struct:
         //  - `title` that returns the `title` field.
         //  - `description` that returns the `description` field.
index ded2ad8..4ab49f1 100644 (file)
@@ -34,16 +34,16 @@ impl Ticket {
         }
     }
 
-    pub fn title(self) -> String {
-        self.title
+    pub fn title(&self) -> &String {
+        &self.title
     }
 
-    pub fn description(self) -> String {
-        self.description
+    pub fn description(&self) -> &String {
+        &self.description
     }
 
-    pub fn status(self) -> String {
-        self.status
+    pub fn status(&self) -> &String {
+        &self.status
     }
 }
 
index e13ec87..9d66e2f 100644 (file)
@@ -11,40 +11,66 @@ pub struct Ticket {
 
 impl Ticket {
     pub fn new(title: String, description: String, status: String) -> Ticket {
+        Ticket::check_title(&title);
+        Ticket::check_description(&description);
+        Ticket::check_status(&status);
+        Ticket {
+            title,
+            description,
+            status,
+        }
+    }
+
+    fn check_title(title: &String) {
         if title.is_empty() {
             panic!("Title cannot be empty");
         }
         if title.len() > 50 {
             panic!("Title cannot be longer than 50 bytes");
         }
+    }
+
+    fn check_description(description: &String) {
         if description.is_empty() {
             panic!("Description cannot be empty");
         }
         if description.len() > 500 {
             panic!("Description cannot be longer than 500 bytes");
         }
+    }
+
+    fn check_status(status: &String) {
         if status != "To-Do" && status != "In Progress" && status != "Done" {
             panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
         }
-
-        Ticket {
-            title,
-            description,
-            status,
-        }
     }
 
     pub fn title(&self) -> &String {
         &self.title
     }
 
+    pub fn set_title(&mut self, title: String) {
+        Ticket::check_title(&title);
+        self.title = title;
+    }
+
     pub fn description(&self) -> &String {
         &self.description
     }
 
+    pub fn set_description(&mut self, description: String) {
+        Ticket::check_description(&description);
+        self.description = description;
+    }
+
     pub fn status(&self) -> &String {
         &self.status
     }
+
+    pub fn set_status(&mut self, status: String) {
+        Ticket::check_status(&status);
+        self.status = status;
+    }
 }
 
 #[cfg(test)]
index e97518c..ad7d2a4 100644 (file)
@@ -6,16 +6,16 @@ mod tests {
 
     #[test]
     fn u16_size() {
-        assert_eq!(size_of::<u16>(), todo!());
+        assert_eq!(size_of::<u16>(), 2);
     }
 
     #[test]
     fn i32_size() {
-        assert_eq!(size_of::<i32>(), todo!());
+        assert_eq!(size_of::<i32>(), 4);
     }
 
     #[test]
     fn bool_size() {
-        assert_eq!(size_of::<bool>(), todo!());
+        assert_eq!(size_of::<bool>(), 1);
     }
 }
index 24d0c6e..5e24f6b 100644 (file)
@@ -13,7 +13,7 @@ mod tests {
 
     #[test]
     fn string_size() {
-        assert_eq!(size_of::<String>(), todo!());
+        assert_eq!(size_of::<String>(), 24);
     }
 
     #[test]
@@ -23,6 +23,6 @@ mod tests {
         // but, in general, the memory layout of structs is a more complex topic.
         // If you're curious, check out the "Data layout" section of the Rustonomicon
         // https://doc.rust-lang.org/nomicon/data.html for more information.
-        assert_eq!(size_of::<Ticket>(), todo!());
+        assert_eq!(size_of::<Ticket>(), 72);
     }
 }
index d580758..d184a19 100644 (file)
@@ -13,16 +13,16 @@ mod tests {
 
     #[test]
     fn u16_ref_size() {
-        assert_eq!(size_of::<&u16>(), todo!());
+        assert_eq!(size_of::<&u16>(), 8);
     }
 
     #[test]
     fn u64_mut_ref_size() {
-        assert_eq!(size_of::<&mut u64>(), todo!());
+        assert_eq!(size_of::<&mut u64>(), 8);
     }
 
     #[test]
     fn ticket_ref_size() {
-        assert_eq!(size_of::<&Ticket>(), todo!());
+        assert_eq!(size_of::<&Ticket>(), 8);
     }
 }
index 45bc89c..6555fbb 100644 (file)
@@ -2,7 +2,7 @@
 // We'll pick the concept up again in a later chapter after covering traits and
 // interior mutability.
 fn outro() -> &'static str {
-    "I have a basic understanding of __!"
+    "I have a basic understanding of destructors!"
 }
 
 #[cfg(test)]
index 15c99b8..5ae1621 100644 (file)
 // Integration here has a very specific meaning: they test **the public API** of your project.
 // You'll need to pay attention to the visibility of your types and methods; integration
 // tests can't access private or `pub(crate)` items.
+
+pub struct Order {
+    product_name: String,
+    quantity: u32,
+    unit_price: u32,
+}
+
+impl Order {
+    pub fn new(product_name: String, quantity: u32, unit_price: u32) -> Self {
+        Order::check_product_name(&product_name);
+        Order::check_quantity(quantity);
+        Order::check_unit_price(unit_price);
+
+        Order {
+            product_name,
+            quantity,
+            unit_price,
+        }
+    }
+
+    fn check_product_name(product_name: &String) {
+        if product_name.len() == 0 || product_name.len() > 300 {
+            panic!("Product name cannot be empty or be longer than 300 bytes");
+        }
+    }
+
+    fn check_quantity(quantity: u32) {
+        if quantity == 0 {
+            panic!("Quantity must be greater than 0");
+        }
+    }
+
+    fn check_unit_price(unit_price: u32) {
+        if unit_price == 0 {
+            panic!("Unit price must be greater than 0");
+        }
+    }
+
+    pub fn product_name(&self) -> &String {
+        &self.product_name
+    }
+
+    pub fn set_product_name(&mut self, product_name: String) {
+        Order::check_product_name(&product_name);
+        self.product_name = product_name;
+    }
+
+    pub fn quantity(&self) -> &u32 {
+        &self.quantity
+    }
+
+    pub fn set_quantity(&mut self, quantity: u32) {
+        Order::check_quantity(quantity);
+        self.quantity = quantity;
+    }
+
+    pub fn unit_price(&self) -> &u32 {
+        &self.unit_price
+    }
+
+    pub fn set_unit_price(&mut self, unit_price: u32) {
+        Order::check_unit_price(unit_price);
+        self.unit_price = unit_price;
+    }
+
+    pub fn total(&self) -> u32 {
+        self.quantity * self.unit_price
+    }
+}
index 9513649..1b0f8ee 100644 (file)
@@ -1,6 +1,6 @@
 fn intro() -> &'static str {
     // TODO: fix me ðŸ‘‡
-    "I'm ready to __!"
+    "I'm ready to learn about traits!"
 }
 
 #[cfg(test)]
index 258eac5..af400da 100644 (file)
@@ -3,6 +3,22 @@
 //
 // Then implement the trait for `u32` and `i32`.
 
+pub trait IsEven {
+    fn is_even(&self) -> bool;
+}
+
+impl IsEven for u32 {
+    fn is_even(&self) -> bool {
+        self % 2 == 0
+    }
+}
+
+impl IsEven for i32 {
+    fn is_even(&self) -> bool {
+        self % 2 == 0
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index b707c10..e862fa8 100644 (file)
@@ -4,8 +4,8 @@
 //  Look at the compiler error to get familiar with what it looks like.
 //  Then delete the code below and move on to the next exercise.
 
-impl PartialEq for u32 {
-    fn eq(&self, _other: &Self) -> bool {
-        todo!()
-    }
-}
+// impl PartialEq for u32 {
+//     fn eq(&self, _other: &Self) -> bool {
+//         todo!()
+//     }
+// }
index b75c0f1..06c2e36 100644 (file)
@@ -8,7 +8,13 @@ struct Ticket {
 
 // TODO: Implement the `PartialEq` trait for `Ticket`.
 
-impl PartialEq for Ticket {}
+impl PartialEq for Ticket {
+    fn eq(&self, other: &Ticket) -> bool {
+        self.title == other.title
+            && self.description == other.description
+            && self.status == other.status
+    }
+}
 
 #[cfg(test)]
 mod tests {
index 0a74a26..d39d6c5 100644 (file)
@@ -8,7 +8,7 @@
 // print both sides of the comparison to the terminal.
 // If the compared type doesn't implement `Debug`, it doesn't know how to represent them!
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Debug)]
 struct Ticket {
     title: String,
     description: String,
index 10f0eb4..9327d86 100644 (file)
@@ -6,7 +6,10 @@
 // collections (e.g. BTreeMap).
 
 /// Return the minimum of two values.
-pub fn min<T>(left: T, right: T) -> T {
+pub fn min<T>(left: T, right: T) -> T
+where
+    T: Ord,
+{
     if left <= right {
         left
     } else {
index 5bf6614..a37c0d4 100644 (file)
@@ -31,15 +31,15 @@ impl Ticket {
         }
     }
 
-    pub fn title(&self) -> &String {
+    pub fn title(&self) -> &str {
         &self.title
     }
 
-    pub fn description(&self) -> &String {
+    pub fn description(&self) -> &str {
         &self.description
     }
 
-    pub fn status(&self) -> &String {
+    pub fn status(&self) -> &str {
         &self.status
     }
 }
index c7a5c35..a21f9ef 100644 (file)
@@ -12,11 +12,11 @@ pub struct Ticket {
 
 impl Ticket {
     pub fn title(&self) -> &str {
-        todo!()
+        self.title.trim()
     }
 
     pub fn description(&self) -> &str {
-        todo!()
+        self.description.trim()
     }
 }
 
index a406fc5..0ebca5a 100644 (file)
@@ -3,5 +3,5 @@ pub fn example() {
     // via `std::mem::size_of` will result in a compile-time error.
     //
     // TODO: Comment out the following line and move on to the next exercise.
-    std::mem::size_of::<str>();
+    // std::mem::size_of::<str>();
 }
index cc6f5b1..b7995d2 100644 (file)
@@ -4,6 +4,12 @@ pub struct WrappingU32 {
     value: u32,
 }
 
+impl From<u32> for WrappingU32 {
+    fn from(value: u32) -> Self {
+        WrappingU32 { value }
+    }
+}
+
 fn example() {
     let wrapping: WrappingU32 = 42.into();
     let wrapping = WrappingU32::from(42);
index 84f3e7b..f1b8407 100644 (file)
 // interested in learning more about it.
 // You don't have to though: it's perfectly okay to write three separate
 // implementations manually. Venture further only if you're curious.
+trait Power<T> {
+    fn power(&self, n: T) -> u32;
+}
+
+impl Power<u16> for u32 {
+    fn power(&self, n: u16) -> u32 {
+        let mut v = *self;
+        for _ in 1..n {
+            v *= self;
+        }
+        v
+    }
+}
+
+impl Power<u32> for u32 {
+    fn power(&self, n: u32) -> u32 {
+        let mut v = *self;
+        for _ in 1..n {
+            v *= self;
+        }
+        v
+    }
+}
+
+impl Power<&u32> for u32 {
+    fn power(&self, n: &u32) -> u32 {
+        let mut v = *self;
+        for _ in 1..*n {
+            v *= self;
+        }
+        v
+    }
+}
 
 #[cfg(test)]
 mod tests {
index 4fbbe47..8d93806 100644 (file)
@@ -2,9 +2,10 @@
 //  to get the code to compile.
 
 pub fn summary(ticket: Ticket) -> (Ticket, Summary) {
-    (ticket, ticket.summary())
+    (ticket.clone(), ticket.summary())
 }
 
+#[derive(Clone)]
 pub struct Ticket {
     pub title: String,
     pub description: String,
index d74720b..b9ebc02 100644 (file)
@@ -1,6 +1,9 @@
 // TODO: implement the necessary traits to make the test compile and pass.
 //  You *can't* modify the test.
 
+use std::ops::Add;
+
+#[derive(Clone, Copy, Debug, PartialEq)]
 pub struct WrappingU32 {
     value: u32,
 }
@@ -11,6 +14,13 @@ impl WrappingU32 {
     }
 }
 
+impl Add for WrappingU32 {
+    type Output = Self;
+    fn add(self, other: WrappingU32) -> Self::Output {
+        Self::new(self.value.wrapping_add(other.value))
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index 2124d34..7c23a90 100644 (file)
@@ -2,6 +2,28 @@
 //  unless a certain operation has been performed on it.
 //  You can see the expected API in the tests below.
 
+struct DropBomb {
+    defused: bool,
+}
+
+impl DropBomb {
+    pub fn new() -> Self {
+        Self { defused: false }
+    }
+
+    pub fn defuse(&mut self) {
+        self.defused = true;
+    }
+}
+
+impl Drop for DropBomb {
+    fn drop(&mut self) {
+        if !self.defused {
+            panic!("BOOM")
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index 547fd94..c58c507 100644 (file)
@@ -8,3 +8,72 @@
 //   It should be possible to print its debug representation.
 //
 // Tests are located in the `tests` folder—pay attention to the visibility of your types and methods.
+
+use std::ops::Add;
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct SaturatingU16 {
+    value: u16,
+}
+
+impl From<u16> for SaturatingU16 {
+    fn from(value: u16) -> Self {
+        Self { value }
+    }
+}
+
+impl From<u8> for SaturatingU16 {
+    fn from(value: u8) -> Self {
+        Self {
+            value: value.into(),
+        }
+    }
+}
+
+impl From<&u16> for SaturatingU16 {
+    fn from(value: &u16) -> Self {
+        (*value).into()
+    }
+}
+
+impl From<&u8> for SaturatingU16 {
+    fn from(value: &u8) -> Self {
+        (*value).into()
+    }
+}
+
+impl Add for SaturatingU16 {
+    type Output = Self;
+    fn add(self, rhs: Self) -> Self::Output {
+        self + rhs.value
+    }
+}
+
+impl Add<&SaturatingU16> for SaturatingU16 {
+    type Output = SaturatingU16;
+    fn add(self, rhs: &Self) -> Self::Output {
+        self + *rhs
+    }
+}
+
+impl Add<u16> for SaturatingU16 {
+    type Output = SaturatingU16;
+    fn add(self, rhs: u16) -> Self::Output {
+        SaturatingU16 {
+            value: self.value.saturating_add(rhs),
+        }
+    }
+}
+
+impl Add<&u16> for SaturatingU16 {
+    type Output = SaturatingU16;
+    fn add(self, rhs: &u16) -> Self::Output {
+        self + *rhs
+    }
+}
+
+impl PartialEq<u16> for SaturatingU16 {
+    fn eq(&self, other: &u16) -> bool {
+        self.value == *other
+    }
+}
index ce1f75f..ff614d1 100644 (file)
@@ -1,6 +1,6 @@
 fn intro() -> &'static str {
     // TODO: fix me ðŸ‘‡
-    "I'm ready to __!"
+    "I'm ready to refine the `Ticket` type!"
 }
 
 #[cfg(test)]
index a3d9592..4490975 100644 (file)
@@ -7,15 +7,18 @@
 struct Ticket {
     title: String,
     description: String,
-    status: String,
+    status: Status,
 }
 
+#[derive(Debug, PartialEq, Clone, Copy)]
 enum Status {
-    // TODO: add the missing variants
+    ToDo,
+    InProgress,
+    Done,
 }
 
 impl Ticket {
-    pub fn new(title: String, description: String, status: String) -> Ticket {
+    pub fn new(title: String, description: String, status: Status) -> Ticket {
         if title.is_empty() {
             panic!("Title cannot be empty");
         }
@@ -28,9 +31,6 @@ impl Ticket {
         if description.len() > 500 {
             panic!("Description cannot be longer than 500 bytes");
         }
-        if status != "To-Do" && status != "In Progress" && status != "Done" {
-            panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
-        }
 
         Ticket {
             title,
@@ -47,7 +47,7 @@ impl Ticket {
         &self.description
     }
 
-    pub fn status(&self) -> &String {
+    pub fn status(&self) -> &Status {
         &self.status
     }
 }
index d30c569..12c7b4a 100644 (file)
@@ -9,7 +9,12 @@ enum Shape {
 impl Shape {
     // TODO: Implement the `n_sides` method using a `match`.
     pub fn n_sides(&self) -> u8 {
-        todo!()
+        match self {
+            Self::Circle => 0,
+            Self::Square | Self::Rectangle => 4,
+            Self::Triangle => 3,
+            Self::Pentagon => 5,
+        }
     }
 }
 
index 03faf0c..e2f60af 100644 (file)
@@ -38,7 +38,10 @@ impl Ticket {
         }
     }
     pub fn assigned_to(&self) -> &str {
-        todo!()
+        match self.status {
+            Status::InProgress { ref assigned_to } => assigned_to,
+            _ => panic!("Only `In-Progress` tickets can be assigned to someone"),
+        }
     }
 }
 
index 0884fb5..5605cd8 100644 (file)
@@ -8,7 +8,11 @@ impl Shape {
     // TODO: Implement the `radius` method using
     //  either an `if let` or a `let/else`.
     pub fn radius(&self) -> f64 {
-        todo!()
+        if let Shape::Circle { radius } = self {
+            *radius
+        } else {
+            panic!("Not a circle")
+        }
     }
 }
 
index f4e5cb2..8da9f35 100644 (file)
@@ -36,7 +36,10 @@ impl Ticket {
         }
     }
     pub fn assigned_to(&self) -> Option<&String> {
-        todo!()
+        match self.status {
+            Status::InProgress { ref assigned_to } => Some(assigned_to),
+            _ => None,
+        }
     }
 }
 
index 3144bee..de9bc30 100644 (file)
@@ -16,25 +16,25 @@ enum Status {
 }
 
 impl Ticket {
-    pub fn new(title: String, description: String, status: Status) -> Ticket {
+    pub fn new(title: String, description: String, status: Status) -> Result<Ticket, String> {
         if title.is_empty() {
-            panic!("Title cannot be empty");
+            return Err("Title cannot be empty".to_string());
         }
         if title.len() > 50 {
-            panic!("Title cannot be longer than 50 bytes");
+            return Err("Title cannot be longer than 50 bytes".to_string());
         }
         if description.is_empty() {
-            panic!("Description cannot be empty");
+            return Err("Description cannot be empty".to_string());
         }
         if description.len() > 500 {
-            panic!("Description cannot be longer than 500 bytes");
+            return Err("Description cannot be longer than 500 bytes".to_string());
         }
 
-        Ticket {
+        Ok(Ticket {
             title,
             description,
             status,
-        }
+        })
     }
 }
 
index 4b6419b..8905194 100644 (file)
@@ -2,7 +2,20 @@
 //   When the description is invalid, instead, it should use a default description:
 //   "Description not provided".
 fn easy_ticket(title: String, description: String, status: Status) -> Ticket {
-    todo!()
+    if let Err(str) = validated_title(&title) {
+        panic!("{}", str);
+    }
+
+    Ticket::new(
+        title,
+        if let Err(_) = validation_description(&description) {
+            "Description not provided".to_string()
+        } else {
+            description
+        },
+        status,
+    )
+    .unwrap()
 }
 
 #[derive(Debug, PartialEq, Clone)]
@@ -19,19 +32,34 @@ enum Status {
     Done,
 }
 
+fn validated_title(title: &str) -> Result<(), String> {
+    if title.is_empty() {
+        Err("Title cannot be empty".to_string())
+    } else if title.len() > 50 {
+        Err("Title cannot be longer than 50 bytes".to_string())
+    } else {
+        Ok(())
+    }
+}
+
+fn validation_description(description: &str) -> Result<(), String> {
+    if description.is_empty() {
+        Err("Description cannot be empty".to_string())
+    } else if description.len() > 500 {
+        Err("Description cannot be longer than 500 bytes".to_string())
+    } else {
+        Ok(())
+    }
+}
+
 impl Ticket {
     pub fn new(title: String, description: String, status: Status) -> Result<Ticket, String> {
-        if title.is_empty() {
-            return Err("Title cannot be empty".to_string());
-        }
-        if title.len() > 50 {
-            return Err("Title cannot be longer than 50 bytes".to_string());
+        if let Err(e) = validated_title(&title) {
+            return Err(e);
         }
-        if description.is_empty() {
-            return Err("Description cannot be empty".to_string());
-        }
-        if description.len() > 500 {
-            return Err("Description cannot be longer than 500 bytes".to_string());
+
+        if let Err(e) = validation_description(&description) {
+            return Err(e);
         }
 
         Ok(Ticket {
index c74fcc9..6a84edc 100644 (file)
@@ -1,14 +1,31 @@
 // TODO: Use two variants, one for a title error and one for a description error.
 //   Each variant should contain a string with the explanation of what went wrong exactly.
 //   You'll have to update the implementation of `Ticket::new` as well.
-enum TicketNewError {}
+#[derive(Debug)]
+enum TicketNewError {
+    TitleError(String),
+    DescriptionError(String),
+}
 
 // TODO: `easy_ticket` should panic when the title is invalid, using the error message
 //   stored inside the relevant variant of the `TicketNewError` enum.
 //   When the description is invalid, instead, it should use a default description:
 //   "Description not provided".
 fn easy_ticket(title: String, description: String, status: Status) -> Ticket {
-    todo!()
+    if let Err(str) = validated_title(&title) {
+        panic!("{}", str);
+    }
+
+    Ticket::new(
+        title,
+        if let Err(_) = validation_description(&description) {
+            "Description not provided".to_string()
+        } else {
+            description
+        },
+        status,
+    )
+    .unwrap()
 }
 
 #[derive(Debug, PartialEq)]
@@ -25,30 +42,43 @@ enum Status {
     Done,
 }
 
+fn validated_title(title: &str) -> Result<(), String> {
+    if title.is_empty() {
+        Err("Title cannot be empty".to_string())
+    } else if title.len() > 50 {
+        Err("Title cannot be longer than 50 bytes".to_string())
+    } else {
+        Ok(())
+    }
+}
+
+fn validation_description(description: &str) -> Result<(), String> {
+    if description.is_empty() {
+        Err("Description cannot be empty".to_string())
+    } else if description.len() > 500 {
+        Err("Description cannot be longer than 500 bytes".to_string())
+    } else {
+        Ok(())
+    }
+}
+
 impl Ticket {
     pub fn new(
         title: String,
         description: String,
         status: Status,
     ) -> Result<Ticket, TicketNewError> {
-        if title.is_empty() {
-            return Err("Title cannot be empty".to_string());
-        }
-        if title.len() > 50 {
-            return Err("Title cannot be longer than 50 bytes".to_string());
+        if let Err(e) = validated_title(&title) {
+            Err(TicketNewError::TitleError(e))
+        } else if let Err(e) = validation_description(&description) {
+            Err(TicketNewError::DescriptionError(e))
+        } else {
+            Ok(Ticket {
+                title,
+                description,
+                status,
+            })
         }
-        if description.is_empty() {
-            return Err("Description cannot be empty".to_string());
-        }
-        if description.len() > 500 {
-            return Err("Description cannot be longer than 500 bytes".to_string());
-        }
-
-        Ok(Ticket {
-            title,
-            description,
-            status,
-        })
     }
 }
 
index 68b5769..ef054bc 100644 (file)
@@ -2,18 +2,46 @@
 //  When implementing `Display`, you may want to use the `write!` macro from Rust's standard library.
 //  The docs for the `std::fmt` module are a good place to start and look for examples:
 //  https://doc.rust-lang.org/std/fmt/index.html#write
-
+#[derive(Debug)]
 enum TicketNewError {
     TitleError(String),
     DescriptionError(String),
 }
 
+impl std::fmt::Display for TicketNewError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self {
+                TicketNewError::TitleError(str) => str,
+                TicketNewError::DescriptionError(str) => str,
+            }
+        )
+    }
+}
+
+impl std::error::Error for TicketNewError {}
+
 // TODO: `easy_ticket` should panic when the title is invalid, using the error message
 //   stored inside the relevant variant of the `TicketNewError` enum.
 //   When the description is invalid, instead, it should use a default description:
 //   "Description not provided".
 fn easy_ticket(title: String, description: String, status: Status) -> Ticket {
-    todo!()
+    if let Err(str) = validated_title(&title) {
+        panic!("{str}");
+    }
+
+    Ticket::new(
+        title,
+        if let Err(_) = validation_description(&description) {
+            "Description not provided".to_string()
+        } else {
+            description
+        },
+        status,
+    )
+    .unwrap()
 }
 
 #[derive(Debug, PartialEq, Clone)]
@@ -30,38 +58,43 @@ enum Status {
     Done,
 }
 
+fn validated_title(title: &str) -> Result<(), String> {
+    if title.is_empty() {
+        Err("Title cannot be empty".to_string())
+    } else if title.len() > 50 {
+        Err("Title cannot be longer than 50 bytes".to_string())
+    } else {
+        Ok(())
+    }
+}
+
+fn validation_description(description: &str) -> Result<(), String> {
+    if description.is_empty() {
+        Err("Description cannot be empty".to_string())
+    } else if description.len() > 500 {
+        Err("Description cannot be longer than 500 bytes".to_string())
+    } else {
+        Ok(())
+    }
+}
+
 impl Ticket {
     pub fn new(
         title: String,
         description: String,
         status: Status,
     ) -> Result<Ticket, TicketNewError> {
-        if title.is_empty() {
-            return Err(TicketNewError::TitleError(
-                "Title cannot be empty".to_string(),
-            ));
+        if let Err(e) = validated_title(&title) {
+            Err(TicketNewError::TitleError(e))
+        } else if let Err(e) = validation_description(&description) {
+            Err(TicketNewError::DescriptionError(e))
+        } else {
+            Ok(Ticket {
+                title,
+                description,
+                status,
+            })
         }
-        if title.len() > 50 {
-            return Err(TicketNewError::TitleError(
-                "Title cannot be longer than 50 bytes".to_string(),
-            ));
-        }
-        if description.is_empty() {
-            return Err(TicketNewError::DescriptionError(
-                "Description cannot be empty".to_string(),
-            ));
-        }
-        if description.len() > 500 {
-            return Err(TicketNewError::DescriptionError(
-                "Description cannot be longer than 500 bytes".to_string(),
-            ));
-        }
-
-        Ok(Ticket {
-            title,
-            description,
-            status,
-        })
     }
 }
 
diff --git a/exercises/05_ticket_v2/10_packages/src/lib.rs b/exercises/05_ticket_v2/10_packages/src/lib.rs
new file mode 100644 (file)
index 0000000..29fc0a5
--- /dev/null
@@ -0,0 +1,3 @@
+pub fn hello_world() {
+    println!("Hello, World!");
+}
index c18abf9..f3d0e45 100644 (file)
@@ -2,3 +2,6 @@
 name = "deps"
 version = "0.1.0"
 edition = "2021"
+
+[dependencies]
+anyhow = "1"
index fb9c7d5..02ff2d7 100644 (file)
@@ -4,6 +4,7 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies]
+thiserror = "1"
 
 [dev-dependencies]
 common = { path = "../../../helpers/common" }
index 9289143..3a8c19a 100644 (file)
@@ -3,13 +3,29 @@
 //   a `String` field into each variant.
 //   You'll also have to add `thiserror` as a dependency in the `Cargo.toml` file.
 
+use thiserror::Error;
+
+#[derive(Error, Debug)]
 enum TicketNewError {
+    #[error("Title cannot be empty")]
     TitleCannotBeEmpty,
+
+    #[error("Title cannot be longer than 50 bytes")]
     TitleTooLong,
+
+    #[error("Description cannot be empty")]
     DescriptionCannotBeEmpty,
+
+    #[error("Description cannot be longer than 500 bytes")]
     DescriptionTooLong,
 }
 
+// impl std::fmt::Display for TicketNewError {
+//     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+//         write!(f, "{:?}", self)
+//     }
+// }
+
 #[derive(Debug, PartialEq, Clone)]
 struct Ticket {
     title: String,
index e0e1115..e3dbef9 100644 (file)
@@ -8,6 +8,25 @@ enum Status {
     Done,
 }
 
+impl TryFrom<&str> for Status {
+    type Error = String;
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        match value.to_lowercase().as_str() {
+            "todo" | "to-do" | "to do" => Ok(Status::ToDo),
+            "inprogress" | "in progress" => Ok(Status::InProgress),
+            "done" => Ok(Status::Done),
+            _ => Err(format!("Uknown status: {}", value)),
+        }
+    }
+}
+
+impl TryFrom<String> for Status {
+    type Error = String;
+    fn try_from(value: String) -> Result<Self, Self::Error> {
+        value.as_str().try_into()
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index 9f7cce5..6568e52 100644 (file)
@@ -1,3 +1,5 @@
+use std::string::ParseError;
+
 use crate::status::Status;
 
 // We've seen how to declare modules in one of the earliest exercises, but
@@ -17,12 +19,18 @@ mod status;
 pub enum TicketNewError {
     #[error("Title cannot be empty")]
     TitleCannotBeEmpty,
+
     #[error("Title cannot be longer than 50 bytes")]
     TitleTooLong,
+
     #[error("Description cannot be empty")]
     DescriptionCannotBeEmpty,
+
     #[error("Description cannot be longer than 500 bytes")]
     DescriptionTooLong,
+
+    #[error("{0}")]
+    InvalidStatus(#[from] status::ParseStatusError),
 }
 
 #[derive(Debug, PartialEq, Clone)]
@@ -33,7 +41,11 @@ pub struct Ticket {
 }
 
 impl Ticket {
-    pub fn new(title: String, description: String, status: String) -> Result<Self, TicketNewError> {
+    pub fn new(
+        title: String,
+        description: String,
+        status_str: String,
+    ) -> Result<Self, TicketNewError> {
         if title.is_empty() {
             return Err(TicketNewError::TitleCannotBeEmpty);
         }
@@ -47,7 +59,7 @@ impl Ticket {
             return Err(TicketNewError::DescriptionTooLong);
         }
 
-        // TODO: Parse the status string into a `Status` enum.
+        let status = Status::try_from(status_str)?;
 
         Ok(Ticket {
             title,
index dc32a41..f944048 100644 (file)
@@ -2,3 +2,6 @@
 name = "outro_04"
 version = "0.1.0"
 edition = "2021"
+
+[dependencies]
+thiserror = "1"
index ecf55ad..c059427 100644 (file)
@@ -2,8 +2,40 @@
 //   enforcing that the description is not empty and is not longer than 500 bytes.
 //   Implement the traits required to make the tests pass too.
 
+use thiserror::Error;
+
+#[derive(Debug, PartialEq, Clone)]
 pub struct TicketDescription(String);
 
+#[derive(Debug, Error)]
+pub enum TicketDescriptionError {
+    #[error("The description cannot be empty")]
+    Empty,
+
+    #[error("The description cannot be longer than 500 bytes")]
+    TooLong,
+}
+
+impl TryFrom<&str> for TicketDescription {
+    type Error = TicketDescriptionError;
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        TicketDescription::try_from(value.to_string())
+    }
+}
+
+impl TryFrom<String> for TicketDescription {
+    type Error = TicketDescriptionError;
+    fn try_from(value: String) -> Result<Self, Self::Error> {
+        if value.len() > 500 {
+            Err(TicketDescriptionError::TooLong)
+        } else if value.is_empty() {
+            Err(TicketDescriptionError::Empty)
+        } else {
+            Ok(TicketDescription(value))
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index 4453d52..1f6b12f 100644 (file)
@@ -1,12 +1,32 @@
 // TODO: Implement `TryFrom<String>` and `TryFrom<&str>` for the `Status` enum.
 //  The parsing should be case-insensitive.
 
+#[derive(Debug, PartialEq, Clone)]
 pub enum Status {
     ToDo,
     InProgress,
     Done,
 }
 
+impl TryFrom<&str> for Status {
+    type Error = String;
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        match value.to_lowercase().as_str() {
+            "todo" | "to-do" | "to do" => Ok(Status::ToDo),
+            "inprogress" | "in progress" => Ok(Status::InProgress),
+            "done" => Ok(Status::Done),
+            _ => Err(format!("Can't parse status '{value}'").to_string()),
+        }
+    }
+}
+
+impl TryFrom<String> for Status {
+    type Error = String;
+    fn try_from(value: String) -> Result<Self, Self::Error> {
+        Status::try_from(value.as_str())
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index cb31996..1ac7374 100644 (file)
@@ -2,8 +2,40 @@
 //   enforcing that the title is not empty and is not longer than 50 characters.
 //   Implement the traits required to make the tests pass too.
 
+use thiserror::Error;
+
+#[derive(Debug, PartialEq, Clone)]
 pub struct TicketTitle(String);
 
+#[derive(Debug, Error)]
+pub enum TitleError {
+    #[error("The title cannot be empty")]
+    Empty,
+
+    #[error("The title cannot be longer than 50 bytes")]
+    TooLong,
+}
+
+impl TryFrom<&str> for TicketTitle {
+    type Error = TitleError;
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        TicketTitle::try_from(value.to_string())
+    }
+}
+
+impl TryFrom<String> for TicketTitle {
+    type Error = TitleError;
+    fn try_from(value: String) -> Result<Self, Self::Error> {
+        if value.len() > 50 {
+            Err(TitleError::TooLong)
+        } else if value.is_empty() {
+            Err(TitleError::Empty)
+        } else {
+            Ok(TicketTitle(value))
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index 118e483..d0fd0da 100644 (file)
@@ -1,6 +1,6 @@
 fn intro() -> &'static str {
     // TODO: fix me ðŸ‘‡
-    "I'm ready to __!"
+    "I'm ready to build a ticket management system!"
 }
 
 #[cfg(test)]
index e06cb2b..49a20a4 100644 (file)
@@ -1,11 +1,11 @@
 // TODO: Flesh out the `WeekTemperatures` struct and its method implementations to pass the tests.
 
 pub struct WeekTemperatures {
-    // TODO
+    values: [Option<i32>; 7],
 }
 
 pub enum Weekday {
-    Monday,
+    Monday = 0,
     Tuesday,
     Wednesday,
     Thursday,
@@ -16,15 +16,15 @@ pub enum Weekday {
 
 impl WeekTemperatures {
     pub fn new() -> Self {
-        todo!()
+        WeekTemperatures { values: [None; 7] }
     }
 
     pub fn get_temperature(&self, day: Weekday) -> Option<i32> {
-        todo!()
+        self.values[day as usize]
     }
 
     pub fn set_temperature(&mut self, day: Weekday, temperature: i32) {
-        todo!()
+        self.values[day as usize] = Some(temperature);
     }
 }
 
index 66ee1de..6e3a2fa 100644 (file)
@@ -2,3 +2,6 @@
 name = "vec"
 version = "0.1.0"
 edition = "2021"
+
+[dependencies]
+lazy_static = "1"
index 2e8b498..08051b0 100644 (file)
 //
 // We expect `fibonacci(0)` to return `0`, `fibonacci(1)` to return `1`,
 // `fibonacci(2)` to return `1`, and so on.
+
+use lazy_static::lazy_static;
+use std::sync::Mutex;
+
+lazy_static! {
+    static ref fibonacci_values: Mutex<Vec<u32>> = Mutex::new(vec![0, 1]);
+}
+
 pub fn fibonacci(n: u32) -> u32 {
     // TODO: implement the `fibonacci` function
     //
     // Hint: use a `Vec` to memoize the results you have already calculated
     // so that you don't have to recalculate them several times.
-    todo!()
+
+    let mut values = fibonacci_values.lock().unwrap();
+    while values.len() <= n as usize {
+        let l = values.len();
+        let v1 = values[l - 2];
+        let v2 = values[l - 1];
+        values.push(v1 + v2);
+    }
+    values[n as usize]
 }
 
 #[cfg(test)]
index 000ca2d..f29eb7e 100644 (file)
@@ -12,6 +12,6 @@ mod tests {
         // Can you guess what the new capacity will be?
         // Beware that the standard library makes no guarantees about the
         // algorithm used to resize the vector, so this may change in the future.
-        assert_eq!(v.capacity(), todo!());
+        assert_eq!(v.capacity(), 4);
     }
 }
index d55906c..7425a08 100644 (file)
@@ -10,6 +10,15 @@ pub struct TicketStore {
     tickets: Vec<Ticket>,
 }
 
+impl IntoIterator for TicketStore {
+    type Item = Ticket;
+    type IntoIter = std::vec::IntoIter<Self::Item>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.tickets.into_iter()
+    }
+}
+
 #[derive(Clone, Debug, PartialEq)]
 pub struct Ticket {
     pub title: TicketTitle,
index da75366..0039136 100644 (file)
@@ -30,6 +30,10 @@ impl TicketStore {
     pub fn add_ticket(&mut self, ticket: Ticket) {
         self.tickets.push(ticket);
     }
+
+    pub fn iter(&self) -> std::slice::Iter<Ticket> {
+        self.tickets.iter()
+    }
 }
 
 #[cfg(test)]
index 545ed75..ec4538e 100644 (file)
@@ -6,6 +6,15 @@ pub struct TicketStore {
     tickets: Vec<Ticket>,
 }
 
+impl<'a> IntoIterator for &'a TicketStore {
+    type Item = &'a Ticket;
+    type IntoIter = std::slice::Iter<'a, Ticket>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.tickets.iter()
+    }
+}
+
 #[derive(Clone, Debug, PartialEq)]
 pub struct Ticket {
     pub title: TicketTitle,
index 2731211..11e81a5 100644 (file)
@@ -31,6 +31,13 @@ impl TicketStore {
     pub fn add_ticket(&mut self, ticket: Ticket) {
         self.tickets.push(ticket);
     }
+
+    pub fn to_dos(&self) -> Vec<&Ticket> {
+        self.tickets
+            .iter()
+            .filter(|t| t.status == Status::ToDo)
+            .collect()
+    }
 }
 
 #[cfg(test)]
index d8afbe0..53eb290 100644 (file)
@@ -31,6 +31,12 @@ impl TicketStore {
     pub fn add_ticket(&mut self, ticket: Ticket) {
         self.tickets.push(ticket);
     }
+
+    pub fn in_progress(&self) -> impl Iterator<Item = &Ticket> {
+        self.tickets
+            .iter()
+            .filter(|t| t.status == Status::InProgress)
+    }
 }
 
 #[cfg(test)]
index 33e982b..fa3e99c 100644 (file)
@@ -33,7 +33,10 @@ impl TicketStore {
     // that can be infallibly converted into a `Ticket`.
     // This can make it nicer to use the method, as it removes the syntax noise of `.into()`
     // from the calling site. It can worsen the quality of the compiler error messages, though.
-    pub fn add_ticket(&mut self, ticket: impl Into<Ticket>) {
+    pub fn add_ticket<T>(&mut self, ticket: T)
+    where
+        T: Into<Ticket>,
+    {
         self.tickets.push(ticket.into());
     }
 }
index 1d2c6f7..9f996b2 100644 (file)
@@ -1,6 +1,10 @@
 // TODO: Define a function named `sum` that takes a reference to a slice of `u32` and returns the sum of all
 //  elements in the slice.
 
+fn sum(elements: &[u32]) -> u32 {
+    elements.iter().sum()
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index 4ba888c..6b1eff5 100644 (file)
@@ -1,6 +1,12 @@
 // TODO: Define a function named `squared` that raises all `i32`s within a slice to the power of 2.
 //  The slice should be modified in place.
 
+fn squared(numbers: &mut [i32]) {
+    for mut n in numbers {
+        *n *= *n;
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index 10b5cb1..360b07a 100644 (file)
@@ -11,6 +11,7 @@ use ticket_fields::{TicketDescription, TicketTitle};
 #[derive(Clone)]
 pub struct TicketStore {
     tickets: Vec<Ticket>,
+    next_id: u64,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq)]
@@ -41,11 +42,25 @@ impl TicketStore {
     pub fn new() -> Self {
         Self {
             tickets: Vec::new(),
+            next_id: 0,
         }
     }
 
-    pub fn add_ticket(&mut self, ticket: Ticket) {
+    pub fn add_ticket(&mut self, ticket_draft: TicketDraft) -> TicketId {
+        let id = TicketId(self.next_id);
+        self.next_id += 1;
+        let ticket = Ticket {
+            id,
+            title: ticket_draft.title,
+            description: ticket_draft.description,
+            status: Status::ToDo,
+        };
         self.tickets.push(ticket);
+        id
+    }
+
+    pub fn get(&self, id: TicketId) -> Option<&Ticket> {
+        self.tickets.iter().find(|t| t.id == id)
     }
 }
 
index 0b08cc1..8b5fa13 100644 (file)
@@ -1,5 +1,7 @@
 // TODO: Implement `Index<&TicketId>` and `Index<TicketId>` for `TicketStore`.
 
+use std::ops::Index;
+
 use ticket_fields::{TicketDescription, TicketTitle};
 
 #[derive(Clone)]
@@ -58,6 +60,20 @@ impl TicketStore {
     }
 }
 
+impl Index<TicketId> for TicketStore {
+    type Output = Ticket;
+    fn index(&self, index: TicketId) -> &Self::Output {
+        self.get(index).unwrap()
+    }
+}
+
+impl Index<&TicketId> for TicketStore {
+    type Output = Ticket;
+    fn index(&self, index: &TicketId) -> &Self::Output {
+        self.index(*index) // or &self.index[*index].
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use crate::{Status, TicketDraft, TicketStore};
index fa39451..aba27d6 100644 (file)
@@ -1,6 +1,6 @@
 // TODO: Implement `IndexMut<&TicketId>` and `IndexMut<TicketId>` for `TicketStore`.
 
-use std::ops::Index;
+use std::ops::{Index, IndexMut};
 use ticket_fields::{TicketDescription, TicketTitle};
 
 #[derive(Clone)]
@@ -75,6 +75,18 @@ impl Index<&TicketId> for TicketStore {
     }
 }
 
+impl IndexMut<TicketId> for TicketStore {
+    fn index_mut(&mut self, index: TicketId) -> &mut Self::Output {
+        self.tickets.iter_mut().find(|t| t.id == index).unwrap()
+    }
+}
+
+impl IndexMut<&TicketId> for TicketStore {
+    fn index_mut(&mut self, index: &TicketId) -> &mut Self::Output {
+        &mut self[*index]
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use crate::{Status, TicketDraft, TicketStore};
index ea109a6..ce21ecd 100644 (file)
@@ -11,7 +11,7 @@ pub struct TicketStore {
     counter: u64,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct TicketId(u64);
 
 #[derive(Clone, Debug, PartialEq)]
@@ -38,7 +38,7 @@ pub enum Status {
 impl TicketStore {
     pub fn new() -> Self {
         Self {
-            tickets: todo!(),
+            tickets: HashMap::new(),
             counter: 0,
         }
     }
@@ -52,16 +52,16 @@ impl TicketStore {
             description: ticket.description,
             status: Status::ToDo,
         };
-        todo!();
+        self.tickets.insert(id, ticket);
         id
     }
 
     pub fn get(&self, id: TicketId) -> Option<&Ticket> {
-        todo!()
+        self.tickets.get(&id)
     }
 
     pub fn get_mut(&mut self, id: TicketId) -> Option<&mut Ticket> {
-        todo!()
+        self.tickets.get_mut(&id)
     }
 }
 
index d9af95d..256619e 100644 (file)
@@ -13,7 +13,7 @@ pub struct TicketStore {
     counter: u64,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub struct TicketId(u64);
 
 #[derive(Clone, Debug, PartialEq)]
@@ -40,7 +40,7 @@ pub enum Status {
 impl TicketStore {
     pub fn new() -> Self {
         Self {
-            tickets: todo!(),
+            tickets: BTreeMap::new(),
             counter: 0,
         }
     }
@@ -54,16 +54,24 @@ impl TicketStore {
             description: ticket.description,
             status: Status::ToDo,
         };
-        todo!();
+        self.tickets.insert(id, ticket);
         id
     }
 
     pub fn get(&self, id: TicketId) -> Option<&Ticket> {
-        todo!()
+        self.tickets.get(&id)
     }
 
     pub fn get_mut(&mut self, id: TicketId) -> Option<&mut Ticket> {
-        todo!()
+        self.tickets.get_mut(&id)
+    }
+}
+
+impl<'a> IntoIterator for &'a TicketStore {
+    type Item = &'a Ticket;
+    type IntoIter = std::collections::btree_map::Values<'a, TicketId, Ticket>;
+    fn into_iter(self) -> Self::IntoIter {
+        self.tickets.values().into_iter()
     }
 }
 
index df6490d..283d8d4 100644 (file)
@@ -1,6 +1,6 @@
 fn intro() -> &'static str {
     // TODO: fix me ðŸ‘‡
-    "I'm ready to _!"
+    "I'm ready to build a concurrent ticket management system!"
 }
 
 #[cfg(test)]
index 7d084ac..49a8292 100644 (file)
 // slices of the vector directly. You'll need to allocate new
 // vectors for each half of the original vector. We'll see why
 // this is necessary in the next exercise.
-use std::thread;
+use std::{thread, vec::Vec};
 
 pub fn sum(v: Vec<i32>) -> i32 {
-    todo!()
+    let v1 = v[0..v.len() / 2].to_vec();
+    let v2 = v[v.len() / 2..].to_vec();
+
+    let t1 = thread::spawn(move || v1.iter().sum::<i32>());
+    let t2 = thread::spawn(move || v2.iter().sum::<i32>());
+
+    t1.join().unwrap() + t2.join().unwrap()
 }
 
 #[cfg(test)]
index 4b9241b..2f608d5 100644 (file)
@@ -4,7 +4,12 @@
 use std::thread;
 
 pub fn sum(slice: &'static [i32]) -> i32 {
-    todo!()
+    let (s1, s2) = slice.split_at(slice.len() / 2);
+
+    let t1 = thread::spawn(|| s1.iter().sum::<i32>());
+    let t2 = thread::spawn(|| s2.iter().sum::<i32>());
+
+    t1.join().unwrap() + t2.join().unwrap()
 }
 
 #[cfg(test)]
index fef6b46..b232826 100644 (file)
@@ -6,6 +6,7 @@
 use std::thread;
 
 pub fn sum(v: Vec<i32>) -> i32 {
+    // Vec::leak(self)
     todo!()
 }