├── .github ├── dependabot.yml └── workflows │ └── main.yml ├── .gitmodules ├── README.md ├── rust-cookbook-ru ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE-CC0 ├── README.md ├── assets ├── book.toml ├── build.rs ├── libtest.rmeta ├── src │ ├── SUMMARY.md │ ├── about.md │ ├── algorithms.md │ ├── algorithms │ │ ├── randomness.md │ │ ├── randomness │ │ │ ├── rand-choose.md │ │ │ ├── rand-custom.md │ │ │ ├── rand-dist.md │ │ │ ├── rand-passwd.md │ │ │ ├── rand-range.md │ │ │ └── rand.md │ │ ├── sorting.md │ │ └── sorting │ │ │ ├── sort.md │ │ │ ├── sort_float.md │ │ │ └── sort_struct.md │ ├── cli.md │ ├── cli │ │ ├── ansi_terminal.md │ │ ├── ansi_terminal │ │ │ └── ansi_term-basic.md │ │ ├── arguments.md │ │ └── arguments │ │ │ └── clap-basic.md │ ├── compression.md │ ├── compression │ │ ├── tar.md │ │ └── tar │ │ │ ├── tar-compress.md │ │ │ ├── tar-decompress.md │ │ │ └── tar-strip-prefix.md │ ├── concurrency.md │ ├── concurrency │ │ ├── parallel.md │ │ ├── parallel │ │ │ ├── rayon-any-all.md │ │ │ ├── rayon-iter-mut.md │ │ │ ├── rayon-map-reduce.md │ │ │ ├── rayon-parallel-search.md │ │ │ └── rayon-parallel-sort.md │ │ ├── thread │ │ │ ├── crossbeam-spawn.md │ │ │ ├── crossbeam-spsc.md │ │ │ ├── global-mut-state.md │ │ │ └── threadpool-walk.md │ │ └── threads.md │ ├── cryptography.md │ ├── cryptography │ │ ├── encryption.md │ │ ├── encryption │ │ │ └── pbkdf2.md │ │ ├── hashing.md │ │ └── hashing │ │ │ ├── hmac.md │ │ │ └── sha-digest.md │ ├── data_structures.md │ ├── data_structures │ │ ├── bitfield.md │ │ └── bitfield │ │ │ └── bitfield.md │ ├── database.md │ ├── database │ │ ├── postgres.md │ │ ├── postgres │ │ │ ├── aggregate_data.md │ │ │ ├── create_tables.md │ │ │ └── insert_query_data.md │ │ ├── sqlite.md │ │ └── sqlite │ │ │ ├── initialization.md │ │ │ ├── insert_select.md │ │ │ └── transactions.md │ ├── datetime.md │ ├── datetime │ │ ├── duration.md │ │ ├── duration │ │ │ ├── checked.md │ │ │ ├── profile.md │ │ │ └── timezone.md │ │ ├── parse.md │ │ └── parse │ │ │ ├── current.md │ │ │ ├── format.md │ │ │ ├── string.md │ │ │ └── timestamp.md │ ├── development_tools.md │ ├── development_tools │ │ ├── build_tools.md │ │ ├── build_tools │ │ │ ├── cc-bundled-cpp.md │ │ │ ├── cc-bundled-static.md │ │ │ └── cc-defines.md │ │ ├── debugging │ │ │ ├── config_log.md │ │ │ ├── config_log │ │ │ │ ├── log-custom.md │ │ │ │ ├── log-env-variable.md │ │ │ │ ├── log-mod.md │ │ │ │ └── log-timestamp.md │ │ │ ├── log.md │ │ │ └── log │ │ │ │ ├── log-custom-logger.md │ │ │ │ ├── log-debug.md │ │ │ │ ├── log-error.md │ │ │ │ ├── log-stdout.md │ │ │ │ └── log-syslog.md │ │ ├── errors.md │ │ ├── versioning.md │ │ └── versioning │ │ │ ├── semver-command.md │ │ │ ├── semver-complex.md │ │ │ ├── semver-increment.md │ │ │ ├── semver-latest.md │ │ │ └── semver-prerelease.md │ ├── encoding.md │ ├── encoding │ │ ├── complex.md │ │ ├── complex │ │ │ ├── endian-byte.md │ │ │ ├── json.md │ │ │ └── toml.md │ │ ├── csv.md │ │ ├── csv │ │ │ ├── delimiter.md │ │ │ ├── filter.md │ │ │ ├── invalid.md │ │ │ ├── read.md │ │ │ ├── serde-serialize.md │ │ │ ├── serialize.md │ │ │ └── transform.md │ │ ├── string │ │ │ ├── base64.md │ │ │ ├── hex.md │ │ │ ├── percent-encode.md │ │ │ └── url-encode.md │ │ └── strings.md │ ├── errors.md │ ├── errors │ │ ├── handle.md │ │ └── handle │ │ │ ├── backtrace.md │ │ │ ├── main.md │ │ │ └── retain.md │ ├── file.md │ ├── file │ │ ├── dir.md │ │ ├── dir │ │ │ ├── duplicate-name.md │ │ │ ├── find-file.md │ │ │ ├── ignore-case.md │ │ │ ├── loops.md │ │ │ ├── modified.md │ │ │ ├── png.md │ │ │ ├── sizes.md │ │ │ └── skip-dot.md │ │ ├── read-write.md │ │ └── read-write │ │ │ ├── memmap.md │ │ │ ├── read-file.md │ │ │ └── same-file.md │ ├── hardware.md │ ├── hardware │ │ ├── processor.md │ │ └── processor │ │ │ └── cpu-count.md │ ├── intro.md │ ├── links.md │ ├── mem.md │ ├── mem │ │ ├── global_static.md │ │ └── global_static │ │ │ └── lazy-constant.md │ ├── net.md │ ├── net │ │ ├── server.md │ │ └── server │ │ │ └── listen-unused.md │ ├── os.md │ ├── os │ │ ├── external.md │ │ └── external │ │ │ ├── continuous.md │ │ │ ├── error-file.md │ │ │ ├── piped.md │ │ │ ├── process-output.md │ │ │ └── send-input.md │ ├── science.md │ ├── science │ │ ├── mathematics.md │ │ └── mathematics │ │ │ ├── complex_numbers.md │ │ │ ├── complex_numbers │ │ │ ├── add-complex.md │ │ │ ├── create-complex.md │ │ │ └── mathematical-functions.md │ │ │ ├── linear_algebra.md │ │ │ ├── linear_algebra │ │ │ ├── add-matrices.md │ │ │ ├── invert-matrix.md │ │ │ ├── multiply-matrices.md │ │ │ ├── multiply-scalar-vector-matrix.md │ │ │ ├── vector-comparison.md │ │ │ └── vector-norm.md │ │ │ ├── miscellaneous.md │ │ │ ├── miscellaneous │ │ │ └── big-integers.md │ │ │ ├── statistics.md │ │ │ ├── statistics │ │ │ ├── central-tendency.md │ │ │ └── standard-deviation.md │ │ │ ├── trigonometry.md │ │ │ └── trigonometry │ │ │ ├── latitude-longitude.md │ │ │ ├── side-length.md │ │ │ └── tan-sin-cos.md │ ├── text.md │ ├── text │ │ ├── regex │ │ │ ├── email.md │ │ │ ├── filter-log.md │ │ │ ├── hashtags.md │ │ │ ├── phone.md │ │ │ └── replace.md │ │ └── string_parsing │ │ │ ├── from_str.md │ │ │ └── graphemes.md │ ├── web.md │ └── web │ │ ├── clients │ │ ├── api │ │ │ ├── paginated.md │ │ │ ├── rate-limited.md │ │ │ ├── rest-get.md │ │ │ ├── rest-head.md │ │ │ └── rest-post.md │ │ ├── apis.md │ │ ├── download.md │ │ ├── download │ │ │ ├── basic.md │ │ │ ├── partial.md │ │ │ └── post-file.md │ │ ├── requests.md │ │ └── requests │ │ │ ├── get.md │ │ │ └── header.md │ │ ├── mime.md │ │ ├── mime │ │ ├── filename.md │ │ ├── request.md │ │ └── string.md │ │ ├── scraping.md │ │ ├── scraping │ │ ├── broken.md │ │ ├── extract-links.md │ │ └── unique.md │ │ ├── url.md │ │ └── url │ │ ├── base.md │ │ ├── fragment.md │ │ ├── new.md │ │ ├── origin.md │ │ └── parse.md └── tests ├── rust-cookbook ├── .cargo │ └── config.toml ├── .github │ └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE-CC0 ├── README.md ├── appveyor.yml ├── assets │ └── graph.png ├── book.toml ├── build.rs ├── ci │ ├── deploy.sh │ ├── dictionary.txt │ ├── install_deps.sh │ ├── spellcheck.sh │ └── test_script.sh ├── crates │ └── web │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ ├── broken.rs │ │ ├── lib.rs │ │ ├── links.rs │ │ ├── paginated.rs │ │ └── wiki.rs ├── libtest.rmeta ├── src │ ├── SUMMARY.md │ ├── about.md │ ├── algorithms.md │ ├── algorithms │ │ ├── randomness.md │ │ ├── randomness │ │ │ ├── rand-choose.md │ │ │ ├── rand-custom.md │ │ │ ├── rand-dist.md │ │ │ ├── rand-passwd.md │ │ │ ├── rand-range.md │ │ │ └── rand.md │ │ ├── sorting.md │ │ └── sorting │ │ │ ├── sort.md │ │ │ ├── sort_float.md │ │ │ └── sort_struct.md │ ├── cli.md │ ├── cli │ │ ├── ansi_terminal.md │ │ ├── ansi_terminal │ │ │ └── ansi_term-basic.md │ │ ├── arguments.md │ │ └── arguments │ │ │ └── clap-basic.md │ ├── compression.md │ ├── compression │ │ ├── tar.md │ │ └── tar │ │ │ ├── tar-compress.md │ │ │ ├── tar-decompress.md │ │ │ └── tar-strip-prefix.md │ ├── concurrency.md │ ├── concurrency │ │ ├── parallel.md │ │ ├── parallel │ │ │ ├── rayon-any-all.md │ │ │ ├── rayon-iter-mut.md │ │ │ ├── rayon-map-reduce.md │ │ │ ├── rayon-parallel-search.md │ │ │ ├── rayon-parallel-sort.md │ │ │ └── rayon-thumbnails.md │ │ ├── thread │ │ │ ├── crossbeam-complex.md │ │ │ ├── crossbeam-spawn.md │ │ │ ├── crossbeam-spsc.md │ │ │ ├── global-mut-state.md │ │ │ ├── threadpool-fractal.md │ │ │ └── threadpool-walk.md │ │ └── threads.md │ ├── cryptography.md │ ├── cryptography │ │ ├── encryption.md │ │ ├── encryption │ │ │ └── pbkdf2.md │ │ ├── hashing.md │ │ └── hashing │ │ │ ├── hmac.md │ │ │ └── sha-digest.md │ ├── data_structures.md │ ├── data_structures │ │ ├── bitfield.md │ │ └── bitfield │ │ │ └── bitfield.md │ ├── database.md │ ├── database │ │ ├── postgres.md │ │ ├── postgres │ │ │ ├── aggregate_data.md │ │ │ ├── create_tables.md │ │ │ └── insert_query_data.md │ │ ├── sqlite.md │ │ └── sqlite │ │ │ ├── initialization.md │ │ │ ├── insert_select.md │ │ │ └── transactions.md │ ├── datetime.md │ ├── datetime │ │ ├── duration.md │ │ ├── duration │ │ │ ├── checked.md │ │ │ ├── profile.md │ │ │ └── timezone.md │ │ ├── parse.md │ │ └── parse │ │ │ ├── current.md │ │ │ ├── format.md │ │ │ ├── string.md │ │ │ └── timestamp.md │ ├── development_tools.md │ ├── development_tools │ │ ├── build_tools.md │ │ ├── build_tools │ │ │ ├── cc-bundled-cpp.md │ │ │ ├── cc-bundled-static.md │ │ │ └── cc-defines.md │ │ ├── debugging.md │ │ ├── debugging │ │ │ ├── config_log.md │ │ │ ├── config_log │ │ │ │ ├── log-custom.md │ │ │ │ ├── log-env-variable.md │ │ │ │ ├── log-mod.md │ │ │ │ └── log-timestamp.md │ │ │ ├── log.md │ │ │ └── log │ │ │ │ ├── log-custom-logger.md │ │ │ │ ├── log-debug.md │ │ │ │ ├── log-error.md │ │ │ │ ├── log-stdout.md │ │ │ │ └── log-syslog.md │ │ ├── versioning.md │ │ └── versioning │ │ │ ├── semver-command.md │ │ │ ├── semver-complex.md │ │ │ ├── semver-increment.md │ │ │ ├── semver-latest.md │ │ │ └── semver-prerelease.md │ ├── encoding.md │ ├── encoding │ │ ├── complex.md │ │ ├── complex │ │ │ ├── endian-byte.md │ │ │ ├── json.md │ │ │ └── toml.md │ │ ├── csv.md │ │ ├── csv │ │ │ ├── delimiter.md │ │ │ ├── filter.md │ │ │ ├── invalid.md │ │ │ ├── read.md │ │ │ ├── serde-serialize.md │ │ │ ├── serialize.md │ │ │ └── transform.md │ │ ├── string │ │ │ ├── base64.md │ │ │ ├── hex.md │ │ │ ├── percent-encode.md │ │ │ └── url-encode.md │ │ └── strings.md │ ├── errors.md │ ├── errors │ │ ├── handle.md │ │ └── handle │ │ │ ├── backtrace.md │ │ │ ├── main.md │ │ │ └── retain.md │ ├── file.md │ ├── file │ │ ├── dir.md │ │ ├── dir │ │ │ ├── duplicate-name.md │ │ │ ├── find-file.md │ │ │ ├── ignore-case.md │ │ │ ├── loops.md │ │ │ ├── modified.md │ │ │ ├── png.md │ │ │ ├── sizes.md │ │ │ └── skip-dot.md │ │ ├── read-write.md │ │ └── read-write │ │ │ ├── memmap.md │ │ │ ├── read-file.md │ │ │ └── same-file.md │ ├── hardware.md │ ├── hardware │ │ ├── processor.md │ │ └── processor │ │ │ └── cpu-count.md │ ├── intro.md │ ├── links.md │ ├── main.rs │ ├── mem.md │ ├── mem │ │ ├── global_static.md │ │ └── global_static │ │ │ └── lazy-constant.md │ ├── net.md │ ├── net │ │ ├── server.md │ │ └── server │ │ │ └── listen-unused.md │ ├── os.md │ ├── os │ │ ├── external.md │ │ └── external │ │ │ ├── continuous.md │ │ │ ├── error-file.md │ │ │ ├── piped.md │ │ │ ├── process-output.md │ │ │ ├── read-env-variable.md │ │ │ └── send-input.md │ ├── science.md │ ├── science │ │ ├── mathematics.md │ │ └── mathematics │ │ │ ├── complex_numbers.md │ │ │ ├── complex_numbers │ │ │ ├── add-complex.md │ │ │ ├── create-complex.md │ │ │ └── mathematical-functions.md │ │ │ ├── linear_algebra.md │ │ │ ├── linear_algebra │ │ │ ├── add-matrices.md │ │ │ ├── deserialize-matrix.md │ │ │ ├── invert-matrix.md │ │ │ ├── multiply-matrices.md │ │ │ ├── multiply-scalar-vector-matrix.md │ │ │ ├── vector-comparison.md │ │ │ └── vector-norm.md │ │ │ ├── miscellaneous.md │ │ │ ├── miscellaneous │ │ │ └── big-integers.md │ │ │ ├── statistics.md │ │ │ ├── statistics │ │ │ ├── central-tendency.md │ │ │ └── standard-deviation.md │ │ │ ├── trigonometry.md │ │ │ └── trigonometry │ │ │ ├── latitude-longitude.md │ │ │ ├── side-length.md │ │ │ └── tan-sin-cos.md │ ├── text.md │ ├── text │ │ ├── regex.md │ │ ├── regex │ │ │ ├── email.md │ │ │ ├── filter-log.md │ │ │ ├── hashtags.md │ │ │ ├── phone.md │ │ │ └── replace.md │ │ ├── string_parsing.md │ │ └── string_parsing │ │ │ ├── from_str.md │ │ │ └── graphemes.md │ ├── web.md │ └── web │ │ ├── clients.md │ │ ├── clients │ │ ├── api │ │ │ ├── paginated.md │ │ │ ├── rate-limited.md │ │ │ ├── rest-get.md │ │ │ ├── rest-head.md │ │ │ └── rest-post.md │ │ ├── apis.md │ │ ├── authentication.md │ │ ├── authentication │ │ │ └── basic.md │ │ ├── download.md │ │ ├── download │ │ │ ├── basic.md │ │ │ ├── partial.md │ │ │ └── post-file.md │ │ ├── requests.md │ │ └── requests │ │ │ ├── get.md │ │ │ └── header.md │ │ ├── mime.md │ │ ├── mime │ │ ├── filename.md │ │ ├── request.md │ │ └── string.md │ │ ├── scraping.md │ │ ├── scraping │ │ ├── broken.md │ │ ├── extract-links.md │ │ └── unique.md │ │ ├── url.md │ │ └── url │ │ ├── base.md │ │ ├── fragment.md │ │ ├── new.md │ │ ├── origin.md │ │ └── parse.md ├── tests │ └── skeptic.rs ├── theme │ └── custom.css └── xtask │ ├── Cargo.toml │ ├── README.md │ └── src │ ├── main.rs │ ├── mdbook.rs │ └── tests.rs └── scripts └── update_original.sh /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gitsubmodule 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | commit-message: 9 | prefix: "[skip ci]" 10 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Checks 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | 8 | jobs: 9 | spellchecking: 10 | name: Spellchecking 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2.2.0 14 | with: 15 | submodules: recursive 16 | fetch-depth: 200 17 | - run: npm install yaspeller 18 | - run: git show -m --name-only -1 --format="format:" | grep --color=never -i '.md' | xargs node_modules/.bin/yaspeller -c common-configs/.yaspellerrc 19 | gitlocalize-bug-checking: 20 | name: Checking Gitlocalize bugs 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v2.2.0 24 | with: 25 | fetch-depth: 200 26 | - uses: rust-lang-ru/simpleinfra/gitocalize-bug-checker@master 27 | - uses: funkill/bug-check-action@master 28 | with: 29 | original_dir: rust-cookbook/src 30 | translation_dir: rust-cookbook-ru/src 31 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "common-configs"] 2 | path = common-configs 3 | url = https://github.com/rust-lang-ru/common-configs 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-cookbook 2 | 3 | [![gitlocalized ](https://gitlocalize.com/repo/3439/ru/badge.svg)](https://gitlocalize.com/repo/3439/ru?utm_source=badge) 4 | 5 | Здесь ведётся перевод книги [Rust Cookbook](https://rust-lang-nursery.github.io/rust-cookbook/) 6 | 7 | [Ссылка на проект в GitLocalize](https://gitlocalize.com/repo/3439/ru/rust-cookbook/) 8 | 9 | ## Замечания для переводчиков 10 | 11 | ### Локальная проверка правописания 12 | 13 | Нужно сформировать Pull Request с переводом. GitLocalize поддерживает функцию формирования 14 | и отправки существующего Review Request в качестве Pull Request. При этом создаётся специфичная 15 | ветка вроде `gitlocalize-11866` и при вливании этого Pull Request соответствующий Review Request 16 | автоматически закрывается. 17 | 18 | Когда ветка уже существует, и нужно провести правки и проверку правописания локально, 19 | можно сделать следующее: 20 | ```bash 21 | npm install yaspeller 22 | 23 | git checkout gitlocalize-11866 # или что у вас там 24 | git diff --name-only master --format="format:" \ 25 | | grep --color=never -i '.md' \ 26 | | xargs node_modules/.bin/yaspeller -c common-configs/.yaspellerr 27 | ``` 28 | -------------------------------------------------------------------------------- /rust-cookbook-ru/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ../rust-cookbook/CONTRIBUTING.md -------------------------------------------------------------------------------- /rust-cookbook-ru/Cargo.toml: -------------------------------------------------------------------------------- 1 | ../rust-cookbook/Cargo.toml -------------------------------------------------------------------------------- /rust-cookbook-ru/LICENSE-CC0: -------------------------------------------------------------------------------- 1 | ../rust-cookbook/LICENSE-CC0 -------------------------------------------------------------------------------- /rust-cookbook-ru/assets: -------------------------------------------------------------------------------- 1 | ../rust-cookbook/assets -------------------------------------------------------------------------------- /rust-cookbook-ru/book.toml: -------------------------------------------------------------------------------- 1 | 2 | [book] 3 | title = "Rust Cookbook" 4 | description = "Collection of useful Rust code examples" 5 | authors = ["Rust Language Community"] 6 | multilingual = false 7 | src = "src" 8 | 9 | [output.html] 10 | mathjax-support = false 11 | google-analytics="UA-142155799-11" 12 | 13 | [output.html.playpen] 14 | editable = false 15 | 16 | [output.html.search] 17 | limit-results = 20 18 | use-boolean-and = true 19 | boost-title = 2 20 | boost-hierarchy = 2 21 | boost-paragraph = 1 22 | expand = true 23 | heading-split-level = 2 24 | -------------------------------------------------------------------------------- /rust-cookbook-ru/build.rs: -------------------------------------------------------------------------------- 1 | ../rust-cookbook/build.rs -------------------------------------------------------------------------------- /rust-cookbook-ru/libtest.rmeta: -------------------------------------------------------------------------------- 1 | ../rust-cookbook/libtest.rmeta -------------------------------------------------------------------------------- /rust-cookbook-ru/src/algorithms/randomness.md: -------------------------------------------------------------------------------- 1 | # Генерация случайных значений 2 | 3 | {{#include randomness/rand.md}} 4 | 5 | {{#include randomness/rand-range.md}} 6 | 7 | {{#include randomness/rand-dist.md}} 8 | 9 | {{#include randomness/rand-custom.md}} 10 | 11 | {{#include randomness/rand-passwd.md}} 12 | 13 | {{#include randomness/rand-choose.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/algorithms/randomness/rand-choose.md: -------------------------------------------------------------------------------- 1 | ## Создание случайных паролей из заданного множества символов 2 | 3 | [![rand-badge]][rand] [![cat-os-badge]][cat-os] 4 | 5 | Пример случайно генерирует строку заданной длины из ASCII символов по заданному пользователем байтовой строки с помощью [`gen_range`](https://docs.rs/rand/*/rand/trait.Rng.html#method.gen_range). 6 | 7 | ```rust,edition2018 8 | fn main() { 9 | use rand::Rng; 10 | const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 11 | abcdefghijklmnopqrstuvwxyz\ 12 | 0123456789)(*&^%$#@!~"; 13 | const PASSWORD_LEN: usize = 30; 14 | let mut rng = rand::thread_rng(); 15 | 16 | let password: String = (0..PASSWORD_LEN) 17 | .map(|_| { 18 | let idx = rng.gen_range(0, CHARSET.len()); 19 | CHARSET[idx] as char 20 | }) 21 | .collect(); 22 | 23 | println!("{:?}", password); 24 | } 25 | ``` 26 | 27 | 28 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/algorithms/randomness/rand-custom.md: -------------------------------------------------------------------------------- 1 | ## Генерация случайных чисел пользовательского типа 2 | 3 | [![rand-badge]][rand] [![cat-science-badge]][cat-science] 4 | 5 | Пример случайно генерирует пару `(i32, bool, f64)` и переменную пользовательского типа `Point`. 6 | Реализует типаж [`Distribution`](https://docs.rs/rand/*/rand/distributions/trait.Distribution.html) от Point для особенного типа [`Standard`](https://docs.rs/rand/*/rand/distributions/struct.Standard.html) для того, чтобы включить возможность случайной генерации значений Point. 7 | 8 | ```rust,ignore 9 | extern crate rand; 10 | 11 | use rand::Rng; 12 | use rand::distributions::{Distribution, Standard}; 13 | 14 | #[derive(Debug)] 15 | struct Point { 16 | x: i32, 17 | y: i32, 18 | } 19 | 20 | impl Distribution for Standard { 21 | fn sample(&self, rng: &mut R) -> Point { 22 | let (rand_x, rand_y) = rng.gen(); 23 | Point { 24 | x: rand_x, 25 | y: rand_y, 26 | } 27 | } 28 | } 29 | 30 | fn main() { 31 | let mut rng = rand::thread_rng(); 32 | let rand_tuple = rng.gen::<(i32, bool, f64)>(); 33 | let rand_point: Point = rng.gen(); 34 | println!("Random tuple: {:?}", rand_tuple); 35 | println!("Random Point: {:?}", rand_point); 36 | } 37 | ``` 38 | 39 | 40 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/algorithms/randomness/rand-passwd.md: -------------------------------------------------------------------------------- 1 | ## Создание случайных паролей из букв и цифр 2 | 3 | [![rand-badge]][rand] [![cat-os-badge]][cat-os] 4 | 5 | Пример случайно генерирует строку с заданной длиной из ASCII символов из диапазона `A-Z, a-z, 0-9` с помощью образца [`Alphanumeric`](https://docs.rs/rand/*/rand/distributions/struct.Alphanumeric.html). 6 | 7 | ```rust,ignore 8 | extern crate rand; 9 | 10 | use rand::{thread_rng, Rng}; 11 | use rand::distributions::Alphanumeric; 12 | 13 | fn main() { 14 | let rand_string: String = thread_rng() 15 | .sample_iter(&Alphanumeric) 16 | .take(30) 17 | .collect(); 18 | 19 | println!("{}", rand_string); 20 | } 21 | ``` 22 | 23 | 24 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/algorithms/randomness/rand-range.md: -------------------------------------------------------------------------------- 1 | ## Генерация случайных чисел из диапазона 2 | 3 | [![rand-badge]][rand] [![cat-science-badge]][cat-science] 4 | 5 | Пример генерирует случайные числа из полуоткрытого диапазона `[0, 10)` (не включающего `10`) с помощью метода [`Rng::gen_range`](https://doc.rust-lang.org/rand/*/rand/trait.Rng.html#method.gen_range). 6 | 7 | ```rust,edition2018 8 | extern crate rand; 9 | 10 | use rand::Rng; 11 | 12 | fn main() { 13 | let mut rng = rand::thread_rng(); 14 | println!("Integer: {}", rng.gen_range(0, 10)); 15 | println!("Float: {}", rng.gen_range(0.0, 10.0)); 16 | } 17 | ``` 18 | 19 | [`Uniform`](https://docs.rs/rand/*/rand/distributions/uniform/struct.Uniform.html) задаёт [равномерное распределение](https://en.wikipedia.org/wiki/Uniform_distribution_(continuous)). Его использование работает точно так же, но может работать быстрее, когда нам нужно генерировать числа из данного диапазона много раз. 20 | 21 | ```rust,edition2018 22 | extern crate rand; 23 | 24 | 25 | use rand::distributions::{Distribution, Uniform}; 26 | 27 | fn main() { 28 | let mut rng = rand::thread_rng(); 29 | let die = Uniform::from(1..7); 30 | 31 | loop { 32 | let throw = die.sample(&mut rng); 33 | println!("Roll the die: {}", throw); 34 | if throw == 6 { 35 | break; 36 | } 37 | } 38 | } 39 | ``` 40 | 41 | 42 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/algorithms/randomness/rand.md: -------------------------------------------------------------------------------- 1 | ## Генерация случайных чисел 2 | 3 | [![rand-badge]][rand] [![cat-science-badge]][cat-science] 4 | 5 | Пример генерирует случайные числа с помощью генератора (псевдо)случайных чисел [`rand::Rng`](https://docs.rs/rand/*/rand/trait.Rng.html) полученного через [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html). Каждый поток операционной системы имеет свой инициализированный генератор. Сгенерированные целые числа распределены равномерно на диапазоне, заданного их типом, а вещественные числа генерируются из диапазона от 0 до 1, не включая само число 1. 6 | 7 | ```rust 8 | extern crate rand; 9 | 10 | use rand::Rng; 11 | 12 | fn main() { 13 | let mut rng = rand::thread_rng(); 14 | 15 | let n1: u8 = rng.gen(); 16 | let n2: u16 = rng.gen(); 17 | println!("Random u8: {}", n1); 18 | println!("Random u16: {}", n2); 19 | println!("Random u32: {}", rng.gen::()); 20 | println!("Random i32: {}", rng.gen::()); 21 | println!("Random float: {}", rng.gen::()); 22 | } 23 | ``` 24 | 25 | 26 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/algorithms/sorting.md: -------------------------------------------------------------------------------- 1 | # Сортировка вектора 2 | 3 | {{#include sorting/sort.md}} 4 | {{#include sorting/sort_float.md}} 5 | {{#include sorting/sort_struct.md}} 6 | 7 | {{#include ../links.md}} 8 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/algorithms/sorting/sort.md: -------------------------------------------------------------------------------- 1 | ## Сортировка вектора целых чисел 2 | 3 | [![std-badge]][std] [![cat-science-badge]][cat-science] 4 | 5 | Этот пример сортирует вектор целых чисел с помощью метода [`vec::sort`]. Альтернативой было бы использовать [`vec::sort_unstable`], который может быть быстрее в некоторых случаях, но не гарантирует сохранение порядка равных элементов. 6 | 7 | ```rust 8 | fn main() { 9 | let mut vec = vec![1, 5, 10, 2, 15]; 10 | 11 | vec.sort(); 12 | 13 | assert_eq!(vec, vec![1, 2, 5, 10, 15]); 14 | } 15 | ``` 16 | 17 | 18 | [`vec::sort`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort 19 | [`vec::sort_unstable`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort_unstable -------------------------------------------------------------------------------- /rust-cookbook-ru/src/algorithms/sorting/sort_float.md: -------------------------------------------------------------------------------- 1 | ## Сортировка вектора вещественных чисел 2 | 3 | [![std-badge]][std] [![cat-science-badge]][cat-science] 4 | 5 | Вектор из f32 or f64 может быть отсортирован с помощью методов [`vec::sort_by`] и [`PartialOrd::partial_cmp`]. 6 | 7 | ```rust 8 | fn main() { 9 | let mut vec = vec![1.1, 1.15, 5.5, 1.123, 2.0]; 10 | 11 | vec.sort_by(|a, b| a.partial_cmp(b).unwrap()); 12 | 13 | assert_eq!(vec, vec![1.1, 1.123, 1.15, 2.0, 5.5]); 14 | } 15 | ``` 16 | 17 | 18 | [`vec::sort_by`]: https://doc.rust-lang.org/std/primitive.slice.html#method.sort_by 19 | [`PartialOrd::partial_cmp`]: https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html#tymethod.partial_cmp -------------------------------------------------------------------------------- /rust-cookbook-ru/src/cli.md: -------------------------------------------------------------------------------- 1 | # Командная строка 2 | 3 | Рецепт | Крейты | Категории 4 | --- | --- | --- 5 | [Разбор аргументов командной строки] | [![clap-badge]][clap] | [![cat-command-line-badge]][cat-command-line] 6 | [ANSI терминал] | [![ansi_term-badge]][ansi_term] | [![cat-command-line-badge]][cat-command-line] 7 | 8 | {{#include links.md}} 9 | 10 | 11 | [Разбор аргументов командной строки]: cli/arguments.html#parse-command-line-arguments 12 | [ANSI терминал]: cli/ansi_terminal.html#ansi-terminal -------------------------------------------------------------------------------- /rust-cookbook-ru/src/cli/ansi_terminal.md: -------------------------------------------------------------------------------- 1 | # ANSI терминал 2 | 3 | {{#include ansi_terminal/ansi_term-basic.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/cli/arguments.md: -------------------------------------------------------------------------------- 1 | # Основы Clap 2 | 3 | {{#include arguments/clap-basic.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/compression.md: -------------------------------------------------------------------------------- 1 | # Сжатие данных 2 | 3 | Рецепт | Крейты | Категории 4 | --- | --- | --- 5 | [Распаковка tar-архива] | [![flate2-badge]][flate2] [![tar-badge]][tar] | [![cat-compression-badge]][cat-compression] 6 | [Запаковка каталога в tar-архив] | [![flate2-badge]][flate2] [![tar-badge]][tar] | [![cat-compression-badge]][cat-compression] 7 | [Распаковка tar-архива с удалением префиксов путей] | [![flate2-badge]][flate2] [![tar-badge]][tar] | [![cat-compression-badge]][cat-compression] 8 | 9 | {{#include links.md}} 10 | 11 | 12 | [Распаковка tar-архива]: compression/tar.html#decompress-a-tarball 13 | [Запаковка каталога в tar-архив]: compression/tar.html#compress-a-directory-into-tarball 14 | [Распаковка tar-архива с удалением префиксов путей]: compression/tar.html#decompress-a-tarball-while-removing-a-prefix-from-the-paths -------------------------------------------------------------------------------- /rust-cookbook-ru/src/compression/tar.md: -------------------------------------------------------------------------------- 1 | # Работа с tar-архивами 2 | 3 | {{#include tar/tar-decompress.md}} 4 | 5 | {{#include tar/tar-compress.md}} 6 | 7 | {{#include tar/tar-strip-prefix.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/compression/tar/tar-compress.md: -------------------------------------------------------------------------------- 1 | ## Запаковка каталога в tar-архив 2 | 3 | [![flate2-badge]][flate2] [![tar-badge]][tar] [![cat-compression-badge]][cat-compression] 4 | 5 | Сжатие каталога `/var/log` directory в `archive.tar.gz`. 6 | 7 | Этот пример создаёт [`File`], обёрнутый в [`GzEncoder`](https://docs.rs/flate2/*/flate2/write/struct.GzEncoder.html) и [`tar::Builder`](https://docs.rs/tar/*/tar/struct.Builder.html). Рекурсивно добавляет содержимое каталога `/var/log` в архив по пути `backup/logs` с помощью [`Builder::append_dir_all`](https://docs.rs/tar/*/tar/struct.Builder.html#method.append_dir_all). 8 | [`GzEncoder`](https://docs.rs/flate2/*/flate2/write/struct.GzEncoder.html) ответственен за прозрачный интерфейс для сжатия данных до записи их в файл `archive.tar.gz`. 9 | 10 | ```rust,no_run 11 | extern crate tar; 12 | extern crate flate2; 13 | 14 | use std::fs::File; 15 | use flate2::Compression; 16 | use flate2::write::GzEncoder; 17 | 18 | fn main() -> Result<(), std::io::Error> { 19 | let tar_gz = File::create("archive.tar.gz")?; 20 | let enc = GzEncoder::new(tar_gz, Compression::default()); 21 | let mut tar = tar::Builder::new(enc); 22 | tar.append_dir_all("backup/logs", "/var/log")?; 23 | Ok(()) 24 | } 25 | ``` 26 | 27 | 28 | [`File`]: https://docs.rs/tar/*/tar/struct.Builder.html#method.append_dir_all -------------------------------------------------------------------------------- /rust-cookbook-ru/src/compression/tar/tar-decompress.md: -------------------------------------------------------------------------------- 1 | ## Распаковка tar-архива 2 | 3 | [![flate2-badge]][flate2] [![tar-badge]][tar] [![cat-compression-badge]][cat-compression] 4 | 5 | Пример разжимает с помощью ([`GzDecoder`](https://docs.rs/flate2/*/flate2/read/struct.GzDecoder.html)) и распаковывает с помощью ([`Archive::unpack`](https://docs.rs/tar/*/tar/struct.Archive.html#method.unpack)) все файлы из сжатого tar-архива `archive.tar.gz` в текущем рабочем каталоге. Распаковка осуществляется в том же самом каталоге. 6 | 7 | ```rust,no_run 8 | extern crate flate2; 9 | extern crate tar; 10 | 11 | use std::fs::File; 12 | use flate2::read::GzDecoder; 13 | use tar::Archive; 14 | 15 | fn main() -> Result<(), std::io::Error> { 16 | let path = "archive.tar.gz"; 17 | 18 | let tar_gz = File::open(path)?; 19 | let tar = GzDecoder::new(tar_gz); 20 | let mut archive = Archive::new(tar); 21 | archive.unpack(".")?; 22 | 23 | Ok(()) 24 | } 25 | ``` 26 | 27 | 28 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/concurrency/parallel.md: -------------------------------------------------------------------------------- 1 | # Параллелизм 2 | 3 | {{#include parallel/rayon-iter-mut.md}} 4 | 5 | {{#include parallel/rayon-any-all.md}} 6 | 7 | {{#include parallel/rayon-parallel-search.md}} 8 | 9 | {{#include parallel/rayon-parallel-sort.md}} 10 | 11 | {{#include parallel/rayon-map-reduce.md}} 12 | 13 | {{#include parallel/rayon-thumbnails.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/concurrency/parallel/rayon-iter-mut.md: -------------------------------------------------------------------------------- 1 | ## Параллельное изменение элементов массива 2 | 3 | [![rayon-badge]][rayon] [![cat-concurrency-badge]][cat-concurrency] 4 | 5 | Этот пример использует крейт `rayon`, библиотеку с примитивами для параллелизма данных в Rust. `rayon` реализует метод [`par_iter_mut`](https://docs.rs/rayon/*/rayon/iter/trait.IntoParallelRefMutIterator.html#tymethod.par_iter_mut) для любого параллельного Iterable типа данных. Это особый тип итератора, который может быть потенциально выполняться параллельно. 6 | 7 | ```rust 8 | extern crate rayon; 9 | 10 | use rayon::prelude::*; 11 | 12 | fn main() { 13 | let mut arr = [0, 7, 9, 11]; 14 | arr.par_iter_mut().for_each(|p| *p -= 1); 15 | println!("{:?}", arr); 16 | } 17 | ``` 18 | 19 | 20 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/concurrency/parallel/rayon-parallel-sort.md: -------------------------------------------------------------------------------- 1 | ## Параллельная сортировка вектора 2 | 3 | [![rayon-badge]][rayon] [![rand-badge]][rand] [![cat-concurrency-badge]][cat-concurrency] 4 | 5 | Этот пример параллельно сортирует вектор строк. 6 | 7 | Более детально, пример создаёт вектор пустых строк, а затем, используя `par_iter_mut().for_each`, параллельно заполняет этот вектор случайными строками. Несмотря на то, что [существует множество способов](https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html) для сортировки элементов, [`par_sort_unstable`](https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html#method.par_sort_unstable) обычно быстрее, чем алгоритмы [стабильной сортировки](https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html#method.par_sort). 8 | 9 | ```rust,ignore 10 | extern crate rand; 11 | extern crate rayon; 12 | 13 | use rand::{Rng, thread_rng}; 14 | use rand::distributions::Alphanumeric; 15 | use rayon::prelude::*; 16 | 17 | fn main() { 18 | let mut vec = vec![String::new(); 100_000]; 19 | vec.par_iter_mut().for_each(|p| { 20 | let mut rng = thread_rng(); 21 | *p = (0..5).map(|_| rng.sample(&Alphanumeric)).collect() 22 | }); 23 | vec.par_sort_unstable(); 24 | } 25 | ``` 26 | 27 | 28 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/concurrency/threads.md: -------------------------------------------------------------------------------- 1 | # Потоки 2 | 3 | {{#include thread/crossbeam-spawn.md}} 4 | 5 | {{#include thread/crossbeam-spsc.md}} 6 | 7 | {{#include thread/global-mut-state.md}} 8 | 9 | {{#include thread/threadpool-walk.md}} 10 | 11 | {{#include thread/threadpool-fractal.md}} 12 | 13 | {{#include ../links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/cryptography.md: -------------------------------------------------------------------------------- 1 | # Криптография 2 | 3 | Рецепт | Крейты | Категории 4 | --- | --- | --- 5 | [Вычисление SHA-256 хеша для файла] | [![ring-badge]][ring] [![data-encoding-badge]][data-encoding] | [![cat-cryptography-badge]][cat-cryptography] 6 | [Подписание и проверка сообщения с помощью HMAC хеша] | [![ring-badge]][ring] | [![cat-cryptography-badge]][cat-cryptography] 7 | [Соление и хеширование пароля с PBKDF2] | [![ring-badge]][ring] [![data-encoding-badge]][data-encoding] | [![cat-cryptography-badge]][cat-cryptography] 8 | 9 | {{#include links.md}} 10 | 11 | 12 | [Вычисление SHA-256 хеша для файла]: cryptography/hashing.html#calculate-the-sha-256-digest-of-a-file 13 | [Подписание и проверка сообщения с помощью HMAC хеша]: cryptography/hashing.html#sign-and-verify-a-message-with-hmac-digest 14 | [Соление и хеширование пароля с PBKDF2]: cryptography/encryption.html#salt-and-hash-a-password-with-pbkdf2 -------------------------------------------------------------------------------- /rust-cookbook-ru/src/cryptography/encryption.md: -------------------------------------------------------------------------------- 1 | # Шифрование 2 | 3 | {{#include encryption/pbkdf2.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/cryptography/hashing.md: -------------------------------------------------------------------------------- 1 | # Хэширование 2 | 3 | {{#include hashing/sha-digest.md}} 4 | 5 | {{#include hashing/hmac.md}} 6 | 7 | {{#include ../links.md}} 8 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/cryptography/hashing/hmac.md: -------------------------------------------------------------------------------- 1 | ## Подпись и проверка сообщения с помощью HMAC хеша 2 | 3 | [![ring-badge]][ring] [![cat-cryptography-badge]][cat-cryptography] 4 | 5 | Пример использует [`ring::hmac`] для создания [`hmac::Signature`] из строки, а затем проверяет, что сигнатура корректна. 6 | 7 | ```rust 8 | extern crate ring; 9 | 10 | use ring::{hmac, rand}; 11 | use ring::rand::SecureRandom; 12 | use ring::error::Unspecified; 13 | 14 | fn main() -> Result<(), Unspecified> { 15 | let mut key_value = [0u8; 48]; 16 | let rng = rand::SystemRandom::new(); 17 | rng.fill(&mut key_value)?; 18 | let key = hmac::Key::new(hmac::HMAC_SHA256, &key_value); 19 | 20 | let message = "Legitimate and important message."; 21 | let signature = hmac::sign(&key, message.as_bytes()); 22 | hmac::verify(&key, message.as_bytes(), signature.as_ref())?; 23 | 24 | Ok(()) 25 | } 26 | ``` 27 | 28 | 29 | [`hmac::Signature`]: https://briansmith.org/rustdoc/ring/hmac/struct.Signature.html 30 | [`ring::hmac`]: https://briansmith.org/rustdoc/ring/hmac/ -------------------------------------------------------------------------------- /rust-cookbook-ru/src/data_structures.md: -------------------------------------------------------------------------------- 1 | # Структуры данных 2 | 3 | Рецепт | Крейты | Категории 4 | --- | --- | --- 5 | [Определение и работа с типами, представленными в виде битовых полей] | [![bitflags-badge]][bitflags] | [![cat-no-std-badge]][cat-no-std] 6 | 7 | {{#include links.md}} 8 | 9 | 10 | [Определение и работа с типами, представленными в виде битовых полей]: data_structures/bitfield.html#define-and-operate-on-a-type-represented-as-a-bitfield -------------------------------------------------------------------------------- /rust-cookbook-ru/src/data_structures/bitfield.md: -------------------------------------------------------------------------------- 1 | # Пользовательские структуры данных 2 | 3 | {{#include bitfield/bitfield.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/database.md: -------------------------------------------------------------------------------- 1 | # Базы данных 2 | 3 | Рецепт | Крейты | Категории 4 | --- | --- | --- 5 | [Создание SQLite базы данных] | [![rusqlite-badge]][rusqlite] | [![cat-database-badge]][cat-database] 6 | [Выборка и вставка данных](database/sqlite.html#insert-and-select-data) | [![rusqlite-badge]][rusqlite] | [![cat-database-badge]][cat-database] 7 | [Создание таблиц в Postgres] | [![postgres-badge]][postgres] | [![cat-database-badge]][cat-database] 8 | [Выборка и вставка данных] | [![postgres-badge]][postgres] | [![cat-database-badge]][cat-database] 9 | [Агрегирование данных] | [![postgres-badge]][postgres] | [![cat-database-badge]][cat-database] 10 | 11 | {{#include links.md}} 12 | 13 | 14 | [Создание SQLite базы данных]: database/sqlite.html#create-a-sqlite-database 15 | [Создание таблиц в Postgres]: database/sqlite.html#insert-and-select-data 16 | [Выборка и вставка данных]: database/postgres.html#create-tables-in-a-postgres-database 17 | [Агрегирование данных]: database/postgres.html#insert-and-query-data -------------------------------------------------------------------------------- /rust-cookbook-ru/src/database/postgres.md: -------------------------------------------------------------------------------- 1 | # Работ с Postgres 2 | 3 | {{#include postgres/create_tables.md}} 4 | 5 | {{#include postgres/insert_query_data.md}} 6 | 7 | {{#include postgres/aggregate_data.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/database/postgres/aggregate_data.md: -------------------------------------------------------------------------------- 1 | ## Агрегирование данных 2 | 3 | [![postgres-badge]][postgres] [![cat-database-badge]][cat-database] 4 | 5 | Этот рецепт выводит в порядке убывания национальности первых 7999 художников из базы данных ["Museum of Modern Art"]. 6 | 7 | ```rust,no_run 8 | extern crate postgres; 9 | use postgres::{Client, Error, NoTls}; 10 | 11 | struct Nation { 12 | nationality: String, 13 | count: i64, 14 | } 15 | 16 | fn main() -> Result<(), Error> { 17 | let mut client = Client::connect( 18 | "postgresql://postgres:postgres@127.0.0.1/moma", 19 | NoTls, 20 | )?; 21 | 22 | for row in client.query 23 | ("SELECT nationality, COUNT(nationality) AS count 24 | FROM artists GROUP BY nationality ORDER BY count DESC", &[])? { 25 | 26 | let (nationality, count) : (Option, Option) 27 | = (row.get (0), row.get (1)); 28 | 29 | if nationality.is_some () && count.is_some () { 30 | 31 | let nation = Nation{ 32 | nationality: nationality.unwrap(), 33 | count: count.unwrap(), 34 | }; 35 | println!("{} {}", nation.nationality, nation.count); 36 | 37 | } 38 | } 39 | 40 | Ok(()) 41 | } 42 | ``` 43 | 44 | 45 | ["Museum of Modern Art"]: https://github.com/MuseumofModernArt/collection/blob/master/Artists.csv -------------------------------------------------------------------------------- /rust-cookbook-ru/src/database/sqlite.md: -------------------------------------------------------------------------------- 1 | # SQLite 2 | 3 | {{#include sqlite/initialization.md}} 4 | 5 | {{#include sqlite/insert_select.md}} 6 | 7 | {{#include sqlite/transactions.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/database/sqlite/initialization.md: -------------------------------------------------------------------------------- 1 | ## Создание базы данных SQLite 2 | 3 | [![rusqlite-badge]][rusqlite] [![cat-database-badge]][cat-database] 4 | 5 | Пакет `rusqlite` позволяет работать с базами данных SQLite. Посмотрите [этот пакет], если вам необходима компиляция под Windows. 6 | 7 | [`Connection::open`](https://docs.rs/rusqlite/*/rusqlite/struct.Connection.html#method.open) создаёт базу данных, если она ещё не существует. 8 | 9 | ```rust,no_run 10 | extern crate rusqlite; 11 | 12 | use rusqlite::{Connection, Result}; 13 | use rusqlite::NO_PARAMS; 14 | 15 | fn main() -> Result<()> { 16 | let conn = Connection::open("cats.db")?; 17 | 18 | conn.execute( 19 | "create table if not exists cat_colors ( 20 | id integer primary key, 21 | name text not null unique 22 | )", 23 | NO_PARAMS, 24 | )?; 25 | conn.execute( 26 | "create table if not exists cats ( 27 | id integer primary key, 28 | name text not null, 29 | color_id integer not null references cat_colors(id) 30 | )", 31 | NO_PARAMS, 32 | )?; 33 | 34 | Ok(()) 35 | } 36 | ``` 37 | 38 | 39 | [этот пакет]: https://docs.rs/rusqlite/*/rusqlite/struct.Connection.html#method.open -------------------------------------------------------------------------------- /rust-cookbook-ru/src/datetime/duration.md: -------------------------------------------------------------------------------- 1 | # Длительность и вычисление интервалов 2 | 3 | {{#include duration/profile.md}} 4 | 5 | {{#include duration/checked.md}} 6 | 7 | {{#include duration/timezone.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/datetime/duration/profile.md: -------------------------------------------------------------------------------- 1 | ## Измерение прошедшего времени между двумя моментами выполнения кода 2 | 3 | [![std-badge]][std] [![cat-time-badge]][cat-time] 4 | 5 | Пример измеряет количество времени [`time::Instant::elapsed`](https://doc.rust-lang.org/std/time/struct.Instant.html#method.elapsed), прошедшее с момента [`time::Instant::now`](https://doc.rust-lang.org/std/time/struct.Instant.html#method.now). 6 | 7 | Вызов [`time::Instant::elapsed`](https://doc.rust-lang.org/std/time/struct.Instant.html#method.elapsed) возвращает [`time::Duration`](https://doc.rust-lang.org/std/time/struct.Duration.html), который мы выводим на экран в конце примера. 8 | Этот метод не изменяет и не сбрасывает состояние объекта [`time::Instant`](https://doc.rust-lang.org/std/time/struct.Instant.html). 9 | 10 | ```rust 11 | use std::time::{Duration, Instant}; 12 | # use std::thread; 13 | # 14 | # fn expensive_function() { 15 | # thread::sleep(Duration::from_secs(1)); 16 | # } 17 | 18 | fn main() { 19 | let start = Instant::now(); 20 | expensive_function(); 21 | let duration = start.elapsed(); 22 | 23 | println!("Time elapsed in expensive_function() is: {:?}", duration); 24 | } 25 | ``` 26 | 27 | 28 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/datetime/duration/timezone.md: -------------------------------------------------------------------------------- 1 | ## Преобразование локального времени во время в другом часовом поясе 2 | 3 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 4 | 5 | Этот пример получает локальное время и отображает его с помощью [`offset::Local::now`](https://docs.rs/chrono/*/chrono/offset/struct.Local.html#method.now) и затем преобразует его в UTC используя метод [`DateTime::from_utc`](https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.from_utc). 6 | Затем время преобразуется посредством структуры [`offset::FixedOffset`](https://docs.rs/chrono/*/chrono/offset/struct.FixedOffset.html) и время из UTC затем преобразуется в UTC+8 и UTC-2. 7 | 8 | ```rust 9 | extern crate chrono; 10 | 11 | use chrono::{DateTime, FixedOffset, Local, Utc}; 12 | 13 | fn main() { 14 | let local_time = Local::now(); 15 | let utc_time = DateTime::::from_utc(local_time.naive_utc(), Utc); 16 | let china_timezone = FixedOffset::east(8 * 3600); 17 | let rio_timezone = FixedOffset::west(2 * 3600); 18 | println!("Local time now is {}", local_time); 19 | println!("UTC time now is {}", utc_time); 20 | println!( 21 | "Time in Hong Kong now is {}", 22 | utc_time.with_timezone(&china_timezone) 23 | ); 24 | println!("Time in Rio de Janeiro now is {}", utc_time.with_timezone(&rio_timezone)); 25 | } 26 | ``` 27 | 28 | 29 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/datetime/parse.md: -------------------------------------------------------------------------------- 1 | # Разбор и отображение 2 | 3 | {{#include parse/current.md}} 4 | 5 | {{#include parse/timestamp.md}} 6 | 7 | {{#include parse/format.md}} 8 | 9 | {{#include parse/string.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/datetime/parse/current.md: -------------------------------------------------------------------------------- 1 | ## Просмотр даты и времени 2 | 3 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 4 | 5 | Код получает текущее [`DateTime`](https://docs.rs/chrono/*/chrono/struct.DateTime.html) в UTC, его час/минуты/секунды посредством типажа [`Timelike`](https://docs.rs/chrono/*/chrono/trait.Timelike.html) и его год/месяц/день/день недели посредством типажа [`Datelike`](https://docs.rs/chrono/*/chrono/trait.Datelike.html). 6 | 7 | ```rust 8 | extern crate chrono; 9 | use chrono::{Datelike, Timelike, Utc}; 10 | 11 | fn main() { 12 | let now = Utc::now(); 13 | 14 | let (is_pm, hour) = now.hour12(); 15 | println!( 16 | "The current UTC time is {:02}:{:02}:{:02} {}", 17 | hour, 18 | now.minute(), 19 | now.second(), 20 | if is_pm { "PM" } else { "AM" } 21 | ); 22 | println!( 23 | "And there have been {} seconds since midnight", 24 | now.num_seconds_from_midnight() 25 | ); 26 | 27 | let (is_common_era, year) = now.year_ce(); 28 | println!( 29 | "The current UTC date is {}-{:02}-{:02} {:?} ({})", 30 | year, 31 | now.month(), 32 | now.day(), 33 | now.weekday(), 34 | if is_common_era { "CE" } else { "BCE" } 35 | ); 36 | println!( 37 | "And the Common Era began {} days ago", 38 | now.num_days_from_ce() 39 | ); 40 | } 41 | ``` 42 | 43 | 44 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/datetime/parse/format.md: -------------------------------------------------------------------------------- 1 | ## Форматированный вывод даты и времени 2 | 3 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 4 | 5 | Пример получает и отображает текущее время в UTC используя метод [`Utc::now`](https://docs.rs/chrono/*/chrono/offset/struct.Utc.html#method.now). Форматирует текущее время в распространённых форматах [RFC 2822](https://www.ietf.org/rfc/rfc2822.txt) посредством [`DateTime::to_rfc2822`](https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.to_rfc2822), [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) посредством [`DateTime::to_rfc3339`](https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.to_rfc3339), и пользовательском формате используя [`DateTime::format`](https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.format). 6 | 7 | ```rust 8 | extern crate chrono; 9 | use chrono::{DateTime, Utc}; 10 | 11 | fn main() { 12 | let now: DateTime = Utc::now(); 13 | 14 | println!("UTC now is: {}", now); 15 | println!("UTC now in RFC 2822 is: {}", now.to_rfc2822()); 16 | println!("UTC now in RFC 3339 is: {}", now.to_rfc3339()); 17 | println!("UTC now in a custom format is: {}", now.format("%a %b %e %T %Y")); 18 | } 19 | ``` 20 | 21 | 22 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/datetime/parse/timestamp.md: -------------------------------------------------------------------------------- 1 | ## Преобразование даты в UNIX-timestamp и обратно 2 | 3 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 4 | 5 | Пример преобразует дату, переданную через [`NaiveDate::from_ymd`](https://docs.rs/chrono/*/chrono/naive/struct.NaiveDate.html#method.from_ymd) и [`NaiveTime::from_hms`](https://docs.rs/chrono/*/chrono/naive/struct.NaiveTime.html#method.from_hms) во [временную метку UNIX](https://en.wikipedia.org/wiki/Unix_time) (UNIX timestemp) используя метод [`NaiveDateTime::timestamp`](https://docs.rs/chrono/*/chrono/naive/struct.NaiveDateTime.html#method.timestamp). 6 | Затем он вычисляет дату, соответствующую одному миллиарду секунд, прошедших с 1 Января, 1970 UTC при помощи функции [`NaiveDateTime::from_timestamp`](https://docs.rs/chrono/*/chrono/naive/struct.NaiveDateTime.html#method.from_timestamp). 7 | 8 | ```rust 9 | extern crate chrono; 10 | 11 | use chrono::{NaiveDate, NaiveDateTime}; 12 | 13 | fn main() { 14 | let date_time: NaiveDateTime = NaiveDate::from_ymd(2017, 11, 12).and_hms(17, 33, 44); 15 | println!( 16 | "Number of seconds between 1970-01-01 00:00:00 and {} is {}.", 17 | date_time, date_time.timestamp()); 18 | 19 | let date_time_after_a_billion_seconds = NaiveDateTime::from_timestamp(1_000_000_000, 0); 20 | println!( 21 | "Date after a billion seconds since 1970-01-01 00:00:00 was {}.", 22 | date_time_after_a_billion_seconds); 23 | } 24 | ``` 25 | 26 | 27 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/build_tools.md: -------------------------------------------------------------------------------- 1 | # Инструменты времени компиляции 2 | 3 | Этот раздел охватывает инструменты времени компиляции, или код который запускается 4 | до момента компиляции исходного кода крейта. По соглашению, код исполняемый во время 5 | сборки находится в файле **build.rs** и он часто называется "скриптом сборки". 6 | Распространённые случаи использования включают генерацию Rust кода и компиляцию 7 | связанного C/C++/asm кода. Смотрите [документацию по этому вопросу] на crates.io 8 | для дополнительной информации. 9 | 10 | {{#include build_tools/cc-bundled-static.md}} 11 | 12 | {{#include build_tools/cc-bundled-cpp.md}} 13 | 14 | {{#include build_tools/cc-defines.md}} 15 | 16 | {{#include ../links.md}} 17 | 18 | 19 | [документацию по этому вопросу]: http://doc.crates.io/build-script.html -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/debugging/config_log.md: -------------------------------------------------------------------------------- 1 | # Конфигурация логирования 2 | 3 | {{#include config_log/log-mod.md}} 4 | 5 | {{#include config_log/log-env-variable.md}} 6 | 7 | {{#include config_log/log-timestamp.md}} 8 | 9 | {{#include config_log/log-custom.md}} 10 | 11 | {{#include ../../links.md}} 12 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/debugging/config_log/log-env-variable.md: -------------------------------------------------------------------------------- 1 | ## Использование переменной среды для настройки логирования 2 | 3 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 4 | 5 | Структура [`Builder`] настраивает логирование. 6 | 7 | Структура [`Builder::parse`] анализирует содержимое переменной среды `MY_APP_LOG` 8 | в форме синтаксиса [`RUST_LOG`]. Затем [`Builder::init`] инициализирует логгер. 9 | Все эти шаги обычно выполняются внутри с помощью [`env_logger::init`]. 10 | 11 | ```rust 12 | #[macro_use] 13 | extern crate log; 14 | extern crate env_logger; 15 | 16 | use std::env; 17 | use env_logger::Builder; 18 | 19 | fn main() { 20 | Builder::new() 21 | .parse(&env::var("MY_APP_LOG").unwrap_or_default()) 22 | .init(); 23 | 24 | info!("informational message"); 25 | warn!("warning message"); 26 | error!("this is an error {}", "message"); 27 | } 28 | ``` 29 | 30 | [`env_logger::init`]: https://docs.rs/env_logger/*/env_logger/fn.init.html 31 | [`Builder`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html 32 | [`Builder::init`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html#method.init 33 | [`Builder::parse`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html#method.parse 34 | [`RUST_LOG`]: https://docs.rs/env_logger/*/env_logger/#enabling-logging 35 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/debugging/log.md: -------------------------------------------------------------------------------- 1 | # Диагностические сообщения 2 | 3 | {{#include log/log-debug.md}} 4 | 5 | {{#include log/log-error.md}} 6 | 7 | {{#include log/log-stdout.md}} 8 | 9 | {{#include log/log-custom-logger.md}} 10 | 11 | {{#include log/log-syslog.md}} 12 | 13 | {{#include ../../links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/debugging/log/log-custom-logger.md: -------------------------------------------------------------------------------- 1 | ## Логирование сообщений с помощью пользовательского логгера 2 | 3 | [![log-badge]][log] [![cat-debugging-badge]][cat-debugging] 4 | 5 | Реализует особый логгер в консоль `ConsoleLogger`, который печатает в стандартный вывод. 6 | Чтобы иметь возможность использовать макросы для логгеров, `ConsoleLogger` реализует типаж 7 | [`log::Log`]. Вызов функции [`log::set_logger`] подключает логгер. 8 | 9 | ```rust 10 | #[macro_use] 11 | extern crate log; 12 | 13 | use log::{Record, Level, Metadata, LevelFilter, SetLoggerError}; 14 | 15 | static CONSOLE_LOGGER: ConsoleLogger = ConsoleLogger; 16 | 17 | struct ConsoleLogger; 18 | 19 | impl log::Log for ConsoleLogger { 20 | fn enabled(&self, metadata: &Metadata) -> bool { 21 | metadata.level() <= Level::Info 22 | } 23 | 24 | fn log(&self, record: &Record) { 25 | if self.enabled(record.metadata()) { 26 | println!("Rust says: {} - {}", record.level(), record.args()); 27 | } 28 | } 29 | 30 | fn flush(&self) {} 31 | } 32 | 33 | fn main() -> Result<(), SetLoggerError> { 34 | log::set_logger(&CONSOLE_LOGGER)?; 35 | log::set_max_level(LevelFilter::Info); 36 | 37 | info!("hello log"); 38 | warn!("warning"); 39 | error!("oops"); 40 | Ok(()) 41 | } 42 | ``` 43 | 44 | [`log::Log`]: https://docs.rs/log/*/log/trait.Log.html 45 | [`log::set_logger`]: https://docs.rs/log/*/log/fn.set_logger.html 46 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/debugging/log/log-debug.md: -------------------------------------------------------------------------------- 1 | ## Вывод отладочного сообщения в консоль 2 | 3 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 4 | 5 | Крейт `log` обеспечивает инструменты для логирования. Крейт `env_logger` конфигурирует 6 | логирование с помощью переменных окружения. Макрос [`debug!`] работает подобно другим 7 | макросам, принимая строки форматирования по образцу [`std::fmt`]. 8 | 9 | ```rust 10 | #[macro_use] 11 | extern crate log; 12 | extern crate env_logger; 13 | 14 | fn execute_query(query: &str) { 15 | debug!("Executing query: {}", query); 16 | } 17 | 18 | fn main() { 19 | env_logger::init(); 20 | 21 | execute_query("DROP TABLE students"); 22 | } 23 | ``` 24 | 25 | Ничего не выводится после запуска этого кода. По умолчанию, уровень логирования установлен 26 | в `error`, и все сообщения более низкого уровня отбрасываются. 27 | 28 | Установка переменной окружения `RUST_LOG` включает печать: 29 | 30 | ``` 31 | $ RUST_LOG=debug cargo run 32 | ``` 33 | 34 | Сначала Cargo печатает отладочную информацию, и затем будет напечатана строка в самом конце вывода на экран: 35 | 36 | ``` 37 | DEBUG:main: Executing query: DROP TABLE students 38 | ``` 39 | 40 | [`debug!`]: https://docs.rs/log/*/log/macro.debug.html 41 | [`std::fmt`]: https://doc.rust-lang.org/std/fmt/ 42 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/debugging/log/log-error.md: -------------------------------------------------------------------------------- 1 | ## Вывод сообщения об ошибке в консоль 2 | 3 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 4 | 5 | Правильная обработка ошибок рассматривает исключительные ситуации как, ну... исключительные. 6 | Здесь ошибка выводится в stderr с помощью удобного макроса [`error!`], определённого в крейте `log`. 7 | 8 | ```rust 9 | #[macro_use] 10 | extern crate log; 11 | extern crate env_logger; 12 | 13 | fn execute_query(_query: &str) -> Result<(), &'static str> { 14 | Err("I'm afraid I can't do that") 15 | } 16 | 17 | fn main() { 18 | env_logger::init(); 19 | 20 | let response = execute_query("DROP TABLE students"); 21 | if let Err(err) = response { 22 | error!("Failed to execute query: {}", err); 23 | } 24 | } 25 | ``` 26 | 27 | [`error!`]: https://docs.rs/log/*/log/macro.error.html 28 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/debugging/log/log-stdout.md: -------------------------------------------------------------------------------- 1 | ## Вывод в stdout вместо stderr 2 | 3 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 4 | 5 | Пример создаёт особую конфигурацию логгера используя [`Builder::target`], 6 | чтобы установить стандартный вывод для логирования в [`Target::Stdout`]. 7 | 8 | ```rust 9 | #[macro_use] 10 | extern crate log; 11 | extern crate env_logger; 12 | 13 | use env_logger::{Builder, Target}; 14 | 15 | fn main() { 16 | Builder::new() 17 | .target(Target::Stdout) 18 | .init(); 19 | 20 | error!("This error has been printed to Stdout"); 21 | } 22 | ``` 23 | 24 | [`Builder::target`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html#method.target 25 | [`Target::Stdout`]: https://docs.rs/env_logger/*/env_logger/fmt/enum.Target.html 26 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/debugging/log/log-syslog.md: -------------------------------------------------------------------------------- 1 | ## Логирование в Unix syslog 2 | 3 | [![log-badge]][log] [![syslog-badge]][syslog] [![cat-debugging-badge]][cat-debugging] 4 | 5 | Код в примере выводит сообщения в [UNIX syslog]. Инициализируется движок логирования 6 | через [`syslog::init`]. Объект [`syslog::Facility`] регистрирует программу путём передачи 7 | класса логирования, [`log::LevelFilter`] определяет уровень логирования, через `Option<&str>` 8 | передаётся необязательное имя программы. 9 | 10 | ```rust 11 | #[macro_use] 12 | extern crate log; 13 | # #[cfg(target_os = "linux")] 14 | extern crate syslog; 15 | 16 | # #[cfg(target_os = "linux")] 17 | use syslog::{Facility, Error}; 18 | 19 | # #[cfg(target_os = "linux")] 20 | fn main() -> Result<(), Error> { 21 | syslog::init(Facility::LOG_USER, 22 | log::LevelFilter::Debug, 23 | Some("My app name"))?; 24 | debug!("this is a debug {}", "message"); 25 | error!("this is an error!"); 26 | Ok(()) 27 | } 28 | 29 | # #[cfg(not(target_os = "linux"))] 30 | # fn main() { 31 | # println!("So far, only Linux systems are supported."); 32 | # } 33 | ``` 34 | 35 | [`log::LevelFilter`]: https://docs.rs/log/*/log/enum.LevelFilter.html 36 | [`syslog::Facility`]: https://docs.rs/syslog/*/syslog/enum.Facility.html 37 | [`syslog::init`]: https://docs.rs/syslog/*/syslog/fn.init.html 38 | 39 | [UNIX syslog]: https://www.gnu.org/software/libc/manual/html_node/Overview-of-Syslog.html 40 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/errors.md: -------------------------------------------------------------------------------- 1 | # Обработка ошибок 2 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/versioning.md: -------------------------------------------------------------------------------- 1 | # Версионирование 2 | 3 | {{#include versioning/semver-increment.md}} 4 | 5 | {{#include versioning/semver-complex.md}} 6 | 7 | {{#include versioning/semver-prerelease.md}} 8 | 9 | {{#include versioning/semver-latest.md}} 10 | 11 | {{#include versioning/semver-command.md}} 12 | 13 | {{#include ../links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/development_tools/versioning/semver-prerelease.md: -------------------------------------------------------------------------------- 1 | ## Проверка того, является ли версия предварительным релизом 2 | 3 | [![semver-badge]][semver] [![cat-config-badge]][cat-config] 4 | 5 | Даны две версии, [`is_prerelease`] проверяет, что одна является предварительным релизом, а вторая - нет. 6 | 7 | ```rust 8 | extern crate semver; 9 | 10 | use semver::{Version, SemVerError}; 11 | 12 | fn main() -> Result<(), SemVerError> { 13 | let version_1 = Version::parse("1.0.0-alpha")?; 14 | let version_2 = Version::parse("1.0.0")?; 15 | 16 | assert!(version_1.is_prerelease()); 17 | assert!(!version_2.is_prerelease()); 18 | 19 | Ok(()) 20 | } 21 | ``` 22 | 23 | [`is_prerelease`]: https://docs.rs/semver/*/semver/struct.Version.html#method.is_prerelease 24 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/complex.md: -------------------------------------------------------------------------------- 1 | # Структурированные данные 2 | 3 | {{#include complex/json.md}} 4 | 5 | {{#include complex/toml.md}} 6 | 7 | {{#include complex/endian-byte.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/complex/endian-byte.md: -------------------------------------------------------------------------------- 1 | ## Чтение и запись целых чисел в прямом порядке байтов 2 | 3 | [![byteorder-badge]][byteorder] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Крейт `byteorder` поможет развернуть значимые байты структурированных данных. Это может быть необходимо при получении информации по сети, в случае если полученные байты поступают из другой системы. 6 | 7 | ```rust 8 | extern crate byteorder; 9 | 10 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 11 | use std::io::Error; 12 | 13 | #[derive(Default, PartialEq, Debug)] 14 | struct Payload { 15 | kind: u8, 16 | value: u16, 17 | } 18 | 19 | fn main() -> Result<(), Error> { 20 | let original_payload = Payload::default(); 21 | let encoded_bytes = encode(&original_payload)?; 22 | let decoded_payload = decode(&encoded_bytes)?; 23 | assert_eq!(original_payload, decoded_payload); 24 | Ok(()) 25 | } 26 | 27 | fn encode(payload: &Payload) -> Result, Error> { 28 | let mut bytes = vec![]; 29 | bytes.write_u8(payload.kind)?; 30 | bytes.write_u16::(payload.value)?; 31 | Ok(bytes) 32 | } 33 | 34 | fn decode(mut bytes: &[u8]) -> Result { 35 | let payload = Payload { 36 | kind: bytes.read_u8()?, 37 | value: bytes.read_u16::()?, 38 | }; 39 | Ok(payload) 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/csv.md: -------------------------------------------------------------------------------- 1 | # Обработка CSV 2 | 3 | {{#include csv/read.md}} 4 | 5 | {{#include csv/delimiter.md}} 6 | 7 | {{#include csv/filter.md}} 8 | 9 | {{#include csv/invalid.md}} 10 | 11 | {{#include csv/serialize.md}} 12 | 13 | {{#include csv/serde-serialize.md}} 14 | 15 | {{#include csv/transform.md}} 16 | 17 | {{#include ../links.md}} 18 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/csv/delimiter.md: -------------------------------------------------------------------------------- 1 | ## Чтение CSV записей с другим разделителем 2 | 3 | [![csv-badge]][csv] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Читает записи CSV с [`delimiter`]. 6 | 7 | ```rust 8 | extern crate csv; 9 | use csv::Error; 10 | #[macro_use] 11 | extern crate serde_derive; 12 | 13 | #[derive(Debug, Deserialize)] 14 | struct Record { 15 | name: String, 16 | place: String, 17 | #[serde(deserialize_with = "csv::invalid_option")] 18 | id: Option, 19 | } 20 | 21 | use csv::ReaderBuilder; 22 | 23 | fn main() -> Result<(), Error> { 24 | let data = "name\tplace\tid 25 | Mark\tMelbourne\t46 26 | Ashley\tZurich\t92"; 27 | 28 | let mut reader = ReaderBuilder::new().delimiter(b'\t').from_reader(data.as_bytes()); 29 | for result in reader.deserialize::() { 30 | println!("{:?}", result?); 31 | } 32 | 33 | Ok(()) 34 | } 35 | ``` 36 | 37 | 38 | [`delimiter`]: https://docs.rs/csv/1.0.0-beta.3/csv/struct.ReaderBuilder.html#method.delimiter -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/csv/filter.md: -------------------------------------------------------------------------------- 1 | ## Фильтрация CSV записей, соответствующих предикату 2 | 3 | [![csv-badge]][csv] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Возвращает *только* строки из `data` с полем, которое соответствует `query` . 6 | 7 | ```rust 8 | # #[macro_use] 9 | # extern crate error_chain; 10 | extern crate csv; 11 | 12 | use std::io; 13 | # 14 | # error_chain!{ 15 | # foreign_links { 16 | # Io(std::io::Error); 17 | # CsvError(csv::Error); 18 | # } 19 | # } 20 | 21 | fn main() -> Result<()> { 22 | let query = "CA"; 23 | let data = "\ 24 | City,State,Population,Latitude,Longitude 25 | Kenai,AK,7610,60.5544444,-151.2583333 26 | Oakman,AL,,33.7133333,-87.3886111 27 | Sandfort,AL,,32.3380556,-85.2233333 28 | West Hollywood,CA,37031,34.0900000,-118.3608333"; 29 | 30 | let mut rdr = csv::ReaderBuilder::new().from_reader(data.as_bytes()); 31 | let mut wtr = csv::Writer::from_writer(io::stdout()); 32 | 33 | wtr.write_record(rdr.headers()?)?; 34 | 35 | for result in rdr.records() { 36 | let record = result?; 37 | if record.iter().any(|field| field == query) { 38 | wtr.write_record(&record)?; 39 | } 40 | } 41 | 42 | wtr.flush()?; 43 | Ok(()) 44 | } 45 | ``` 46 | 47 | *Отказ от ответственности: этот пример был адаптирован из [the csv crate tutorial](https://docs.rs/csv/*/csv/tutorial/index.html#filter-by-search)*. 48 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/csv/invalid.md: -------------------------------------------------------------------------------- 1 | ## Обработка неверных CSV данных с помощью Serde 2 | 3 | [![csv-badge]][csv] [![serde-badge]][serde] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Файлы CSV часто содержат неверные данные. Для этих случаев крейт `csv` предоставляет специальный десериализатор [`csv::invalid_option`](https://docs.rs/csv/*/csv/fn.invalid_option.html), который автоматически преобразует недопустимые данные в значения `None`. 6 | 7 | ```rust 8 | extern crate csv; 9 | use csv::Error; 10 | #[macro_use] 11 | extern crate serde_derive; 12 | 13 | #[derive(Debug, Deserialize)] 14 | struct Record { 15 | name: String, 16 | place: String, 17 | #[serde(deserialize_with = "csv::invalid_option")] 18 | id: Option, 19 | } 20 | 21 | fn main() -> Result<(), Error> { 22 | let data = "name,place,id 23 | mark,sydney,46.5 24 | ashley,zurich,92 25 | akshat,delhi,37 26 | alisha,colombo,xyz"; 27 | 28 | let mut rdr = csv::Reader::from_reader(data.as_bytes()); 29 | for result in rdr.deserialize() { 30 | let record: Record = result?; 31 | println!("{:?}", record); 32 | } 33 | 34 | Ok(()) 35 | } 36 | ``` 37 | 38 | 39 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/csv/serde-serialize.md: -------------------------------------------------------------------------------- 1 | ## Сериализация записей в CSV с использованием Serde 2 | 3 | [![csv-badge]][csv] [![serde-badge]][serde] [![cat-encoding-badge]][cat-encoding] 4 | 5 | В следующем примере показано, как сериализовать пользовательские структуры в виде записей CSV, используя крейт [serde]. 6 | 7 | ```rust 8 | # #[macro_use] 9 | # extern crate error_chain; 10 | extern crate csv; 11 | #[macro_use] 12 | extern crate serde_derive; 13 | 14 | use std::io; 15 | # 16 | # error_chain! { 17 | # foreign_links { 18 | # IOError(std::io::Error); 19 | # CSVError(csv::Error); 20 | # } 21 | # } 22 | 23 | #[derive(Serialize)] 24 | struct Record<'a> { 25 | name: &'a str, 26 | place: &'a str, 27 | id: u64, 28 | } 29 | 30 | fn main() -> Result<()> { 31 | let mut wtr = csv::Writer::from_writer(io::stdout()); 32 | 33 | let rec1 = Record { name: "Mark", place: "Melbourne", id: 56}; 34 | let rec2 = Record { name: "Ashley", place: "Sydney", id: 64}; 35 | let rec3 = Record { name: "Akshat", place: "Delhi", id: 98}; 36 | 37 | wtr.serialize(rec1)?; 38 | wtr.serialize(rec2)?; 39 | wtr.serialize(rec3)?; 40 | 41 | wtr.flush()?; 42 | 43 | Ok(()) 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/csv/serialize.md: -------------------------------------------------------------------------------- 1 | ## Сериализация записей в CSV формат 2 | 3 | [![csv-badge]][csv] [![cat-encoding-badge]][cat-encoding] 4 | 5 | В этом примере показано, как сериализовать Rust кортеж. [`csv::writer`](https://docs.rs/csv/*/csv/struct.Writer.html) поддерживает автоматическую сериализацию Rust типов в CSV записи. Метод [`write_record`](https://docs.rs/csv/*/csv/struct.Writer.html#method.write_record) записывает простую запись, содержащую только строковые данные. Данные с более сложными значениями, такими как числа, числа с плавающей запятой и перечисления используют метод [`serialize`](https://docs.rs/csv/*/csv/struct.Writer.html#method.serialize). Поскольку CSV writer использует внутренний буфер, всегда явно выполняйте [`flush`](https://docs.rs/csv/*/csv/struct.Writer.html#method.flush). 6 | 7 | ```rust 8 | # #[macro_use] 9 | # extern crate error_chain; 10 | extern crate csv; 11 | 12 | use std::io; 13 | # 14 | # error_chain! { 15 | # foreign_links { 16 | # CSVError(csv::Error); 17 | # IOError(std::io::Error); 18 | # } 19 | # } 20 | 21 | fn main() -> Result<()> { 22 | let mut wtr = csv::Writer::from_writer(io::stdout()); 23 | 24 | wtr.write_record(&["Name", "Place", "ID"])?; 25 | 26 | wtr.serialize(("Mark", "Sydney", 87))?; 27 | wtr.serialize(("Ashley", "Dublin", 32))?; 28 | wtr.serialize(("Akshat", "Delhi", 11))?; 29 | 30 | wtr.flush()?; 31 | Ok(()) 32 | } 33 | ``` 34 | 35 | 36 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/string/base64.md: -------------------------------------------------------------------------------- 1 | ## Кодирование и декодирование base64 2 | 3 | [![base64-badge]][base64] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Кодирует байтовый срез в строку `base64` с использованием функции [`encode`](https://docs.rs/base64/*/base64/fn.encode.html) и декодирует её с помощью функции [`decode`](https://docs.rs/base64/*/base64/fn.decode.html). 6 | 7 | ```rust 8 | # #[macro_use] 9 | # extern crate error_chain; 10 | extern crate base64; 11 | 12 | use std::str; 13 | use base64::{encode, decode}; 14 | # 15 | # error_chain! { 16 | # foreign_links { 17 | # Base64(base64::DecodeError); 18 | # Utf8Error(str::Utf8Error); 19 | # } 20 | # } 21 | 22 | fn main() -> Result<()> { 23 | let hello = b"hello rustaceans"; 24 | let encoded = encode(hello); 25 | let decoded = decode(&encoded)?; 26 | 27 | println!("origin: {}", str::from_utf8(hello)?); 28 | println!("base64 encoded: {}", encoded); 29 | println!("back to origin: {}", str::from_utf8(&decoded)?); 30 | 31 | Ok(()) 32 | } 33 | ``` 34 | 35 | 36 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/string/hex.md: -------------------------------------------------------------------------------- 1 | ## Кодирование и декодирование шестнадцатеричного кода 2 | 3 | [![data-encoding-badge]][data-encoding] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Крейт [`data_encoding`](https://docs.rs/data-encoding/*/data_encoding/) предоставляет метод `HEXUPPER::encode`, который принимает `&[u8]` и возвращает `String` содержащую шестнадцатеричное представление данных. 6 | 7 | Аналогичным образом предоставляется метод `HEXUPPER::decode`, который принимает `&[u8]` и возвращает `Vec`, если входные данные успешно декодированы. 8 | 9 | Пример ниже конвертирует данные `&[u8]` в шестнадцатеричный эквивалент. Сравнивает эти значение с ожидаемым значением. 10 | 11 | ```rust 12 | extern crate data_encoding; 13 | 14 | use data_encoding::{HEXUPPER, DecodeError}; 15 | 16 | fn main() -> Result<(), DecodeError> { 17 | let original = b"The quick brown fox jumps over the lazy dog."; 18 | let expected = "54686520717569636B2062726F776E20666F78206A756D7073206F76\ 19 | 657220746865206C617A7920646F672E"; 20 | 21 | let encoded = HEXUPPER.encode(original); 22 | assert_eq!(encoded, expected); 23 | 24 | let decoded = HEXUPPER.decode(&encoded.into_bytes())?; 25 | assert_eq!(&decoded[..], &original[..]); 26 | 27 | Ok(()) 28 | } 29 | ``` 30 | 31 | 32 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/string/url-encode.md: -------------------------------------------------------------------------------- 1 | ## Кодирование строки в application/x-www-form-urlencoded 2 | 3 | [![url-badge]][url] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Кодирует строку в синтаксис [application/x-www-form-urlencoded] используя [`form_urlencoded::byte_serialize`](https://docs.rs/url/*/url/form_urlencoded/fn.byte_serialize.html), а затем декодирует её с помощью [`form_urlencoded::parse`](https://docs.rs/url/*/url/form_urlencoded/fn.parse.html). Обе функции возвращают итераторы, которые преобразуются в `String`. 6 | 7 | ```rust 8 | extern crate url; 9 | use url::form_urlencoded::{byte_serialize, parse}; 10 | 11 | fn main() { 12 | let urlencoded: String = byte_serialize("What is ❤?".as_bytes()).collect(); 13 | assert_eq!(urlencoded, "What+is+%E2%9D%A4%3F"); 14 | println!("urlencoded:'{}'", urlencoded); 15 | 16 | let decoded: String = parse(urlencoded.as_bytes()) 17 | .map(|(key, val)| [key, val].concat()) 18 | .collect(); 19 | assert_eq!(decoded, "What is ❤?"); 20 | println!("decoded:'{}'", decoded); 21 | } 22 | ``` 23 | 24 | 25 | [application/x-www-form-urlencoded]: https://docs.rs/url/*/url/form_urlencoded/fn.byte_serialize.html -------------------------------------------------------------------------------- /rust-cookbook-ru/src/encoding/strings.md: -------------------------------------------------------------------------------- 1 | # Наборы символов 2 | 3 | {{#include string/percent-encode.md}} 4 | 5 | {{#include string/url-encode.md}} 6 | 7 | {{#include string/hex.md}} 8 | 9 | {{#include string/base64.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/errors.md: -------------------------------------------------------------------------------- 1 | # Обработка ошибок 2 | 3 | Рецепт | Крейты | Категории 4 | --- | --- | --- 5 | [Корректная обработка ошибок в функции main] | [![error-chain-badge]][error-chain] | [![cat-rust-patterns-badge]][cat-rust-patterns] 6 | [Избегание отбрасывания ошибок в преобразованиях между ними] | [![error-chain-badge]][error-chain] | [![cat-rust-patterns-badge]][cat-rust-patterns] 7 | [Получение трассировки в сложных сценариях обработки ошибок] | [![error-chain-badge]][error-chain] | [![cat-rust-patterns-badge]][cat-rust-patterns] 8 | 9 | {{#include links.md}} 10 | 11 | 12 | [Корректная обработка ошибок в функции main]: errors/handle.html#handle-errors-correctly-in-main 13 | [Избегание отбрасывания ошибок в преобразованиях между ними]: errors/handle.html#avoid-discarding-errors-during-error-conversions 14 | [Получение трассировки в сложных сценариях обработки ошибок]: errors/handle.html#obtain-backtrace-of-complex-error-scenarios -------------------------------------------------------------------------------- /rust-cookbook-ru/src/errors/handle.md: -------------------------------------------------------------------------------- 1 | # Обработка ошибок 2 | 3 | {{#include handle/main.md}} 4 | 5 | {{#include handle/retain.md}} 6 | 7 | {{#include handle/backtrace.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/file/dir.md: -------------------------------------------------------------------------------- 1 | # Обход каталогов 2 | 3 | {{#include dir/modified.md}} 4 | 5 | {{#include dir/loops.md}} 6 | 7 | {{#include dir/duplicate-name.md}} 8 | 9 | {{#include dir/find-file.md}} 10 | 11 | {{#include dir/skip-dot.md}} 12 | 13 | {{#include dir/sizes.md}} 14 | 15 | {{#include dir/png.md}} 16 | 17 | {{#include dir/ignore-case.md}} 18 | 19 | {{#include ../links.md}} 20 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/file/dir/duplicate-name.md: -------------------------------------------------------------------------------- 1 | ## Рекурсивно найти повторяющиеся имена файлов 2 | 3 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Найти рекурсивно в текущем каталоге дубликаты имён файлов, печатая их только один раз. 6 | 7 | ```rust,no_run 8 | extern crate walkdir; 9 | 10 | use std::collections::HashMap; 11 | use walkdir::WalkDir; 12 | 13 | fn main() { 14 | let mut filenames = HashMap::new(); 15 | 16 | for entry in WalkDir::new(".") 17 | .into_iter() 18 | .filter_map(Result::ok) 19 | .filter(|e| !e.file_type().is_dir()) { 20 | let f_name = String::from(entry.file_name().to_string_lossy()); 21 | let counter = filenames.entry(f_name.clone()).or_insert(0); 22 | *counter += 1; 23 | 24 | if *counter == 2 { 25 | println!("{}", f_name); 26 | } 27 | } 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/file/dir/find-file.md: -------------------------------------------------------------------------------- 1 | ## Рекурсивно найти все файлы с заданным предикатом 2 | 3 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Найти JSON файлы, изменённые за последний день в текущем каталоге. Использование метода [`follow_links`](https://docs.rs/walkdir/*/walkdir/struct.WalkDir.html#method.follow_links) гарантирует, что символические ссылки будут пройдены, как если бы они были обычными каталогами и файлами. 6 | 7 | ```rust,no_run 8 | # #[macro_use] 9 | # extern crate error_chain; 10 | extern crate walkdir; 11 | 12 | use walkdir::WalkDir; 13 | # 14 | # error_chain! { 15 | # foreign_links { 16 | # WalkDir(walkdir::Error); 17 | # Io(std::io::Error); 18 | # SystemTime(std::time::SystemTimeError); 19 | # } 20 | # } 21 | 22 | fn main() -> Result<()> { 23 | for entry in WalkDir::new(".") 24 | .follow_links(true) 25 | .into_iter() 26 | .filter_map(|e| e.ok()) { 27 | let f_name = entry.file_name().to_string_lossy(); 28 | let sec = entry.metadata()?.modified()?; 29 | 30 | if f_name.ends_with(".json") && sec.elapsed()?.as_secs() < 86400 { 31 | println!("{}", f_name); 32 | } 33 | } 34 | 35 | Ok(()) 36 | } 37 | ``` 38 | 39 | 40 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/file/dir/ignore-case.md: -------------------------------------------------------------------------------- 1 | ## Найти все файлы с заданным шаблоном, игнорируя регистр в имени файла 2 | 3 | [![glob-badge]][glob] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Найдите все файлы изображений в каталоге `/media/` соответствующие образцу `img_[0-9]*.png`. 6 | 7 | Пользовательская структура [`MatchOptions`](https://docs.rs/glob/*/glob/struct.MatchOptions.html) передаётся в функцию [`glob_with`](https://docs.rs/glob/*/glob/fn.glob_with.html) делая шаблон glob нечувствительным к регистру, оставляя другие параметры по умолчанию как [`Default`]. 8 | 9 | ```rust,no_run 10 | # #[macro_use] 11 | # extern crate error_chain; 12 | extern crate glob; 13 | 14 | use glob::{glob_with, MatchOptions}; 15 | # 16 | # error_chain! { 17 | # foreign_links { 18 | # Glob(glob::GlobError); 19 | # Pattern(glob::PatternError); 20 | # } 21 | # } 22 | 23 | fn main() -> Result<()> { 24 | let options = MatchOptions { 25 | case_sensitive: false, 26 | ..Default::default() 27 | }; 28 | 29 | for entry in glob_with("/media/img_[0-9]*.png", &options)? { 30 | println!("{}", entry?.display()); 31 | } 32 | 33 | Ok(()) 34 | } 35 | ``` 36 | 37 | 38 | [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html -------------------------------------------------------------------------------- /rust-cookbook-ru/src/file/dir/loops.md: -------------------------------------------------------------------------------- 1 | ## Найти зацикливания у заданного пути 2 | 3 | [![same_file-badge]][same_file] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Используется [`same_file::is_same_file`](https://docs.rs/same-file/*/same_file/fn.is_same_file.html) для обнаружения зацикливания по заданному пути. Например, цикл может быть создан в системе Unix через символические ссылки: 6 | 7 | ```bash 8 | mkdir -p /tmp/foo/bar/baz 9 | ln -s /tmp/foo/ /tmp/foo/bar/baz/qux 10 | ``` 11 | 12 | Следующей код будет утверждать, что цикл существует. 13 | 14 | ```rust,no_run 15 | extern crate same_file; 16 | 17 | use std::io; 18 | use std::path::{Path, PathBuf}; 19 | use same_file::is_same_file; 20 | 21 | fn contains_loop>(path: P) -> io::Result> { 22 | let path = path.as_ref(); 23 | let mut path_buf = path.to_path_buf(); 24 | while path_buf.pop() { 25 | if is_same_file(&path_buf, path)? { 26 | return Ok(Some((path_buf, path.to_path_buf()))); 27 | } else if let Some(looped_paths) = contains_loop(&path_buf)? { 28 | return Ok(Some(looped_paths)); 29 | } 30 | } 31 | return Ok(None); 32 | } 33 | 34 | fn main() { 35 | assert_eq!( 36 | contains_loop("/tmp/foo/bar/baz/qux/bar/baz").unwrap(), 37 | Some(( 38 | PathBuf::from("/tmp/foo"), 39 | PathBuf::from("/tmp/foo/bar/baz/qux") 40 | )) 41 | ); 42 | } 43 | ``` 44 | 45 | 46 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/file/dir/png.md: -------------------------------------------------------------------------------- 1 | ## Найти рекурсивно все png файлы 2 | 3 | [![glob-badge]][glob] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | В этом примере выполняется задача рекурсивно найти все файлы PNG в текущем каталоге. В данном случае шаблон `**` соответствует текущему каталогу и всем его подкаталогам. 6 | 7 | Шаблон `**` используется для любой части пути. Например, `/media/**/*.png` соответствует всем PNG в каталоге `media` и его подкаталогах. 8 | 9 | ```rust,no_run 10 | # #[macro_use] 11 | # extern crate error_chain; 12 | extern crate glob; 13 | 14 | use glob::glob; 15 | # 16 | # error_chain! { 17 | # foreign_links { 18 | # Glob(glob::GlobError); 19 | # Pattern(glob::PatternError); 20 | # } 21 | # } 22 | 23 | fn main() -> Result<()> { 24 | for entry in glob("**/*.png")? { 25 | println!("{}", entry?.display()); 26 | } 27 | 28 | Ok(()) 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/file/dir/sizes.md: -------------------------------------------------------------------------------- 1 | ## Рекурсивно рассчитать размеры файлов на заданной глубине 2 | 3 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Глубина рекурсии может быть гибко установлена методами [`WalkDir::min_depth`](https://docs.rs/walkdir/*/walkdir/struct.WalkDir.html#method.min_depth) и [`WalkDir::max_depth`](https://docs.rs/walkdir/*/walkdir/struct.WalkDir.html#method.max_depth). Вычисление суммы всех размеров файлов до глубины под папок в 3 уровня, игнорируя файлы в корневом каталоге. 6 | 7 | ```rust 8 | extern crate walkdir; 9 | 10 | use walkdir::WalkDir; 11 | 12 | fn main() { 13 | let total_size = WalkDir::new(".") 14 | .min_depth(1) 15 | .max_depth(3) 16 | .into_iter() 17 | .filter_map(|entry| entry.ok()) 18 | .filter_map(|entry| entry.metadata().ok()) 19 | .filter(|metadata| metadata.is_file()) 20 | .fold(0, |acc, m| acc + m.len()); 21 | 22 | println!("Total size: {} bytes.", total_size); 23 | } 24 | ``` 25 | 26 | 27 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/file/dir/skip-dot.md: -------------------------------------------------------------------------------- 1 | ## Обход каталогов с пропуском файлов с точкой в начале имени 2 | 3 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Используется [`filter_entry`](https://docs.rs/walkdir/*/walkdir/struct.IntoIter.html#method.filter_entry) для рекурсивного обхода записей, передавая предикат `is_not_hidden` для пропуска скрытых файлов и каталогов. Метод [`Iterator::filter`] применяется к каждому [`WalkDir::DirEntry`](https://docs.rs/walkdir/*/walkdir/struct.DirEntry.html), даже если родительский объект является скрытым каталогом. 6 | 7 | Корневой каталог `"."` передаётся в использование методом [`WalkDir::depth`](https://docs.rs/walkdir/*/walkdir/struct.DirEntry.html#method.depth) в предикате `is_not_hidden` . 8 | 9 | ```rust,no_run 10 | extern crate walkdir; 11 | 12 | use walkdir::{DirEntry, WalkDir}; 13 | 14 | fn is_not_hidden(entry: &DirEntry) -> bool { 15 | entry 16 | .file_name() 17 | .to_str() 18 | .map(|s| entry.depth() == 0 || !s.starts_with(".")) 19 | .unwrap_or(false) 20 | } 21 | 22 | fn main() { 23 | WalkDir::new(".") 24 | .into_iter() 25 | .filter_entry(|e| is_not_hidden(e)) 26 | .filter_map(|v| v.ok()) 27 | .for_each(|x| println!("{}", x.path().display())); 28 | } 29 | ``` 30 | 31 | 32 | [`Iterator::filter`]: https://docs.rs/walkdir/*/walkdir/struct.IntoIter.html#method.filter_entry -------------------------------------------------------------------------------- /rust-cookbook-ru/src/file/read-write.md: -------------------------------------------------------------------------------- 1 | # Чтение и запись 2 | 3 | {{#include read-write/read-file.md}} 4 | 5 | {{#include read-write/same-file.md}} 6 | 7 | {{#include read-write/memmap.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/file/read-write/memmap.md: -------------------------------------------------------------------------------- 1 | ## Произвольный доступ к файлу с помощью карты памяти 2 | 3 | [![memmap-badge]][memmap] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Создаёт карту памяти файла с использованием крейта [memmap] и моделирует некоторые непоследовательные чтения из файла. Использование карты памяти означает, что вы просто индексируете срезы, а не делаете с помощью [`seek`] навигацию по файлу. 6 | 7 | Функция [`Mmap::map`](https://docs.rs/memmap/*/memmap/struct.Mmap.html#method.map) предполагает, что файл индексированный картой памяти не изменяется одновременно с другим процессом, в противном случае возникает [состояние гонки] . 8 | 9 | ```rust 10 | extern crate memmap; 11 | 12 | use memmap::Mmap; 13 | use std::fs::File; 14 | use std::io::{Write, Error}; 15 | 16 | fn main() -> Result<(), Error> { 17 | # write!(File::create("content.txt")?, "My hovercraft is full of eels!")?; 18 | # 19 | let file = File::open("content.txt")?; 20 | let map = unsafe { Mmap::map(&file)? }; 21 | 22 | let random_indexes = [0, 1, 2, 19, 22, 10, 11, 29]; 23 | assert_eq!(&map[3..13], b"hovercraft"); 24 | let random_bytes: Vec = random_indexes.iter() 25 | .map(|&idx| map[idx]) 26 | .collect(); 27 | assert_eq!(&random_bytes[..], b"My loaf!"); 28 | Ok(()) 29 | } 30 | ``` 31 | 32 | 33 | [`seek`]: https://docs.rs/memmap/*/memmap/struct.Mmap.html#method.map 34 | [состояние гонки]: https://doc.rust-lang.org/std/fs/struct.File.html#method.seek -------------------------------------------------------------------------------- /rust-cookbook-ru/src/hardware.md: -------------------------------------------------------------------------------- 1 | # Аппаратный доступ 2 | 3 | Рецепт | Крейты | Категории 4 | --- | --- | --- 5 | [Проверка количества ядер процессора] | Проверка количества ядер процессора | [![cat-hardware-support-badge]][cat-hardware-support] 6 | 7 | {{#include links.md}} 8 | 9 | 10 | [Проверка количества ядер процессора]: hardware/processor.html#check-number-of-logical-cpu-cores -------------------------------------------------------------------------------- /rust-cookbook-ru/src/hardware/processor.md: -------------------------------------------------------------------------------- 1 | # Процессор 2 | 3 | {{#include processor/cpu-count.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/hardware/processor/cpu-count.md: -------------------------------------------------------------------------------- 1 | ## Проверка количество логических ядер процессора 2 | 3 | [![num_cpus-badge]][num_cpus] [![cat-hardware-support-badge]][cat-hardware-support] 4 | 5 | Показывает количество логических ядер процессора на текущей машине, используя [ `num_cpus::get` ]. 6 | 7 | ```rust 8 | extern crate num_cpus; 9 | 10 | fn main() { 11 | println!("Number of logical cores is {}", num_cpus::get()); 12 | } 13 | ``` 14 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/mem.md: -------------------------------------------------------------------------------- 1 | # Управление памятью 2 | 3 | Рецепт | Крейты | Категории 4 | --- | --- | --- 5 | [Определение лениво вычисляемой константы] | [![lazy_static-badge]][lazy_static] | [![cat-caching-badge]][cat-caching] [![cat-rust-patterns-badge]][cat-rust-patterns] 6 | 7 | {{#include links.md}} 8 | 9 | 10 | [Определение лениво вычисляемой константы]: mem/global_static.html#declare-lazily-evaluated-constant -------------------------------------------------------------------------------- /rust-cookbook-ru/src/mem/global_static.md: -------------------------------------------------------------------------------- 1 | # Константы 2 | 3 | {{#include global_static/lazy-constant.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/mem/global_static/lazy-constant.md: -------------------------------------------------------------------------------- 1 | ## Объявление лениво вычисляемой константы 2 | 3 | [![lazy_static-badge]][lazy_static] [![cat-caching-badge]][cat-caching] [![cat-rust-patterns-badge]][cat-rust-patterns] 4 | 5 | Объявляет лениво вычисляемую константу типа [`HashMap`]. Коллекция [`HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html) будет сразу вычислена и сохранена в глобальной статической ссылке. 6 | 7 | ```rust 8 | #[macro_use] 9 | extern crate lazy_static; 10 | 11 | use std::collections::HashMap; 12 | 13 | lazy_static! { 14 | static ref PRIVILEGES: HashMap<&'static str, Vec<&'static str>> = { 15 | let mut map = HashMap::new(); 16 | map.insert("James", vec!["user", "admin"]); 17 | map.insert("Jim", vec!["user"]); 18 | map 19 | }; 20 | } 21 | 22 | fn show_access(name: &str) { 23 | let access = PRIVILEGES.get(name); 24 | println!("{}: {:?}", name, access); 25 | } 26 | 27 | fn main() { 28 | let access = PRIVILEGES.get("James"); 29 | println!("James: {:?}", access); 30 | 31 | show_access("Jim"); 32 | } 33 | ``` 34 | 35 | 36 | [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html 37 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/net.md: -------------------------------------------------------------------------------- 1 | # Работа с сетью 2 | 3 | Рецепт | Крейты | Категории 4 | --- | --- | --- 5 | [Прослушивание неиспользуемого TCP/IP порта] | [![std-badge]][std] | [![cat-net-badge]][cat-net] 6 | 7 | {{#include links.md}} 8 | 9 | 10 | [Прослушивание неиспользуемого TCP/IP порта]: net/server.html#listen-on-unused-port-tcpip -------------------------------------------------------------------------------- /rust-cookbook-ru/src/net/server.md: -------------------------------------------------------------------------------- 1 | # Сервер 2 | 3 | {{#include server/listen-unused.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/net/server/listen-unused.md: -------------------------------------------------------------------------------- 1 | ## Прослушивание неиспользуемого порта TCP/IP 2 | 3 | [![std-badge]][std] [![cat-net-badge]][cat-net] 4 | 5 | В этом примере порт отображается в консоли и программа будет прослушивать, пока на него не будет сделан запрос. `SocketAddrV4` назначает случайный порт при установке порта в 0. 6 | 7 | ```rust,no_run 8 | use std::net::{SocketAddrV4, Ipv4Addr, TcpListener}; 9 | use std::io::{Read, Error}; 10 | 11 | fn main() -> Result<(), Error> { 12 | let loopback = Ipv4Addr::new(127, 0, 0, 1); 13 | let socket = SocketAddrV4::new(loopback, 0); 14 | let listener = TcpListener::bind(socket)?; 15 | let port = listener.local_addr()?; 16 | println!("Listening on {}, access this port to end the program", port); 17 | let (mut tcp_stream, addr) = listener.accept()?; //block until requested 18 | println!("Connection received! {:?} is sending data.", addr); 19 | let mut input = String::new(); 20 | let _ = tcp_stream.read_to_string(&mut input)?; 21 | println!("{:?} says {}", addr, input); 22 | Ok(()) 23 | } 24 | ``` 25 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/os/external.md: -------------------------------------------------------------------------------- 1 | # Внешняя команда 2 | 3 | {{#include external/process-output.md}} 4 | 5 | {{#include external/send-input.md}} 6 | 7 | {{#include external/piped.md}} 8 | 9 | {{#include external/error-file.md}} 10 | 11 | {{#include external/continuous.md}} 12 | 13 | {{#include ../links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/os/external/continuous.md: -------------------------------------------------------------------------------- 1 | ## Постоянная обработка вывода дочернего процесса 2 | 3 | [![std-badge]][std] [![cat-os-badge]][cat-os] 4 | 5 | В разделе [Выполнить внешнюю команду и обработать её стандартный вывод](#run-an-external-command-and-process-stdout) обработка не начинается до тех пор, пока не завершится внешняя [`Command`]. Приведённый ниже рецепт вызывает [`Stdio::piped`] для создания канала и непрерывно читает стандартный `stdout` как только обновляется [`BufReader`] . 6 | 7 | Этот рецепт эквивалентен команде оболочки Unix `journalctl | grep usb`. 8 | 9 | ```rust,no_run 10 | use std::process::{Command, Stdio}; 11 | use std::io::{BufRead, BufReader, Error, ErrorKind}; 12 | 13 | fn main() -> Result<(), Error> { 14 | let stdout = Command::new("journalctl") 15 | .stdout(Stdio::piped()) 16 | .spawn()? 17 | .stdout 18 | .ok_or_else(|| Error::new(ErrorKind::Other,"Could not capture standard output."))?; 19 | 20 | let reader = BufReader::new(stdout); 21 | 22 | reader 23 | .lines() 24 | .filter_map(|line| line.ok()) 25 | .filter(|line| line.find("usb").is_some()) 26 | .for_each(|line| println!("{}", line)); 27 | 28 | Ok(()) 29 | } 30 | ``` 31 | 32 | 33 | [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html 34 | [`Command`]: https://doc.rust-lang.org/std/process/struct.Command.html 35 | [`Stdio::piped`]: https://doc.rust-lang.org/std/process/struct.Stdio.html 36 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/os/external/error-file.md: -------------------------------------------------------------------------------- 1 | ## Перенаправить stdout и stderr дочернего процесса в один файл 2 | 3 | [![std-badge]][std] [![cat-os-badge]][cat-os] 4 | 5 | Создаёт дочерний процесс и перенаправляет `stdout` и `stderr` в один и тот же файл. Рецепт следует той же идее, что и [запуск внешних команд цепочкой](#run-piped-external-commands) , однако [`process::Stdio`] записывает в указанный файл. [`File::try_clone`] ссылается на один и тот же дескриптор файла для `stdout` и `stderr`. Это гарантирует, что оба дескриптора пишут с одинаковой позиции курсора. 6 | 7 | Приведённый ниже рецепт эквивалентен запуску команды оболочки Unix `ls . oops >out.txt 2>&1`. 8 | 9 | ```rust,no_run 10 | use std::fs::File; 11 | use std::io::Error; 12 | use std::process::{Command, Stdio}; 13 | 14 | fn main() -> Result<(), Error> { 15 | let outputs = File::create("out.txt")?; 16 | let errors = outputs.try_clone()?; 17 | 18 | Command::new("ls") 19 | .args(&[".", "oops"]) 20 | .stdout(Stdio::from(outputs)) 21 | .stderr(Stdio::from(errors)) 22 | .spawn()? 23 | .wait_with_output()?; 24 | 25 | Ok(()) 26 | } 27 | ``` 28 | 29 | 30 | [`File::try_clone`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.try_clone 31 | [`process::Stdio`]: https://doc.rust-lang.org/std/process/struct.Stdio.html 32 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science.md: -------------------------------------------------------------------------------- 1 | # Наука 2 | 3 | {{#include science/mathematics.md}} 4 | 5 | {{#include links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/complex_numbers.md: -------------------------------------------------------------------------------- 1 | # Комплексные числа 2 | 3 | {{#include complex_numbers/create-complex.md}} {{#include complex_numbers/add-complex.md}} {{#include complex_numbers/mathematical-functions.md}} 4 | 5 | {{#include ../../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/complex_numbers/add-complex.md: -------------------------------------------------------------------------------- 1 | ## Сложение комплексных чисел 2 | 3 | [![num-badge]][num] [![cat-science-badge]][cat-science] 4 | 5 | Выполнение математических операций над комплексными числами является таким же как и для встроенных типов: рассматриваемые числа должны быть одного типа (то есть с плавающей точкой или целыми числами). 6 | 7 | ```rust 8 | extern crate num; 9 | 10 | fn main() { 11 | let complex_num1 = num::complex::Complex::new(10.0, 20.0); // Must use floats 12 | let complex_num2 = num::complex::Complex::new(3.1, -4.2); 13 | 14 | let sum = complex_num1 + complex_num2; 15 | 16 | println!("Sum: {}", sum); 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/complex_numbers/create-complex.md: -------------------------------------------------------------------------------- 1 | ## Создание комплексных чисел 2 | 3 | [![num-badge]][num] [![cat-science-badge]][cat-science] 4 | 5 | Создаёт комплексные числа типа [`num::complex::Complex`]. И действительная, и мнимая части комплексного числа должны быть одного типа. 6 | 7 | ```rust 8 | extern crate num; 9 | 10 | fn main() { 11 | let complex_integer = num::complex::Complex::new(10, 20); 12 | let complex_float = num::complex::Complex::new(10.1, 20.1); 13 | 14 | println!("Complex integer: {}", complex_integer); 15 | println!("Complex float: {}", complex_float); 16 | } 17 | ``` 18 | 19 | 20 | [`num::complex::Complex`]: https://autumnai.github.io/cuticula/num/complex/struct.Complex.html 21 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/complex_numbers/mathematical-functions.md: -------------------------------------------------------------------------------- 1 | ## Математические функции 2 | 3 | [![num-badge]][num] [![cat-science-badge]][cat-science] 4 | 5 | Комплексные числа обладают рядом интересных свойств, когда речь заходит о том как они взаимодействуют с другими математическими функциями, в частности с семейством синусоидальных функций, а также с числом e. Чтобы использовать эти функции с комплексными числами, у типа Complex есть несколько встроенных функций, все из которых можно найти здесь: [`num::complex::Complex`]. 6 | 7 | ```rust 8 | extern crate num; 9 | 10 | use std::f64::consts::PI; 11 | use num::complex::Complex; 12 | 13 | fn main() { 14 | let x = Complex::new(0.0, 2.0*PI); 15 | 16 | println!("e^(2i * pi) = {}", x.exp()); // =~1 17 | } 18 | ``` 19 | 20 | 21 | [`num::complex::Complex`]: https://autumnai.github.io/cuticula/num/complex/struct.Complex.html -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/linear_algebra.md: -------------------------------------------------------------------------------- 1 | # Линейная алгебра 2 | 3 | {{#include linear_algebra/add-matrices.md}} {{#include linear_algebra/multiply-matrices.md}} {{#include linear_algebra/multiply-scalar-vector-matrix.md}} {{#include linear_algebra/vector-comparison.md}} {{#include linear_algebra/vector-norm.md}} {{#include linear_algebra/invert-matrix.md}} 4 | 5 | {{#include ../../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/linear_algebra/add-matrices.md: -------------------------------------------------------------------------------- 1 | ## Сложение матриц 2 | 3 | [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] 4 | 5 | Создаёт две двумерные матрицы (2-D) с помощью [`ndarray::arr2`](https://docs.rs/ndarray/*/ndarray/fn.arr2.html) и суммирует их поэлементно. 6 | 7 | Обратите внимание, что сумма вычисляется как `let sum = &a + &b`. Оператор `&` используется, чтобы избежать поглощения `a` и `b` и сделать их доступными для отображения позже. Создаётся новый массив, содержащий их сумму. 8 | 9 | ```rust 10 | extern crate ndarray; 11 | 12 | use ndarray::arr2; 13 | 14 | fn main() { 15 | let a = arr2(&[[1, 2, 3], 16 | [4, 5, 6]]); 17 | 18 | let b = arr2(&[[6, 5, 4], 19 | [3, 2, 1]]); 20 | 21 | let sum = &a + &b; 22 | 23 | println!("{}", a); 24 | println!("+"); 25 | println!("{}", b); 26 | println!("="); 27 | println!("{}", sum); 28 | } 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/linear_algebra/invert-matrix.md: -------------------------------------------------------------------------------- 1 | ## Инвертирование матрицы 2 | 3 | [![nalgebra-badge]][nalgebra] [![cat-science-badge]][cat-science] 4 | 5 | Создаёт матрицу 3x3 с помощью [`nalgebra::Matrix3`](https://docs.rs/nalgebra/*/nalgebra/base/type.Matrix3.html) и инвертирует её, если возможно. 6 | 7 | ```rust 8 | extern crate nalgebra; 9 | 10 | use nalgebra::Matrix3; 11 | 12 | fn main() { 13 | let m1 = Matrix3::new(2.0, 1.0, 1.0, 3.0, 2.0, 1.0, 2.0, 1.0, 2.0); 14 | println!("m1 = {}", m1); 15 | match m1.try_inverse() { 16 | Some(inv) => { 17 | println!("The inverse of m1 is: {}", inv); 18 | } 19 | None => { 20 | println!("m1 is not invertible!"); 21 | } 22 | } 23 | } 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/linear_algebra/multiply-matrices.md: -------------------------------------------------------------------------------- 1 | ## Перемножение матриц 2 | 3 | [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] 4 | 5 | Создаёт две матрицы с помощью [`ndarray::arr2`](https://docs.rs/ndarray/*/ndarray/fn.arr2.html) и выполняет перемножение матриц с помощью [`ndarray::ArrayBase::dot`](https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.dot-1). 6 | 7 | ```rust 8 | extern crate ndarray; 9 | 10 | use ndarray::arr2; 11 | 12 | fn main() { 13 | let a = arr2(&[[1, 2, 3], 14 | [4, 5, 6]]); 15 | let b = arr2(&[[6, 3], 16 | [5, 2], 17 | [4, 1]]); 18 | 19 | println!("{}", a.dot(&b)); 20 | } 21 | ``` 22 | 23 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/miscellaneous.md: -------------------------------------------------------------------------------- 1 | # Разное 2 | 3 | {{#include miscellaneous/big-integers.md}} 4 | 5 | {{#include ../../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/miscellaneous/big-integers.md: -------------------------------------------------------------------------------- 1 | ## Большие целые числа 2 | 3 | [![num-badge]][num] [![cat-science-badge]][cat-science] 4 | 5 | Расчёт для целых чисел превышающих 128 бит возможен с помощью типа [`BigInt`] . 6 | 7 | ```rust 8 | extern crate num; 9 | 10 | use num::bigint::{BigInt, ToBigInt}; 11 | 12 | fn factorial(x: i32) -> BigInt { 13 | if let Some(mut factorial) = 1.to_bigint() { 14 | for i in 1..(x+1) { 15 | factorial = factorial * i; 16 | } 17 | factorial 18 | } 19 | else { 20 | panic!("Failed to calculate factorial!"); 21 | } 22 | } 23 | 24 | fn main() { 25 | println!("{}! equals {}", 100, factorial(100)); 26 | } 27 | ``` 28 | 29 | 30 | [`BigInt`]: https://docs.rs/num/0.2.0/num/struct.BigInt.html 31 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/statistics.md: -------------------------------------------------------------------------------- 1 | # Статистика 2 | 3 | {{#include statistics/central-tendency.md}} {{#include statistics/standard-deviation.md}} 4 | 5 | {{#include ../../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/trigonometry.md: -------------------------------------------------------------------------------- 1 | # Тригонометрия 2 | 3 | {{#include trigonometry/side-length.md}} {{#include trigonometry/tan-sin-cos.md}} {{#include trigonometry/latitude-longitude.md}} 4 | 5 | {{#include ../../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/trigonometry/side-length.md: -------------------------------------------------------------------------------- 1 | ## Расчёт длины стороны треугольника 2 | 3 | [![std-badge]][std] [![cat-science-badge]][cat-science] 4 | 5 | Вычисляет длину гипотенузы прямоугольного треугольника с углом 2 радиана и противоположной стороной длиной 80. 6 | 7 | ```rust 8 | fn main() { 9 | let angle: f64 = 2.0; 10 | let side_length = 80.0; 11 | 12 | let hypotenuse = side_length / angle.sin(); 13 | 14 | println!("Hypotenuse: {}", hypotenuse); 15 | } 16 | ``` 17 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/science/mathematics/trigonometry/tan-sin-cos.md: -------------------------------------------------------------------------------- 1 | ## Проверка того, что тангенс равен синусу, разделённому на косинус 2 | 3 | [![std-badge]][std] [![cat-science-badge]][cat-science] 4 | 5 | Проверяет, что tan (x) равен sin (x) / cos (x) для x = 6. 6 | 7 | ```rust 8 | fn main() { 9 | let x: f64 = 6.0; 10 | 11 | let a = x.tan(); 12 | let b = x.sin() / x.cos(); 13 | 14 | assert_eq!(a, b); 15 | } 16 | ``` 17 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/text/regex/email.md: -------------------------------------------------------------------------------- 1 | ## Проверка и извлечение логина из адреса электронной почты 2 | 3 | [![regex-badge]][regex] [![lazy_static-badge]][lazy_static] [![cat-text-processing-badge]][cat-text-processing] 4 | 5 | Проверяет, что адрес электронной почты отформатирован правильно, и извлекает всё до символа @. 6 | 7 | ```rust 8 | #[macro_use] 9 | extern crate lazy_static; 10 | extern crate regex; 11 | 12 | use regex::Regex; 13 | 14 | fn extract_login(input: &str) -> Option<&str> { 15 | lazy_static! { 16 | static ref RE: Regex = Regex::new(r"(?x) 17 | ^(?P[^@\s]+)@ 18 | ([[:word:]]+\.)* 19 | [[:word:]]+$ 20 | ").unwrap(); 21 | } 22 | RE.captures(input).and_then(|cap| { 23 | cap.name("login").map(|login| login.as_str()) 24 | }) 25 | } 26 | 27 | fn main() { 28 | assert_eq!(extract_login(r"I❤email@example.com"), Some(r"I❤email")); 29 | assert_eq!( 30 | extract_login(r"sdf+sdsfsd.as.sdsd@jhkk.d.rl"), 31 | Some(r"sdf+sdsfsd.as.sdsd") 32 | ); 33 | assert_eq!(extract_login(r"More@Than@One@at.com"), None); 34 | assert_eq!(extract_login(r"Not an email@email"), None); 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/text/regex/hashtags.md: -------------------------------------------------------------------------------- 1 | ## Извлечение списка уникальных #хэштегов из текста 2 | 3 | [![regex-badge]][regex] [![lazy_static-badge]][lazy_static] [![cat-text-processing-badge]][cat-text-processing] 4 | 5 | Извлечь, отсортировать и очистить от дубликатов список хэштегов из текста. 6 | 7 | Приведённое здесь регулярное выражение перехватывает только латинские хэштеги, начинающиеся с буквы. Полное [регулярное выражение хэштега в твиттере](https://github.com/twitter/twitter-text/blob/c9fc09782efe59af4ee82855768cfaf36273e170/java/src/com/twitter/Regex.java#L255) намного сложнее. 8 | 9 | ```rust 10 | extern crate regex; 11 | #[macro_use] 12 | extern crate lazy_static; 13 | 14 | use regex::Regex; 15 | use std::collections::HashSet; 16 | 17 | fn extract_hashtags(text: &str) -> HashSet<&str> { 18 | lazy_static! { 19 | static ref HASHTAG_REGEX : Regex = Regex::new( 20 | r"\#[a-zA-Z][0-9a-zA-Z_]*" 21 | ).unwrap(); 22 | } 23 | HASHTAG_REGEX.find_iter(text).map(|mat| mat.as_str()).collect() 24 | } 25 | 26 | fn main() { 27 | let tweet = "Hey #world, I just got my new #dog, say hello to Till. #dog #forever #2 #_ "; 28 | let tags = extract_hashtags(tweet); 29 | assert!(tags.contains("#dog") && tags.contains("#forever") && tags.contains("#world")); 30 | assert_eq!(tags.len(), 3); 31 | } 32 | ``` 33 | 34 | 35 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/text/string_parsing/graphemes.md: -------------------------------------------------------------------------------- 1 | ## Сбор Unicode графем 2 | 3 | [![unicode-segmentation-badge]](https://docs.rs/unicode-segmentation/1.2.1/unicode_segmentation/) [![cat-text-processing-badge]][cat-text-processing] 4 | 5 | Здесь отдельные Unicode графемы из строки UTF-8 собираются вместе, используя функцию [`UnicodeSegmentation::graphemes`](https://docs.rs/unicode-segmentation/*/unicode_segmentation/trait.UnicodeSegmentation.html#tymethod.graphemes) из крейта [`unicode-segmentation`]. 6 | 7 | ```rust 8 | #[macro_use] 9 | extern crate unicode_segmentation; 10 | use unicode_segmentation::UnicodeSegmentation; 11 | 12 | fn main() { 13 | let name = "José Guimarães\r\n"; 14 | let graphemes = UnicodeSegmentation::graphemes(name, true) 15 | .collect::>(); 16 | assert_eq!(graphemes[3], "é"); 17 | } 18 | ``` 19 | 20 | 21 | [`unicode-segmentation`]: https://docs.rs/unicode-segmentation/*/unicode_segmentation/trait.UnicodeSegmentation.html#tymethod.graphemes -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/clients/apis.md: -------------------------------------------------------------------------------- 1 | # Вызов Веб API 2 | 3 | {{#include api/rest-get.md}} 4 | 5 | {{#include api/rest-head.md}} 6 | 7 | {{#include api/rest-post.md}} 8 | 9 | {{#include api/paginated.md}} 10 | 11 | {{#include ../../links.md}} 12 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/clients/download.md: -------------------------------------------------------------------------------- 1 | # Скачивание файлов 2 | 3 | {{#include download/basic.md}} 4 | 5 | {{#include download/post-file.md}} 6 | 7 | {{#include download/partial.md}} 8 | 9 | {{#include ../../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/clients/requests.md: -------------------------------------------------------------------------------- 1 | # Выполнение запросов 2 | 3 | {{#include requests/get.md}} 4 | 5 | {{#include ../../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/clients/requests/get.md: -------------------------------------------------------------------------------- 1 | ## Выполнение HTTP GET-запроса 2 | 3 | [![reqwest-badge]][reqwest] [![cat-net-badge]][cat-net] 4 | 5 | В примере разбирается переданный адрес URL и выполняется синхронный HTTP GET запрос с помощью [`reqwest::get`](https://docs.rs/reqwest/*/reqwest/fn.get.html). Затем печатается статус ответа [`reqwest::Response`](https://docs.rs/reqwest/*/reqwest/struct.Response.html) и его заголовки. Также читается тело HTTP ответа в предварительно выделенную строку [`String`](https://doc.rust-lang.org/std/string/struct.String.html) используя [`read_to_string`](https://doc.rust-lang.org/std/io/trait.Read.html#method.read_to_string). 6 | 7 | ```rust,no_run 8 | # #[macro_use] 9 | # extern crate error_chain; 10 | extern crate reqwest; 11 | 12 | use std::io::Read; 13 | # 14 | # error_chain! { 15 | # foreign_links { 16 | # Io(std::io::Error); 17 | # HttpRequest(reqwest::Error); 18 | # } 19 | # } 20 | 21 | fn main() -> Result<()> { 22 | let mut res = reqwest::get("http://httpbin.org/get")?; 23 | let mut body = String::new(); 24 | res.read_to_string(&mut body)?; 25 | 26 | println!("Status: {}", res.status()); 27 | println!("Headers:\n{:#?}", res.headers()); 28 | println!("Body:\n{}", body); 29 | 30 | Ok(()) 31 | } 32 | ``` 33 | 34 | 35 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/mime.md: -------------------------------------------------------------------------------- 1 | # Типы Медиа 2 | 3 | {{#include mime/string.md}} 4 | 5 | {{#include mime/string.md}} 6 | 7 | {{#include mime/request.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/mime/filename.md: -------------------------------------------------------------------------------- 1 | ## Вывести тип MIME по имени файла 2 | 3 | [![mime-badge]][mime] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Следующий пример показывает, как получить корректный MIME тип из имени файла с помощью крейта [mime]. Программа возьмёт расширение файла и сопоставит его с заранее известным списком. Возвращаемое значение имеет тип [`mime:Mime`](https://docs.rs/mime/*/mime/struct.Mime.html). 6 | 7 | ```rust 8 | extern crate mime; 9 | use mime::Mime; 10 | 11 | fn find_mimetype (filename : &String) -> Mime{ 12 | 13 | let parts : Vec<&str> = filename.split('.').collect(); 14 | 15 | let res = match parts.last() { 16 | Some(v) => 17 | match *v { 18 | "png" => mime::IMAGE_PNG, 19 | "jpg" => mime::IMAGE_JPEG, 20 | "json" => mime::APPLICATION_JSON, 21 | &_ => mime::TEXT_PLAIN, 22 | }, 23 | None => mime::TEXT_PLAIN, 24 | }; 25 | return res; 26 | } 27 | 28 | fn main() { 29 | let filenames = vec!("foobar.jpg", "foo.bar", "foobar.png"); 30 | for file in filenames { 31 | let mime = find_mimetype(&file.to_owned()); 32 | println!("MIME for {}: {}", file, mime); 33 | } 34 | 35 | } 36 | ``` 37 | 38 | 39 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/mime/string.md: -------------------------------------------------------------------------------- 1 | ## Получение MIME типа из строки 2 | 3 | [![mime-badge]][mime] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Этот пример показывает, как осуществить разбор в тип [`MIME`](https://docs.rs/mime/*/mime/struct.Mime.html) из некоторой строки при помощи функций из крейта [mime]. [`FromStrError`](https://docs.rs/mime/*/mime/struct.FromStrError.html) выводит [`MIME`](https://docs.rs/mime/*/mime/struct.Mime.html) тип по умолчанию для параметра, переданного в `unwrap_or`. 6 | 7 | ```rust 8 | extern crate mime; 9 | use mime::{Mime, APPLICATION_OCTET_STREAM}; 10 | 11 | fn main() { 12 | let invalid_mime_type = "i n v a l i d"; 13 | let default_mime = invalid_mime_type 14 | .parse::() 15 | .unwrap_or(APPLICATION_OCTET_STREAM); 16 | 17 | println!( 18 | "MIME for {:?} used default value {:?}", 19 | invalid_mime_type, default_mime 20 | ); 21 | 22 | let valid_mime_type = "TEXT/PLAIN"; 23 | let parsed_mime = valid_mime_type 24 | .parse::() 25 | .unwrap_or(APPLICATION_OCTET_STREAM); 26 | 27 | println!( 28 | "MIME for {:?} was parsed as {:?}", 29 | valid_mime_type, parsed_mime 30 | ); 31 | } 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/scraping.md: -------------------------------------------------------------------------------- 1 | # Извлечение ссылок 2 | 3 | {{#include scraping/extract-links.md}} 4 | 5 | {{#include scraping/broken.md}} 6 | 7 | {{#include scraping/unique.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/url.md: -------------------------------------------------------------------------------- 1 | # Унифицированное Местонахождение Ресурса (Uniform Resource Location, URL) 2 | 3 | {{#include url/parse.md}} 4 | 5 | {{#include url/base.md}} 6 | 7 | {{#include url/new.md}} 8 | 9 | {{#include url/origin.md}} 10 | 11 | {{#include url/fragment.md}} 12 | 13 | {{#include ../links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/url/fragment.md: -------------------------------------------------------------------------------- 1 | ## Удаление идентификаторов фрагментов и пар "параметр-значение" из URL адреса 2 | 3 | [![url-badge]][url] [![cat-net-badge]][cat-net] 4 | 5 | Пример делает разбор [`Url`](https://docs.rs/url/*/url/struct.Url.html) и разбивает их с помощью [`url::Position`](https://docs.rs/url/*/url/enum.Position.html) чтобы отрезать ненужные части URL адреса. 6 | 7 | ```rust 8 | 9 | extern crate url; 10 | 11 | use url::{Url, Position, ParseError}; 12 | 13 | fn main() -> Result<(), ParseError> { 14 | let parsed = Url::parse("https://github.com/rust-lang/rust/issues?labels=E-easy&state=open")?; 15 | let cleaned: &str = &parsed[..Position::AfterPath]; 16 | println!("cleaned: {}", cleaned); 17 | Ok(()) 18 | } 19 | ``` 20 | 21 | 22 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/url/new.md: -------------------------------------------------------------------------------- 1 | ## Создание новых URL адресов из базового URL адреса 2 | 3 | [![url-badge]][url] [![cat-net-badge]][cat-net] 4 | 5 | Метод [`join`](https://docs.rs/url/*/url/struct.Url.html#method.join) создаёт новый URL адрес из базового и относительного пути. 6 | 7 | ```rust 8 | extern crate url; 9 | 10 | use url::{Url, ParseError}; 11 | 12 | fn main() -> Result<(), ParseError> { 13 | let path = "/rust-lang/cargo"; 14 | 15 | let gh = build_github_url(path)?; 16 | 17 | assert_eq!(gh.as_str(), "https://github.com/rust-lang/cargo"); 18 | println!("The joined URL is: {}", gh); 19 | 20 | Ok(()) 21 | } 22 | 23 | fn build_github_url(path: &str) -> Result { 24 | const GITHUB: &'static str = "https://github.com"; 25 | 26 | let base = Url::parse(GITHUB).expect("hardcoded URL is known to be valid"); 27 | let joined = base.join(path)?; 28 | 29 | Ok(joined) 30 | } 31 | ``` 32 | 33 | 34 | -------------------------------------------------------------------------------- /rust-cookbook-ru/src/web/url/parse.md: -------------------------------------------------------------------------------- 1 | ## Разбор строки в экземпляр типа `Url` 2 | 3 | [![url-badge]][url] [![cat-net-badge]][cat-net] 4 | 5 | Метод [`parse`](https://docs.rs/url/*/url/struct.Url.html#method.parse) из крейта `url` делает синтаксический разбор и валидацию некоторой `&str` в структуру [`Url`](https://docs.rs/url/*/url/struct.Url.html). Поскольку входная строка может быть некорректной, то метод возвращает `Result`. 6 | 7 | Как только строка, представляющая собой URL адрес оказывается разобрана в структуру типа `Url`, на этом экземпляре можно вызвать любой нужный метод. 8 | 9 | ```rust 10 | extern crate url; 11 | 12 | use url::{Url, ParseError}; 13 | 14 | fn main() -> Result<(), ParseError> { 15 | let s = "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open"; 16 | 17 | let parsed = Url::parse(s)?; 18 | println!("The path part of the URL is: {}", parsed.path()); 19 | 20 | Ok(()) 21 | } 22 | ``` 23 | 24 | 25 | -------------------------------------------------------------------------------- /rust-cookbook-ru/tests: -------------------------------------------------------------------------------- 1 | ../rust-cookbook/tests -------------------------------------------------------------------------------- /rust-cookbook/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [alias] 2 | xtask = "run --manifest-path ./xtask/Cargo.toml --" -------------------------------------------------------------------------------- /rust-cookbook/.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | fixes #ISSUE_ID 2 | 3 | :tada: Hi and welcome! Please read the text below and remove it - Thank you! :tada: 4 | 5 | No worries if anything in these lists is unclear. Just submit the PR and ask away! :+1: 6 | 7 | -------------------------- 8 | ### Things to check before submitting a PR 9 | 10 | - [ ] the tests are passing locally with `cargo xtask test all` 11 | - [ ] commits are squashed into one and rebased to latest master 12 | - [ ] PR contains correct "fixes #ISSUE_ID" clause to autoclose the issue on PR merge 13 | - if issue does not exist consider creating it or remove the clause 14 | - [ ] non rendered items are in sorted order (links, reference, identifiers, Cargo.toml) 15 | - [ ] links to docs.rs have wildcard version `https://docs.rs/tar/*/tar/struct.Entry.html` 16 | - [ ] example has standard [error handling](https://rust-lang-nursery.github.io/rust-cookbook/about.html#a-note-about-error-handling) 17 | - [ ] code identifiers in description are in hyperlinked backticks 18 | ```markdown 19 | [`Entry::unpack`]: https://docs.rs/tar/*/tar/struct.Entry.html#method.unpack 20 | ``` 21 | 22 | ### Things to do after submitting PR 23 | - [ ] check if CI is happy with your PR 24 | 25 | Thank you for reading, you may now delete this text! Thank you! :smile: -------------------------------------------------------------------------------- /rust-cookbook/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target/ 3 | *~ 4 | book/ 5 | *.swp 6 | lines.txt 7 | .idea/ -------------------------------------------------------------------------------- /rust-cookbook/.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | rust: 4 | - stable 5 | - nightly 6 | 7 | os: 8 | - linux 9 | - osx 10 | 11 | env: 12 | global: 13 | - secure: m28oDDxTcaLlbCXv9la/yz0PzafOCDuhOhmHRoc1ELQC0wc3r6HT3a2myrP5ewQQhaxYDzd2XXYDJB3odFV1qLQOp0hFDgNn/w3ctWZpJdLxIJN6dsaPL/azhE2hz7T+SPEoWLwTW1va6bu4wwzSOykt9//RIK0ZoyVMCRSAlMB965iMV2Nkw7SWdQZ8SlskMVk8sB103N5+WTtt6rse54jHnXTpFEq9q0EAXC1R3GBDKEWB7iwb0c++Kw46Fz86ZJJDotiVuxMtsEk0VfT0Yxx665is5Ko6sV4cahbuXqMIqYYEfqpTHNHadHWD1m1i32hW9Rjtt9fFZ+a8m9zfTixPlkfOZvQ94RnD2zqv9qiwFr8oR7t2SsZaB4aqPlJd45DqgnwQ1B0cmrUAsjSB2+1DQDkR4FgKFB/o1c6F6g8imNh+2OwiZXVLwIimXNJQ5xfZeObXFMrEZ0+uj7oxFX49EcwE/SvwsVJHST3/zL5QuQwa9/uVhW/x135/Z2ypVao2xydpow/KL8VwhX9YsOSP5ApffL4OLJ5hE9qwS/SShHGg8AenFqqm/UNFqWDU+C097YaWvG5PEvCVXvOofic65AUTCmwB+h3MSQmZIqz2sb/kwdbtkoRRR6maMgelQmg1JdIfQcKeTJIStIihjk54VENHPVAslz0oV7Ia5Bo= 14 | 15 | matrix: 16 | include: 17 | - rust: stable 18 | os: linux 19 | env: CONTENT_TESTS=1 20 | - rust: stable 21 | os: linux 22 | env: CONTENT_TESTS=1 CONTENT_TESTS_LINKS=1 23 | allow_failures: 24 | - rust: stable 25 | os: linux 26 | env: CONTENT_TESTS=1 CONTENT_TESTS_LINKS=1 27 | - rust: stable 28 | os: osx 29 | 30 | addons: 31 | apt: 32 | packages: 33 | - aspell 34 | - aspell-en 35 | 36 | before_install: 37 | - ./ci/install_deps.sh 38 | - export PATH=$HOME/.cargo/bin:$PATH 39 | 40 | script: ./ci/test_script.sh 41 | 42 | after_success: ./ci/deploy.sh 43 | -------------------------------------------------------------------------------- /rust-cookbook/appveyor.yml: -------------------------------------------------------------------------------- 1 | # Based on the "trust" template v0.1.1 2 | # https://github.com/japaric/trust/tree/v0.1.1 3 | 4 | environment: 5 | global: 6 | CRATE_NAME: rust-cookbook 7 | 8 | matrix: 9 | # - TARGET: x86_64-pc-windows-gnu 10 | # RUST_VERSION: stable 11 | - TARGET: x86_64-pc-windows-msvc 12 | RUST_VERSION: stable 13 | - TARGET: x86_64-pc-windows-msvc 14 | RUST_VERSION: nightly 15 | 16 | install: 17 | - ps: >- 18 | If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') { 19 | $Env:PATH += ';C:\msys64\mingw64\bin' 20 | } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') { 21 | $Env:PATH += ';C:\msys64\mingw32\bin' 22 | } 23 | - curl -sSf -o rustup-init.exe https://win.rustup.rs/ 24 | - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION% 25 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 26 | - rustc -Vv 27 | - cargo -V 28 | 29 | test_script: 30 | - cargo clean 31 | - cargo build 32 | - cargo test 33 | 34 | branches: 35 | only: 36 | # Release tags 37 | - /^v\d+\.\d+\.\d+.*$/ 38 | - master 39 | 40 | notifications: 41 | - provider: Email 42 | on_build_success: false 43 | 44 | # Building is done in the test phase, so we disable Appveyor's build phase. 45 | build: false 46 | -------------------------------------------------------------------------------- /rust-cookbook/assets/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-lang-ru/rust-cookbook/21b83d87cd464359b61129a50e94986f5ecd9fa0/rust-cookbook/assets/graph.png -------------------------------------------------------------------------------- /rust-cookbook/book.toml: -------------------------------------------------------------------------------- 1 | 2 | [book] 3 | title = "Rust Cookbook" 4 | description = "Collection of useful Rust code examples" 5 | authors = ["Rust Language Community"] 6 | edition = "2018" 7 | multilingual = false 8 | language = "en" 9 | src = "src" 10 | 11 | [output.html] 12 | mathjax-support = false 13 | # theme = "theme" 14 | additional-css = ["theme/custom.css"] 15 | git-repository-url = "https://github.com/rust-lang-nursery/rust-cookbook" 16 | edit-url-template = "https://github.com/rust-lang-nursery/rust-cookbook/edit/master/{path}" 17 | 18 | [output.html.playpen] 19 | editable = false 20 | 21 | [output.html.search] 22 | limit-results = 20 23 | use-boolean-and = true 24 | boost-title = 2 25 | boost-hierarchy = 2 26 | boost-paragraph = 1 27 | expand = true 28 | heading-split-level = 2 29 | -------------------------------------------------------------------------------- /rust-cookbook/build.rs: -------------------------------------------------------------------------------- 1 | use walkdir::WalkDir; 2 | 3 | const REMOVED_TESTS: &[&str] = &[ 4 | "./src/web/clients/requests/header.md", 5 | "./src/web/clients/api/rate-limited.md", 6 | ]; 7 | 8 | fn main() { 9 | let paths = WalkDir::new("./src/").into_iter() 10 | // convert paths to Strings 11 | .map(|p| p.unwrap().path().to_str().unwrap().to_string()) 12 | // only compile markdown files 13 | .filter(|p| p.ends_with(".md")) 14 | .filter(|p| !REMOVED_TESTS.contains(&p.as_ref())) 15 | .collect::>(); 16 | 17 | skeptic::generate_doc_tests(&paths[..]); 18 | } 19 | -------------------------------------------------------------------------------- /rust-cookbook/ci/install_deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset 4 | 5 | echo "Running $0" 6 | 7 | if [ -z "${TRAVIS_BRANCH:-}" ]; then 8 | echo "This script may only be run from Travis!" 9 | exit 1 10 | fi 11 | 12 | if [[ "${CONTENT_TESTS:-}" == 1 ]]; then 13 | echo "Installing additional dependencies" 14 | 15 | if [[ "${CONTENT_TESTS_LINKS:-}" == 1 ]]; then 16 | 17 | pyenv install 3.6.0 18 | pyenv local 3.6.0 19 | pip3 install --user link-checker==0.1.0 20 | fi 21 | cargo install mdbook --vers '0.4.43' --debug 22 | fi 23 | 24 | exit 0 25 | -------------------------------------------------------------------------------- /rust-cookbook/crates/web/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "web" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | anyhow = "1.0.94" 8 | mime = "0.3.17" 9 | regex = "1.11.1" 10 | reqwest = { version = "0.12.9", features = ["blocking", "json", "stream"] } 11 | select = "0.6.0" 12 | serde = { version = "1.0.215", features = ["derive"] } 13 | tempfile = "3.14.0" 14 | thiserror = "2.0.5" 15 | tokio = { version = "1.42.0", features = ["full"] } 16 | url = "2.5.4" 17 | -------------------------------------------------------------------------------- /rust-cookbook/crates/web/README.md: -------------------------------------------------------------------------------- 1 | To see the test output run 2 | 3 | ```bash 4 | cargo test -- --nocapture 5 | ``` 6 | 7 | To test the wiki module run 8 | 9 | ```bash 10 | cargo test wiki -- --nocapture 11 | ``` 12 | -------------------------------------------------------------------------------- /rust-cookbook/crates/web/src/links.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | use select::document::Document; 3 | use select::predicate::Name; 4 | 5 | #[derive(Error, Debug)] 6 | pub enum LinkError { 7 | #[error("Reqwest error: {0}")] 8 | ReqError(#[from] reqwest::Error), 9 | #[error("IO error: {0}")] 10 | IoError(#[from] std::io::Error), 11 | } 12 | 13 | pub async fn get_links(page: &str) -> Result>, LinkError> { 14 | let res = reqwest::get(page) 15 | .await? 16 | .text() 17 | .await?; 18 | 19 | let links = Document::from(res.as_str()) 20 | .find(Name("a")) 21 | .filter_map(|node| node.attr("href")) 22 | .into_iter() 23 | .map(|link| Box::::from(link.to_string())) 24 | .collect(); 25 | 26 | Ok(links) 27 | } 28 | 29 | -------------------------------------------------------------------------------- /rust-cookbook/crates/web/src/wiki.rs: -------------------------------------------------------------------------------- 1 | use regex::Regex; 2 | use std::borrow::Cow; 3 | use std::collections::HashSet; 4 | use std::sync::LazyLock; 5 | 6 | pub fn extract_links(content: &str) -> HashSet> { 7 | static WIKI_REGEX: LazyLock = LazyLock::new(|| Regex::new( 8 | r"(?x) 9 | \[\[(?P[^\[\]|]*)[^\[\]]*\]\] # internal links 10 | | 11 | (url=|URL\||\[)(?Phttp.*?)[ \|}] # external links 12 | " 13 | ) 14 | .unwrap() 15 | ); 16 | 17 | let links: HashSet<_> = WIKI_REGEX 18 | .captures_iter(content) 19 | .map(|c| match (c.name("internal"), c.name("external")) { 20 | (Some(val), None) => Cow::from(val.as_str()), 21 | (None, Some(val)) => Cow::from(val.as_str()), 22 | _ => unreachable!(), 23 | }) 24 | .collect::>(); 25 | 26 | links 27 | } 28 | -------------------------------------------------------------------------------- /rust-cookbook/libtest.rmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-lang-ru/rust-cookbook/21b83d87cd464359b61129a50e94986f5ecd9fa0/rust-cookbook/libtest.rmeta -------------------------------------------------------------------------------- /rust-cookbook/src/algorithms/randomness.md: -------------------------------------------------------------------------------- 1 | # Generate Random Values 2 | 3 | {{#include randomness/rand.md}} 4 | 5 | {{#include randomness/rand-range.md}} 6 | 7 | {{#include randomness/rand-dist.md}} 8 | 9 | {{#include randomness/rand-custom.md}} 10 | 11 | {{#include randomness/rand-passwd.md}} 12 | 13 | {{#include randomness/rand-choose.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /rust-cookbook/src/algorithms/randomness/rand-choose.md: -------------------------------------------------------------------------------- 1 | ## Create random passwords from a set of user-defined characters 2 | 3 | [![rand-badge]][rand] [![cat-os-badge]][cat-os] 4 | 5 | Randomly generates a string of given length ASCII characters with custom 6 | user-defined bytestring, with [`gen_range`]. 7 | 8 | ```rust,edition2018 9 | fn main() { 10 | use rand::Rng; 11 | const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 12 | abcdefghijklmnopqrstuvwxyz\ 13 | 0123456789)(*&^%$#@!~"; 14 | const PASSWORD_LEN: usize = 30; 15 | let mut rng = rand::thread_rng(); 16 | 17 | let password: String = (0..PASSWORD_LEN) 18 | .map(|_| { 19 | let idx = rng.gen_range(0..CHARSET.len()); 20 | CHARSET[idx] as char 21 | }) 22 | .collect(); 23 | 24 | println!("{:?}", password); 25 | } 26 | ``` 27 | 28 | [`gen_range`]: https://docs.rs/rand/*/rand/trait.Rng.html#method.gen_range 29 | -------------------------------------------------------------------------------- /rust-cookbook/src/algorithms/randomness/rand-custom.md: -------------------------------------------------------------------------------- 1 | ## Generate random values of a custom type 2 | 3 | [![rand-badge]][rand] [![cat-science-badge]][cat-science] 4 | 5 | Randomly generates a tuple `(i32, bool, f64)` and variable of user defined type `Point`. 6 | Implements the [`Distribution`] trait on type Point for [`Standard`] in order to allow random generation. 7 | 8 | ```rust,edition2018 9 | use rand::Rng; 10 | use rand::distributions::{Distribution, Standard}; 11 | 12 | #[derive(Debug)] 13 | struct Point { 14 | x: i32, 15 | y: i32, 16 | } 17 | 18 | impl Distribution for Standard { 19 | fn sample(&self, rng: &mut R) -> Point { 20 | let (rand_x, rand_y) = rng.gen(); 21 | Point { 22 | x: rand_x, 23 | y: rand_y, 24 | } 25 | } 26 | } 27 | 28 | fn main() { 29 | let mut rng = rand::thread_rng(); 30 | let rand_tuple = rng.gen::<(i32, bool, f64)>(); 31 | let rand_point: Point = rng.gen(); 32 | println!("Random tuple: {:?}", rand_tuple); 33 | println!("Random Point: {:?}", rand_point); 34 | } 35 | ``` 36 | 37 | [`Distribution`]: https://docs.rs/rand/*/rand/distributions/trait.Distribution.html 38 | [`Standard`]: https://docs.rs/rand/*/rand/distributions/struct.Standard.html 39 | -------------------------------------------------------------------------------- /rust-cookbook/src/algorithms/randomness/rand-passwd.md: -------------------------------------------------------------------------------- 1 | ## Create random passwords from a set of alphanumeric characters 2 | 3 | [![rand-badge]][rand] [![cat-os-badge]][cat-os] 4 | 5 | Randomly generates a string of given length ASCII characters in the range `A-Z, 6 | a-z, 0-9`, with [`Alphanumeric`] sample. 7 | 8 | ```rust,edition2018 9 | use rand::{thread_rng, Rng}; 10 | use rand::distributions::Alphanumeric; 11 | 12 | fn main() { 13 | let rand_string: String = thread_rng() 14 | .sample_iter(&Alphanumeric) 15 | .take(30) 16 | .map(char::from) 17 | .collect(); 18 | 19 | println!("{}", rand_string); 20 | } 21 | ``` 22 | 23 | [`Alphanumeric`]: https://docs.rs/rand/*/rand/distributions/struct.Alphanumeric.html 24 | -------------------------------------------------------------------------------- /rust-cookbook/src/algorithms/randomness/rand-range.md: -------------------------------------------------------------------------------- 1 | ## Generate random numbers within a range 2 | 3 | [![rand-badge]][rand] [![cat-science-badge]][cat-science] 4 | 5 | Generates a random value within half-open `[0, 10)` range (not including `10`) with [`Rng::gen_range`]. 6 | 7 | ```rust,edition2018 8 | use rand::Rng; 9 | 10 | fn main() { 11 | let mut rng = rand::thread_rng(); 12 | println!("Integer: {}", rng.gen_range(0..10)); 13 | println!("Float: {}", rng.gen_range(0.0..10.0)); 14 | } 15 | ``` 16 | 17 | [`Uniform`] can obtain values with [uniform distribution]. 18 | This has the same effect, but may be faster when repeatedly generating numbers 19 | in the same range. 20 | 21 | ```rust,edition2018 22 | 23 | use rand::distributions::{Distribution, Uniform}; 24 | 25 | fn main() { 26 | let mut rng = rand::thread_rng(); 27 | let die = Uniform::from(1..7); 28 | 29 | loop { 30 | let throw = die.sample(&mut rng); 31 | println!("Roll the die: {}", throw); 32 | if throw == 6 { 33 | break; 34 | } 35 | } 36 | } 37 | ``` 38 | 39 | [`Uniform`]: https://docs.rs/rand/*/rand/distributions/uniform/struct.Uniform.html 40 | [`Rng::gen_range`]: https://doc.rust-lang.org/rand/*/rand/trait.Rng.html#method.gen_range 41 | [uniform distribution]: https://en.wikipedia.org/wiki/Uniform_distribution_(continuous) 42 | -------------------------------------------------------------------------------- /rust-cookbook/src/algorithms/randomness/rand.md: -------------------------------------------------------------------------------- 1 | ## Generate random numbers 2 | 3 | [![rand-badge]][rand] [![cat-science-badge]][cat-science] 4 | 5 | Generates random numbers with help of random-number 6 | generator [`rand::Rng`] obtained via [`rand::thread_rng`]. Each thread has an 7 | initialized generator. Integers are uniformly distributed over the range of the 8 | type, and floating point numbers are uniformly distributed from 0 up to but not 9 | including 1. 10 | 11 | ```rust,edition2018 12 | use rand::Rng; 13 | 14 | fn main() { 15 | let mut rng = rand::thread_rng(); 16 | 17 | let n1: u8 = rng.gen(); 18 | let n2: u16 = rng.gen(); 19 | println!("Random u8: {}", n1); 20 | println!("Random u16: {}", n2); 21 | println!("Random u32: {}", rng.gen::()); 22 | println!("Random i32: {}", rng.gen::()); 23 | println!("Random float: {}", rng.gen::()); 24 | } 25 | ``` 26 | 27 | [`rand::Rng`]: https://docs.rs/rand/*/rand/trait.Rng.html 28 | [`rand::thread_rng`]: https://docs.rs/rand/*/rand/fn.thread_rng.html 29 | -------------------------------------------------------------------------------- /rust-cookbook/src/algorithms/sorting.md: -------------------------------------------------------------------------------- 1 | # Sorting Vectors 2 | 3 | {{#include sorting/sort.md}} 4 | {{#include sorting/sort_float.md}} 5 | {{#include sorting/sort_struct.md}} 6 | 7 | {{#include ../links.md}} 8 | -------------------------------------------------------------------------------- /rust-cookbook/src/algorithms/sorting/sort.md: -------------------------------------------------------------------------------- 1 | ## Sort a Vector of Integers 2 | 3 | [![std-badge]][std] [![cat-science-badge]][cat-science] 4 | 5 | This example sorts a Vector of integers via [`vec::sort`]. Alternative would 6 | be to use [`vec::sort_unstable`] which can be faster, but does not preserve 7 | the order of equal elements. 8 | 9 | ```rust,edition2018 10 | fn main() { 11 | let mut vec = vec![1, 5, 10, 2, 15]; 12 | 13 | vec.sort(); 14 | 15 | assert_eq!(vec, vec![1, 2, 5, 10, 15]); 16 | } 17 | ``` 18 | 19 | [`vec::sort`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort 20 | [`vec::sort_unstable`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort_unstable 21 | -------------------------------------------------------------------------------- /rust-cookbook/src/algorithms/sorting/sort_float.md: -------------------------------------------------------------------------------- 1 | ## Sort a Vector of Floats 2 | 3 | [![std-badge]][std] [![cat-science-badge]][cat-science] 4 | 5 | A Vector of f32 or f64 can be sorted with [`vec::sort_by`] and [`PartialOrd::partial_cmp`]. 6 | 7 | ```rust,edition2018 8 | fn main() { 9 | let mut vec = vec![1.1, 1.15, 5.5, 1.123, 2.0]; 10 | 11 | vec.sort_by(|a, b| a.partial_cmp(b).unwrap()); 12 | 13 | assert_eq!(vec, vec![1.1, 1.123, 1.15, 2.0, 5.5]); 14 | } 15 | ``` 16 | 17 | [`vec::sort_by`]: https://doc.rust-lang.org/std/primitive.slice.html#method.sort_by 18 | [`PartialOrd::partial_cmp`]: https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html#tymethod.partial_cmp 19 | -------------------------------------------------------------------------------- /rust-cookbook/src/cli.md: -------------------------------------------------------------------------------- 1 | # Command Line 2 | 3 | | Recipe | Crates | Categories | 4 | |--------|--------|------------| 5 | | [Parse command line arguments][ex-clap-basic] | [![clap-badge]][clap] | [![cat-command-line-badge]][cat-command-line] | 6 | | [ANSI Terminal][ex-ansi_term-basic] | [![ansi_term-badge]][ansi_term]| [![cat-command-line-badge]][cat-command-line] | 7 | 8 | [ex-clap-basic]: cli/arguments.html#parse-command-line-arguments 9 | [ex-ansi_term-basic]: cli/ansi_terminal.html#ansi-terminal 10 | 11 | {{#include links.md}} -------------------------------------------------------------------------------- /rust-cookbook/src/cli/ansi_terminal.md: -------------------------------------------------------------------------------- 1 | # ANSI Terminal 2 | 3 | {{#include ansi_terminal/ansi_term-basic.md}} 4 | 5 | {{#include ../links.md}} -------------------------------------------------------------------------------- /rust-cookbook/src/cli/arguments.md: -------------------------------------------------------------------------------- 1 | # Clap basic 2 | 3 | {{#include arguments/clap-basic.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook/src/compression.md: -------------------------------------------------------------------------------- 1 | # Compression 2 | 3 | | Recipe | Crates | Categories | 4 | |--------|--------|------------| 5 | | [Decompress a tarball][ex-tar-decompress] | [![flate2-badge]][flate2] [![tar-badge]][tar] | [![cat-compression-badge]][cat-compression] | 6 | | [Compress a directory into a tarball][ex-tar-compress] | [![flate2-badge]][flate2] [![tar-badge]][tar] | [![cat-compression-badge]][cat-compression] | 7 | | [Decompress a tarball while removing a prefix from the paths][ex-tar-strip-prefix] | [![flate2-badge]][flate2] [![tar-badge]][tar] | [![cat-compression-badge]][cat-compression] | 8 | 9 | [ex-tar-decompress]: compression/tar.html#decompress-a-tarball 10 | [ex-tar-compress]: compression/tar.html#compress-a-directory-into-tarball 11 | [ex-tar-strip-prefix]: compression/tar.html#decompress-a-tarball-while-removing-a-prefix-from-the-paths 12 | 13 | {{#include links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook/src/compression/tar.md: -------------------------------------------------------------------------------- 1 | # Working with Tarballs 2 | 3 | {{#include tar/tar-decompress.md}} 4 | 5 | {{#include tar/tar-compress.md}} 6 | 7 | {{#include tar/tar-strip-prefix.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/compression/tar/tar-decompress.md: -------------------------------------------------------------------------------- 1 | ## Decompress a tarball 2 | 3 | [![flate2-badge]][flate2] [![tar-badge]][tar] [![cat-compression-badge]][cat-compression] 4 | 5 | Decompress ([`GzDecoder`]) and 6 | extract ([`Archive::unpack`]) all files from a compressed tarball 7 | named `archive.tar.gz` located in the current working directory 8 | to the same location. 9 | 10 | ```rust,edition2018,no_run 11 | 12 | use std::fs::File; 13 | use flate2::read::GzDecoder; 14 | use tar::Archive; 15 | 16 | fn main() -> Result<(), std::io::Error> { 17 | let path = "archive.tar.gz"; 18 | 19 | let tar_gz = File::open(path)?; 20 | let tar = GzDecoder::new(tar_gz); 21 | let mut archive = Archive::new(tar); 22 | archive.unpack(".")?; 23 | 24 | Ok(()) 25 | } 26 | ``` 27 | 28 | [`Archive::unpack`]: https://docs.rs/tar/*/tar/struct.Archive.html#method.unpack 29 | [`GzDecoder`]: https://docs.rs/flate2/*/flate2/read/struct.GzDecoder.html 30 | -------------------------------------------------------------------------------- /rust-cookbook/src/concurrency/parallel.md: -------------------------------------------------------------------------------- 1 | # Parallel Tasks 2 | 3 | {{#include parallel/rayon-iter-mut.md}} 4 | 5 | {{#include parallel/rayon-any-all.md}} 6 | 7 | {{#include parallel/rayon-parallel-search.md}} 8 | 9 | {{#include parallel/rayon-parallel-sort.md}} 10 | 11 | {{#include parallel/rayon-map-reduce.md}} 12 | 13 | {{#include parallel/rayon-thumbnails.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /rust-cookbook/src/concurrency/parallel/rayon-iter-mut.md: -------------------------------------------------------------------------------- 1 | ## Mutate the elements of an array in parallel 2 | 3 | [![rayon-badge]][rayon] [![cat-concurrency-badge]][cat-concurrency] 4 | 5 | The example uses the `rayon` crate, which is a data parallelism library for Rust. 6 | `rayon` provides the [`par_iter_mut`] method for any parallel iterable data type. 7 | This is an iterator-like chain that potentially executes in parallel. 8 | 9 | ```rust,edition2018 10 | use rayon::prelude::*; 11 | 12 | fn main() { 13 | let mut arr = [0, 7, 9, 11]; 14 | arr.par_iter_mut().for_each(|p| *p -= 1); 15 | println!("{:?}", arr); 16 | } 17 | ``` 18 | 19 | [`par_iter_mut`]: https://docs.rs/rayon/*/rayon/iter/trait.IntoParallelRefMutIterator.html#tymethod.par_iter_mut 20 | -------------------------------------------------------------------------------- /rust-cookbook/src/concurrency/parallel/rayon-parallel-search.md: -------------------------------------------------------------------------------- 1 | ## Search items using given predicate in parallel 2 | 3 | [![rayon-badge]][rayon] [![cat-concurrency-badge]][cat-concurrency] 4 | 5 | This example uses [`rayon::find_any`] and [`par_iter`] to search a vector in 6 | parallel for an element satisfying the predicate in the given closure. 7 | 8 | If there are multiple elements satisfying the predicate defined in the closure 9 | argument of [`rayon::find_any`], `rayon` returns the first one found, not 10 | necessarily the first one. 11 | 12 | Also note that the argument to the closure is a reference to a reference 13 | (`&&x`). See the discussion on [`std::find`] for additional details. 14 | 15 | ```rust,edition2018 16 | use rayon::prelude::*; 17 | 18 | fn main() { 19 | let v = vec![6, 2, 1, 9, 3, 8, 11]; 20 | 21 | let f1 = v.par_iter().find_any(|&&x| x == 9); 22 | let f2 = v.par_iter().find_any(|&&x| x % 2 == 0 && x > 6); 23 | let f3 = v.par_iter().find_any(|&&x| x > 8); 24 | 25 | assert_eq!(f1, Some(&9)); 26 | assert_eq!(f2, Some(&8)); 27 | assert!(f3 > Some(&8)); 28 | } 29 | ``` 30 | 31 | [`par_iter`]: https://docs.rs/rayon/*/rayon/iter/trait.IntoParallelRefIterator.html#tymethod.par_iter 32 | [`rayon::find_any`]: https://docs.rs/rayon/*/rayon/iter/trait.ParallelIterator.html#method.find_any 33 | [`std::find`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find 34 | -------------------------------------------------------------------------------- /rust-cookbook/src/concurrency/parallel/rayon-parallel-sort.md: -------------------------------------------------------------------------------- 1 | ## Sort a vector in parallel 2 | 3 | [![rayon-badge]][rayon] [![rand-badge]][rand] [![cat-concurrency-badge]][cat-concurrency] 4 | 5 | This example will sort in parallel a vector of Strings. 6 | 7 | Allocate a vector of empty Strings. `par_iter_mut().for_each` populates random 8 | values in parallel. Although [multiple options] 9 | exist to sort an enumerable data type, [`par_sort_unstable`] 10 | is usually faster than [stable sorting] algorithms. 11 | 12 | ```rust,edition2018 13 | 14 | use rand::{Rng, thread_rng}; 15 | use rand::distributions::Alphanumeric; 16 | use rayon::prelude::*; 17 | 18 | fn main() { 19 | let mut vec = vec![String::new(); 100_000]; 20 | vec.par_iter_mut().for_each(|p| { 21 | let mut rng = thread_rng(); 22 | *p = (0..5).map(|_| rng.sample(&Alphanumeric) as char).collect() 23 | }); 24 | vec.par_sort_unstable(); 25 | } 26 | ``` 27 | 28 | [`par_sort_unstable`]: https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html#method.par_sort_unstable 29 | [multiple options]: https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html 30 | [stable sorting]: https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html#method.par_sort 31 | -------------------------------------------------------------------------------- /rust-cookbook/src/concurrency/threads.md: -------------------------------------------------------------------------------- 1 | # Threads 2 | 3 | {{#include thread/crossbeam-spawn.md}} 4 | 5 | {{#include thread/crossbeam-complex.md}} 6 | 7 | {{#include thread/crossbeam-spsc.md}} 8 | 9 | {{#include thread/global-mut-state.md}} 10 | 11 | {{#include thread/threadpool-walk.md}} 12 | 13 | {{#include thread/threadpool-fractal.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /rust-cookbook/src/cryptography.md: -------------------------------------------------------------------------------- 1 | # Cryptography 2 | 3 | | Recipe | Crates | Categories | 4 | |--------|--------|------------| 5 | | [Calculate the SHA-256 digest of a file][ex-sha-digest] | [![ring-badge]][ring] [![data-encoding-badge]][data-encoding] | [![cat-cryptography-badge]][cat-cryptography] | 6 | | [Sign and verify a message with an HMAC digest][ex-hmac] | [![ring-badge]][ring] | [![cat-cryptography-badge]][cat-cryptography] | 7 | | [Salt and hash a password with PBKDF2][ex-pbkdf2] | [![ring-badge]][ring] [![data-encoding-badge]][data-encoding] | [![cat-cryptography-badge]][cat-cryptography] | 8 | 9 | [ex-sha-digest]: cryptography/hashing.html#calculate-the-sha-256-digest-of-a-file 10 | [ex-hmac]: cryptography/hashing.html#sign-and-verify-a-message-with-hmac-digest 11 | [ex-pbkdf2]: cryptography/encryption.html#salt-and-hash-a-password-with-pbkdf2 12 | 13 | {{#include links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook/src/cryptography/encryption.md: -------------------------------------------------------------------------------- 1 | # Encryption 2 | 3 | {{#include encryption/pbkdf2.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook/src/cryptography/hashing.md: -------------------------------------------------------------------------------- 1 | # Hashing 2 | 3 | {{#include hashing/sha-digest.md}} 4 | 5 | {{#include hashing/hmac.md}} 6 | 7 | {{#include ../links.md}} 8 | -------------------------------------------------------------------------------- /rust-cookbook/src/cryptography/hashing/hmac.md: -------------------------------------------------------------------------------- 1 | ## Sign and verify a message with HMAC digest 2 | 3 | [![ring-badge]][ring] [![cat-cryptography-badge]][cat-cryptography] 4 | 5 | Uses [`ring::hmac`] to creates a [`hmac::Signature`] of a string then verifies the signature is correct. 6 | 7 | 8 | ```rust,edition2018 9 | use ring::{hmac, rand}; 10 | use ring::rand::SecureRandom; 11 | use ring::error::Unspecified; 12 | 13 | fn main() -> Result<(), Unspecified> { 14 | let mut key_value = [0u8; 48]; 15 | let rng = rand::SystemRandom::new(); 16 | rng.fill(&mut key_value)?; 17 | let key = hmac::Key::new(hmac::HMAC_SHA256, &key_value); 18 | 19 | let message = "Legitimate and important message."; 20 | let signature = hmac::sign(&key, message.as_bytes()); 21 | hmac::verify(&key, message.as_bytes(), signature.as_ref())?; 22 | 23 | Ok(()) 24 | } 25 | ``` 26 | 27 | [`hmac::Signature`]: https://briansmith.org/rustdoc/ring/hmac/struct.Signature.html 28 | [`ring::hmac`]: https://briansmith.org/rustdoc/ring/hmac/ 29 | -------------------------------------------------------------------------------- /rust-cookbook/src/data_structures.md: -------------------------------------------------------------------------------- 1 | # Data Structures 2 | 3 | | Recipe | Crates | Categories | 4 | |--------|--------|------------| 5 | | [Define and operate on a type represented as a bitfield][ex-bitflags] | [![bitflags-badge]][bitflags] | [![cat-no-std-badge]][cat-no-std] | 6 | 7 | [ex-bitflags]: data_structures/bitfield.html#define-and-operate-on-a-type-represented-as-a-bitfield 8 | 9 | {{#include links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/data_structures/bitfield.md: -------------------------------------------------------------------------------- 1 | # Bitfield 2 | 3 | {{#include bitfield/bitfield.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook/src/database.md: -------------------------------------------------------------------------------- 1 | # Database 2 | 3 | | Recipe | Crates | Categories | 4 | |--------|--------|------------| 5 | | [Create a SQLite database][ex-sqlite-initialization] | [![rusqlite-badge]][rusqlite] | [![cat-database-badge]][cat-database] | 6 | | [Insert and Query data][ex-sqlite-insert-select] | [![rusqlite-badge]][rusqlite] | [![cat-database-badge]][cat-database] | 7 | | [Create tables in a Postgres database][ex-postgres-create-tables] | [![postgres-badge]][postgres] | [![cat-database-badge]][cat-database] | 8 | | [Insert and Query data][ex-postgres-insert-query-data] | [![postgres-badge]][postgres] | [![cat-database-badge]][cat-database] | 9 | | [Aggregate data][ex-postgres-aggregate-data] | [![postgres-badge]][postgres] | [![cat-database-badge]][cat-database] | 10 | 11 | [ex-sqlite-initialization]: database/sqlite.html#create-a-sqlite-database 12 | [ex-sqlite-insert-select]: database/sqlite.html#insert-and-select-data 13 | [ex-postgres-create-tables]: database/postgres.html#create-tables-in-a-postgres-database 14 | [ex-postgres-insert-query-data]: database/postgres.html#insert-and-query-data 15 | [ex-postgres-aggregate-data]: database/postgres.html#aggregate-data 16 | 17 | {{#include links.md}} 18 | -------------------------------------------------------------------------------- /rust-cookbook/src/database/postgres.md: -------------------------------------------------------------------------------- 1 | # Working with Postgres 2 | 3 | {{#include postgres/create_tables.md}} 4 | 5 | {{#include postgres/insert_query_data.md}} 6 | 7 | {{#include postgres/aggregate_data.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/database/postgres/aggregate_data.md: -------------------------------------------------------------------------------- 1 | ## Aggregate data 2 | 3 | [![postgres-badge]][postgres] [![cat-database-badge]][cat-database] 4 | 5 | This recipe lists the nationalities of the first 7999 artists in the database of the [`Museum of Modern Art`] in descending order. 6 | 7 | ```rust,edition2018,no_run 8 | use postgres::{Client, Error, NoTls}; 9 | 10 | struct Nation { 11 | nationality: String, 12 | count: i64, 13 | } 14 | 15 | fn main() -> Result<(), Error> { 16 | let mut client = Client::connect( 17 | "postgresql://postgres:postgres@127.0.0.1/moma", 18 | NoTls, 19 | )?; 20 | 21 | for row in client.query 22 | ("SELECT nationality, COUNT(nationality) AS count 23 | FROM artists GROUP BY nationality ORDER BY count DESC", &[])? { 24 | 25 | let (nationality, count) : (Option, Option) 26 | = (row.get (0), row.get (1)); 27 | 28 | if nationality.is_some () && count.is_some () { 29 | 30 | let nation = Nation{ 31 | nationality: nationality.unwrap(), 32 | count: count.unwrap(), 33 | }; 34 | println!("{} {}", nation.nationality, nation.count); 35 | 36 | } 37 | } 38 | 39 | Ok(()) 40 | } 41 | ``` 42 | 43 | [`Museum of Modern Art`]: https://github.com/MuseumofModernArt/collection/blob/main/Artists.csv 44 | -------------------------------------------------------------------------------- /rust-cookbook/src/database/postgres/create_tables.md: -------------------------------------------------------------------------------- 1 | ## Create tables in a Postgres database 2 | 3 | [![postgres-badge]][postgres] [![cat-database-badge]][cat-database] 4 | 5 | Use the [`postgres`] crate to create tables in a Postgres database. 6 | 7 | [`Client::connect`] helps in connecting to an existing database. The recipe uses a URL string format with `Client::connect`. It assumes an existing database named `library`, the username is `postgres` and the password is `postgres`. 8 | 9 | ```rust,edition2018,no_run 10 | use postgres::{Client, NoTls, Error}; 11 | 12 | fn main() -> Result<(), Error> { 13 | let mut client = Client::connect("postgresql://postgres:postgres@localhost/library", NoTls)?; 14 | 15 | client.batch_execute(" 16 | CREATE TABLE IF NOT EXISTS author ( 17 | id SERIAL PRIMARY KEY, 18 | name VARCHAR NOT NULL, 19 | country VARCHAR NOT NULL 20 | ) 21 | ")?; 22 | 23 | client.batch_execute(" 24 | CREATE TABLE IF NOT EXISTS book ( 25 | id SERIAL PRIMARY KEY, 26 | title VARCHAR NOT NULL, 27 | author_id INTEGER NOT NULL REFERENCES author 28 | ) 29 | ")?; 30 | 31 | Ok(()) 32 | 33 | } 34 | ``` 35 | 36 | [`postgres`]: https://docs.rs/postgres/0.17.2/postgres/ 37 | [`Client::connect`]: https://docs.rs/postgres/0.17.2/postgres/struct.Client.html#method.connect 38 | -------------------------------------------------------------------------------- /rust-cookbook/src/database/sqlite.md: -------------------------------------------------------------------------------- 1 | # SQLite 2 | 3 | {{#include sqlite/initialization.md}} 4 | 5 | {{#include sqlite/insert_select.md}} 6 | 7 | {{#include sqlite/transactions.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/database/sqlite/initialization.md: -------------------------------------------------------------------------------- 1 | ## Create a SQLite database 2 | 3 | [![rusqlite-badge]][rusqlite] [![cat-database-badge]][cat-database] 4 | 5 | Use the `rusqlite` crate to open SQLite databases. See 6 | [crate][documentation] for compiling on Windows. 7 | 8 | [`Connection::open`] will create the database if it doesn't already exist. 9 | 10 | ```rust,edition2024,no_run 11 | use rusqlite::{Connection, Result}; 12 | 13 | fn main() -> Result<()> { 14 | let conn = Connection::open("cats.db")?; 15 | 16 | conn.execute( 17 | "create table if not exists cat_colors ( 18 | id integer primary key, 19 | name text not null unique 20 | )", 21 | (), 22 | )?; 23 | conn.execute( 24 | "create table if not exists cats ( 25 | id integer primary key, 26 | name text not null, 27 | color_id integer not null references cat_colors(id) 28 | )", 29 | (), 30 | )?; 31 | 32 | Ok(()) 33 | } 34 | ``` 35 | 36 | [`Connection::open`]: https://docs.rs/rusqlite/*/rusqlite/struct.Connection.html#method.open 37 | 38 | [documentation]: https://github.com/rusqlite/rusqlite#user-content-notes-on-building-rusqlite-and-libsqlite3-sys 39 | -------------------------------------------------------------------------------- /rust-cookbook/src/datetime/duration.md: -------------------------------------------------------------------------------- 1 | # Duration and Calculation 2 | 3 | {{#include duration/profile.md}} 4 | 5 | {{#include duration/checked.md}} 6 | 7 | {{#include duration/timezone.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/datetime/duration/profile.md: -------------------------------------------------------------------------------- 1 | ## Measure the elapsed time between two code sections 2 | 3 | [![std-badge]][std] [![cat-time-badge]][cat-time] 4 | 5 | Measures [`time::Instant::elapsed`] since [`time::Instant::now`]. 6 | 7 | Calling [`time::Instant::elapsed`] returns a [`time::Duration`] that we print at the end of the example. 8 | This method will not mutate or reset the [`time::Instant`] object. 9 | 10 | ```rust,edition2018 11 | use std::time::{Duration, Instant}; 12 | # use std::thread; 13 | # 14 | # fn expensive_function() { 15 | # thread::sleep(Duration::from_secs(1)); 16 | # } 17 | 18 | fn main() { 19 | let start = Instant::now(); 20 | expensive_function(); 21 | let duration = start.elapsed(); 22 | 23 | println!("Time elapsed in expensive_function() is: {:?}", duration); 24 | } 25 | ``` 26 | 27 | [`time::Duration`]: https://doc.rust-lang.org/std/time/struct.Duration.html 28 | [`time::Instant::elapsed`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.elapsed 29 | [`time::Instant::now`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.now 30 | [`time::Instant`]:https://doc.rust-lang.org/std/time/struct.Instant.html 31 | -------------------------------------------------------------------------------- /rust-cookbook/src/datetime/duration/timezone.md: -------------------------------------------------------------------------------- 1 | ## Convert a local time to another timezone 2 | 3 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 4 | 5 | Gets the local time and displays it using [`offset::Local::now`] and then converts it to the UTC standard using the [`DateTime::from_utc`] struct method. A time is then converted using the [`offset::FixedOffset`] struct and the UTC time is then converted to UTC+8 and UTC-2. 6 | 7 | ```rust,edition2018 8 | 9 | use chrono::{DateTime, FixedOffset, Local, Utc}; 10 | 11 | fn main() { 12 | let local_time = Local::now(); 13 | let utc_time = DateTime::::from_utc(local_time.naive_utc(), Utc); 14 | let china_timezone = FixedOffset::east(8 * 3600); 15 | let rio_timezone = FixedOffset::west(2 * 3600); 16 | println!("Local time now is {}", local_time); 17 | println!("UTC time now is {}", utc_time); 18 | println!( 19 | "Time in Hong Kong now is {}", 20 | utc_time.with_timezone(&china_timezone) 21 | ); 22 | println!("Time in Rio de Janeiro now is {}", utc_time.with_timezone(&rio_timezone)); 23 | } 24 | ``` 25 | 26 | [`DateTime::from_utc`]:https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.from_utc 27 | [`offset::FixedOffset`]: https://docs.rs/chrono/*/chrono/offset/struct.FixedOffset.html 28 | [`offset::Local::now`]: https://docs.rs/chrono/*/chrono/offset/struct.Local.html#method.now 29 | -------------------------------------------------------------------------------- /rust-cookbook/src/datetime/parse.md: -------------------------------------------------------------------------------- 1 | # Parsing and Displaying 2 | 3 | {{#include parse/current.md}} 4 | 5 | {{#include parse/timestamp.md}} 6 | 7 | {{#include parse/format.md}} 8 | 9 | {{#include parse/string.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /rust-cookbook/src/datetime/parse/format.md: -------------------------------------------------------------------------------- 1 | ## Display formatted date and time 2 | 3 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 4 | 5 | Gets and displays the current time in UTC using [`Utc::now`]. Formats the 6 | current time in the well-known formats [RFC 2822] using [`DateTime::to_rfc2822`] 7 | and [RFC 3339] using [`DateTime::to_rfc3339`], and in a custom format using 8 | [`DateTime::format`]. 9 | 10 | ```rust,edition2018 11 | use chrono::{DateTime, Utc}; 12 | 13 | fn main() { 14 | let now: DateTime = Utc::now(); 15 | 16 | println!("UTC now is: {}", now); 17 | println!("UTC now in RFC 2822 is: {}", now.to_rfc2822()); 18 | println!("UTC now in RFC 3339 is: {}", now.to_rfc3339()); 19 | println!("UTC now in a custom format is: {}", now.format("%a %b %e %T %Y")); 20 | } 21 | ``` 22 | 23 | [`DateTime::format`]: https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.format 24 | [`DateTime::to_rfc2822`]: https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.to_rfc2822 25 | [`DateTime::to_rfc3339`]: https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.to_rfc3339 26 | [`Utc::now`]: https://docs.rs/chrono/*/chrono/offset/struct.Utc.html#method.now 27 | 28 | [RFC 2822]: https://www.ietf.org/rfc/rfc2822.txt 29 | [RFC 3339]: https://www.ietf.org/rfc/rfc3339.txt 30 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/build_tools.md: -------------------------------------------------------------------------------- 1 | # Build Time Tooling 2 | 3 | This section covers "build-time" tooling, or code that is run prior to compiling a crate's source code. 4 | Conventionally, build-time code lives in a **build.rs** file and is commonly referred to as a "build script". 5 | Common use cases include rust code generation and compilation of bundled C/C++/asm code. 6 | See crates.io's [documentation on the matter][build-script-docs] for more information. 7 | 8 | {{#include build_tools/cc-bundled-static.md}} 9 | 10 | {{#include build_tools/cc-bundled-cpp.md}} 11 | 12 | {{#include build_tools/cc-defines.md}} 13 | 14 | {{#include ../links.md}} 15 | 16 | [build-script-docs]: http://doc.crates.io/build-script.html 17 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/build_tools/cc-bundled-cpp.md: -------------------------------------------------------------------------------- 1 | ## Compile and link statically to a bundled C++ library 2 | 3 | [![cc-badge]][cc] [![cat-development-tools-badge]][cat-development-tools] 4 | 5 | Linking a bundled C++ library is very similar to linking a bundled C library. The two core differences when compiling and statically linking a bundled C++ library are specifying a C++ compiler via the builder method [`cpp(true)`][cc-build-cpp] and preventing name mangling by the C++ compiler by adding the `extern "C"` section at the top of our C++ source file. 6 | 7 | 8 | ### `Cargo.toml` 9 | 10 | ```toml 11 | [package] 12 | ... 13 | build = "build.rs" 14 | 15 | [build-dependencies] 16 | cc = "1" 17 | ``` 18 | 19 | ### `build.rs` 20 | 21 | ```rust,edition2018,no_run 22 | fn main() { 23 | cc::Build::new() 24 | .cpp(true) 25 | .file("src/foo.cpp") 26 | .compile("foo"); 27 | } 28 | ``` 29 | 30 | ### `src/foo.cpp` 31 | 32 | ```cpp 33 | extern "C" { 34 | int multiply(int x, int y); 35 | } 36 | 37 | int multiply(int x, int y) { 38 | return x*y; 39 | } 40 | ``` 41 | 42 | ### `src/main.rs` 43 | 44 | ```rust,edition2018,ignore 45 | extern { 46 | fn multiply(x : i32, y : i32) -> i32; 47 | } 48 | 49 | fn main(){ 50 | unsafe { 51 | println!("{}", multiply(5,7)); 52 | } 53 | } 54 | ``` 55 | 56 | [cc-build-cpp]: https://docs.rs/cc/*/cc/struct.Build.html#method.cpp 57 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/debugging/config_log.md: -------------------------------------------------------------------------------- 1 | # Configure Logging 2 | 3 | {{#include config_log/log-mod.md}} 4 | 5 | {{#include config_log/log-env-variable.md}} 6 | 7 | {{#include config_log/log-timestamp.md}} 8 | 9 | {{#include config_log/log-custom.md}} 10 | 11 | {{#include ../../links.md}} 12 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/debugging/config_log/log-env-variable.md: -------------------------------------------------------------------------------- 1 | ## Use a custom environment variable to set up logging 2 | 3 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 4 | 5 | [`Builder`] configures logging. 6 | 7 | [`Builder::from_env`] parses `MY_APP_LOG` 8 | environment variable contents in the form of [`RUST_LOG`] syntax. 9 | Then, [`Builder::init`] initializes the logger. 10 | 11 | ```rust,edition2018 12 | use env_logger::Builder; 13 | 14 | fn main() { 15 | Builder::from_env("MY_APP_LOG").init(); 16 | 17 | log::info!("informational message"); 18 | log::warn!("warning message"); 19 | log::error!("this is an error {}", "message"); 20 | } 21 | ``` 22 | 23 | [`Builder`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html 24 | [`Builder::from_env`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html#method.from_env 25 | [`Builder::init`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html#method.init 26 | [`RUST_LOG`]: https://docs.rs/env_logger/*/env_logger/#enabling-logging 27 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/debugging/log.md: -------------------------------------------------------------------------------- 1 | # Log Messages 2 | 3 | {{#include log/log-debug.md}} 4 | 5 | {{#include log/log-error.md}} 6 | 7 | {{#include log/log-stdout.md}} 8 | 9 | {{#include log/log-custom-logger.md}} 10 | 11 | {{#include log/log-syslog.md}} 12 | 13 | {{#include ../../links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/debugging/log/log-custom-logger.md: -------------------------------------------------------------------------------- 1 | ## Log messages with a custom logger 2 | 3 | [![log-badge]][log] [![cat-debugging-badge]][cat-debugging] 4 | 5 | Implements a custom logger `ConsoleLogger` which prints to stdout. 6 | In order to use the logging macros, `ConsoleLogger` implements 7 | the [`log::Log`] trait and [`log::set_logger`] installs it. 8 | 9 | ```rust,edition2018 10 | use log::{Record, Level, Metadata, LevelFilter, SetLoggerError}; 11 | 12 | static CONSOLE_LOGGER: ConsoleLogger = ConsoleLogger; 13 | 14 | struct ConsoleLogger; 15 | 16 | impl log::Log for ConsoleLogger { 17 | fn enabled(&self, metadata: &Metadata) -> bool { 18 | metadata.level() <= Level::Info 19 | } 20 | 21 | fn log(&self, record: &Record) { 22 | if self.enabled(record.metadata()) { 23 | println!("Rust says: {} - {}", record.level(), record.args()); 24 | } 25 | } 26 | 27 | fn flush(&self) {} 28 | } 29 | 30 | fn main() -> Result<(), SetLoggerError> { 31 | log::set_logger(&CONSOLE_LOGGER)?; 32 | log::set_max_level(LevelFilter::Info); 33 | 34 | log::info!("hello log"); 35 | log::warn!("warning"); 36 | log::error!("oops"); 37 | Ok(()) 38 | } 39 | ``` 40 | 41 | [`log::Log`]: https://docs.rs/log/*/log/trait.Log.html 42 | [`log::set_logger`]: https://docs.rs/log/*/log/fn.set_logger.html 43 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/debugging/log/log-debug.md: -------------------------------------------------------------------------------- 1 | ## Log a debug message to the console 2 | 3 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 4 | 5 | The `log` crate provides logging utilities. The `env_logger` crate configures 6 | logging via an environment variable. The [`log::debug!`] macro works like other 7 | [`std::fmt`] formatted strings. 8 | 9 | ```rust,edition2018 10 | 11 | fn execute_query(query: &str) { 12 | log::debug!("Executing query: {}", query); 13 | } 14 | 15 | fn main() { 16 | env_logger::init(); 17 | 18 | execute_query("DROP TABLE students"); 19 | } 20 | ``` 21 | 22 | No output prints when running this code. By default, the 23 | log level is `error`, and any lower levels are dropped. 24 | 25 | Set the `RUST_LOG` environment variable to print the message: 26 | 27 | ``` 28 | $ RUST_LOG=debug cargo run 29 | ``` 30 | 31 | Cargo prints debugging information then the 32 | following line at the very end of the output: 33 | 34 | ``` 35 | DEBUG:main: Executing query: DROP TABLE students 36 | ``` 37 | 38 | [`log::debug!`]: https://docs.rs/log/*/log/macro.debug.html 39 | [`std::fmt`]: https://doc.rust-lang.org/std/fmt/ 40 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/debugging/log/log-error.md: -------------------------------------------------------------------------------- 1 | ## Log an error message to the console 2 | 3 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 4 | 5 | Proper error handling considers exceptions exceptional. Here, an error logs 6 | to stderr with `log`'s convenience macro [`log::error!`]. 7 | 8 | ```rust,edition2018 9 | 10 | fn execute_query(_query: &str) -> Result<(), &'static str> { 11 | Err("I'm afraid I can't do that") 12 | } 13 | 14 | fn main() { 15 | env_logger::init(); 16 | 17 | let response = execute_query("DROP TABLE students"); 18 | if let Err(err) = response { 19 | log::error!("Failed to execute query: {}", err); 20 | } 21 | } 22 | ``` 23 | 24 | [`log::error!`]: https://docs.rs/log/*/log/macro.error.html 25 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/debugging/log/log-stdout.md: -------------------------------------------------------------------------------- 1 | ## Log to stdout instead of stderr 2 | 3 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 4 | 5 | Creates a custom logger configuration using the [`Builder::target`] to set the target of the log output to [`Target::Stdout`]. 6 | 7 | ```rust,edition2018 8 | 9 | use env_logger::{Builder, Target}; 10 | 11 | fn main() { 12 | Builder::new() 13 | .target(Target::Stdout) 14 | .init(); 15 | 16 | log::error!("This error has been printed to Stdout"); 17 | } 18 | ``` 19 | 20 | [`Builder::target`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html#method.target 21 | [`Target::Stdout`]: https://docs.rs/env_logger/*/env_logger/fmt/enum.Target.html 22 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/debugging/log/log-syslog.md: -------------------------------------------------------------------------------- 1 | ## Log to the Unix syslog 2 | 3 | [![log-badge]][log] [![syslog-badge]][syslog] [![cat-debugging-badge]][cat-debugging] 4 | 5 | Logs messages to [UNIX syslog]. Initializes logger backend 6 | with [`syslog::init`]. [`syslog::Facility`] records the program submitting 7 | the log entry's classification, [`log::LevelFilter`] denotes allowed log verbosity 8 | and `Option<&str>` holds optional application name. 9 | 10 | ```rust,edition2018 11 | # #[cfg(target_os = "linux")] 12 | # #[cfg(target_os = "linux")] 13 | use syslog::{Facility, Error}; 14 | 15 | # #[cfg(target_os = "linux")] 16 | fn main() -> Result<(), Error> { 17 | syslog::init(Facility::LOG_USER, 18 | log::LevelFilter::Debug, 19 | Some("My app name"))?; 20 | log::debug!("this is a debug {}", "message"); 21 | log::error!("this is an error!"); 22 | Ok(()) 23 | } 24 | 25 | # #[cfg(not(target_os = "linux"))] 26 | # fn main() { 27 | # println!("So far, only Linux systems are supported."); 28 | # } 29 | ``` 30 | 31 | [`log::LevelFilter`]: https://docs.rs/log/*/log/enum.LevelFilter.html 32 | [`syslog::Facility`]: https://docs.rs/syslog/*/syslog/enum.Facility.html 33 | [`syslog::init`]: https://docs.rs/syslog/*/syslog/fn.init.html 34 | 35 | [UNIX syslog]: https://www.gnu.org/software/libc/manual/html_node/Overview-of-Syslog.html 36 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/versioning.md: -------------------------------------------------------------------------------- 1 | # Versioning 2 | 3 | {{#include versioning/semver-increment.md}} 4 | 5 | {{#include versioning/semver-complex.md}} 6 | 7 | {{#include versioning/semver-prerelease.md}} 8 | 9 | {{#include versioning/semver-latest.md}} 10 | 11 | {{#include versioning/semver-command.md}} 12 | 13 | {{#include ../links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook/src/development_tools/versioning/semver-prerelease.md: -------------------------------------------------------------------------------- 1 | ## Check if given version is pre-release. 2 | 3 | [![semver-badge]][semver] [![cat-config-badge]][cat-config] 4 | 5 | Given two versions, [`is_prerelease`] asserts that one is pre-release and the other is not. 6 | 7 | ```rust,edition2018 8 | use semver::{Version, SemVerError}; 9 | 10 | fn main() -> Result<(), SemVerError> { 11 | let version_1 = Version::parse("1.0.0-alpha")?; 12 | let version_2 = Version::parse("1.0.0")?; 13 | 14 | assert!(version_1.is_prerelease()); 15 | assert!(!version_2.is_prerelease()); 16 | 17 | Ok(()) 18 | } 19 | ``` 20 | 21 | [`is_prerelease`]: https://docs.rs/semver/*/semver/struct.Version.html#method.is_prerelease 22 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/complex.md: -------------------------------------------------------------------------------- 1 | # Structured Data 2 | 3 | {{#include complex/json.md}} 4 | 5 | {{#include complex/toml.md}} 6 | 7 | {{#include complex/endian-byte.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/complex/endian-byte.md: -------------------------------------------------------------------------------- 1 | ## Read and write integers in little-endian byte order 2 | 3 | [![byteorder-badge]][byteorder] [![cat-encoding-badge]][cat-encoding] 4 | 5 | `byteorder` can reverse the significant bytes of structured data. This may 6 | be necessary when receiving information over the network, such that bytes 7 | received are from another system. 8 | 9 | ```rust,edition2018 10 | 11 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 12 | use std::io::Error; 13 | 14 | #[derive(Default, PartialEq, Debug)] 15 | struct Payload { 16 | kind: u8, 17 | value: u16, 18 | } 19 | 20 | fn main() -> Result<(), Error> { 21 | let original_payload = Payload::default(); 22 | let encoded_bytes = encode(&original_payload)?; 23 | let decoded_payload = decode(&encoded_bytes)?; 24 | assert_eq!(original_payload, decoded_payload); 25 | Ok(()) 26 | } 27 | 28 | fn encode(payload: &Payload) -> Result, Error> { 29 | let mut bytes = vec![]; 30 | bytes.write_u8(payload.kind)?; 31 | bytes.write_u16::(payload.value)?; 32 | Ok(bytes) 33 | } 34 | 35 | fn decode(mut bytes: &[u8]) -> Result { 36 | let payload = Payload { 37 | kind: bytes.read_u8()?, 38 | value: bytes.read_u16::()?, 39 | }; 40 | Ok(payload) 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/csv.md: -------------------------------------------------------------------------------- 1 | # CSV processing 2 | 3 | {{#include csv/read.md}} 4 | 5 | {{#include csv/delimiter.md}} 6 | 7 | {{#include csv/filter.md}} 8 | 9 | {{#include csv/invalid.md}} 10 | 11 | {{#include csv/serialize.md}} 12 | 13 | {{#include csv/serde-serialize.md}} 14 | 15 | {{#include csv/transform.md}} 16 | 17 | {{#include ../links.md}} 18 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/csv/delimiter.md: -------------------------------------------------------------------------------- 1 | ## Read CSV records with different delimiter 2 | 3 | [![csv-badge]][csv] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Reads CSV records with a tab [`delimiter`]. 6 | 7 | ```rust,edition2018 8 | use csv::Error; 9 | use serde::Deserialize; 10 | #[derive(Debug, Deserialize)] 11 | struct Record { 12 | name: String, 13 | place: String, 14 | #[serde(deserialize_with = "csv::invalid_option")] 15 | id: Option, 16 | } 17 | 18 | use csv::ReaderBuilder; 19 | 20 | fn main() -> Result<(), Error> { 21 | let data = "name\tplace\tid\n\ 22 | Mark\tMelbourne\t46\n\ 23 | Ashley\tZurich\t92"; 24 | 25 | let mut reader = ReaderBuilder::new().delimiter(b'\t').from_reader(data.as_bytes()); 26 | for result in reader.deserialize::() { 27 | println!("{:?}", result?); 28 | } 29 | 30 | Ok(()) 31 | } 32 | ``` 33 | 34 | [`delimiter`]: https://docs.rs/csv/1.0.0-beta.3/csv/struct.ReaderBuilder.html#method.delimiter 35 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/csv/filter.md: -------------------------------------------------------------------------------- 1 | ## Filter CSV records matching a predicate 2 | 3 | [![csv-badge]][csv] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Returns _only_ the rows from `data` with a field that matches `query`. 6 | 7 | ```rust,edition2018 8 | # use error_chain::error_chain; 9 | 10 | use std::io; 11 | # 12 | # error_chain!{ 13 | # foreign_links { 14 | # Io(std::io::Error); 15 | # CsvError(csv::Error); 16 | # } 17 | # } 18 | 19 | fn main() -> Result<()> { 20 | let query = "CA"; 21 | let data = "\ 22 | City,State,Population,Latitude,Longitude 23 | Kenai,AK,7610,60.5544444,-151.2583333 24 | Oakman,AL,,33.7133333,-87.3886111 25 | Sandfort,AL,,32.3380556,-85.2233333 26 | West Hollywood,CA,37031,34.0900000,-118.3608333"; 27 | 28 | let mut rdr = csv::ReaderBuilder::new().from_reader(data.as_bytes()); 29 | let mut wtr = csv::Writer::from_writer(io::stdout()); 30 | 31 | wtr.write_record(rdr.headers()?)?; 32 | 33 | for result in rdr.records() { 34 | let record = result?; 35 | if record.iter().any(|field| field == query) { 36 | wtr.write_record(&record)?; 37 | } 38 | } 39 | 40 | wtr.flush()?; 41 | Ok(()) 42 | } 43 | ``` 44 | 45 | _Disclaimer: this example has been adapted from [the csv crate tutorial](https://docs.rs/csv/*/csv/tutorial/index.html#filter-by-search)_. 46 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/csv/invalid.md: -------------------------------------------------------------------------------- 1 | ## Handle invalid CSV data with Serde 2 | 3 | [![csv-badge]][csv] [![serde-badge]][serde] [![cat-encoding-badge]][cat-encoding] 4 | 5 | CSV files often contain invalid data. For these cases, the `csv` crate 6 | provides a custom deserializer, [`csv::invalid_option`], which automatically 7 | converts invalid data to None values. 8 | 9 | ```rust,edition2018 10 | use csv::Error; 11 | use serde::Deserialize; 12 | 13 | #[derive(Debug, Deserialize)] 14 | struct Record { 15 | name: String, 16 | place: String, 17 | #[serde(deserialize_with = "csv::invalid_option")] 18 | id: Option, 19 | } 20 | 21 | fn main() -> Result<(), Error> { 22 | let data = "name,place,id 23 | mark,sydney,46.5 24 | ashley,zurich,92 25 | akshat,delhi,37 26 | alisha,colombo,xyz"; 27 | 28 | let mut rdr = csv::Reader::from_reader(data.as_bytes()); 29 | for result in rdr.deserialize() { 30 | let record: Record = result?; 31 | println!("{:?}", record); 32 | } 33 | 34 | Ok(()) 35 | } 36 | ``` 37 | 38 | [`csv::invalid_option`]: https://docs.rs/csv/*/csv/fn.invalid_option.html 39 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/csv/serde-serialize.md: -------------------------------------------------------------------------------- 1 | ## Serialize records to CSV using Serde 2 | 3 | [![csv-badge]][csv] [![serde-badge]][serde] [![cat-encoding-badge]][cat-encoding] 4 | 5 | The following example shows how to serialize custom structs as CSV records using 6 | the [serde] crate. 7 | 8 | ```rust,edition2018 9 | # use error_chain::error_chain; 10 | use serde::Serialize; 11 | use std::io; 12 | # 13 | # error_chain! { 14 | # foreign_links { 15 | # IOError(std::io::Error); 16 | # CSVError(csv::Error); 17 | # } 18 | # } 19 | 20 | #[derive(Serialize)] 21 | struct Record<'a> { 22 | name: &'a str, 23 | place: &'a str, 24 | id: u64, 25 | } 26 | 27 | fn main() -> Result<()> { 28 | let mut wtr = csv::Writer::from_writer(io::stdout()); 29 | 30 | let rec1 = Record { name: "Mark", place: "Melbourne", id: 56}; 31 | let rec2 = Record { name: "Ashley", place: "Sydney", id: 64}; 32 | let rec3 = Record { name: "Akshat", place: "Delhi", id: 98}; 33 | 34 | wtr.serialize(rec1)?; 35 | wtr.serialize(rec2)?; 36 | wtr.serialize(rec3)?; 37 | 38 | wtr.flush()?; 39 | 40 | Ok(()) 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/csv/serialize.md: -------------------------------------------------------------------------------- 1 | ## Serialize records to CSV 2 | 3 | [![csv-badge]][csv] [![cat-encoding-badge]][cat-encoding] 4 | 5 | This example shows how to serialize a Rust tuple. [`csv::writer`] supports automatic 6 | serialization from Rust types into CSV records. [`write_record`] writes 7 | a simple record containing string data only. Data with more complex values 8 | such as numbers, floats, and options use [`serialize`]. Since CSV 9 | writer uses internal buffer, always explicitly [`flush`] when done. 10 | 11 | ```rust,edition2018 12 | # use error_chain::error_chain; 13 | 14 | use std::io; 15 | # 16 | # error_chain! { 17 | # foreign_links { 18 | # CSVError(csv::Error); 19 | # IOError(std::io::Error); 20 | # } 21 | # } 22 | 23 | fn main() -> Result<()> { 24 | let mut wtr = csv::Writer::from_writer(io::stdout()); 25 | 26 | wtr.write_record(&["Name", "Place", "ID"])?; 27 | 28 | wtr.serialize(("Mark", "Sydney", 87))?; 29 | wtr.serialize(("Ashley", "Dublin", 32))?; 30 | wtr.serialize(("Akshat", "Delhi", 11))?; 31 | 32 | wtr.flush()?; 33 | Ok(()) 34 | } 35 | ``` 36 | 37 | [`csv::Writer`]: https://docs.rs/csv/*/csv/struct.Writer.html 38 | [`flush`]: https://docs.rs/csv/*/csv/struct.Writer.html#method.flush 39 | [`serialize`]: https://docs.rs/csv/*/csv/struct.Writer.html#method.serialize 40 | [`write_record`]: https://docs.rs/csv/*/csv/struct.Writer.html#method.write_record 41 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/string/base64.md: -------------------------------------------------------------------------------- 1 | ## Encode and decode base64 2 | 3 | [![base64-badge]][base64] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Encodes byte slice into `base64` String using [`encode`] 6 | and decodes it with [`decode`]. 7 | 8 | ```rust,edition2018 9 | # use error_chain::error_chain; 10 | 11 | use std::str; 12 | use base64::{encode, decode}; 13 | # 14 | # error_chain! { 15 | # foreign_links { 16 | # Base64(base64::DecodeError); 17 | # Utf8Error(str::Utf8Error); 18 | # } 19 | # } 20 | 21 | fn main() -> Result<()> { 22 | let hello = b"hello rustaceans"; 23 | let encoded = encode(hello); 24 | let decoded = decode(&encoded)?; 25 | 26 | println!("origin: {}", str::from_utf8(hello)?); 27 | println!("base64 encoded: {}", encoded); 28 | println!("back to origin: {}", str::from_utf8(&decoded)?); 29 | 30 | Ok(()) 31 | } 32 | ``` 33 | 34 | [`decode`]: https://docs.rs/base64/*/base64/fn.decode.html 35 | [`encode`]: https://docs.rs/base64/*/base64/fn.encode.html 36 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/string/hex.md: -------------------------------------------------------------------------------- 1 | ## Encode and decode hex 2 | 3 | [![data-encoding-badge]][data-encoding] [![cat-encoding-badge]][cat-encoding] 4 | 5 | The [`data_encoding`] crate provides a `HEXUPPER::encode` method which 6 | takes a `&[u8]` and returns a `String` containing the hexadecimal 7 | representation of the data. 8 | 9 | Similarly, a `HEXUPPER::decode` method is provided which takes a `&[u8]` and 10 | returns a `Vec` if the input data is successfully decoded. 11 | 12 | The example below converts `&[u8]` data to hexadecimal equivalent. Compares this 13 | value to the expected value. 14 | 15 | ```rust,edition2018 16 | use data_encoding::{HEXUPPER, DecodeError}; 17 | 18 | fn main() -> Result<(), DecodeError> { 19 | let original = b"The quick brown fox jumps over the lazy dog."; 20 | let expected = "54686520717569636B2062726F776E20666F78206A756D7073206F76\ 21 | 657220746865206C617A7920646F672E"; 22 | 23 | let encoded = HEXUPPER.encode(original); 24 | assert_eq!(encoded, expected); 25 | 26 | let decoded = HEXUPPER.decode(&encoded.into_bytes())?; 27 | assert_eq!(&decoded[..], &original[..]); 28 | 29 | Ok(()) 30 | } 31 | ``` 32 | 33 | [`data_encoding`]: https://docs.rs/data-encoding/*/data_encoding/ 34 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/string/url-encode.md: -------------------------------------------------------------------------------- 1 | ## Encode a string as application/x-www-form-urlencoded 2 | 3 | [![url-badge]][url] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Encodes a string into [application/x-www-form-urlencoded] syntax 6 | using the [`form_urlencoded::byte_serialize`] and subsequently 7 | decodes it with [`form_urlencoded::parse`]. Both functions return iterators 8 | that collect into a `String`. 9 | 10 | ```rust,edition2018 11 | use url::form_urlencoded::{byte_serialize, parse}; 12 | 13 | fn main() { 14 | let urlencoded: String = byte_serialize("What is ❤?".as_bytes()).collect(); 15 | assert_eq!(urlencoded, "What+is+%E2%9D%A4%3F"); 16 | println!("urlencoded:'{}'", urlencoded); 17 | 18 | let decoded: String = parse(urlencoded.as_bytes()) 19 | .map(|(key, val)| [key, val].concat()) 20 | .collect(); 21 | assert_eq!(decoded, "What is ❤?"); 22 | println!("decoded:'{}'", decoded); 23 | } 24 | ``` 25 | 26 | [`form_urlencoded::byte_serialize`]: https://docs.rs/url/*/url/form_urlencoded/fn.byte_serialize.html 27 | [`form_urlencoded::parse`]: https://docs.rs/url/*/url/form_urlencoded/fn.parse.html 28 | 29 | [application/x-www-form-urlencoded]: https://url.spec.whatwg.org/#application/x-www-form-urlencoded 30 | -------------------------------------------------------------------------------- /rust-cookbook/src/encoding/strings.md: -------------------------------------------------------------------------------- 1 | # Character Sets 2 | 3 | {{#include string/percent-encode.md}} 4 | 5 | {{#include string/url-encode.md}} 6 | 7 | {{#include string/hex.md}} 8 | 9 | {{#include string/base64.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /rust-cookbook/src/errors.md: -------------------------------------------------------------------------------- 1 | # Error Handling 2 | 3 | | Recipe | Crates | Categories | 4 | |--------|--------|------------| 5 | | [Composing errors with an enum][ex-thiserror] | [![thiserror-badge]][thiserror] | [![cat-rust-patterns-badge]][cat-rust-patterns] | 6 | | [Dynamic errors with anyhow][ex-anyhow] | [![anyhow-badge]][anyhow] | [![cat-rust-patterns-badge]][cat-rust-patterns] | 7 | | [Handle errors correctly in main][ex-error-chain-simple-error-handling] | [![error-chain-badge]][error-chain] | [![cat-rust-patterns-badge]][cat-rust-patterns] | 8 | 9 | [ex-thiserror]: errors/handle.html#thiserror 10 | [ex-anyhow]: errors/handle.html#anyhow 11 | [ex-error-chain-simple-error-handling]: errors/handle.html#handle-errors-correctly-in-main 12 | 13 | {{#include links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook/src/errors/handle.md: -------------------------------------------------------------------------------- 1 | # Error Handling 2 | 3 | {{#include handle/main.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook/src/file/dir.md: -------------------------------------------------------------------------------- 1 | # Directory Traversal 2 | 3 | {{#include dir/modified.md}} 4 | 5 | {{#include dir/loops.md}} 6 | 7 | {{#include dir/duplicate-name.md}} 8 | 9 | {{#include dir/find-file.md}} 10 | 11 | {{#include dir/skip-dot.md}} 12 | 13 | {{#include dir/sizes.md}} 14 | 15 | {{#include dir/png.md}} 16 | 17 | {{#include dir/ignore-case.md}} 18 | 19 | {{#include ../links.md}} 20 | -------------------------------------------------------------------------------- /rust-cookbook/src/file/dir/duplicate-name.md: -------------------------------------------------------------------------------- 1 | ## Recursively find duplicate file names 2 | 3 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Find recursively in the current directory duplicate filenames, 6 | printing them only once. 7 | 8 | ```rust,edition2018,no_run 9 | use std::collections::HashMap; 10 | use walkdir::WalkDir; 11 | 12 | fn main() { 13 | let mut filenames = HashMap::new(); 14 | 15 | for entry in WalkDir::new(".") 16 | .into_iter() 17 | .filter_map(Result::ok) 18 | .filter(|e| !e.file_type().is_dir()) { 19 | let f_name = String::from(entry.file_name().to_string_lossy()); 20 | let counter = filenames.entry(f_name.clone()).or_insert(0); 21 | *counter += 1; 22 | 23 | if *counter == 2 { 24 | println!("{}", f_name); 25 | } 26 | } 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /rust-cookbook/src/file/dir/find-file.md: -------------------------------------------------------------------------------- 1 | ## Recursively find all files with given predicate 2 | 3 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Find JSON files modified within the last day in the current directory. 6 | Using [`follow_links`] ensures symbolic links are followed like they were 7 | normal directories and files. 8 | 9 | ```rust,edition2018,no_run 10 | # use error_chain::error_chain; 11 | 12 | use walkdir::WalkDir; 13 | # 14 | # error_chain! { 15 | # foreign_links { 16 | # WalkDir(walkdir::Error); 17 | # Io(std::io::Error); 18 | # SystemTime(std::time::SystemTimeError); 19 | # } 20 | # } 21 | 22 | fn main() -> Result<()> { 23 | for entry in WalkDir::new(".") 24 | .follow_links(true) 25 | .into_iter() 26 | .filter_map(|e| e.ok()) { 27 | let f_name = entry.file_name().to_string_lossy(); 28 | let sec = entry.metadata()?.modified()?; 29 | 30 | if f_name.ends_with(".json") && sec.elapsed()?.as_secs() < 86400 { 31 | println!("{}", f_name); 32 | } 33 | } 34 | 35 | Ok(()) 36 | } 37 | ``` 38 | 39 | [`follow_links`]: https://docs.rs/walkdir/*/walkdir/struct.WalkDir.html#method.follow_links 40 | -------------------------------------------------------------------------------- /rust-cookbook/src/file/dir/ignore-case.md: -------------------------------------------------------------------------------- 1 | ## Find all files with given pattern ignoring filename case. 2 | 3 | [![glob-badge]][glob] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Find all image files in the `/media/` directory matching the `img_[0-9]*.png` pattern. 6 | 7 | A custom [`MatchOptions`] struct is passed to the [`glob_with`] function making the glob pattern case insensitive while keeping the other options [`Default`]. 8 | 9 | ```rust,edition2018,no_run 10 | use error_chain::error_chain; 11 | use glob::{glob_with, MatchOptions}; 12 | 13 | error_chain! { 14 | foreign_links { 15 | Glob(glob::GlobError); 16 | Pattern(glob::PatternError); 17 | } 18 | } 19 | 20 | fn main() -> Result<()> { 21 | let options = MatchOptions { 22 | case_sensitive: false, 23 | ..Default::default() 24 | }; 25 | 26 | for entry in glob_with("/media/img_[0-9]*.png", options)? { 27 | println!("{}", entry?.display()); 28 | } 29 | 30 | Ok(()) 31 | } 32 | ``` 33 | 34 | [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html 35 | [`glob_with`]: https://docs.rs/glob/*/glob/fn.glob_with.html 36 | [`MatchOptions`]: https://docs.rs/glob/*/glob/struct.MatchOptions.html 37 | -------------------------------------------------------------------------------- /rust-cookbook/src/file/dir/loops.md: -------------------------------------------------------------------------------- 1 | ## Find loops for a given path 2 | 3 | [![same_file-badge]][same_file] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Use [`same_file::is_same_file`] to detect loops for a given path. 6 | For example, a loop could be created on a Unix system via symlinks: 7 | ```bash 8 | mkdir -p /tmp/foo/bar/baz 9 | ln -s /tmp/foo/ /tmp/foo/bar/baz/qux 10 | ``` 11 | The following would assert that a loop exists. 12 | 13 | ```rust,edition2018,no_run 14 | use std::io; 15 | use std::path::{Path, PathBuf}; 16 | use same_file::is_same_file; 17 | 18 | fn contains_loop>(path: P) -> io::Result> { 19 | let path = path.as_ref(); 20 | let mut path_buf = path.to_path_buf(); 21 | while path_buf.pop() { 22 | if is_same_file(&path_buf, path)? { 23 | return Ok(Some((path_buf, path.to_path_buf()))); 24 | } else if let Some(looped_paths) = contains_loop(&path_buf)? { 25 | return Ok(Some(looped_paths)); 26 | } 27 | } 28 | return Ok(None); 29 | } 30 | 31 | fn main() { 32 | assert_eq!( 33 | contains_loop("/tmp/foo/bar/baz/qux/bar/baz").unwrap(), 34 | Some(( 35 | PathBuf::from("/tmp/foo"), 36 | PathBuf::from("/tmp/foo/bar/baz/qux") 37 | )) 38 | ); 39 | } 40 | ``` 41 | 42 | [`same_file::is_same_file`]: https://docs.rs/same-file/*/same_file/fn.is_same_file.html 43 | -------------------------------------------------------------------------------- /rust-cookbook/src/file/dir/png.md: -------------------------------------------------------------------------------- 1 | ## Find all png files recursively 2 | 3 | [![glob-badge]][glob] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Recursively find all PNG files in the current directory. 6 | In this case, the `**` pattern matches the current directory and all subdirectories. 7 | 8 | Use the `**` pattern in any path portion. For example, `/media/**/*.png` 9 | matches all PNGs in `media` and it's subdirectories. 10 | 11 | ```rust,edition2018,no_run 12 | # use error_chain::error_chain; 13 | 14 | use glob::glob; 15 | # 16 | # error_chain! { 17 | # foreign_links { 18 | # Glob(glob::GlobError); 19 | # Pattern(glob::PatternError); 20 | # } 21 | # } 22 | 23 | fn main() -> Result<()> { 24 | for entry in glob("**/*.png")? { 25 | println!("{}", entry?.display()); 26 | } 27 | 28 | Ok(()) 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /rust-cookbook/src/file/dir/sizes.md: -------------------------------------------------------------------------------- 1 | ## Recursively calculate file sizes at given depth 2 | 3 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Recursion depth can be flexibly set by [`WalkDir::min_depth`] & [`WalkDir::max_depth`] methods. 6 | Calculates sum of all file sizes to 3 subfolders depth, ignoring files in the root folder. 7 | 8 | ```rust,edition2018 9 | use walkdir::WalkDir; 10 | 11 | fn main() { 12 | let total_size = WalkDir::new(".") 13 | .min_depth(1) 14 | .max_depth(3) 15 | .into_iter() 16 | .filter_map(|entry| entry.ok()) 17 | .filter_map(|entry| entry.metadata().ok()) 18 | .filter(|metadata| metadata.is_file()) 19 | .fold(0, |acc, m| acc + m.len()); 20 | 21 | println!("Total size: {} bytes.", total_size); 22 | } 23 | ``` 24 | 25 | [`WalkDir::max_depth`]: https://docs.rs/walkdir/*/walkdir/struct.WalkDir.html#method.max_depth 26 | [`WalkDir::min_depth`]: https://docs.rs/walkdir/*/walkdir/struct.WalkDir.html#method.min_depth 27 | -------------------------------------------------------------------------------- /rust-cookbook/src/file/dir/skip-dot.md: -------------------------------------------------------------------------------- 1 | ## Traverse directories while skipping dotfiles 2 | 3 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Uses [`filter_entry`] to descend recursively into entries passing the 6 | `is_not_hidden` predicate thus skipping hidden files and directories. 7 | [`Iterator::filter`] applies to each [`WalkDir::DirEntry`] even if the parent 8 | is a hidden directory. 9 | 10 | Root dir `"."` yields through [`WalkDir::depth`] usage in `is_not_hidden` 11 | predicate. 12 | 13 | ```rust,edition2018,no_run 14 | use walkdir::{DirEntry, WalkDir}; 15 | 16 | fn is_not_hidden(entry: &DirEntry) -> bool { 17 | entry 18 | .file_name() 19 | .to_str() 20 | .map(|s| entry.depth() == 0 || !s.starts_with(".")) 21 | .unwrap_or(false) 22 | } 23 | 24 | fn main() { 25 | WalkDir::new(".") 26 | .into_iter() 27 | .filter_entry(|e| is_not_hidden(e)) 28 | .filter_map(|v| v.ok()) 29 | .for_each(|x| println!("{}", x.path().display())); 30 | } 31 | ``` 32 | 33 | [`filter_entry`]: https://docs.rs/walkdir/*/walkdir/struct.IntoIter.html#method.filter_entry 34 | [`Iterator::filter`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter 35 | [`WalkDir::depth`]: https://docs.rs/walkdir/*/walkdir/struct.DirEntry.html#method.depth 36 | [`WalkDir::DirEntry`]: https://docs.rs/walkdir/*/walkdir/struct.DirEntry.html 37 | -------------------------------------------------------------------------------- /rust-cookbook/src/file/read-write.md: -------------------------------------------------------------------------------- 1 | # Read & Write 2 | 3 | {{#include read-write/read-file.md}} 4 | 5 | {{#include read-write/same-file.md}} 6 | 7 | {{#include read-write/memmap.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/file/read-write/memmap.md: -------------------------------------------------------------------------------- 1 | ## Access a file randomly using a memory map 2 | 3 | [![memmap-badge]][memmap] [![cat-filesystem-badge]][cat-filesystem] 4 | 5 | Creates a memory map of a file using [memmap] and simulates some non-sequential 6 | reads from the file. Using a memory map means you just index into a slice rather 7 | than dealing with [`seek`] to navigate a File. 8 | 9 | The [`Mmap::map`] function assumes the file 10 | behind the memory map is not being modified at the same time by another process 11 | or else a [race condition] occurs. 12 | 13 | ```rust,edition2018 14 | use memmap::Mmap; 15 | use std::fs::File; 16 | use std::io::{Write, Error}; 17 | 18 | fn main() -> Result<(), Error> { 19 | # write!(File::create("content.txt")?, "My hovercraft is full of eels!")?; 20 | # 21 | let file = File::open("content.txt")?; 22 | let map = unsafe { Mmap::map(&file)? }; 23 | 24 | let random_indexes = [0, 1, 2, 19, 22, 10, 11, 29]; 25 | assert_eq!(&map[3..13], b"hovercraft"); 26 | let random_bytes: Vec = random_indexes.iter() 27 | .map(|&idx| map[idx]) 28 | .collect(); 29 | assert_eq!(&random_bytes[..], b"My loaf!"); 30 | Ok(()) 31 | } 32 | ``` 33 | 34 | [`Mmap::map`]: https://docs.rs/memmap/*/memmap/struct.Mmap.html#method.map 35 | [`seek`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.seek 36 | 37 | [race condition]: https://en.wikipedia.org/wiki/Race_condition#File_systems 38 | -------------------------------------------------------------------------------- /rust-cookbook/src/hardware.md: -------------------------------------------------------------------------------- 1 | # Hardware Support 2 | 3 | | Recipe | Crates | Categories | 4 | |--------|--------|------------| 5 | | [Check number of logical cpu cores][ex-check-cpu-cores] | [![num_cpus-badge]][num_cpus] | [![cat-hardware-support-badge]][cat-hardware-support] | 6 | 7 | [ex-check-cpu-cores]: hardware/processor.html#check-number-of-logical-cpu-cores 8 | 9 | {{#include links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/hardware/processor.md: -------------------------------------------------------------------------------- 1 | # Processor 2 | 3 | {{#include processor/cpu-count.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook/src/hardware/processor/cpu-count.md: -------------------------------------------------------------------------------- 1 | ## Check number of logical cpu cores 2 | 3 | [![num_cpus-badge]][num_cpus] [![cat-hardware-support-badge]][cat-hardware-support] 4 | 5 | Shows the number of logical CPU cores in current machine using [`num_cpus::get`]. 6 | 7 | ```rust,edition2018 8 | fn main() { 9 | println!("Number of logical cores is {}", num_cpus::get()); 10 | } 11 | ``` 12 | -------------------------------------------------------------------------------- /rust-cookbook/src/intro.md: -------------------------------------------------------------------------------- 1 | # Cookin' with Rust 2 | 3 | This _Rust Cookbook_ is a collection of 4 | simple examples that demonstrate good practices to accomplish common 5 | programming tasks, using the crates of the Rust ecosystem. 6 | 7 | [Read more about _Rust Cookbook_](about.html), including tips for 8 | how to read the book, how to use the examples, and notes on conventions. 9 | 10 | ## Contributing 11 | 12 | This project is intended to be easy for new Rust programmers to 13 | contribute to, and an easy way to get involved with the Rust 14 | community. It needs and welcomes help. For details see 15 | [CONTRIBUTING.md]. 16 | 17 | [CONTRIBUTING.md]: https://github.com/rust-lang-nursery/rust-cookbook/blob/master/CONTRIBUTING.md 18 | 19 | {{#include algorithms.md}} 20 | 21 | {{#include cli.md}} 22 | 23 | {{#include compression.md}} 24 | 25 | {{#include concurrency.md}} 26 | 27 | {{#include cryptography.md}} 28 | 29 | {{#include data_structures.md}} 30 | 31 | {{#include database.md}} 32 | 33 | {{#include datetime.md}} 34 | 35 | {{#include development_tools.md}} 36 | 37 | {{#include encoding.md}} 38 | 39 | {{#include file.md}} 40 | 41 | {{#include hardware.md}} 42 | 43 | {{#include mem.md}} 44 | 45 | {{#include net.md}} 46 | 47 | {{#include os.md}} 48 | 49 | {{#include science.md}} 50 | 51 | {{#include text.md}} 52 | 53 | {{#include web.md}} 54 | 55 | 56 | -------------------------------------------------------------------------------- /rust-cookbook/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("This program does nothing."); 3 | println!("See documentation at https://github.com/rust-lang-nursery/rust-cookbook"); 4 | } 5 | -------------------------------------------------------------------------------- /rust-cookbook/src/mem.md: -------------------------------------------------------------------------------- 1 | # Memory Management 2 | 3 | | Recipe | Crates | Categories | 4 | |--------|--------|------------| 5 | | [Declare lazily evaluated constant][ex-lazy-constant] | [![lazy_static-badge]][lazy_static] | [![cat-caching-badge]][cat-caching] [![cat-rust-patterns-badge]][cat-rust-patterns] | 6 | 7 | [ex-lazy-constant]: mem/global_static.html#declare-lazily-evaluated-constant 8 | 9 | {{#include links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/mem/global_static.md: -------------------------------------------------------------------------------- 1 | # Constants 2 | 3 | {{#include global_static/lazy-constant.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook/src/mem/global_static/lazy-constant.md: -------------------------------------------------------------------------------- 1 | ## Declare lazily evaluated constant 2 | 3 | [![lazy_static-badge]][lazy_static] [![cat-caching-badge]][cat-caching] [![cat-rust-patterns-badge]][cat-rust-patterns] 4 | 5 | Declares a lazily evaluated constant [`HashMap`]. The [`HashMap`] will 6 | be evaluated once and stored behind a global static reference. 7 | 8 | ```rust,edition2018 9 | use lazy_static::lazy_static; 10 | use std::collections::HashMap; 11 | 12 | lazy_static! { 13 | static ref PRIVILEGES: HashMap<&'static str, Vec<&'static str>> = { 14 | let mut map = HashMap::new(); 15 | map.insert("James", vec!["user", "admin"]); 16 | map.insert("Jim", vec!["user"]); 17 | map 18 | }; 19 | } 20 | 21 | fn show_access(name: &str) { 22 | let access = PRIVILEGES.get(name); 23 | println!("{}: {:?}", name, access); 24 | } 25 | 26 | fn main() { 27 | let access = PRIVILEGES.get("James"); 28 | println!("James: {:?}", access); 29 | 30 | show_access("Jim"); 31 | } 32 | ``` 33 | 34 | [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html 35 | -------------------------------------------------------------------------------- /rust-cookbook/src/net.md: -------------------------------------------------------------------------------- 1 | # Networking 2 | 3 | 4 | | Recipe | Crates | Categories | 5 | |--------|--------|------------| 6 | | [Listen on unused port TCP/IP][ex-random-port-tcp] | [![std-badge]][std] | [![cat-net-badge]][cat-net] | 7 | 8 | [ex-random-port-tcp]: net/server.html#listen-on-unused-port-tcpip 9 | 10 | {{#include links.md}} 11 | -------------------------------------------------------------------------------- /rust-cookbook/src/net/server.md: -------------------------------------------------------------------------------- 1 | # Server 2 | 3 | {{#include server/listen-unused.md}} 4 | 5 | {{#include ../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook/src/net/server/listen-unused.md: -------------------------------------------------------------------------------- 1 | ## Listen on unused port TCP/IP 2 | 3 | [![std-badge]][std] [![cat-net-badge]][cat-net] 4 | 5 | In this example, the port is displayed on the console, and the program will 6 | listen until a request is made. `TcpListener::bind` uses a random port 7 | allocated by the OS when requested to bind to port 0. 8 | 9 | ```rust,edition2018,no_run 10 | use std::net::TcpListener; 11 | use std::io::{Read, Error}; 12 | 13 | fn main() -> Result<(), Error> { 14 | let listener = TcpListener::bind("localhost:0")?; 15 | let port = listener.local_addr()?; 16 | println!("Listening on {}, access this port to end the program", port); 17 | let (mut tcp_stream, addr) = listener.accept()?; //block until requested 18 | println!("Connection received! {:?} is sending data.", addr); 19 | let mut input = String::new(); 20 | let _ = tcp_stream.read_to_string(&mut input)?; 21 | println!("{:?} says {}", addr, input); 22 | Ok(()) 23 | } 24 | ``` 25 | -------------------------------------------------------------------------------- /rust-cookbook/src/os/external.md: -------------------------------------------------------------------------------- 1 | # External Command 2 | 3 | {{#include external/process-output.md}} 4 | 5 | {{#include external/send-input.md}} 6 | 7 | {{#include external/piped.md}} 8 | 9 | {{#include external/error-file.md}} 10 | 11 | {{#include external/continuous.md}} 12 | 13 | {{#include external/read-env-variable.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /rust-cookbook/src/os/external/continuous.md: -------------------------------------------------------------------------------- 1 | ## Continuously process child process' outputs 2 | 3 | [![std-badge]][std] [![cat-os-badge]][cat-os] 4 | 5 | In [Run an external command and process stdout](#run-an-external-command-and-process-stdout), 6 | processing doesn't start until external [`Command`] is finished. 7 | The recipe below calls [`Stdio::piped`] to create a pipe, and reads 8 | `stdout` continuously as soon as the [`BufReader`] is updated. 9 | 10 | The below recipe is equivalent to the Unix shell command 11 | `journalctl | grep usb`. 12 | 13 | ```rust,edition2018,no_run 14 | use std::process::{Command, Stdio}; 15 | use std::io::{BufRead, BufReader, Error, ErrorKind}; 16 | 17 | fn main() -> Result<(), Error> { 18 | let stdout = Command::new("journalctl") 19 | .stdout(Stdio::piped()) 20 | .spawn()? 21 | .stdout 22 | .ok_or_else(|| Error::new(ErrorKind::Other,"Could not capture standard output."))?; 23 | 24 | let reader = BufReader::new(stdout); 25 | 26 | reader 27 | .lines() 28 | .filter_map(|line| line.ok()) 29 | .filter(|line| line.find("usb").is_some()) 30 | .for_each(|line| println!("{}", line)); 31 | 32 | Ok(()) 33 | } 34 | ``` 35 | 36 | [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html 37 | [`Command`]: https://doc.rust-lang.org/std/process/struct.Command.html 38 | [`Stdio::piped`]: https://doc.rust-lang.org/std/process/struct.Stdio.html 39 | -------------------------------------------------------------------------------- /rust-cookbook/src/os/external/error-file.md: -------------------------------------------------------------------------------- 1 | ## Redirect both stdout and stderr of child process to the same file 2 | 3 | [![std-badge]][std] [![cat-os-badge]][cat-os] 4 | 5 | Spawns a child process and redirects `stdout` and `stderr` to the same 6 | file. It follows the same idea as [run piped external 7 | commands](#run-piped-external-commands), however [`process::Stdio`] 8 | writes to a specified file. [`File::try_clone`] references the same file handle 9 | for `stdout` and `stderr`. It will ensure that both handles write with the same 10 | cursor position. 11 | 12 | The below recipe is equivalent to run the Unix shell command `ls 13 | . oops >out.txt 2>&1`. 14 | 15 | ```rust,edition2018,no_run 16 | use std::fs::File; 17 | use std::io::Error; 18 | use std::process::{Command, Stdio}; 19 | 20 | fn main() -> Result<(), Error> { 21 | let outputs = File::create("out.txt")?; 22 | let errors = outputs.try_clone()?; 23 | 24 | Command::new("ls") 25 | .args(&[".", "oops"]) 26 | .stdout(Stdio::from(outputs)) 27 | .stderr(Stdio::from(errors)) 28 | .spawn()? 29 | .wait_with_output()?; 30 | 31 | Ok(()) 32 | } 33 | ``` 34 | 35 | [`File::try_clone`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.try_clone 36 | [`process::Stdio`]: https://doc.rust-lang.org/std/process/struct.Stdio.html 37 | -------------------------------------------------------------------------------- /rust-cookbook/src/os/external/read-env-variable.md: -------------------------------------------------------------------------------- 1 | ## Read Environment Variable 2 | 3 | [![std-badge]][std] [![cat-os-badge]][cat-os] 4 | 5 | Reads an environment variable via [std::env::var]. 6 | 7 | ```rust,edition2018,no_run 8 | use std::env; 9 | use std::fs; 10 | use std::io::Error; 11 | 12 | fn main() -> Result<(), Error> { 13 | // read `config_path` from the environment variable `CONFIG`. 14 | // If `CONFIG` isn't set, fall back to a default config path. 15 | let config_path = env::var("CONFIG") 16 | .unwrap_or("/etc/myapp/config".to_string()); 17 | 18 | let config: String = fs::read_to_string(config_path)?; 19 | println!("Config: {}", config); 20 | 21 | Ok(()) 22 | } 23 | ``` 24 | 25 | [std::env::var]: https://doc.rust-lang.org/std/env/fn.var.html 26 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/complex_numbers.md: -------------------------------------------------------------------------------- 1 | # Complex numbers 2 | 3 | {{#include complex_numbers/create-complex.md}} 4 | {{#include complex_numbers/add-complex.md}} 5 | {{#include complex_numbers/mathematical-functions.md}} 6 | 7 | {{#include ../../links.md}} 8 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/complex_numbers/add-complex.md: -------------------------------------------------------------------------------- 1 | ## Adding complex numbers 2 | 3 | [![num-badge]][num] [![cat-science-badge]][cat-science] 4 | 5 | Performing mathematical operations on complex numbers is the same as on 6 | built in types: the numbers in question must be of the same type (i.e. floats 7 | or integers). 8 | 9 | ```rust,edition2018 10 | fn main() { 11 | let complex_num1 = num::complex::Complex::new(10.0, 20.0); // Must use floats 12 | let complex_num2 = num::complex::Complex::new(3.1, -4.2); 13 | 14 | let sum = complex_num1 + complex_num2; 15 | 16 | println!("Sum: {}", sum); 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/complex_numbers/create-complex.md: -------------------------------------------------------------------------------- 1 | ## Creating complex numbers 2 | 3 | [![num-badge]][num] [![cat-science-badge]][cat-science] 4 | 5 | Creates complex numbers of type [`num::complex::Complex`]. Both the real and 6 | imaginary part of the complex number must be of the same type. 7 | 8 | ```rust,edition2018 9 | fn main() { 10 | let complex_integer = num::complex::Complex::new(10, 20); 11 | let complex_float = num::complex::Complex::new(10.1, 20.1); 12 | 13 | println!("Complex integer: {}", complex_integer); 14 | println!("Complex float: {}", complex_float); 15 | } 16 | ``` 17 | 18 | [`num::complex::Complex`]: https://autumnai.github.io/cuticula/num/complex/struct.Complex.html 19 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/complex_numbers/mathematical-functions.md: -------------------------------------------------------------------------------- 1 | ## Mathematical functions 2 | 3 | [![num-badge]][num] [![cat-science-badge]][cat-science] 4 | 5 | Complex numbers have a range of interesting properties when it comes to 6 | how they interact with other mathematical functions, most notibly the family 7 | of sine functions as well as the number e. To use these functions with 8 | complex numbers, the Complex type has a few built in 9 | functions, all of which can be found here: [`num::complex::Complex`]. 10 | 11 | ```rust,edition2018 12 | use std::f64::consts::PI; 13 | use num::complex::Complex; 14 | 15 | fn main() { 16 | let x = Complex::new(0.0, 2.0*PI); 17 | 18 | println!("e^(2i * pi) = {}", x.exp()); // =~1 19 | } 20 | ``` 21 | 22 | [`num::complex::Complex`]: https://autumnai.github.io/cuticula/num/complex/struct.Complex.html 23 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/linear_algebra.md: -------------------------------------------------------------------------------- 1 | # Linear Algebra 2 | 3 | {{#include linear_algebra/add-matrices.md}} 4 | {{#include linear_algebra/multiply-matrices.md}} 5 | {{#include linear_algebra/multiply-scalar-vector-matrix.md}} 6 | {{#include linear_algebra/vector-comparison.md}} 7 | {{#include linear_algebra/vector-norm.md}} 8 | {{#include linear_algebra/invert-matrix.md}} 9 | {{#include linear_algebra/deserialize-matrix.md}} 10 | 11 | {{#include ../../links.md}} 12 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/linear_algebra/add-matrices.md: -------------------------------------------------------------------------------- 1 | ## Adding matrices 2 | [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] 3 | 4 | Creates two 2-D matrices with [`ndarray::arr2`] and sums them element-wise. 5 | 6 | Note the sum is computed as `let sum = &a + &b`. The `&` operator is used to avoid consuming `a` and `b`, making them available later for display. A new array is created containing their sum. 7 | 8 | ```rust,edition2018 9 | use ndarray::arr2; 10 | 11 | fn main() { 12 | let a = arr2(&[[1, 2, 3], 13 | [4, 5, 6]]); 14 | 15 | let b = arr2(&[[6, 5, 4], 16 | [3, 2, 1]]); 17 | 18 | let sum = &a + &b; 19 | 20 | println!("{}", a); 21 | println!("+"); 22 | println!("{}", b); 23 | println!("="); 24 | println!("{}", sum); 25 | } 26 | ``` 27 | 28 | [`ndarray::arr2`]: https://docs.rs/ndarray/*/ndarray/fn.arr2.html 29 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/linear_algebra/deserialize-matrix.md: -------------------------------------------------------------------------------- 1 | ## (De)-Serialize a Matrix 2 | [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] 3 | 4 | Serialize and deserialize a matrix to and from JSON. Serialization is taken care of 5 | by [`serde_json::to_string`] and [`serde_json::from_str`] performs deserialization. 6 | 7 | Note that serialization followed by deserialization gives back the original matrix. 8 | 9 | ```rust,edition2018 10 | use nalgebra::DMatrix; 11 | 12 | fn main() -> Result<(), std::io::Error> { 13 | let row_slice: Vec = (1..5001).collect(); 14 | let matrix = DMatrix::from_row_slice(50, 100, &row_slice); 15 | 16 | // serialize matrix 17 | let serialized_matrix = serde_json::to_string(&matrix)?; 18 | 19 | // deserialize matrix 20 | let deserialized_matrix: DMatrix = serde_json::from_str(&serialized_matrix)?; 21 | 22 | // verify that `deserialized_matrix` is equal to `matrix` 23 | assert!(deserialized_matrix == matrix); 24 | 25 | Ok(()) 26 | } 27 | ``` 28 | 29 | [`serde_json::to_string`]: https://docs.rs/serde_json/*/serde_json/fn.to_string.html 30 | [`serde_json::from_str`]: https://docs.rs/serde_json/*/serde_json/fn.from_str.html 31 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/linear_algebra/invert-matrix.md: -------------------------------------------------------------------------------- 1 | ## Invert matrix 2 | [![nalgebra-badge]][nalgebra] [![cat-science-badge]][cat-science] 3 | 4 | Creates a 3x3 matrix with [`nalgebra::Matrix3`] and inverts it, if possible. 5 | 6 | ```rust,edition2018 7 | use nalgebra::Matrix3; 8 | 9 | fn main() { 10 | let m1 = Matrix3::new(2.0, 1.0, 1.0, 3.0, 2.0, 1.0, 2.0, 1.0, 2.0); 11 | println!("m1 = {}", m1); 12 | match m1.try_inverse() { 13 | Some(inv) => { 14 | println!("The inverse of m1 is: {}", inv); 15 | } 16 | None => { 17 | println!("m1 is not invertible!"); 18 | } 19 | } 20 | } 21 | ``` 22 | 23 | [`nalgebra::Matrix3`]: https://docs.rs/nalgebra/*/nalgebra/base/type.Matrix3.html 24 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/linear_algebra/multiply-matrices.md: -------------------------------------------------------------------------------- 1 | ## Multiplying matrices 2 | [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] 3 | 4 | Creates two matrices with [`ndarray::arr2`] and performs matrix multiplication on them with [`ndarray::ArrayBase::dot`]. 5 | 6 | ```rust,edition2018 7 | use ndarray::arr2; 8 | 9 | fn main() { 10 | let a = arr2(&[[1, 2, 3], 11 | [4, 5, 6]]); 12 | 13 | let b = arr2(&[[6, 3], 14 | [5, 2], 15 | [4, 1]]); 16 | 17 | println!("{}", a.dot(&b)); 18 | } 19 | ``` 20 | 21 | [`ndarray::arr2`]: https://docs.rs/ndarray/*/ndarray/fn.arr2.html 22 | [`ndarray::ArrayBase::dot`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.dot-1 23 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/miscellaneous.md: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | 3 | {{#include miscellaneous/big-integers.md}} 4 | 5 | {{#include ../../links.md}} -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/miscellaneous/big-integers.md: -------------------------------------------------------------------------------- 1 | ## Big integers 2 | 3 | [![num-badge]][num] [![cat-science-badge]][cat-science] 4 | 5 | Calculation for integers exceeding 128 bits are possible with [`BigInt`]. 6 | 7 | ```rust,edition2018 8 | use num::bigint::{BigInt, ToBigInt}; 9 | 10 | fn factorial(x: i32) -> BigInt { 11 | if let Some(mut factorial) = 1.to_bigint() { 12 | for i in 1..=x { 13 | factorial = factorial * i; 14 | } 15 | factorial 16 | } 17 | else { 18 | panic!("Failed to calculate factorial!"); 19 | } 20 | } 21 | 22 | fn main() { 23 | println!("{}! equals {}", 100, factorial(100)); 24 | } 25 | ``` 26 | 27 | [`BigInt`]: https://docs.rs/num/0.2.0/num/struct.BigInt.html -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/statistics.md: -------------------------------------------------------------------------------- 1 | # Statistics 2 | {{#include statistics/central-tendency.md}} 3 | {{#include statistics/standard-deviation.md}} 4 | 5 | 6 | {{#include ../../links.md}} 7 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/trigonometry.md: -------------------------------------------------------------------------------- 1 | # Trigonometry 2 | 3 | {{#include trigonometry/side-length.md}} 4 | {{#include trigonometry/tan-sin-cos.md}} 5 | {{#include trigonometry/latitude-longitude.md}} 6 | 7 | {{#include ../../links.md}} 8 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/trigonometry/side-length.md: -------------------------------------------------------------------------------- 1 | ## Calculating the side length of a triangle 2 | 3 | [![std-badge]][std] [![cat-science-badge]][cat-science] 4 | 5 | Calculates the length of the hypotenuse of a right-angle triangle with an angle of 1 radian and opposite side length of 80. 6 | 7 | ```rust,edition2018 8 | fn main() { 9 | let angle: f64 = 1.0; 10 | let side_length = 80.0; 11 | 12 | let hypotenuse = side_length / angle.sin(); 13 | 14 | println!("Hypotenuse: {}", hypotenuse); 15 | } 16 | ``` 17 | -------------------------------------------------------------------------------- /rust-cookbook/src/science/mathematics/trigonometry/tan-sin-cos.md: -------------------------------------------------------------------------------- 1 | ## Verifying tan is equal to sin divided by cos 2 | 3 | [![std-badge]][std] [![cat-science-badge]][cat-science] 4 | 5 | Verifies tan(x) is equal to sin(x)/cos(x) for x = 6. 6 | 7 | ```rust,edition2018 8 | fn main() { 9 | let x: f64 = 6.0; 10 | 11 | let a = x.tan(); 12 | let b = x.sin() / x.cos(); 13 | 14 | assert_eq!(a, b); 15 | } 16 | ``` 17 | -------------------------------------------------------------------------------- /rust-cookbook/src/text/regex.md: -------------------------------------------------------------------------------- 1 | # Regular Expressions 2 | 3 | {{#include regex/email.md}} 4 | 5 | {{#include regex/hashtags.md}} 6 | 7 | {{#include regex/phone.md}} 8 | 9 | {{#include regex/filter-log.md}} 10 | 11 | {{#include regex/replace.md}} 12 | 13 | {{#include ../links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook/src/text/regex/email.md: -------------------------------------------------------------------------------- 1 | ## Verify and extract login from an email address 2 | 3 | [![regex-badge]][regex] [![lazy_static-badge]][lazy_static] [![cat-text-processing-badge]][cat-text-processing] 4 | 5 | Validates that an email address is formatted correctly, and extracts everything 6 | before the @ symbol. 7 | 8 | ```rust,edition2018 9 | use lazy_static::lazy_static; 10 | 11 | use regex::Regex; 12 | 13 | fn extract_login(input: &str) -> Option<&str> { 14 | lazy_static! { 15 | static ref RE: Regex = Regex::new(r"(?x) 16 | ^(?P[^@\s]+)@ 17 | ([[:word:]]+\.)* 18 | [[:word:]]+$ 19 | ").unwrap(); 20 | } 21 | RE.captures(input).and_then(|cap| { 22 | cap.name("login").map(|login| login.as_str()) 23 | }) 24 | } 25 | 26 | fn main() { 27 | assert_eq!(extract_login(r"I❤email@example.com"), Some(r"I❤email")); 28 | assert_eq!( 29 | extract_login(r"sdf+sdsfsd.as.sdsd@jhkk.d.rl"), 30 | Some(r"sdf+sdsfsd.as.sdsd") 31 | ); 32 | assert_eq!(extract_login(r"More@Than@One@at.com"), None); 33 | assert_eq!(extract_login(r"Not an email@email"), None); 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /rust-cookbook/src/text/regex/hashtags.md: -------------------------------------------------------------------------------- 1 | ## Extract a list of unique #Hashtags from a text 2 | 3 | [![regex-badge]][regex] [![lazy_static-badge]][lazy_static] [![cat-text-processing-badge]][cat-text-processing] 4 | 5 | Extracts, sorts, and deduplicates list of hashtags from text. 6 | 7 | The hashtag regex given here only catches Latin hashtags that start with a 8 | letter. The complete [twitter hashtag regex] is much more complicated. 9 | 10 | ```rust,edition2018 11 | use lazy_static::lazy_static; 12 | 13 | use regex::Regex; 14 | use std::collections::HashSet; 15 | 16 | fn extract_hashtags(text: &str) -> HashSet<&str> { 17 | lazy_static! { 18 | static ref HASHTAG_REGEX : Regex = Regex::new( 19 | r"\#[a-zA-Z][0-9a-zA-Z_]*" 20 | ).unwrap(); 21 | } 22 | HASHTAG_REGEX.find_iter(text).map(|mat| mat.as_str()).collect() 23 | } 24 | 25 | fn main() { 26 | let tweet = "Hey #world, I just got my new #dog, say hello to Till. #dog #forever #2 #_ "; 27 | let tags = extract_hashtags(tweet); 28 | assert!(tags.contains("#dog") && tags.contains("#forever") && tags.contains("#world")); 29 | assert_eq!(tags.len(), 3); 30 | } 31 | ``` 32 | 33 | [twitter hashtag regex]: https://github.com/twitter/twitter-text/blob/c9fc09782efe59af4ee82855768cfaf36273e170/java/src/com/twitter/Regex.java#L255 34 | -------------------------------------------------------------------------------- /rust-cookbook/src/text/string_parsing.md: -------------------------------------------------------------------------------- 1 | # String Parsing 2 | 3 | {{#include string_parsing/graphemes.md}} 4 | 5 | {{#include string_parsing/from_str.md}} 6 | 7 | {{#include ../links.md}} 8 | -------------------------------------------------------------------------------- /rust-cookbook/src/text/string_parsing/graphemes.md: -------------------------------------------------------------------------------- 1 | ## Collect Unicode Graphemes 2 | 3 | [![unicode-segmentation-badge]][`unicode-segmentation`] [![cat-text-processing-badge]][cat-text-processing] 4 | 5 | Collect individual Unicode graphemes from UTF-8 string using the 6 | [`UnicodeSegmentation::graphemes`] function from the [`unicode-segmentation`] crate. 7 | 8 | ```rust,edition2018 9 | use unicode_segmentation::UnicodeSegmentation; 10 | 11 | fn main() { 12 | let name = "José Guimarães\r\n"; 13 | let graphemes = UnicodeSegmentation::graphemes(name, true) 14 | .collect::>(); 15 | assert_eq!(graphemes[3], "é"); 16 | } 17 | ``` 18 | 19 | [`UnicodeSegmentation::graphemes`]: https://docs.rs/unicode-segmentation/*/unicode_segmentation/trait.UnicodeSegmentation.html#tymethod.graphemes 20 | [`unicode-segmentation`]: https://docs.rs/unicode-segmentation/1.2.1/unicode_segmentation/ 21 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/clients/api/paginated.md: -------------------------------------------------------------------------------- 1 | ## Consume a paginated RESTful API 2 | 3 | [![reqwest-badge]][reqwest] [![serde-badge]][serde] [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] 4 | 5 | Wraps a paginated web API in a convenient Rust iterator. The iterator lazily 6 | fetches the next page of results from the remote server as it arrives at the end of each page. 7 | 8 | ```rust,edition2024,no_run 9 | mod paginated { 10 | {{#include ../../../../crates/web/src/paginated.rs}} 11 | } 12 | 13 | fn main() -> Result<()> { 14 | for dep in paginated::ReverseDependencies::of("serde")? { 15 | let dependency = dep?; 16 | println!("{} depends on {}", dependency.id, dependency.crate_id); 17 | } 18 | Ok(()) 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/clients/apis.md: -------------------------------------------------------------------------------- 1 | # Calling a Web API 2 | 3 | {{#include api/rest-get.md}} 4 | 5 | {{#include api/rest-head.md}} 6 | 7 | {{#include api/rest-post.md}} 8 | 9 | {{#include api/paginated.md}} 10 | 11 | {{#include ../../links.md}} 12 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/clients/authentication.md: -------------------------------------------------------------------------------- 1 | # Authentication 2 | 3 | {{#include authentication/basic.md}} 4 | 5 | {{#include ../../links.md}} 6 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/clients/authentication/basic.md: -------------------------------------------------------------------------------- 1 | ## Basic Authentication 2 | 3 | [![reqwest-badge]][reqwest] [![cat-net-badge]][cat-net] 4 | 5 | Uses [`reqwest::RequestBuilder::basic_auth`] to perform a basic HTTP authentication. 6 | 7 | ```rust,edition2018,no_run 8 | use reqwest::blocking::Client; 9 | use reqwest::Error; 10 | 11 | fn main() -> Result<(), Error> { 12 | let client = Client::new(); 13 | 14 | let user_name = "testuser".to_string(); 15 | let password: Option = None; 16 | 17 | let response = client 18 | .get("https://httpbin.org/") 19 | .basic_auth(user_name, password) 20 | .send(); 21 | 22 | println!("{:?}", response); 23 | 24 | Ok(()) 25 | } 26 | ``` 27 | 28 | [`reqwest::RequestBuilder::basic_auth`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.basic_auth 29 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/clients/download.md: -------------------------------------------------------------------------------- 1 | # Downloads 2 | 3 | {{#include download/basic.md}} 4 | 5 | {{#include download/post-file.md}} 6 | 7 | {{#include download/partial.md}} 8 | 9 | {{#include ../../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/clients/requests.md: -------------------------------------------------------------------------------- 1 | # Making Requests 2 | 3 | {{#include requests/get.md}} 4 | 5 | {{#include requests/header.md}} 6 | 7 | {{#include ../../links.md}} 8 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/mime.md: -------------------------------------------------------------------------------- 1 | # Media Types 2 | 3 | {{#include mime/string.md}} 4 | 5 | {{#include mime/filename.md}} 6 | 7 | {{#include mime/request.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/mime/filename.md: -------------------------------------------------------------------------------- 1 | ## Get MIME type from filename 2 | 3 | [![mime-badge]][mime] [![cat-encoding-badge]][cat-encoding] 4 | 5 | The following example shows how to return the correct MIME type from a given 6 | filename using the [mime] crate. The program will check for file extensions 7 | and match against a known list. The return value is [`mime:Mime`]. 8 | 9 | ```rust,edition2018 10 | use mime::Mime; 11 | 12 | fn find_mimetype (filename : &String) -> Mime{ 13 | 14 | let parts : Vec<&str> = filename.split('.').collect(); 15 | 16 | let res = match parts.last() { 17 | Some(v) => 18 | match *v { 19 | "png" => mime::IMAGE_PNG, 20 | "jpg" => mime::IMAGE_JPEG, 21 | "json" => mime::APPLICATION_JSON, 22 | &_ => mime::TEXT_PLAIN, 23 | }, 24 | None => mime::TEXT_PLAIN, 25 | }; 26 | return res; 27 | } 28 | 29 | fn main() { 30 | let filenames = vec!("foobar.jpg", "foo.bar", "foobar.png"); 31 | for file in filenames { 32 | let mime = find_mimetype(&file.to_owned()); 33 | println!("MIME for {}: {}", file, mime); 34 | } 35 | 36 | } 37 | ``` 38 | 39 | [`mime:Mime`]: https://docs.rs/mime/*/mime/struct.Mime.html 40 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/mime/string.md: -------------------------------------------------------------------------------- 1 | ## Get MIME type from string 2 | 3 | [![mime-badge]][mime] [![cat-encoding-badge]][cat-encoding] 4 | 5 | The following example shows how to parse a [`MIME`] type from a string using the 6 | [mime] crate. [`FromStrError`] produces a default [`MIME`] type in an 7 | `unwrap_or` clause. 8 | 9 | ```rust,edition2018 10 | use mime::{Mime, APPLICATION_OCTET_STREAM}; 11 | 12 | fn main() { 13 | let invalid_mime_type = "i n v a l i d"; 14 | let default_mime = invalid_mime_type 15 | .parse::() 16 | .unwrap_or(APPLICATION_OCTET_STREAM); 17 | 18 | println!( 19 | "MIME for {:?} used default value {:?}", 20 | invalid_mime_type, default_mime 21 | ); 22 | 23 | let valid_mime_type = "TEXT/PLAIN"; 24 | let parsed_mime = valid_mime_type 25 | .parse::() 26 | .unwrap_or(APPLICATION_OCTET_STREAM); 27 | 28 | println!( 29 | "MIME for {:?} was parsed as {:?}", 30 | valid_mime_type, parsed_mime 31 | ); 32 | } 33 | ``` 34 | 35 | [`FromStrError`]: https://docs.rs/mime/*/mime/struct.FromStrError.html 36 | [`MIME`]: https://docs.rs/mime/*/mime/struct.Mime.html 37 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/scraping.md: -------------------------------------------------------------------------------- 1 | # Extracting Links 2 | 3 | {{#include scraping/extract-links.md}} 4 | 5 | {{#include scraping/broken.md}} 6 | 7 | {{#include scraping/unique.md}} 8 | 9 | {{#include ../links.md}} 10 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/url.md: -------------------------------------------------------------------------------- 1 | # Uniform Resource Location 2 | 3 | {{#include url/parse.md}} 4 | 5 | {{#include url/base.md}} 6 | 7 | {{#include url/new.md}} 8 | 9 | {{#include url/origin.md}} 10 | 11 | {{#include url/fragment.md}} 12 | 13 | {{#include ../links.md}} 14 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/url/fragment.md: -------------------------------------------------------------------------------- 1 | ## Remove fragment identifiers and query pairs from a URL 2 | 3 | [![url-badge]][url] [![cat-net-badge]][cat-net] 4 | 5 | Parses [`Url`] and slices it with [`url::Position`] to strip unneeded URL parts. 6 | 7 | ```rust,edition2018 8 | 9 | 10 | use url::{Url, Position, ParseError}; 11 | 12 | fn main() -> Result<(), ParseError> { 13 | let parsed = Url::parse("https://github.com/rust-lang/rust/issues?labels=E-easy&state=open")?; 14 | let cleaned: &str = &parsed[..Position::AfterPath]; 15 | println!("cleaned: {}", cleaned); 16 | Ok(()) 17 | } 18 | ``` 19 | 20 | [`url::Position`]: https://docs.rs/url/*/url/enum.Position.html 21 | [`Url`]: https://docs.rs/url/*/url/struct.Url.html 22 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/url/new.md: -------------------------------------------------------------------------------- 1 | ## Create new URLs from a base URL 2 | 3 | [![url-badge]][url] [![cat-net-badge]][cat-net] 4 | 5 | The [`join`] method creates a new URL from a base and relative path. 6 | 7 | ```rust,edition2018 8 | 9 | use url::{Url, ParseError}; 10 | 11 | fn main() -> Result<(), ParseError> { 12 | let path = "/rust-lang/cargo"; 13 | 14 | let gh = build_github_url(path)?; 15 | 16 | assert_eq!(gh.as_str(), "https://github.com/rust-lang/cargo"); 17 | println!("The joined URL is: {}", gh); 18 | 19 | Ok(()) 20 | } 21 | 22 | fn build_github_url(path: &str) -> Result { 23 | const GITHUB: &'static str = "https://github.com"; 24 | 25 | let base = Url::parse(GITHUB).expect("hardcoded URL is known to be valid"); 26 | let joined = base.join(path)?; 27 | 28 | Ok(joined) 29 | } 30 | ``` 31 | 32 | [`join`]: https://docs.rs/url/*/url/struct.Url.html#method.join 33 | -------------------------------------------------------------------------------- /rust-cookbook/src/web/url/parse.md: -------------------------------------------------------------------------------- 1 | ## Parse a URL from a string to a `Url` type 2 | 3 | [![url-badge]][url] [![cat-net-badge]][cat-net] 4 | 5 | The [`parse`] method from the `url` crate validates and parses a `&str` into a 6 | [`Url`] struct. The input string may be malformed so this method returns 7 | `Result`. 8 | 9 | Once the URL has been parsed, it can be used with all of the methods in the 10 | `Url` type. 11 | 12 | ```rust,edition2018 13 | 14 | use url::{Url, ParseError}; 15 | 16 | fn main() -> Result<(), ParseError> { 17 | let s = "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open"; 18 | 19 | let parsed = Url::parse(s)?; 20 | println!("The path part of the URL is: {}", parsed.path()); 21 | 22 | Ok(()) 23 | } 24 | ``` 25 | 26 | [`parse`]: https://docs.rs/url/*/url/struct.Url.html#method.parse 27 | [`Url`]: https://docs.rs/url/*/url/struct.Url.html 28 | -------------------------------------------------------------------------------- /rust-cookbook/tests/skeptic.rs: -------------------------------------------------------------------------------- 1 | include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs")); 2 | -------------------------------------------------------------------------------- /rust-cookbook/theme/custom.css: -------------------------------------------------------------------------------- 1 | table { 2 | width: 100%; 3 | } 4 | 5 | table td:first-child { 6 | width: 65%; 7 | } 8 | 9 | table td:nth-child(2) { 10 | width: 20%; 11 | padding: 3px; 12 | } 13 | 14 | table td:nth-child(3) { 15 | padding: 3px; 16 | } 17 | 18 | /* underline hyperlinked inline code items */ 19 | a:hover > .hljs { 20 | text-decoration: underline; 21 | } 22 | 23 | /* color hyperlinked inline code items 24 | identically to normal links */ 25 | .rust a > .hljs, 26 | .navy a > .hljs, 27 | .coal a > .hljs{ 28 | color: #2b79a2; 29 | } 30 | 31 | .light a > .hljs { 32 | color: #4183c4; 33 | } 34 | -------------------------------------------------------------------------------- /rust-cookbook/xtask/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xtask" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /rust-cookbook/xtask/README.md: -------------------------------------------------------------------------------- 1 | # xtask - (Rust Cookbook) 2 | 3 | **Rust Dependencies**: 4 | - Make sure you have the required tools installed: 5 | ```bash 6 | cargo install mdbook@0.4.43 lychee@0.17.0 7 | ``` 8 | 9 | ## Available Tasks 10 | 11 | ### `test` 12 | Run various tests for the project. You can specify individual tests or run them all. 13 | 14 | - `cargo`: Run the `cargo test` command for the Rust code. 15 | - `spellcheck`: Run the spellcheck script. 16 | - `link`: Verify links within the project. 17 | - `all`: Run all the tests (default). 18 | 19 | **Usage:** 20 | ```bash 21 | cargo xtask test [all|cargo|spellcheck|link] 22 | ``` 23 | 24 | ### `book` 25 | Build or serve the project's documentation using `mdbook`. 26 | 27 | - `build`: Build the book (default). 28 | - `serve`: Serve the book locally and open it in a browser. 29 | 30 | **Usage:** 31 | ```bash 32 | cargo xtask book [build|serve] 33 | ``` 34 | -------------------------------------------------------------------------------- /scripts/update_original.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | SCRIPTS_DIR=`dirname "$0" | xargs realpath` 6 | ROOT_DIR=`realpath "${SCRIPTS_DIR}/../"` 7 | ORIGINAL_DIR="${ROOT_DIR}/rust-cookbook" 8 | ORIGINAL_LANG="en" 9 | ORIGINAL_REPO="https://github.com/rust-lang-nursery/rust-cookbook.git" 10 | 11 | TRANSLATION_LANG="ru" 12 | TRANSLATION_DIR="${ORIGINAL_DIR}-${TRANSLATION_LANG}" 13 | 14 | source "${ROOT_DIR}/common-configs/scripts/update_original.sh" 15 | --------------------------------------------------------------------------------