From 9a564566132487f9d71a1c0d9af51c44f6a06835 Mon Sep 17 00:00:00 2001 From: funkill2 Date: Sat, 30 Nov 2024 04:00:10 +0300 Subject: [PATCH] update original --- rust-cookbook/Cargo.toml | 54 ++++++------ rust-cookbook/src/about.md | 82 +++---------------- .../build_tools/cc-bundled-static.md | 10 +-- rust-cookbook/src/errors.md | 8 +- rust-cookbook/src/errors/handle.md | 4 - rust-cookbook/src/errors/handle/main.md | 45 +++++++++- rust-cookbook/src/links.md | 4 + 7 files changed, 92 insertions(+), 115 deletions(-) diff --git a/rust-cookbook/Cargo.toml b/rust-cookbook/Cargo.toml index e08f150..f0d4979 100755 --- a/rust-cookbook/Cargo.toml +++ b/rust-cookbook/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust-cookbook" -version = "1.0.0" +version = "1.1.0" authors = ["Brian Anderson ", "Andrew Gauger "] edition = "2018" license = "MIT/Apache-2.0" @@ -21,7 +21,6 @@ crossbeam-channel = "0.3.9" csv = "1.0" data-encoding = "2.1.0" env_logger = "0.11.3" -error-chain = "0.12" flate2 = "1.0" glob = "0.3" image = "0.20" @@ -30,42 +29,43 @@ log = "0.4" log4rs = "0.8" memmap = "0.7" mime = "0.3" -nalgebra = { version = "0.16.12", features = ["serde-serialize"] } -ndarray = { version = "0.13", features = ["approx"] } -num = "0.2" -num_cpus = "1.8" -percent-encoding = "2.1" -petgraph = "0.4" -postgres = "0.17.2" -rand = "0.8.0" -rand_distr = "0.4.0" -rayon = "1.0" -regex = "1.0" -reqwest = { version = "0.10", features = ["blocking", "json", "stream"] } -ring = "0.16.11" -rusqlite = { version = "0.25", features = ["chrono"] } +nalgebra = { version = "0.33", features = ["serde-serialize"] } +ndarray = { version = "0.16", features = ["approx"] } +num = "0.4" +num_cpus = "1.16" +percent-encoding = "2.3" +petgraph = "0.6" +postgres = "0.19" +rand = "0.8" +rand_distr = "0.4" +rayon = "1.10" +regex = "1.11" +reqwest = { version = "0.12", features = ["blocking", "json", "stream"] } +ring = "0.17" +rusqlite = { version = "0.32", features = ["chrono"] } same-file = "1.0" -select = "0.4" -semver = "0.9" +select = "0.6" +semver = "1.0" serde = { version = "1.0", features = ["derive"] } serde_derive = "1.0" serde_json = "1.0" -tar = "0.4.12" -tempfile = "3.1" -threadpool = "1.6" -toml = "0.4" -tokio = { version = "0.2", features = ["full"] } +tar = "0.4" +tempfile = "3.14" +thiserror = "2" +threadpool = "1.8" +toml = "0.8" +tokio = { version = "1", features = ["full"] } unicode-segmentation = "1.2.1" -url = "2.1" -walkdir = "2.0" +url = "2.5" +walkdir = "2.5" [target.'cfg(target_os = "linux")'.dependencies] syslog = "5.0" [build-dependencies] skeptic = "0.13" -walkdir = "2.0" +walkdir = "2.5" [dev-dependencies] skeptic = "0.13" -walkdir = "2.0" +walkdir = "2.5" diff --git a/rust-cookbook/src/about.md b/rust-cookbook/src/about.md index 7de8904..1ca8026 100644 --- a/rust-cookbook/src/about.md +++ b/rust-cookbook/src/about.md @@ -96,78 +96,15 @@ documentation on [docs.rs], and is often the next documentation you should read after deciding which crate suites your purpose. ## A note about error handling +Rust has [`std::error::Trait`] which is implemented to handle exceptions. +Handling multiple types of these traits can be simplified using [`anyhow`] +or specified with an `enum` which macros exist to make this easier within +[`thiserror`] for library authors. -Error handling in Rust is robust when done correctly, but in today's -Rust it requires a fair bit of boilerplate. Because of this one often -sees Rust examples filled with `unwrap` calls instead of proper error -handling. - -Since these recipes are intended to be reused as-is and encourage best -practices, they set up error handling correctly when there are -`Result` types involved. - -The basic pattern we use is to have a `fn main() -> Result`. - -The structure generally looks like: - -```rust,edition2018 -use error_chain::error_chain; -use std::net::IpAddr; -use std::str; - -error_chain! { - foreign_links { - Utf8(std::str::Utf8Error); - AddrParse(std::net::AddrParseError); - } -} - -fn main() -> Result<()> { - let bytes = b"2001:db8::1"; - - // Bytes to string. - let s = str::from_utf8(bytes)?; - - // String to IP address. - let addr: IpAddr = s.parse()?; - - println!("{:?}", addr); - Ok(()) -} - -``` - -This is using the `error_chain!` macro to define a custom `Error` and -`Result` type, along with automatic conversions from two standard -library error types. The automatic conversions make the `?` operator -work. - -For the sake of readability error handling boilerplate is hidden by -default like below. In order to read full contents click on the -"Show hidden lines" () button located in the top -right corner of the snippet. - -```rust,edition2018 -# use error_chain::error_chain; - -use url::{Url, Position}; -# -# error_chain! { -# foreign_links { -# UrlParse(url::ParseError); -# } -# } - -fn main() -> Result<()> { - let parsed = Url::parse("https://httpbin.org/cookies/set?k2=v2&k1=v1")?; - let cleaned: &str = &parsed[..Position::AfterPath]; - println!("cleaned: {}", cleaned); - Ok(()) -} -``` - -For more background on error handling in Rust, read [this page of the -Rust book][error-docs] and [this blog post][error-blog]. +Error chain has been shown in this book for historical reasons before Rust +`std` and crates represented macro use as a preference. For more background +on error handling in Rust, read [this page of the Rust book][error-docs] +and [this blog post][error-blog]. ## A note about crate representation @@ -199,4 +136,7 @@ as are crates that are pending evaluation. [crates.io]: https://crates.io [docs.rs]: https://docs.rs [Cargo.toml]: http://doc.crates.io/manifest.html +[`anyhow`]: https://docs.rs/anyhow/latest/anyhow/ [`cargo-edit`]: https://github.com/killercup/cargo-edit +[`std::error::Trait`]: https://doc.rust-lang.org/std/error/trait.Error.html +[`thiserror`]: https://docs.rs/thiserror/latest/thiserror/ diff --git a/rust-cookbook/src/development_tools/build_tools/cc-bundled-static.md b/rust-cookbook/src/development_tools/build_tools/cc-bundled-static.md index d77a5bc..afd4b8e 100644 --- a/rust-cookbook/src/development_tools/build_tools/cc-bundled-static.md +++ b/rust-cookbook/src/development_tools/build_tools/cc-bundled-static.md @@ -25,7 +25,7 @@ build = "build.rs" cc = "1" [dependencies] -error-chain = "0.11" +anyhow = "1" ``` ### `build.rs` @@ -56,16 +56,10 @@ void greet(const char* name) { ### `src/main.rs` ```rust,edition2018,ignore -use error_chain::error_chain; +use anyhow::Result; use std::ffi::CString; use std::os::raw::c_char; -error_chain! { - foreign_links { - NulError(::std::ffi::NulError); - Io(::std::io::Error); - } -} fn prompt(s: &str) -> Result { use std::io::Write; print!("{}", s); diff --git a/rust-cookbook/src/errors.md b/rust-cookbook/src/errors.md index 8358366..d4be075 100644 --- a/rust-cookbook/src/errors.md +++ b/rust-cookbook/src/errors.md @@ -2,12 +2,12 @@ | Recipe | Crates | Categories | |--------|--------|------------| +| [Composing errors with an enum][ex-thiserror] | [![thiserror-badge]][thiserror] | [![cat-rust-patterns-badge]][cat-rust-patterns] | +| [Dynamic errors with anyhow][ex-anyhow] | [![anyhow-badge]][anyhow] | [![cat-rust-patterns-badge]][cat-rust-patterns] | | [Handle errors correctly in main][ex-error-chain-simple-error-handling] | [![error-chain-badge]][error-chain] | [![cat-rust-patterns-badge]][cat-rust-patterns] | -| [Avoid discarding errors during error conversions][ex-error-chain-avoid-discarding] | [![error-chain-badge]][error-chain] | [![cat-rust-patterns-badge]][cat-rust-patterns] | -| [Obtain backtrace of complex error scenarios][ex-error-chain-backtrace] | [![error-chain-badge]][error-chain] | [![cat-rust-patterns-badge]][cat-rust-patterns] | +[ex-thiserror]: errors/handle.html#thiserror +[ex-anyhow]: errors/handle.html#anyhow [ex-error-chain-simple-error-handling]: errors/handle.html#handle-errors-correctly-in-main -[ex-error-chain-avoid-discarding]: errors/handle.html#avoid-discarding-errors-during-error-conversions -[ex-error-chain-backtrace]: errors/handle.html#obtain-backtrace-of-complex-error-scenarios {{#include links.md}} diff --git a/rust-cookbook/src/errors/handle.md b/rust-cookbook/src/errors/handle.md index 16ad1e6..26cb03b 100644 --- a/rust-cookbook/src/errors/handle.md +++ b/rust-cookbook/src/errors/handle.md @@ -2,8 +2,4 @@ {{#include handle/main.md}} -{{#include handle/retain.md}} - -{{#include handle/backtrace.md}} - {{#include ../links.md}} diff --git a/rust-cookbook/src/errors/handle/main.md b/rust-cookbook/src/errors/handle/main.md index de72750..61fe1c5 100644 --- a/rust-cookbook/src/errors/handle/main.md +++ b/rust-cookbook/src/errors/handle/main.md @@ -1,7 +1,46 @@ ## Handle errors correctly in main +[![anyhow-badge]][anyhow] [![cat-rust-patterns-badge]][cat-rust-patterns] +[![thiserror-badge]][thiserror] [![cat-rust-patterns-badge]][cat-rust-patterns] [![error-chain-badge]][error-chain] [![cat-rust-patterns-badge]][cat-rust-patterns] +# Error Strategies (2024) + +As recommended in Rust by Example, [`Box`ing errors] is seen as an easy +strategy for getting started. + +```rust,edition2018 +Box +```` + +To understand what kind of error handling may be required study [Designing +error types in Rust] and consider [`thiserror`] for libraries or [`anyhow`] as +a maintained error aggregation option. + +```rust,edition2018 +use thiserror::Error; + +#[derive(Error,Debug)] +pub enum MultiError { + #[error("🦀 got {0}")] + ErrorClass(String), +} +``` + +Application authors can compose enums using `anyhow` can import the `Result` +type from the crate to provide auto-`Box`ing behavior + +```rust,edition2018,should_panic +use anyhow::Result; + +fn main() -> Result<()> { + let my_string = "yellow".to_string(); + let _my_int = my_string.parse::()?; + Ok(()) +} +``` + +# Error Chain (2015-2018) Handles error that occur when trying to open a file that does not exist. It is achieved by using [error-chain], a library that takes care of a lot of boilerplate code needed in order to [handle errors in Rust]. @@ -17,7 +56,7 @@ first number. Returns uptime unless there is an error. Other recipes in this book will hide the [error-chain] boilerplate, and can be seen by expanding the code with the ⤢ button. -```rust,edition2018 +```rust,edition2018,ignore use error_chain::error_chain; use std::fs::File; @@ -49,9 +88,13 @@ fn main() { } ``` +[`anyhow`]: https://docs.rs/anyhow/latest/anyhow/ [`error_chain!`]: https://docs.rs/error-chain/*/error_chain/macro.error_chain.html [`Error`]: https://doc.rust-lang.org/std/error/trait.Error.html [`foreign_links`]: https://docs.rs/error-chain/*/error_chain/#foreign-links [`std::io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html +[`thiserror`]: https://docs.rs/thiserror/latest/thiserror/ [handle errors in Rust]: https://doc.rust-lang.org/book/second-edition/ch09-00-error-handling.html +[`Box`ing errors]: https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html +[Designing error types in Rust]: https://mmapped.blog/posts/12-rust-error-handling diff --git a/rust-cookbook/src/links.md b/rust-cookbook/src/links.md index 9458590..d916e45 100644 --- a/rust-cookbook/src/links.md +++ b/rust-cookbook/src/links.md @@ -52,6 +52,8 @@ Keep lines sorted. [ansi_term-badge]: https://badge-cache.kominick.com/crates/v/ansi_term.svg?label=ansi_term [ansi_term]: https://docs.rs/ansi_term/ +[anyhow-badge]: https://badge-cache.kominick.com/crates/v/anyhow.svg?label=anyhow +[anyhow]: https://docs.rs/anyhow/ [base64-badge]: https://badge-cache.kominick.com/crates/v/base64.svg?label=base64 [base64]: https://docs.rs/base64/ [bitflags-badge]: https://badge-cache.kominick.com/crates/v/bitflags.svg?label=bitflags @@ -135,6 +137,8 @@ Keep lines sorted. [tar]: https://docs.rs/tar/ [tempfile-badge]: https://badge-cache.kominick.com/crates/v/tempfile.svg?label=tempfile [tempfile]: https://docs.rs/tempfile/ +[thiserror-badge]: https://badge-cache.kominick.com/crates/v/thiserror.svg?label=thiserror +[thiserror]: https://docs.rs/thiserror/ [threadpool-badge]: https://badge-cache.kominick.com/crates/v/threadpool.svg?label=threadpool [threadpool]: https://docs.rs/threadpool/ [toml-badge]: https://badge-cache.kominick.com/crates/v/toml.svg?label=toml