[[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"
[[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"
[[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]]
[[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"
[[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"
[[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",
[[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",
[[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",
[[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",
]
[[package]]
name = "deps"
version = "0.1.0"
+dependencies = [
+ "anyhow",
+]
[[package]]
name = "deref"
[[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]]
[[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",
[[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",
[[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",
[[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",
[[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"
[[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"
[[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",
[[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",
[[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",
[[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",
[[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",
]
"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"
"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"
"clap",
"itertools",
"mdbook",
- "pulldown-cmark 0.11.0",
+ "pulldown-cmark 0.11.3",
"pulldown-cmark-to-cmark",
"semver",
"serde_json",
[[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]]
[[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",
[[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]]
[[package]]
name = "outro_04"
version = "0.1.0"
+dependencies = [
+ "thiserror",
+]
[[package]]
name = "outro_08"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall 0.5.3",
+ "redox_syscall",
"smallvec",
"windows-targets 0.52.6",
]
[[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"
[[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",
[[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",
[[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",
[[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",
[[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",
[[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"
[[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",
]
[[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",
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",
]
[[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",
]
[[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",
[[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",
[[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"
[[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",
[[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",
[[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",
[[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",
[[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]]
[[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",
version = "0.1.0"
dependencies = [
"common",
+ "thiserror",
]
[[package]]
[[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",
[[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",
[[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"
[[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"
[[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"
[[package]]
name = "vec"
version = "0.1.0"
+dependencies = [
+ "lazy_static",
+]
[[package]]
name = "version_check"
[[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",
[[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",
[[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",
[[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"
fn intro() -> &'static str {
// TODO: fix me 👇
- "I'm ready to __!"
+ "I'm ready to start modelling a software ticket!"
}
#[cfg(test)]
// 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::*;
+// enum Status {
+// Todo,
+// InProgress,
+// Done,
+// }
+
+// impl From<String> for Status {
+// fn from(str: String) -> Self {}
+// }
+
struct Ticket {
title: String,
description: String,
// 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,
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())
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");
}
//
// 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() {
//
// 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(),
+ // };
}
}
}
}
+ 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.
}
}
- 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
}
}
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)]
#[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);
}
}
#[test]
fn string_size() {
- assert_eq!(size_of::<String>(), todo!());
+ assert_eq!(size_of::<String>(), 24);
}
#[test]
// 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);
}
}
#[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);
}
}
// 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)]
// 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
+ }
+}
fn intro() -> &'static str {
// TODO: fix me 👇
- "I'm ready to __!"
+ "I'm ready to learn about traits!"
}
#[cfg(test)]
//
// 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::*;
// 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!()
+// }
+// }
// 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 {
// 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,
// 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 {
}
}
- 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
}
}
impl Ticket {
pub fn title(&self) -> &str {
- todo!()
+ self.title.trim()
}
pub fn description(&self) -> &str {
- todo!()
+ self.description.trim()
}
}
// 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>();
}
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);
// 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 {
// 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,
// 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,
}
}
}
+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::*;
// 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::*;
// 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
+ }
+}
fn intro() -> &'static str {
// TODO: fix me 👇
- "I'm ready to __!"
+ "I'm ready to refine the `Ticket` type!"
}
#[cfg(test)]
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");
}
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,
&self.description
}
- pub fn status(&self) -> &String {
+ pub fn status(&self) -> &Status {
&self.status
}
}
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,
+ }
}
}
}
}
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"),
+ }
}
}
// 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")
+ }
}
}
}
}
pub fn assigned_to(&self) -> Option<&String> {
- todo!()
+ match self.status {
+ Status::InProgress { ref assigned_to } => Some(assigned_to),
+ _ => None,
+ }
}
}
}
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,
- }
+ })
}
}
// 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)]
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 {
// 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)]
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,
- })
}
}
// 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)]
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,
- })
}
}
--- /dev/null
+pub fn hello_world() {
+ println!("Hello, World!");
+}
name = "deps"
version = "0.1.0"
edition = "2021"
+
+[dependencies]
+anyhow = "1"
edition = "2021"
[dependencies]
+thiserror = "1"
[dev-dependencies]
common = { path = "../../../helpers/common" }
// 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,
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::*;
+use std::string::ParseError;
+
use crate::status::Status;
// We've seen how to declare modules in one of the earliest exercises, but
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)]
}
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);
}
return Err(TicketNewError::DescriptionTooLong);
}
- // TODO: Parse the status string into a `Status` enum.
+ let status = Status::try_from(status_str)?;
Ok(Ticket {
title,
name = "outro_04"
version = "0.1.0"
edition = "2021"
+
+[dependencies]
+thiserror = "1"
// 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::*;
// 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::*;
// 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::*;
fn intro() -> &'static str {
// TODO: fix me 👇
- "I'm ready to __!"
+ "I'm ready to build a ticket management system!"
}
#[cfg(test)]
// 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,
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);
}
}
name = "vec"
version = "0.1.0"
edition = "2021"
+
+[dependencies]
+lazy_static = "1"
//
// 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)]
// 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);
}
}
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,
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)]
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,
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)]
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)]
// 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());
}
}
// 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::*;
// 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::*;
#[derive(Clone)]
pub struct TicketStore {
tickets: Vec<Ticket>,
+ next_id: u64,
}
#[derive(Clone, Copy, Debug, PartialEq)]
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)
}
}
// TODO: Implement `Index<&TicketId>` and `Index<TicketId>` for `TicketStore`.
+use std::ops::Index;
+
use ticket_fields::{TicketDescription, TicketTitle};
#[derive(Clone)]
}
}
+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};
// 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)]
}
}
+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};
counter: u64,
}
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TicketId(u64);
#[derive(Clone, Debug, PartialEq)]
impl TicketStore {
pub fn new() -> Self {
Self {
- tickets: todo!(),
+ tickets: HashMap::new(),
counter: 0,
}
}
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)
}
}
counter: u64,
}
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct TicketId(u64);
#[derive(Clone, Debug, PartialEq)]
impl TicketStore {
pub fn new() -> Self {
Self {
- tickets: todo!(),
+ tickets: BTreeMap::new(),
counter: 0,
}
}
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()
}
}
fn intro() -> &'static str {
// TODO: fix me 👇
- "I'm ready to _!"
+ "I'm ready to build a concurrent ticket management system!"
}
#[cfg(test)]
// 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)]
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)]
use std::thread;
pub fn sum(v: Vec<i32>) -> i32 {
+ // Vec::leak(self)
todo!()
}