Compare commits
31 Commits
0910f3909f
...
my_solutio
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a1ca00837 | |||
| 1789d43730 | |||
| 604a5a20ae | |||
| 0829174983 | |||
| ebe07acd1e | |||
| 4a4fc2ea0d | |||
| 91e6bf5ae4 | |||
| 3f57819e4c | |||
| d54a1e160b | |||
| 4913da035f | |||
| 1f0823a6a4 | |||
| 56075fa40e | |||
| 852cd5f0b9 | |||
| 1c16ac8c22 | |||
| d3b4c0d653 | |||
| 8b78ea3a83 | |||
| 0e5cdc6d10 | |||
| 1d876eff10 | |||
| dfcb9736b2 | |||
| c1e7c3fadd | |||
| 978a99b00d | |||
| 34189d212e | |||
| 9d1869fc9c | |||
| 3e56cf1287 | |||
| f91cc0089a | |||
| 211f23cea4 | |||
| 1e516bf0a5 | |||
| 03a0a77394 | |||
| bb27bfad41 | |||
| 4d12facc2f | |||
| 1251a6c1b1 |
66
.github/workflows/ci.yml
vendored
66
.github/workflows/ci.yml
vendored
@@ -18,47 +18,6 @@ jobs:
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
- name: Install plugin
|
||||
run: cargo install --path helpers/mdbook-exercise-linker
|
||||
- name: Install mdbook-pandoc and related dependencies
|
||||
run: |
|
||||
cargo install mdbook-pandoc --locked --version 0.7.1
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y fonts-noto
|
||||
|
||||
export PANDOC_VERSION=3.3
|
||||
curl -LsSf https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-linux-amd64.tar.gz | tar zxf -
|
||||
echo "$PWD/pandoc-${PANDOC_VERSION}/bin" >> $GITHUB_PATH
|
||||
shell: bash
|
||||
- name: Setup TeX Live
|
||||
uses: teatimeguest/setup-texlive-action@v3
|
||||
with:
|
||||
packages:
|
||||
scheme-basic
|
||||
luatex
|
||||
lualatex-math
|
||||
luacolor
|
||||
luatexbase
|
||||
luaotfload
|
||||
framed
|
||||
unicode-math
|
||||
xcolor
|
||||
geometry
|
||||
longtable
|
||||
booktabs
|
||||
array
|
||||
lua-ul
|
||||
etoolbox
|
||||
fancyvrb
|
||||
footnote
|
||||
selnolig
|
||||
natbib
|
||||
csquotes
|
||||
bookmark
|
||||
xurl
|
||||
amsmath
|
||||
setspace
|
||||
iftex
|
||||
- name: Check `tlmgr` version
|
||||
run: tlmgr --version
|
||||
- uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: mdbook
|
||||
@@ -74,19 +33,24 @@ jobs:
|
||||
--exclude-loopback
|
||||
--require-https
|
||||
--no-progress
|
||||
book/book/html/
|
||||
# Upload the HTML book as an artifact
|
||||
book/book
|
||||
# Upload the book as an artifact
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: book
|
||||
# When you support multiple formats, the output directory changes
|
||||
# to include the format in its path.
|
||||
path: book/book/html
|
||||
# Upload the PDF book as an artifact
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: paperback
|
||||
path: book/book/pandoc/pdf/100-exercises-to-learn-rust.pdf
|
||||
path: book/book
|
||||
# Commit and push all changed files.
|
||||
# Must only affect files that are listed in "paths-ignore".
|
||||
- name: Git commit build artifacts
|
||||
# Only run on main branch push (e.g. pull request merge).
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
git checkout -b deploy
|
||||
git config --global user.name "Deployer"
|
||||
git config --global user.email "username@users.noreply.github.com"
|
||||
git add --force book/book
|
||||
git commit -m "Render book"
|
||||
git push --set-upstream --force-with-lease origin deploy
|
||||
|
||||
formatter:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
358
Cargo.lock
generated
358
Cargo.lock
generated
@@ -4,9 +4,9 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.22.0"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
@@ -56,9 +56,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.15"
|
||||
version = "0.6.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
@@ -71,33 +71,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.8"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.5"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.1"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||
checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.4"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.52.0",
|
||||
@@ -144,9 +144,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.73"
|
||||
version = "0.3.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
|
||||
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
@@ -171,9 +171,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
@@ -201,9 +201,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.10.0"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
|
||||
checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
@@ -231,9 +231,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.7.1"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
|
||||
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
||||
|
||||
[[package]]
|
||||
name = "cancellation"
|
||||
@@ -244,9 +244,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.7"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
|
||||
checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -270,23 +270,23 @@ dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.13"
|
||||
version = "4.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
|
||||
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.13"
|
||||
version = "4.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99"
|
||||
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -297,18 +297,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.5.12"
|
||||
version = "4.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8670053e87c316345e384ca1f3eba3006fc6355ed8b8a1140d104e109e3df34"
|
||||
checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.2"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||
|
||||
[[package]]
|
||||
name = "client"
|
||||
@@ -323,9 +323,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.2"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||
|
||||
[[package]]
|
||||
name = "combinators"
|
||||
@@ -473,9 +473,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.2"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
|
||||
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
@@ -483,9 +483,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.5"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
|
||||
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -680,9 +680,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.29.0"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
@@ -826,9 +826,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.9.4"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
|
||||
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
@@ -844,9 +844,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.30"
|
||||
version = "0.14.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9"
|
||||
checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -953,9 +953,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.3.0"
|
||||
version = "2.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0"
|
||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -1019,9 +1019,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
version = "1.70.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||
|
||||
[[package]]
|
||||
name = "iter"
|
||||
@@ -1078,9 +1078,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
version = "0.2.154"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
|
||||
|
||||
[[package]]
|
||||
name = "libdbus-sys"
|
||||
@@ -1125,9 +1125,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
|
||||
[[package]]
|
||||
name = "mac"
|
||||
@@ -1208,9 +1208,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
@@ -1220,9 +1220,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.5"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
|
||||
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
@@ -1230,9 +1230,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
|
||||
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
@@ -1249,18 +1249,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modules"
|
||||
version = "0.1.0"
|
||||
@@ -1277,11 +1265,11 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||
|
||||
[[package]]
|
||||
name = "normpath"
|
||||
version = "1.3.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed"
|
||||
checksum = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1290,7 +1278,7 @@ version = "6.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.5.0",
|
||||
"crossbeam-channel",
|
||||
"filetime",
|
||||
"fsevent-sys",
|
||||
@@ -1298,7 +1286,7 @@ dependencies = [
|
||||
"kqueue",
|
||||
"libc",
|
||||
"log",
|
||||
"mio 0.8.11",
|
||||
"mio",
|
||||
"walkdir",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
@@ -1331,10 +1319,20 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.2"
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -1402,9 +1400,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
@@ -1418,9 +1416,9 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.5.3",
|
||||
"redox_syscall 0.5.1",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1445,9 +1443,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.7.11"
|
||||
version = "2.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95"
|
||||
checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror",
|
||||
@@ -1456,9 +1454,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.7.11"
|
||||
version = "2.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a"
|
||||
checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
@@ -1466,9 +1464,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.7.11"
|
||||
version = "2.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183"
|
||||
checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
@@ -1479,9 +1477,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.7.11"
|
||||
version = "2.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f"
|
||||
checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
@@ -1585,12 +1583,9 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.20"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "precomputed-hash"
|
||||
@@ -1600,9 +1595,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
version = "1.0.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -1613,7 +1608,7 @@ version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.5.0",
|
||||
"memchr",
|
||||
"pulldown-cmark-escape",
|
||||
"unicase",
|
||||
@@ -1675,11 +1670,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.3"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
|
||||
checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1688,9 +1683,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.6"
|
||||
version = "1.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -1700,9 +1695,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.7"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -1711,9 +1706,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.4"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
|
||||
[[package]]
|
||||
name = "resizing"
|
||||
@@ -1746,7 +1741,7 @@ version = "0.38.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.5.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
@@ -1804,18 +1799,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.204"
|
||||
version = "1.0.202"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
||||
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.204"
|
||||
version = "1.0.202"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1824,12 +1819,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.122"
|
||||
version = "1.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
|
||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
@@ -2004,9 +1998,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.72"
|
||||
version = "2.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
|
||||
checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2023,13 +2017,12 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.11.0"
|
||||
version = "3.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
|
||||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
@@ -2057,18 +2050,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.63"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.63"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2096,9 +2089,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.8.0"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
@@ -2111,27 +2104,28 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.39.2"
|
||||
version = "1.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
|
||||
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio 1.0.1",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.4.0"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2299,9 +2293,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.2"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
|
||||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
@@ -2316,9 +2310,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "validation"
|
||||
@@ -2344,9 +2338,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "visibility"
|
||||
@@ -2485,11 +2479,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2504,7 +2498,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2522,16 +2516,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2551,18 +2536,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_aarch64_gnullvm 0.52.5",
|
||||
"windows_aarch64_msvc 0.52.5",
|
||||
"windows_i686_gnu 0.52.5",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
"windows_i686_msvc 0.52.5",
|
||||
"windows_x86_64_gnu 0.52.5",
|
||||
"windows_x86_64_gnullvm 0.52.5",
|
||||
"windows_x86_64_msvc 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2573,9 +2558,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
@@ -2585,9 +2570,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
@@ -2597,15 +2582,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
@@ -2615,9 +2600,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
@@ -2627,9 +2612,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
@@ -2639,9 +2624,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
@@ -2651,9 +2636,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "without_channels"
|
||||
@@ -2661,24 +2646,3 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"ticket_fields",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
@@ -2,7 +2,5 @@
|
||||
members = ["exercises/*/*", "helpers/common", "helpers/mdbook-exercise-linker", "helpers/ticket_fields"]
|
||||
resolver = "2"
|
||||
|
||||
# This is needed to guarantee the expected behaviour on that specific exercise,
|
||||
# regardless of the "global" setting for `overflow-checks` on the `dev` profile.
|
||||
[profile.dev.package.copy]
|
||||
overflow-checks = true
|
||||
[profile.dev]
|
||||
overflow-checks = false
|
||||
|
||||
@@ -1,44 +1,10 @@
|
||||
[book]
|
||||
authors = ["Luca Palmieri"]
|
||||
authors = ["Luca Palmieri (Mainmatter)"]
|
||||
language = "en"
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "100 Exercises To Learn Rust"
|
||||
|
||||
[output.pandoc]
|
||||
optional = true
|
||||
hosted-html = "https://rust-exercises.com/100-exercises/"
|
||||
|
||||
[output.pandoc.profile.pdf] # options to pass to Pandoc (see https://pandoc.org/MANUAL.html)
|
||||
output-file = "100-exercises-to-learn-rust.pdf"
|
||||
to = "latex"
|
||||
highlight-style = "tango"
|
||||
# We use `lualatext` because, right now, it's the only engine
|
||||
# that supports fallback fonts, which we need for emojis.
|
||||
pdf-engine = "lualatex"
|
||||
|
||||
[output.pandoc.profile.pdf.variables]
|
||||
subtitle = "A hands-on course by Mainmatter"
|
||||
# You can get these fonts here: https://fonts.google.com/selection?query=noto+color+
|
||||
mainfont = "Noto Serif"
|
||||
sansfont = "Noto Sans"
|
||||
monofont = "Noto Sans Mono"
|
||||
mainfontfallback = ["Noto Color Emoji:mode=harf"]
|
||||
sansfontfallback = ["Noto Color Emoji:mode=harf"]
|
||||
monofontfallback = [
|
||||
"Noto Color Emoji:mode=harf",
|
||||
]
|
||||
linkcolor = "blue"
|
||||
urlcolor = "blue"
|
||||
urlstyle = "rm"
|
||||
documentclass = "book"
|
||||
fontsize = "11pt"
|
||||
geometry = "papersize={8in,10in},top=2cm,bottom=2cm,left=2.4cm,right=2.4cm"
|
||||
header-includes = [
|
||||
# Reduce font size of code blocks
|
||||
"\\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\\\\{\\},fontsize=\\small}",
|
||||
]
|
||||
|
||||
[output.html]
|
||||
git-repository-url = "https://github.com/mainmatter/100-exercises-to-learn-rust"
|
||||
|
||||
|
||||
@@ -32,11 +32,6 @@ a mentor to help you along the way should you get stuck. You can
|
||||
also find solutions to all exercises in the
|
||||
[`solutions` branch of the GitHub repository](https://github.com/mainmatter/100-exercises-to-learn-rust/tree/solutions).
|
||||
|
||||
## Formats
|
||||
|
||||
You can browse the course material in the browser, at [rust-exercises.com/100-exercises/](https://rust-exercises.com/100-exercises/).\
|
||||
You can also [download the course material as a PDF file](https://rust-exercises.com/100-exercises-to-learn-rust.pdf), for offline reading.
|
||||
|
||||
## Structure
|
||||
|
||||
On the left side of the screen, you can see that the course is divided into sections.
|
||||
|
||||
@@ -72,8 +72,7 @@ error: literal out of range for `i8`
|
||||
4 | let a = 255 as i8;
|
||||
| ^^^
|
||||
|
|
||||
= note: the literal `255` does not fit into the type `i8`
|
||||
whose range is `-128..=127`
|
||||
= note: the literal `255` does not fit into the type `i8` whose range is `-128..=127`
|
||||
= help: consider using the type `u8` instead
|
||||
= note: `#[deny(overflowing_literals)]` on by default
|
||||
```
|
||||
|
||||
@@ -48,7 +48,7 @@ You can create an instance of a struct by specifying the values for each field:
|
||||
// Syntax: <StructName> { <field_name>: <value>, ... }
|
||||
let ticket = Ticket {
|
||||
title: "Build a ticket system".into(),
|
||||
description: "A Kanban board".into(),
|
||||
description: "Create a system that can manage tickets across a Kanban board".into(),
|
||||
status: "Open".into()
|
||||
};
|
||||
```
|
||||
@@ -130,8 +130,7 @@ let default_config = Configuration::default();
|
||||
You can use the function call syntax even for methods that take `self` as their first parameter:
|
||||
|
||||
```rust
|
||||
// Function call syntax:
|
||||
// <StructName>::<method_name>(<instance>, <parameters>)
|
||||
// Function call syntax: <StructName>::<method_name>(<instance>, <parameters>)
|
||||
let is_open = Ticket::is_open(ticket);
|
||||
```
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ You have to use a **path** pointing to the entity you want to access.
|
||||
|
||||
You can compose the path in various ways:
|
||||
|
||||
- starting from the root of the current crate, e.g. `crate::module_1::MyStruct`
|
||||
- starting from the root of the current crate, e.g. `crate::module_1::module_2::MyStruct`
|
||||
- starting from the parent module, e.g. `super::my_function`
|
||||
- starting from the current module, e.g. `sub_module_1::MyStruct`
|
||||
|
||||
@@ -112,10 +112,3 @@ where each name comes from and potentially introducing name conflicts.\
|
||||
Nonetheless, it can be useful in some cases, like when writing unit tests. You might have noticed
|
||||
that most of our test modules start with a `use super::*;` statement to bring all the items from the parent module
|
||||
(the one being tested) into scope.
|
||||
|
||||
## Visualizing the module tree
|
||||
|
||||
If you're struggling to picture the module tree of your project, you can try using
|
||||
[`cargo-modules`](https://crates.io/crates/cargo-modules) to visualize it!
|
||||
|
||||
Refer to their documentation for installation instructions and usage examples.
|
||||
|
||||
@@ -23,14 +23,14 @@ To enforce stricter rules, we must keep the fields private[^newtype].
|
||||
We can then provide public methods to interact with a `Ticket` instance.
|
||||
Those public methods will have the responsibility of upholding our invariants (e.g. a title must not be empty).
|
||||
|
||||
If at least one field is private it is no longer possible to create a `Ticket` instance directly using the struct
|
||||
If all fields are private, it is no longer possible to create a `Ticket` instance directly using the struct
|
||||
instantiation syntax:
|
||||
|
||||
```rust
|
||||
// This won't work!
|
||||
let ticket = Ticket {
|
||||
title: "Build a ticket system".into(),
|
||||
description: "A Kanban board".into(),
|
||||
description: "Create a system that can manage tickets across a Kanban board".into(),
|
||||
status: "Open".into()
|
||||
};
|
||||
```
|
||||
|
||||
@@ -44,11 +44,9 @@ error[E0382]: use of moved value: `ticket`
|
||||
| -------- `ticket` moved due to this method call
|
||||
...
|
||||
30 | println!("Your next task is: {}", ticket.title());
|
||||
| ^^^^^^
|
||||
| value used here after move
|
||||
| ^^^^^^ value used here after move
|
||||
|
|
||||
note: `Ticket::status` takes ownership of the receiver `self`,
|
||||
which moves `ticket`
|
||||
note: `Ticket::status` takes ownership of the receiver `self`, which moves `ticket`
|
||||
--> src/main.rs:12:23
|
||||
|
|
||||
12 | pub fn status(self) -> String {
|
||||
@@ -132,11 +130,9 @@ error[E0382]: use of moved value: `ticket`
|
||||
| -------- `ticket` moved due to this method call
|
||||
...
|
||||
30 | println!("Your next task is: {}", ticket.title());
|
||||
| ^^^^^^
|
||||
| value used here after move
|
||||
| ^^^^^^ value used here after move
|
||||
|
|
||||
note: `Ticket::status` takes ownership of the receiver `self`,
|
||||
which moves `ticket`
|
||||
note: `Ticket::status` takes ownership of the receiver `self`, which moves `ticket`
|
||||
--> src/main.rs:12:23
|
||||
|
|
||||
12 | pub fn status(self) -> String {
|
||||
@@ -203,10 +199,8 @@ fn main() {
|
||||
active: true,
|
||||
};
|
||||
// `b` is a reference to the `version` field of `config`.
|
||||
// The type of `b` is `&u32`, since it contains a reference to
|
||||
// a `u32` value.
|
||||
// We create a reference by borrowing `config.version`, using
|
||||
// the `&` operator.
|
||||
// The type of `b` is `&u32`, since it contains a reference to a `u32` value.
|
||||
// We create a reference by borrowing `config.version`, using the `&` operator.
|
||||
// Same symbol (`&`), different meaning depending on the context!
|
||||
let b: &u32 = &config.version;
|
||||
// ^ The type annotation is not necessary,
|
||||
|
||||
@@ -50,11 +50,7 @@ It takes ownership of `self`, changes the title, and returns the modified `Ticke
|
||||
This is how you'd use it:
|
||||
|
||||
```rust
|
||||
let ticket = Ticket::new(
|
||||
"Title".into(),
|
||||
"Description".into(),
|
||||
"To-Do".into()
|
||||
);
|
||||
let ticket = Ticket::new("Title".into(), "Description".into(), "To-Do".into());
|
||||
let ticket = ticket.set_title("New title".into());
|
||||
```
|
||||
|
||||
@@ -92,11 +88,7 @@ Nothing is returned.
|
||||
You'd use it like this:
|
||||
|
||||
```rust
|
||||
let mut ticket = Ticket::new(
|
||||
"Title".into(),
|
||||
"Description".into(),
|
||||
"To-Do".into()
|
||||
);
|
||||
let mut ticket = Ticket::new("Title".into(), "Description".into(), "To-Do".into());
|
||||
ticket.set_title("New title".into());
|
||||
|
||||
// Use the modified ticket
|
||||
|
||||
@@ -18,25 +18,11 @@ the function's arguments, local variables and a few "bookkeeping" values.\
|
||||
When the function returns, the stack frame is popped off the stack[^stack-overflow].
|
||||
|
||||
```text
|
||||
+-----------------+
|
||||
| frame for func1 |
|
||||
+-----------------+
|
||||
|
|
||||
| func2 is
|
||||
| called
|
||||
v
|
||||
+-----------------+
|
||||
| frame for func2 |
|
||||
+-----------------+
|
||||
| frame for func1 |
|
||||
+-----------------+
|
||||
|
|
||||
| func2
|
||||
| returns
|
||||
v
|
||||
+-----------------+
|
||||
| frame for func1 |
|
||||
+-----------------+
|
||||
+-----------------+
|
||||
func2 | frame for func2 | func2
|
||||
+-----------------+ is called +-----------------+ returns +-----------------+
|
||||
| frame for func1 | -----------> | frame for func1 | ---------> | frame for func1 |
|
||||
+-----------------+ +-----------------+ +-----------------+
|
||||
```
|
||||
|
||||
From an operational point of view, stack allocation/de-allocation is **very fast**.\
|
||||
|
||||
@@ -94,8 +94,7 @@ fn print_if_even<T>(n: T) {
|
||||
This code won't compile:
|
||||
|
||||
```text
|
||||
error[E0599]: no method named `is_even` found for type parameter `T`
|
||||
in the current scope
|
||||
error[E0599]: no method named `is_even` found for type parameter `T` in the current scope
|
||||
--> src/lib.rs:2:10
|
||||
|
|
||||
1 | fn print_if_even<T>(n: T) {
|
||||
@@ -107,9 +106,7 @@ error[E0277]: `T` doesn't implement `Debug`
|
||||
--> src/lib.rs:3:19
|
||||
|
|
||||
3 | println!("{n:?} is even");
|
||||
| ^^^^^
|
||||
| `T` cannot be formatted using `{:?}` because
|
||||
| it doesn't implement `Debug`
|
||||
| ^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
|
||||
@@ -72,8 +72,7 @@ You can, for example, create a `&str` from a `String` like this:
|
||||
```rust
|
||||
let mut s = String::with_capacity(5);
|
||||
s.push_str("Hello");
|
||||
// Create a string slice reference from the `String`,
|
||||
// skipping the first byte.
|
||||
// Create a string slice reference from the `String`, skipping the first byte.
|
||||
let slice: &str = &s[1..];
|
||||
```
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@ to the pointer: the length of the slice it points to. Going back to the example
|
||||
```rust
|
||||
let mut s = String::with_capacity(5);
|
||||
s.push_str("Hello");
|
||||
// Create a string slice reference from the `String`,
|
||||
// skipping the first byte.
|
||||
// Create a string slice reference from the `String`, skipping the first byte.
|
||||
let slice: &str = &s[1..];
|
||||
```
|
||||
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
Let's go back to where our string journey started:
|
||||
|
||||
```rust
|
||||
let ticket = Ticket::new(
|
||||
"A title".into(),
|
||||
"A description".into(),
|
||||
"To-Do".into()
|
||||
);
|
||||
let ticket = Ticket::new("A title".into(), "A description".into(), "To-Do".into());
|
||||
```
|
||||
|
||||
We now know enough to start unpacking what `.into()` is doing here.
|
||||
@@ -18,11 +14,7 @@ This is the signature of the `new` method:
|
||||
|
||||
```rust
|
||||
impl Ticket {
|
||||
pub fn new(
|
||||
title: String,
|
||||
description: String,
|
||||
status: String
|
||||
) -> Self {
|
||||
pub fn new(title: String, description: String, status: String) -> Self {
|
||||
// [...]
|
||||
}
|
||||
}
|
||||
@@ -116,7 +108,7 @@ let title = String::from("A title");
|
||||
|
||||
We've been primarily using `.into()`, though.\
|
||||
If you check out the [implementors of `Into`](https://doc.rust-lang.org/std/convert/trait.Into.html#implementors)
|
||||
you won't find `Into<String> for &str`. What's going on?
|
||||
you won't find `Into<&str> for String`. What's going on?
|
||||
|
||||
`From` and `Into` are **dual traits**.\
|
||||
In particular, `Into` is implemented for any type that implements `From` using a **blanket implementation**:
|
||||
|
||||
@@ -44,8 +44,7 @@ impl Drop for MyType {
|
||||
The compiler will complain with this error message:
|
||||
|
||||
```text
|
||||
error[E0184]: the trait `Copy` cannot be implemented for this type;
|
||||
the type has a destructor
|
||||
error[E0184]: the trait `Copy` cannot be implemented for this type; the type has a destructor
|
||||
--> src/lib.rs:2:17
|
||||
|
|
||||
2 | #[derive(Clone, Copy)]
|
||||
|
||||
@@ -14,11 +14,7 @@ pub struct Ticket {
|
||||
}
|
||||
|
||||
impl Ticket {
|
||||
pub fn new(
|
||||
title: String,
|
||||
description: String,
|
||||
status: String
|
||||
) -> Self {
|
||||
pub fn new(title: String, description: String, status: String) -> Self {
|
||||
// [...]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ impl Ticket {
|
||||
match &self.status {
|
||||
Status::InProgress { assigned_to } => assigned_to,
|
||||
Status::Done | Status::ToDo => {
|
||||
panic!(
|
||||
"Only `In-Progress` tickets can be \
|
||||
assigned to someone"
|
||||
)
|
||||
panic!("Only `In-Progress` tickets can be assigned to someone"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,9 +33,7 @@ impl Ticket {
|
||||
if let Status::InProgress { assigned_to } = &self.status {
|
||||
assigned_to
|
||||
} else {
|
||||
panic!(
|
||||
"Only `In-Progress` tickets can be assigned to someone"
|
||||
);
|
||||
panic!("Only `In-Progress` tickets can be assigned to someone");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,9 +48,7 @@ you can use the `let/else` construct:
|
||||
impl Ticket {
|
||||
pub fn assigned_to(&self) -> &str {
|
||||
let Status::InProgress { assigned_to } = &self.status else {
|
||||
panic!(
|
||||
"Only `In-Progress` tickets can be assigned to someone"
|
||||
);
|
||||
panic!("Only `In-Progress` tickets can be assigned to someone");
|
||||
};
|
||||
assigned_to
|
||||
}
|
||||
|
||||
@@ -4,11 +4,7 @@ Let's revisit the `Ticket::new` function from the previous exercise:
|
||||
|
||||
```rust
|
||||
impl Ticket {
|
||||
pub fn new(
|
||||
title: String,
|
||||
description: String,
|
||||
status: Status
|
||||
) -> Ticket {
|
||||
pub fn new(title: String, description: String, status: Status) -> Ticket {
|
||||
if title.is_empty() {
|
||||
panic!("Title cannot be empty");
|
||||
}
|
||||
@@ -74,9 +70,8 @@ Rust, with `Result`, forces you to **encode fallibility in the function's signat
|
||||
If a function can fail (and you want the caller to have a shot at handling the error), it must return a `Result`.
|
||||
|
||||
```rust
|
||||
// Just by looking at the signature, you know that this function
|
||||
// can fail. You can also inspect `ParseIntError` to see what
|
||||
// kind of failures to expect.
|
||||
// Just by looking at the signature, you know that this function can fail.
|
||||
// You can also inspect `ParseIntError` to see what kind of failures to expect.
|
||||
fn parse_int(s: &str) -> Result<i32, ParseIntError> {
|
||||
// ...
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ fn parse_int(s: &str) -> Result<i32, ParseIntError> {
|
||||
}
|
||||
|
||||
// This won't compile: we're not handling the error case.
|
||||
// We must either use `match` or one of the combinators provided by
|
||||
// `Result` to "unwrap" the success value or handle the error.
|
||||
// We must either use `match` or one of the combinators provided by `Result`
|
||||
// to "unwrap" the success value or handle the error.
|
||||
let number = parse_int("42") + 2;
|
||||
```
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ that implements the `Error` trait.
|
||||
pub trait Error: Debug + Display {}
|
||||
```
|
||||
|
||||
You might recall the `:` syntax from [the `From` trait](../04_traits/09_from.md#supertrait--subtrait)—it's used to specify **supertraits**.
|
||||
You might recall the `:` syntax from [the `Sized` trait](../04_traits/08_sized.md)—it's used to specify **supertraits**.
|
||||
For `Error`, there are two supertraits: `Debug` and `Display`. If a type wants to implement `Error`, it must also
|
||||
implement `Debug` and `Display`.
|
||||
|
||||
|
||||
@@ -46,3 +46,18 @@ You can override these defaults by explicitly declaring your targets in the `Car
|
||||
[`cargo`'s documentation](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#cargo-targets) for more details.
|
||||
|
||||
Keep in mind that while a package can contain multiple crates, it can only contain one library crate.
|
||||
|
||||
## Scaffolding a new package
|
||||
|
||||
You can use `cargo` to scaffold a new package:
|
||||
|
||||
```bash
|
||||
cargo new my-binary
|
||||
```
|
||||
|
||||
This will create a new folder, `my-binary`, containing a new Rust package with the same name and a single
|
||||
binary crate inside. If you want to create a library crate instead, you can use the `--lib` flag:
|
||||
|
||||
```bash
|
||||
cargo new my-library --lib
|
||||
```
|
||||
|
||||
@@ -6,7 +6,7 @@ and why we might want to use them.
|
||||
## What is a thread?
|
||||
|
||||
A **thread** is an execution context managed by the underlying operating system.\
|
||||
Each thread has its own stack and instruction pointer.
|
||||
Each thread has its own stack, instruction pointer, and program counter.
|
||||
|
||||
A single **process** can manage multiple threads.
|
||||
These threads share the same memory space, which means they can access the same data.
|
||||
|
||||
@@ -11,9 +11,9 @@ error[E0597]: `v` does not live long enough
|
||||
...
|
||||
15 | let right = &v[split_point..];
|
||||
| ^ borrowed value does not live long enough
|
||||
16 | let left_handle = spawn(move || left.iter().sum::<i32>());
|
||||
| --------------------------------
|
||||
argument requires that `v` is borrowed for `'static`
|
||||
16 | let left_handle = thread::spawn(move || left.iter().sum::<i32>());
|
||||
| ------------------------------------------------
|
||||
argument requires that `v` is borrowed for `'static`
|
||||
19 | }
|
||||
| - `v` dropped here while still borrowed
|
||||
```
|
||||
|
||||
@@ -27,12 +27,12 @@ run out and crash with an out-of-memory error.
|
||||
fn oom_trigger() {
|
||||
loop {
|
||||
let v: Vec<usize> = Vec::with_capacity(1024);
|
||||
v.leak();
|
||||
Box::leak(v);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
At the same time, memory leaked via `leak` method is not truly forgotten.\
|
||||
At the same time, memory leaked via `Box::leak` is not truly forgotten.\
|
||||
The operating system can map each memory region to the process responsible for it.
|
||||
When the process exits, the operating system will reclaim that memory.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
So far we've been using unbounded channels.\
|
||||
You can send as many messages as you want, and the channel will grow to accommodate them.\
|
||||
In a multi-producer single-consumer scenario, this can be problematic: if the producers
|
||||
enqueue messages at a faster rate than the consumer can process them, the channel will
|
||||
enqueues messages at a faster rate than the consumer can process them, the channel will
|
||||
keep growing, potentially consuming all available memory.
|
||||
|
||||
Our recommendation is to **never** use an unbounded channel in a production system.\
|
||||
|
||||
@@ -10,9 +10,9 @@ In the non-threaded version of the system, updates were fairly straightforward:
|
||||
|
||||
## Multithreaded updates
|
||||
|
||||
The same strategy won't work in the current multithreaded version. The borrow checker would
|
||||
stop us: `SyncSender<&mut Ticket>` isn't `'static` because `&mut Ticket` doesn't satisfy the `'static` lifetime, therefore
|
||||
they can't be captured by the closure that gets passed to `std::thread::spawn`.
|
||||
The same strategy won't work in the current multi-threaded version,
|
||||
because the mutable reference would have to be sent over a channel. The borrow checker would
|
||||
stop us, because `&mut Ticket` doesn't satisfy the `'static` lifetime requirement of `SyncSender::send`.
|
||||
|
||||
There are a few ways to work around this limitation. We'll explore a few of them in the following exercises.
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ fn main() {
|
||||
let guard = lock.lock().unwrap();
|
||||
|
||||
spawn(move || {
|
||||
receiver.recv().unwrap();
|
||||
receiver.recv().unwrap();;
|
||||
});
|
||||
|
||||
// Try to send the guard over the channel
|
||||
@@ -118,14 +118,12 @@ error[E0277]: `MutexGuard<'_, i32>` cannot be sent between threads safely
|
||||
| _-----_^
|
||||
| | |
|
||||
| | required by a bound introduced by this call
|
||||
11 | | receiver.recv().unwrap();
|
||||
11 | | receiver.recv().unwrap();;
|
||||
12 | | });
|
||||
| |_^ `MutexGuard<'_, i32>` cannot be sent between threads safely
|
||||
|
|
||||
= help: the trait `Send` is not implemented for `MutexGuard<'_, i32>`,
|
||||
which is required by `{closure@src/main.rs:10:7: 10:14}: Send`
|
||||
= note: required for `std::sync::mpsc::Receiver<MutexGuard<'_, i32>>`
|
||||
to implement `Send`
|
||||
= help: the trait `Send` is not implemented for `MutexGuard<'_, i32>`, which is required by `{closure@src/main.rs:10:7: 10:14}: Send`
|
||||
= note: required for `std::sync::mpsc::Receiver<MutexGuard<'_, i32>>` to implement `Send`
|
||||
note: required because it's used within this closure
|
||||
```
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ pub async fn work() {
|
||||
|
||||
### `std::thread::spawn` vs `tokio::spawn`
|
||||
|
||||
You can think of `tokio::spawn` as the asynchronous sibling of `std::thread::spawn`.
|
||||
You can think of `tokio::spawn` as the asynchronous sibling of `std::spawn::thread`.
|
||||
|
||||
Notice a key difference: with `std::thread::spawn`, you're delegating control to the OS scheduler.
|
||||
You're not in control of how threads are scheduled.
|
||||
|
||||
@@ -55,8 +55,7 @@ note: future is not `Send` as this value is used across an await
|
||||
| -------- has type `Rc<i32>` which is not `Send`
|
||||
12 | // A `.await` point
|
||||
13 | yield_now().await;
|
||||
| ^^^^^
|
||||
| await occurs here, with `non_send` maybe used later
|
||||
| ^^^^^ await occurs here, with `non_send` maybe used later
|
||||
note: required by a bound in `tokio::spawn`
|
||||
|
|
||||
164 | pub fn spawn<F>(future: F) -> JoinHandle<F::Output>
|
||||
@@ -85,10 +84,7 @@ trait Future {
|
||||
type Output;
|
||||
|
||||
// Ignore `Pin` and `Context` for now
|
||||
fn poll(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>
|
||||
) -> Poll<Self::Output>;
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ Yields to runtime
|
||||
Tries to acquire lock
|
||||
```
|
||||
|
||||
We have a deadlock. Task B will never manage to acquire the lock, because the lock
|
||||
We have a deadlock. Task B we'll never manage to acquire the lock, because the lock
|
||||
is currently held by task A, which has yielded to the runtime before releasing the
|
||||
lock and won't be scheduled again because the runtime cannot preempt task B.
|
||||
|
||||
|
||||
@@ -105,5 +105,5 @@ async fn run() {
|
||||
Check out [`select!`'s documentation](https://tokio.rs/tokio/tutorial/select) for more details.\
|
||||
If you need to interleave two asynchronous streams of data (e.g. a socket and a channel), prefer using
|
||||
[`StreamExt::merge`](https://docs.rs/tokio-stream/latest/tokio_stream/trait.StreamExt.html#method.merge) instead.
|
||||
- A [`CancellationToken`](https://docs.rs/tokio-util/latest/tokio_util/sync/struct.CancellationToken.html) may be
|
||||
preferable to `JoinHandle::abort` in some cases.
|
||||
- Rather than "abrupt" cancellation, it can be preferable to rely
|
||||
on [`CancellationToken`](https://docs.rs/tokio-util/latest/tokio_util/sync/struct.CancellationToken.html).
|
||||
|
||||
@@ -48,5 +48,5 @@ check out the [Embedded Rust book](https://docs.rust-embedded.org/book/).
|
||||
|
||||
You can then find resources on key topics that cut across domains.\
|
||||
For testing, check out
|
||||
["Advanced testing, going beyond the basics"](https://rust-exercises.com/advanced-testing/).\
|
||||
For telemetry, check out ["You can't fix what you can't see"](https://rust-exercises.com/telemetry/).
|
||||
["Advanced testing, going beyond the basics"](https://github.com/mainmatter/rust-advanced-testing-workshop).\
|
||||
For telemetry, check out ["You can't fix what you can't see"](https://github.com/mainmatter/rust-telemetry-workshop).
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// You can also find solutions to all exercises in the `solutions` git branch.
|
||||
fn greeting() -> &'static str {
|
||||
// TODO: fix me 👇
|
||||
"I'm ready to __!"
|
||||
"I'm ready to learn Rust!"
|
||||
}
|
||||
|
||||
// Your solutions will be automatically verified by a set of tests.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// partner in this course and it'll often guide you in the right direction!
|
||||
//
|
||||
// The input parameters should have the same type of the return type.
|
||||
fn compute(a, b) -> u32 {
|
||||
fn compute(a: u32, b: u32) -> u32 {
|
||||
// Don't touch the function body.
|
||||
a + b * 2
|
||||
}
|
||||
@@ -16,4 +16,4 @@ mod tests {
|
||||
fn case() {
|
||||
assert_eq!(compute(1, 2), 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
fn intro() -> &'static str {
|
||||
// TODO: fix me 👇
|
||||
"I'm ready to __!"
|
||||
"I'm ready to build a calculator in Rust!"
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
fn compute(a: u32, b: u32) -> u32 {
|
||||
// TODO: change the line below to fix the compiler error and make the tests pass.
|
||||
a + b * 4u8
|
||||
a + b * 4u32
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
pub fn speed(start: u32, end: u32, time_elapsed: u32) -> u32 {
|
||||
// TODO: define a variable named `distance` with the right value to get tests to pass
|
||||
// Do you need to annotate the type of `distance`? Why or why not?
|
||||
|
||||
let distance: u32 = end - start;
|
||||
// Don't change the line below
|
||||
distance / time_elapsed
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// Return `true` if `n` is even, `false` otherwise.
|
||||
fn is_even(n: u32) -> bool {
|
||||
todo!()
|
||||
n % 2 == 0
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
/// calculate the average speed of the journey.
|
||||
fn speed(start: u32, end: u32, time_elapsed: u32) -> u32 {
|
||||
// TODO: Panic with a custom message if `time_elapsed` is 0
|
||||
|
||||
if time_elapsed == 0 {
|
||||
panic!("The journey took no time at all, that's impossible!");
|
||||
}
|
||||
(end - start) / time_elapsed
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
// `factorial(2)` to return `2`, and so on.
|
||||
//
|
||||
// Use only what you learned! No loops yet, so you'll have to use recursion!
|
||||
fn factorial(n: u16) -> u16 {
|
||||
if n == 0 {
|
||||
1
|
||||
} else {
|
||||
n * factorial(n - 1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -4,7 +4,13 @@ pub fn factorial(n: u32) -> u32 {
|
||||
// interprets as "I'll get back to this later", thus
|
||||
// suppressing type errors.
|
||||
// It panics at runtime.
|
||||
todo!()
|
||||
let mut result: u32 = 1; // base case
|
||||
let mut i: u32 = 1;
|
||||
while i <= n {
|
||||
result *= i;
|
||||
i += 1;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
// Rewrite the factorial function using a `for` loop.
|
||||
pub fn factorial(n: u32) -> u32 {
|
||||
todo!()
|
||||
let mut result: u32 = 1; // base case
|
||||
for i in 2..=n {
|
||||
result *= i;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
pub fn factorial(n: u32) -> u32 {
|
||||
let mut result = 1;
|
||||
let mut result: u32 = 1;
|
||||
for i in 1..=n {
|
||||
// Use saturating multiplication to stop at the maximum value of u32
|
||||
// rather than overflowing and wrapping around
|
||||
result *= i;
|
||||
result = result.saturating_mul(i);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn u16_to_u32() {
|
||||
let v: u32 = todo!();
|
||||
let v: u32 = 47;
|
||||
assert_eq!(47u16 as u32, v);
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@ mod tests {
|
||||
// You could solve this by using exactly the same expression as above,
|
||||
// but that would defeat the purpose of the exercise. Instead, use a genuine
|
||||
// `i8` value that is equivalent to `255` when converted from `u8`.
|
||||
let y: i8 = todo!();
|
||||
let y: i8 = -1;
|
||||
|
||||
assert_eq!(x, y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bool_to_u8() {
|
||||
let v: u8 = todo!();
|
||||
let v: u8 = 1;
|
||||
assert_eq!(true as u8, v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -4,6 +4,16 @@
|
||||
//
|
||||
// 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: u8,
|
||||
quantity: u8,
|
||||
}
|
||||
|
||||
impl Order {
|
||||
fn is_available(self) -> bool {
|
||||
self.quantity > 0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -17,7 +17,22 @@ 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!();
|
||||
if status != "To-Do" && status != "In Progress" && status != "Done" {
|
||||
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed")
|
||||
}
|
||||
if title.is_empty() {
|
||||
panic!("Title cannot be empty")
|
||||
}
|
||||
if description.is_empty() {
|
||||
panic!("Description cannot be empty")
|
||||
}
|
||||
if title.len() > 50 {
|
||||
panic!("Title cannot be longer than 50 bytes")
|
||||
}
|
||||
if description.len() > 500 {
|
||||
panic!("Description cannot be longer than 500 bytes")
|
||||
}
|
||||
|
||||
Self {
|
||||
title,
|
||||
description,
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
@@ -48,14 +48,14 @@ mod tests {
|
||||
|
||||
// You should be seeing this error when trying to run this exercise:
|
||||
//
|
||||
// error[E0616]: field `description` of struct `Ticket` is private
|
||||
// error[E0616]: field `description` of struct `encapsulation::ticket::Ticket` is private
|
||||
// |
|
||||
// | assert_eq!(ticket.description, "A description");
|
||||
// | ^^^^^^^^^^^^^^^^^^
|
||||
//
|
||||
// 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(),
|
||||
// };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,17 @@ pub mod ticket {
|
||||
// - `title` that returns the `title` field.
|
||||
// - `description` that returns the `description` field.
|
||||
// - `status` that returns the `status` field.
|
||||
pub fn title(self) -> String {
|
||||
self.title
|
||||
}
|
||||
|
||||
pub fn description(self) -> String {
|
||||
self.description
|
||||
}
|
||||
|
||||
pub fn status(self) -> String {
|
||||
self.status
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,21 +11,9 @@ pub struct Ticket {
|
||||
|
||||
impl Ticket {
|
||||
pub fn new(title: String, description: String, status: String) -> Ticket {
|
||||
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");
|
||||
}
|
||||
if status != "To-Do" && status != "In Progress" && status != "Done" {
|
||||
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
|
||||
}
|
||||
validate_title(&title);
|
||||
validate_description(&description);
|
||||
validate_status(&status);
|
||||
|
||||
Ticket {
|
||||
title,
|
||||
@@ -45,6 +33,45 @@ impl Ticket {
|
||||
pub fn status(&self) -> &String {
|
||||
&self.status
|
||||
}
|
||||
|
||||
pub fn set_title(&mut self, title: String) {
|
||||
validate_title(&title);
|
||||
self.title = title;
|
||||
}
|
||||
|
||||
pub fn set_description(&mut self, description: String) {
|
||||
validate_description(&description);
|
||||
self.description = description;
|
||||
}
|
||||
|
||||
pub fn set_status(&mut self, status: String) {
|
||||
validate_status(&status);
|
||||
self.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_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 validate_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 validate_status(status: &String) {
|
||||
if status != "To-Do" && status != "In Progress" && status != "Done" {
|
||||
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -11,3 +11,74 @@
|
||||
// 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) -> Order {
|
||||
validate_product_name(&product_name);
|
||||
validate_quantity(&quantity);
|
||||
validate_unit_price(&unit_price);
|
||||
|
||||
Order {
|
||||
product_name,
|
||||
quantity,
|
||||
unit_price,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn product_name(&self) -> &String {
|
||||
&self.product_name
|
||||
}
|
||||
|
||||
pub fn quantity(&self) -> &u32 {
|
||||
&self.quantity
|
||||
}
|
||||
|
||||
pub fn unit_price(&self) -> &u32 {
|
||||
&self.unit_price
|
||||
}
|
||||
|
||||
pub fn set_product_name(&mut self, product_name: String) {
|
||||
validate_product_name(&product_name);
|
||||
self.product_name = product_name;
|
||||
}
|
||||
|
||||
pub fn set_quantity(&mut self, quantity: u32) {
|
||||
validate_quantity(&quantity);
|
||||
self.quantity = quantity;
|
||||
}
|
||||
|
||||
pub fn set_unit_price(&mut self, unit_price: u32) {
|
||||
validate_unit_price(&unit_price);
|
||||
self.unit_price = unit_price;
|
||||
}
|
||||
|
||||
pub fn total(&self) -> u32 {
|
||||
self.quantity * self.unit_price
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_product_name(product_name: &String) {
|
||||
if product_name.is_empty() {
|
||||
panic!("Product name cannot be empty");
|
||||
}
|
||||
if product_name.len() > 300 {
|
||||
panic!("Product name cannot be longer than 300 bytes");
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_quantity(quantity: &u32) {
|
||||
if quantity == &0 {
|
||||
panic!("Quantity must be greater than zero");
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_unit_price(unit_price: &u32) {
|
||||
if unit_price == &0 {
|
||||
panic!("Unit price must be greater than zero");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
fn intro() -> &'static str {
|
||||
// TODO: fix me 👇
|
||||
"I'm ready to __!"
|
||||
"I'm ready to learn about traits!"
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -3,9 +3,3 @@
|
||||
// a foreign type (`u32`, from `std`).
|
||||
// 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!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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: &Self) -> bool {
|
||||
self.title == other.title
|
||||
&& self.description == other.description
|
||||
&& self.status == other.status
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -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(Debug, PartialEq)]
|
||||
struct Ticket {
|
||||
title: String,
|
||||
description: String,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -6,12 +6,11 @@ fn test_saturating_u16() {
|
||||
let b: SaturatingU16 = 5u8.into();
|
||||
let c: SaturatingU16 = u16::MAX.into();
|
||||
let d: SaturatingU16 = (&1u16).into();
|
||||
let e = &c;
|
||||
|
||||
assert_eq!(a + b, SaturatingU16::from(15u16));
|
||||
assert_eq!(a + c, SaturatingU16::from(u16::MAX));
|
||||
assert_eq!(a + d, SaturatingU16::from(11u16));
|
||||
assert_eq!(a + a, 20u16);
|
||||
assert_eq!(a + 5u16, 15u16);
|
||||
assert_eq!(a + e, SaturatingU16::from(u16::MAX));
|
||||
assert_eq!(a + &u16::MAX, SaturatingU16::from(u16::MAX));
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thirtieth() {
|
||||
fn thirthieth() {
|
||||
assert_eq!(fibonacci(30), 832040);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// 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.
|
||||
// TODO: Define a function named `lowercase` that converts all characters in a string to lowercase,
|
||||
// modifying the input in place.
|
||||
// Does it need to take a `&mut String`? Does a `&mut [str]` work? Why or why not?
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -7,22 +8,29 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let mut s = vec![];
|
||||
squared(&mut s);
|
||||
assert_eq!(s, vec![]);
|
||||
let mut s = String::from("");
|
||||
lowercase(&mut s);
|
||||
assert_eq!(s, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one() {
|
||||
let mut s = [2];
|
||||
squared(&mut s);
|
||||
assert_eq!(s, [4]);
|
||||
fn one_char() {
|
||||
let mut s = String::from("A");
|
||||
lowercase(&mut s);
|
||||
assert_eq!(s, "a");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple() {
|
||||
let mut s = vec![2, 4];
|
||||
squared(&mut s);
|
||||
assert_eq!(s, vec![4, 16]);
|
||||
fn multiple_chars() {
|
||||
let mut s = String::from("Hello, World!");
|
||||
lowercase(&mut s);
|
||||
assert_eq!(s, "hello, world!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mut_slice() {
|
||||
let mut s = "Hello, World!".to_string();
|
||||
lowercase(s.as_mut_str());
|
||||
assert_eq!(s, "hello, world!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ enum Command {
|
||||
},
|
||||
}
|
||||
|
||||
fn server(receiver: Receiver<Command>) {
|
||||
pub fn server(receiver: Receiver<Command>) {
|
||||
let mut store = TicketStore::new();
|
||||
loop {
|
||||
match receiver.recv() {
|
||||
|
||||
@@ -33,7 +33,7 @@ impl Preprocessor for ExerciseLinker {
|
||||
|
||||
book.sections
|
||||
.iter_mut()
|
||||
.for_each(|i| process_book_item(i, &ctx.renderer, &root_url));
|
||||
.for_each(|i| process_book_item(i, &root_url));
|
||||
Ok(book)
|
||||
}
|
||||
|
||||
@@ -42,11 +42,11 @@ impl Preprocessor for ExerciseLinker {
|
||||
}
|
||||
}
|
||||
|
||||
fn process_book_item(item: &mut BookItem, renderer: &str, root_url: &str) {
|
||||
fn process_book_item(item: &mut BookItem, root_url: &str) {
|
||||
match item {
|
||||
BookItem::Chapter(chapter) => {
|
||||
chapter.sub_items.iter_mut().for_each(|item| {
|
||||
process_book_item(item, renderer, root_url);
|
||||
process_book_item(item, root_url);
|
||||
});
|
||||
|
||||
let Some(source_path) = &chapter.source_path else {
|
||||
@@ -61,14 +61,10 @@ fn process_book_item(item: &mut BookItem, renderer: &str, root_url: &str) {
|
||||
|
||||
let exercise_path = source_path.strip_suffix(".md").unwrap();
|
||||
let link_section = format!(
|
||||
"\n## Exercise\n\nThe exercise for this section is located in [`{exercise_path}`]({})\n",
|
||||
"\n## Exercise\n\nThe exercise for this section is located in [`{exercise_path}`]({})",
|
||||
format!("{}/{}", root_url, exercise_path)
|
||||
);
|
||||
chapter.content.push_str(&link_section);
|
||||
|
||||
if renderer == "pandoc" {
|
||||
chapter.content.push_str("`\\newpage`{=latex}\n");
|
||||
}
|
||||
}
|
||||
BookItem::Separator => {}
|
||||
BookItem::PartTitle(_) => {}
|
||||
|
||||
Reference in New Issue
Block a user