diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml
index 51556a74..07af781d 100644
--- a/.github/workflows/check-links.yml
+++ b/.github/workflows/check-links.yml
@@ -24,7 +24,7 @@ jobs:
fail: false
checkbox: false
output: ./lychee/out.md
- args: "--mode task --base . --config ./ci/lychee.toml ."
+ args: "--base . --config ./ci/lychee.toml ."
- name: Save lychee cache
uses: actions/cache/save@v4
diff --git a/.github/workflows/mdbook-test.yml b/.github/workflows/mdbook-test.yml
index 59b32714..9823d08d 100644
--- a/.github/workflows/mdbook-test.yml
+++ b/.github/workflows/mdbook-test.yml
@@ -17,22 +17,19 @@ jobs:
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: 'true'
- toolchain: nightly
+ toolchain: stable
- name: Run tests
id: cargo_test
run: |
- cargo +nightly test --test skeptic -- -Z unstable-options --format junit --report-time --test-threads=1 | tee ./TEST-cookbook.xml
+ cargo test --test skeptic -- --test-threads=1
- - name: List files for debugging
+ - name: Test Results
if: always()
- run: ls -R
-
- - name: Publish Test Report
- uses: mikepenz/action-junit-report@v5.2.0
- if: always()
- with:
- fail_on_failure: true
- require_tests: true
- summary: ${{ steps.cargo_test.outputs.summary }}
- report_paths: '**/TEST-*.xml'
+ run: |
+ if [ ${{ steps.cargo_test.outcome }} == 'success' ]; then
+ echo "✅ All tests passed!"
+ else
+ echo "❌ Some tests failed. Check the logs above for details."
+ exit 1
+ fi
diff --git a/.gitignore b/.gitignore
index 82f95b45..768a3df2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,6 @@ target/
book/
*.swp
lines.txt
-.idea/
\ No newline at end of file
+.idea/
+.skeptic-cache
+.lycheecache
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..082b1943
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "makefile.configureOnOpen": false
+}
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index dbdd3740..80617f83 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -259,9 +259,9 @@ after the code sample.
> The [distributions available are documented here][rand-distributions].
[uniform distribution]: https://en.wikipedia.org/wiki/Uniform_distribution_(continuous)
-[`Distribution::sample`]: https://docs.rs/rand/*/rand/distributions/trait.Distribution.html#tymethod.sample
-[`rand::Rng`]: https://docs.rs/rand/*/rand/trait.Rng.html
-[rand-distributions]: https://docs.rs/rand/*/rand/distributions/index.html
+[`Distribution::sample`]: https://docs.rs/rand/0.9/rand/distr/trait.Distribution.html#tymethod.sample
+[`rand::Rng`]: https://docs.rs/rand/0.9/rand/trait.Rng.html
+[rand-distributions]: https://docs.rs/rand/0.9/rand/distr/index.html
#### Code
diff --git a/Cargo.toml b/Cargo.toml
index a0acf873..fb2b2b67 100755
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,23 +7,28 @@ license = "MIT/Apache-2.0"
publish = false
build = "build.rs"
+[features]
+default = []
+test-rand = []
+
[dependencies]
ansi_term = "0.11.0"
approx = "0.3"
-base64 = "0.9"
-bitflags = "1.0"
+base64 = "0.22.1"
+bitflags = "1.3.2"
byteorder = "1.0"
cc = "1.0"
chrono = "0.4"
clap = "4.5"
-crossbeam = "0.5"
-crossbeam-channel = "0.3.9"
+crossbeam = "0.8"
+crossbeam-channel = "0.5"
csv = "1.0"
data-encoding = "2.1.0"
env_logger = "0.11.3"
flate2 = "1.0"
glob = "0.3"
-image = "0.20"
+image = "0.24"
+
lazy_static = "1.0"
log = "0.4"
log4rs = "0.8"
@@ -35,23 +40,26 @@ num = "0.4"
num_cpus = "1.16"
percent-encoding = "2.3"
petgraph = "0.6"
-postgres = "0.19"
+postgres = "0.19.7"
rand = "0.9"
-rand_distr = "0.5.1"
+rand_distr = "0.5"
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.6"
+select = "0.6.0"
+
semver = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_derive = "1.0"
serde_json = "1.0"
+sha2 = "0.10"
tar = "0.4"
tempfile = "3.14"
thiserror = "2"
+anyhow = "1.0"
threadpool = "1.8"
toml = "0.8"
tokio = { version = "1", features = ["full"] }
@@ -63,9 +71,9 @@ walkdir = "2.5"
syslog = "5.0"
[build-dependencies]
-skeptic = "0.13"
+skeptic = { git = "https://github.com/AndyGauge/rust-skeptic", branch = "rlib-patch" }
walkdir = "2.5"
[dev-dependencies]
-skeptic = "0.13"
+skeptic = { git = "https://github.com/AndyGauge/rust-skeptic", branch = "rlib-patch" }
walkdir = "2.5"
diff --git a/LICENSE-CC0 b/LICENSE-CC0
index 670154e3..4594fb73 100644
--- a/LICENSE-CC0
+++ b/LICENSE-CC0
@@ -113,4 +113,4 @@ Affirmer's express Statement of Purpose.
CC0 or use of the Work.
For more information, please see
-
+
diff --git a/README.md b/README.md
index 9c5d10f1..e95cc685 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,4 @@
-# A Rust Cookbook [![Build Status][build-badge]][build-url]
-
-[build-badge]: https://github.com/rust-lang-nursery/rust-cookbook/workflows/Deploy%20to%20GitHub%20Pages/badge.svg
-[build-url]: https://github.com/rust-lang-nursery/rust-cookbook/actions?query=workflow%3A%22Deploy+to+GitHub+Pages%22
+# A Rust Cookbook
**[Read it here]**.
@@ -92,12 +89,12 @@ For details see [CONTRIBUTING.md] on GitHub.
## License [![CC0-badge]][CC0-deed]
Rust Cookbook is licensed under Creative Commons Zero v1.0 Universal License
-([LICENSE-CC0](LICENSE-CC0) or https://creativecommons.org/publicdomain/zero/1.0/legalcode)
+([LICENSE-CC0](LICENSE-CC0) or https://creativecommons.org/)
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Rust Cookbook by you, as defined in the CC0-1.0 license, shall be
[dedicated to the public domain][CC0-deed] and licensed as above, without any additional
terms or conditions.
-[CC0-deed]: https://creativecommons.org/publicdomain/zero/1.0/deed.en
+[CC0-deed]: https://creativecommons.org/publicdomain/zero/1.0/
[CC0-badge]: https://mirrors.creativecommons.org/presskit/buttons/80x15/svg/cc-zero.svg
diff --git a/build.rs b/build.rs
index a167ed45..db06322e 100644
--- a/build.rs
+++ b/build.rs
@@ -6,6 +6,20 @@ const REMOVED_TESTS: &[&str] = &[
];
fn main() {
+ #[cfg(feature = "test-rand")]
+ {
+ let rand_paths = vec![
+ "./src/algorithms/randomness/rand.md",
+ "./src/algorithms/randomness/rand-range.md",
+ "./src/algorithms/randomness/rand-dist.md",
+ "./src/algorithms/randomness/rand-custom.md",
+ "./src/algorithms/randomness/rand-passwd.md",
+ "./src/algorithms/randomness/rand-choose.md",
+ ];
+ skeptic::generate_doc_tests(&rand_paths[..]);
+ return;
+ }
+
let paths = WalkDir::new("./src/").into_iter()
// convert paths to Strings
.map(|p| p.unwrap().path().to_str().unwrap().to_string())
diff --git a/ci/lychee.toml b/ci/lychee.toml
index 402a61ef..7bd8a13f 100644
--- a/ci/lychee.toml
+++ b/ci/lychee.toml
@@ -30,3 +30,10 @@ exclude_loopback = false
# Check mail addresses
include_mail = true
+
+# Exclude problematic links that consistently fail
+exclude = [
+ # Creative Commons links return 403 for automated requests
+ "https://creativecommons.org/publicdomain/zero/1.0/",
+ "https://creativecommons.org/"
+]
diff --git a/src/about.md b/src/about.md
index f95d0635..18e7794f 100644
--- a/src/about.md
+++ b/src/about.md
@@ -60,8 +60,9 @@ Consider this example for "generate random numbers within a range":
use rand::Rng;
fn main() {
- let mut rng = rand::thread_rng();
- println!("Random f64: {}", rng.gen::());
+ let mut rng = rand::rng();
+ let random_number: u32 = rng.random();
+ println!("Random number: {}", random_number);
}
```
@@ -97,14 +98,15 @@ 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.
+This cookbook uses [`anyhow`] for simplified error handling in examples,
+which provides easy error propagation and context. For library authors,
+[`thiserror`] provides a more structured approach using derive macros
+to create custom error types.
-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].
+This cookbook previously used the `error-chain` crate, but has been updated
+to use `anyhow` as it's now the preferred approach for application-level
+error handling. 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
@@ -129,7 +131,7 @@ as are crates that are pending evaluation.
{{#include links.md}}
[index]: intro.html
-[error-docs]: https://do.rust-lang.org/book/error-handling.html
+[error-docs]: https://doc.rust-lang.org/book/ch09-00-error-handling.html
[error-blog]: https://brson.github.io/2016/11/30/starting-with-error-chain
[error-chain]: https://docs.rs/error-chain/
[Rust Libz Blitz]: https://internals.rust-lang.org/t/rust-libz-blitz/5184
diff --git a/src/algorithms/randomness/rand-choose.md b/src/algorithms/randomness/rand-choose.md
index 5754915e..ad4a2f25 100644
--- a/src/algorithms/randomness/rand-choose.md
+++ b/src/algorithms/randomness/rand-choose.md
@@ -3,21 +3,23 @@
[![rand-badge]][rand] [![cat-os-badge]][cat-os]
Randomly generates a string of given length ASCII characters with custom
-user-defined bytestring, with [`random_range`].
+user-defined bytestring, with [`gen_range`].
```rust,edition2018
+use rand::Rng;
+
+const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+ abcdefghijklmnopqrstuvwxyz\
+ 0123456789)(*&^%$#@!~";
+const PASSWORD_LEN: usize = 30;
+
fn main() {
- use rand::Rng;
- const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
- abcdefghijklmnopqrstuvwxyz\
- 0123456789)(*&^%$#@!~";
- const PASSWORD_LEN: usize = 30;
let mut rng = rand::rng();
let password: String = (0..PASSWORD_LEN)
.map(|_| {
- let idx = rng.random_range(0..CHARSET.len());
- CHARSET[idx] as char
+ let idx = rng.gen_range(0..CHARSET.len());
+ char::from(CHARSET[idx])
})
.collect();
@@ -25,4 +27,4 @@ fn main() {
}
```
-[`random_range`]: https://docs.rs/rand/*/rand/trait.Rng.html#method.random_range
+[`gen_range`]: https://docs.rs/rand/0.9/rand/trait.Rng.html#method.gen_range
diff --git a/src/algorithms/randomness/rand-custom.md b/src/algorithms/randomness/rand-custom.md
index 33fd238c..e0b0e854 100644
--- a/src/algorithms/randomness/rand-custom.md
+++ b/src/algorithms/randomness/rand-custom.md
@@ -7,7 +7,6 @@ Implements the [`Distribution`] trait on type Point for [`Standard`] in order to
```rust,edition2018
use rand::Rng;
-use rand::distributions::{Distribution, Standard};
#[derive(Debug)]
struct Point {
@@ -15,12 +14,11 @@ struct Point {
y: i32,
}
-impl Distribution for Standard {
- fn sample(&self, rng: &mut R) -> Point {
- let (rand_x, rand_y) = rng.random();
+impl Point {
+ fn random(rng: &mut R) -> Self {
Point {
- x: rand_x,
- y: rand_y,
+ x: rng.random(),
+ y: rng.random(),
}
}
}
@@ -28,11 +26,11 @@ impl Distribution for Standard {
fn main() {
let mut rng = rand::rng();
let rand_tuple = rng.random::<(i32, bool, f64)>();
- let rand_point: Point = rng.random();
+ let rand_point = Point::random(&mut rng);
println!("Random tuple: {:?}", rand_tuple);
println!("Random Point: {:?}", rand_point);
}
```
-[`Distribution`]: https://docs.rs/rand/*/rand/distributions/trait.Distribution.html
-[`Standard`]: https://docs.rs/rand/*/rand/distributions/struct.Standard.html
+[Distribution]: https://docs.rs/rand/0.9/rand/distr/trait.Distribution.html
+[Standard]: https://docs.rs/rand/0.9/rand/distr/struct.Standard.html
diff --git a/src/algorithms/randomness/rand-dist.md b/src/algorithms/randomness/rand-dist.md
index 35efe31c..bbe89ccb 100644
--- a/src/algorithms/randomness/rand-dist.md
+++ b/src/algorithms/randomness/rand-dist.md
@@ -12,22 +12,27 @@ generator [`rand::Rng`].
The [distributions available are documented here][rand-distributions].
An example using the [`Normal`] distribution is shown below.
-```rust,edition2018,ignore
-use rand_distr::{Distribution, Normal, NormalError};
-use rand::rng;
+```rust,edition2018
+use rand::Rng;
+use rand_distr::{Distribution, LogNormal, Normal};
+
+fn main() {
+ let mut rng = rand::rng();
+ let normal = Normal::new(2.0, 3.0)
+ .expect("Failed to create normal distribution");
+ let log_normal = LogNormal::new(1.0, 0.5)
+ .expect("Failed to create log-normal distribution");
-fn main() -> Result<(), NormalError> {
- let mut rng = rng();
- let normal = Normal::new(2.0, 3.0)?;
let v = normal.sample(&mut rng);
println!("{} is from a N(2, 9) distribution", v);
- Ok(())
+ let v = log_normal.sample(&mut rng);
+ println!("{} is from an ln N(1, 0.25) distribution", v);
}
```
-[`Distribution::sample`]: https://docs.rs/rand/*/rand/distributions/trait.Distribution.html#tymethod.sample
+[`Distribution::sample`]: https://docs.rs/rand/0.9/rand/distr/trait.Distribution.html#tymethod.sample
[`Normal`]: https://docs.rs/rand_distr/*/rand_distr/struct.Normal.html
-[`rand::Rng`]: https://docs.rs/rand/*/rand/trait.Rng.html
+[`rand::Rng`]: https://docs.rs/rand/0.9/rand/trait.Rng.html
[`rand_distr`]: https://docs.rs/rand_distr/*/rand_distr/index.html
[rand-distributions]: https://docs.rs/rand_distr/*/rand_distr/index.html
diff --git a/src/algorithms/randomness/rand-passwd.md b/src/algorithms/randomness/rand-passwd.md
index 8c74662e..de010800 100644
--- a/src/algorithms/randomness/rand-passwd.md
+++ b/src/algorithms/randomness/rand-passwd.md
@@ -6,18 +6,28 @@ Randomly generates a string of given length ASCII characters in the range `A-Z,
a-z, 0-9`, with [`Alphanumeric`] sample.
```rust,edition2018
-use rand::{rng, Rng};
-use rand::distributions::Alphanumeric;
+use rand::Rng;
fn main() {
- let rand_string: String = rng()
- .sample_iter(&Alphanumeric)
- .take(30)
- .map(char::from)
+ const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+ abcdefghijklmnopqrstuvwxyz\
+ 0123456789";
+ const PASSWORD_LEN: usize = 30;
+ let mut rng = rand::rng();
+
+ let password: String = (0..PASSWORD_LEN)
+ .map(|_| {
+ let idx = rng.random_range(0..CHARSET.len());
+ CHARSET[idx] as char
+ })
.collect();
- println!("{}", rand_string);
+ println!("{}", password);
}
```
-[`Alphanumeric`]: https://docs.rs/rand/*/rand/distributions/struct.Alphanumeric.html
+[`Alphanumeric`]: https://docs.rs/rand/0.9/rand/distr/struct.Alphanumeric.html
+
+
+
+
diff --git a/src/algorithms/randomness/rand-range.md b/src/algorithms/randomness/rand-range.md
index acae3475..0935aaa6 100644
--- a/src/algorithms/randomness/rand-range.md
+++ b/src/algorithms/randomness/rand-range.md
@@ -2,15 +2,15 @@
[![rand-badge]][rand] [![cat-science-badge]][cat-science]
-Generates a random value within half-open `[0, 10)` range (not including `10`) with [`Rng::random_range`].
+Generates a random value within half-open `[0, 10)` range (not including `10`) with [`Rng::gen_range`].
```rust,edition2018
use rand::Rng;
fn main() {
let mut rng = rand::rng();
- println!("Integer: {}", rng.random_range(0..10));
- println!("Float: {}", rng.random_range(0.0..10.0));
+ println!("Integer: {}", rng.gen_range(0..10));
+ println!("Float: {}", rng.gen_range(0.0..10.0));
}
```
@@ -19,12 +19,13 @@ This has the same effect, but may be faster when repeatedly generating numbers
in the same range.
```rust,edition2018
-
-use rand::distributions::{Distribution, Uniform};
+use rand::Rng;
+use rand_distr::{Distribution, Uniform};
fn main() {
let mut rng = rand::rng();
- let die = Uniform::from(1..7);
+ let die = Uniform::new_inclusive(1, 6)
+ .expect("Failed to create uniform distribution: invalid range");
loop {
let throw = die.sample(&mut rng);
@@ -34,8 +35,4 @@ fn main() {
}
}
}
-```
-
-[`Uniform`]: https://docs.rs/rand/*/rand/distributions/uniform/struct.Uniform.html
-[`Rng::random_range`]: https://doc.rust-lang.org/rand/*/rand/trait.Rng.html#method.random_range
-[uniform distribution]: https://en.wikipedia.org/wiki/Uniform_distribution_(continuous)
+```
\ No newline at end of file
diff --git a/src/algorithms/randomness/rand.md b/src/algorithms/randomness/rand.md
index 4db33c89..c24e5983 100644
--- a/src/algorithms/randomness/rand.md
+++ b/src/algorithms/randomness/rand.md
@@ -12,17 +12,11 @@ including 1.
use rand::Rng;
fn main() {
- let mut rng = rand::rng();
-
- let n1: u8 = rng.random();
- let n2: u16 = rng.random();
- println!("Random u8: {}", n1);
- println!("Random u16: {}", n2);
- println!("Random u32: {}", rng.random::());
- println!("Random i32: {}", rng.random::());
- println!("Random float: {}", rng.random::());
+ let mut rng = rand::thread_rng();
+ let random_number: u32 = rng.gen();
+ println!("Random number: {}", random_number);
}
```
-[`rand::Rng`]: https://docs.rs/rand/*/rand/trait.Rng.html
-[`rand::rng`]: https://docs.rs/rand/*/rand/fn.rng.html
+[`rand::Rng`]: https://docs.rs/rand/0.9/rand/trait.Rng.html
+[`rand::rng`]: https://docs.rs/rand/0.9/rand/fn.rng.html
diff --git a/src/compression/tar/tar-compress.md b/src/compression/tar/tar-compress.md
index d2454343..64ec37f2 100644
--- a/src/compression/tar/tar-compress.md
+++ b/src/compression/tar/tar-compress.md
@@ -11,7 +11,6 @@ under `backup/logs` path with [`Builder::append_dir_all`].
data prior to writing it into `archive.tar.gz`.
```rust,edition2018,no_run
-
use std::fs::File;
use flate2::Compression;
use flate2::write::GzEncoder;
@@ -29,7 +28,6 @@ fn main() -> Result<(), std::io::Error> {
To add the contents without renaming them, an empty string can be used as the first argument of [`Builder::append_dir_all`]:
```rust,edition2018,no_run
-
use std::fs::File;
use flate2::Compression;
use flate2::write::GzEncoder;
diff --git a/src/compression/tar/tar-decompress.md b/src/compression/tar/tar-decompress.md
index 324af291..0d7006dd 100644
--- a/src/compression/tar/tar-decompress.md
+++ b/src/compression/tar/tar-decompress.md
@@ -8,7 +8,6 @@ named `archive.tar.gz` located in the current working directory
to the same location.
```rust,edition2018,no_run
-
use std::fs::File;
use flate2::read::GzDecoder;
use tar::Archive;
diff --git a/src/compression/tar/tar-strip-prefix.md b/src/compression/tar/tar-strip-prefix.md
index dd2f0abb..69d8120e 100644
--- a/src/compression/tar/tar-strip-prefix.md
+++ b/src/compression/tar/tar-strip-prefix.md
@@ -7,20 +7,13 @@ the specified path prefix (`bundle/logs`). Finally, extract the [`tar::Entry`]
via [`Entry::unpack`].
```rust,edition2018,no_run
-# use error_chain::error_chain;
+use anyhow::Result;
use std::fs::File;
use std::path::PathBuf;
use flate2::read::GzDecoder;
use tar::Archive;
-#
-# error_chain! {
-# foreign_links {
-# Io(std::io::Error);
-# StripPrefixError(::std::path::StripPrefixError);
-# }
-# }
-fn main() -> Result<(), std::io::Error> {
+fn main() -> Result<()> {
let file = File::open("archive.tar.gz")?;
let mut archive = Archive::new(GzDecoder::new(file));
let prefix = "bundle/logs";
diff --git a/src/concurrency/parallel/rayon-parallel-sort.md b/src/concurrency/parallel/rayon-parallel-sort.md
index 83efc85b..8bb205a8 100644
--- a/src/concurrency/parallel/rayon-parallel-sort.md
+++ b/src/concurrency/parallel/rayon-parallel-sort.md
@@ -10,18 +10,18 @@ exist to sort an enumerable data type, [`par_sort_unstable`]
is usually faster than [stable sorting] algorithms.
```rust,edition2018
-
-use rand::{Rng, thread_rng};
-use rand::distributions::Alphanumeric;
+use rand::Rng;
use rayon::prelude::*;
fn main() {
- let mut vec = vec![String::new(); 100_000];
- vec.par_iter_mut().for_each(|p| {
- let mut rng = thread_rng();
- *p = (0..5).map(|_| rng.sample(&Alphanumeric) as char).collect()
- });
- vec.par_sort_unstable();
+ let mut vec = vec![0; 1_000_000];
+ rand::thread_rng().fill(&mut vec[..]);
+
+ vec.par_sort_unstable();
+
+ let first = vec.first().unwrap();
+ let last = vec.last().unwrap();
+ assert!(first <= last);
}
```
diff --git a/src/concurrency/parallel/rayon-thumbnails.md b/src/concurrency/parallel/rayon-thumbnails.md
index 40f295ed..dc9f6b84 100644
--- a/src/concurrency/parallel/rayon-thumbnails.md
+++ b/src/concurrency/parallel/rayon-thumbnails.md
@@ -9,24 +9,14 @@ then saves them in a new folder called `thumbnails`.
images in parallel using [`par_iter`] calling [`DynamicImage::resize`].
```rust,edition2018,no_run
-# use error_chain::error_chain;
-
+use anyhow::Result;
use std::path::Path;
use std::fs::create_dir_all;
-# use error_chain::ChainedError;
use glob::{glob_with, MatchOptions};
-use image::{FilterType, ImageError};
+use image::imageops::FilterType;
use rayon::prelude::*;
-# error_chain! {
-# foreign_links {
-# Image(ImageError);
-# Io(std::io::Error);
-# Glob(glob::PatternError);
-# }
-# }
-
fn main() -> Result<()> {
let options: MatchOptions = Default::default();
let files: Vec<_> = glob_with("*.jpg", options)?
@@ -34,7 +24,7 @@ fn main() -> Result<()> {
.collect();
if files.len() == 0 {
- error_chain::bail!("No .jpg files found in current directory");
+ anyhow::bail!("No .jpg files found in current directory");
}
let thumb_dir = "thumbnails";
@@ -46,12 +36,12 @@ fn main() -> Result<()> {
.par_iter()
.map(|path| {
make_thumbnail(path, thumb_dir, 300)
- .map_err(|e| e.chain_err(|| path.display().to_string()))
+ .map_err(|e| anyhow::anyhow!("Failed to process {}: {}", path.display(), e))
})
.filter_map(|x| x.err())
.collect();
- image_failures.iter().for_each(|x| println!("{}", x.display_chain()));
+ image_failures.iter().for_each(|x| println!("{}", x));
println!("{} thumbnails saved successfully", files.len() - image_failures.len());
Ok(())
diff --git a/src/concurrency/thread/crossbeam-complex.md b/src/concurrency/thread/crossbeam-complex.md
index cb1a513e..e084e148 100644
--- a/src/concurrency/thread/crossbeam-complex.md
+++ b/src/concurrency/thread/crossbeam-complex.md
@@ -27,7 +27,7 @@ think of the calls to `drop` as signaling that no more messages will be sent.
```rust,edition2018
use std::thread;
use std::time::Duration;
-use crossbeam_channel::bounded;
+use crossbeam::channel::bounded;
fn main() {
let (snd1, rcv1) = bounded(1);
diff --git a/src/concurrency/thread/crossbeam-spsc.md b/src/concurrency/thread/crossbeam-spsc.md
index 59e0571e..763c6d19 100644
--- a/src/concurrency/thread/crossbeam-spsc.md
+++ b/src/concurrency/thread/crossbeam-spsc.md
@@ -10,9 +10,8 @@ channel, meaning there is no limit to the number of storeable messages. The
producer thread sleeps for half a second in between messages.
```rust,edition2018
-
use std::{thread, time};
-use crossbeam_channel::unbounded;
+use crossbeam::channel::unbounded;
fn main() {
let (snd, rcv) = unbounded();
diff --git a/src/concurrency/thread/global-mut-state.md b/src/concurrency/thread/global-mut-state.md
index 91a149b9..f2f6e88e 100644
--- a/src/concurrency/thread/global-mut-state.md
+++ b/src/concurrency/thread/global-mut-state.md
@@ -10,18 +10,16 @@ race conditions. A [`MutexGuard`] must be acquired to read or mutate the
value stored in a [`Mutex`].
```rust,edition2018
-# use error_chain::error_chain;
+use anyhow::{Result, anyhow};
use lazy_static::lazy_static;
use std::sync::Mutex;
-#
-# error_chain!{ }
lazy_static! {
static ref FRUIT: Mutex> = Mutex::new(Vec::new());
}
fn insert(fruit: &str) -> Result<()> {
- let mut db = FRUIT.lock().map_err(|_| "Failed to acquire MutexGuard")?;
+ let mut db = FRUIT.lock().map_err(|_| anyhow!("Failed to acquire MutexGuard"))?;
db.push(fruit.to_string());
Ok(())
}
@@ -31,7 +29,7 @@ fn main() -> Result<()> {
insert("orange")?;
insert("peach")?;
{
- let db = FRUIT.lock().map_err(|_| "Failed to acquire MutexGuard")?;
+ let db = FRUIT.lock().map_err(|_| anyhow!("Failed to acquire MutexGuard"))?;
db.iter().enumerate().for_each(|(i, item)| println!("{}: {}", i, item));
}
diff --git a/src/concurrency/thread/threadpool-fractal.md b/src/concurrency/thread/threadpool-fractal.md
index 5a7807e0..9b5eb8a1 100644
--- a/src/concurrency/thread/threadpool-fractal.md
+++ b/src/concurrency/thread/threadpool-fractal.md
@@ -17,20 +17,12 @@ Create [`ThreadPool`] with thread count equal to number of cores with [`num_cpus
[`ImageBuffer::save`] writes the image to `output.png`.
```rust,edition2018,no_run
-# use error_chain::error_chain;
-use std::sync::mpsc::{channel, RecvError};
+use anyhow::Result;
+use std::sync::mpsc::channel;
use threadpool::ThreadPool;
use num::complex::Complex;
use image::{ImageBuffer, Pixel, Rgb};
#
-# error_chain! {
-# foreign_links {
-# MpscRecv(RecvError);
-# Io(std::io::Error);
-# Image(image::ImageError);
-# }
-# }
-#
# // Function converting intensity values to RGB
# // Based on http://www.efg2.com/Lab/ScienceAndEngineering/Spectra.htm
# fn wavelength_to_rgb(wavelength: u32) -> Rgb {
@@ -53,7 +45,7 @@ use image::{ImageBuffer, Pixel, Rgb};
# };
#
# let (r, g, b) = (normalize(r, factor), normalize(g, factor), normalize(b, factor));
-# Rgb::from_channels(r, g, b, 0)
+# Rgb([r, g, b])
# }
#
# // Maps Julia set distance estimation to intensity values
diff --git a/src/concurrency/thread/threadpool-walk.md b/src/concurrency/thread/threadpool-walk.md
index 5f8559a7..938ce1f9 100644
--- a/src/concurrency/thread/threadpool-walk.md
+++ b/src/concurrency/thread/threadpool-walk.md
@@ -9,7 +9,6 @@ the current directory and calls [`execute`] to perform the operations of reading
and computing SHA256 hash.
```rust,edition2018,no_run
-
use walkdir::WalkDir;
use std::fs::File;
use std::io::{BufReader, Read, Error};
diff --git a/src/cryptography/encryption/pbkdf2.md b/src/cryptography/encryption/pbkdf2.md
index bf61bd36..3752e305 100644
--- a/src/cryptography/encryption/pbkdf2.md
+++ b/src/cryptography/encryption/pbkdf2.md
@@ -9,8 +9,7 @@ function [`pbkdf2::derive`]. Verifies the hash is correct with
[`SecureRandom::fill`], which fills the salt byte array with
securely generated random numbers.
-```rust,edition2018
-
+```rust,edition2021
use data_encoding::HEXUPPER;
use ring::error::Unspecified;
use ring::rand::SecureRandom;
diff --git a/src/cryptography/hashing/hmac.md b/src/cryptography/hashing/hmac.md
index 90f442d0..aee46f84 100644
--- a/src/cryptography/hashing/hmac.md
+++ b/src/cryptography/hashing/hmac.md
@@ -6,7 +6,7 @@ The [`hmac::sign`] method is used to calculate the HMAC digest (also called a ta
The resulting [`hmac::Tag`] structure contains the raw bytes of the HMAC,
which can later be verified with[`hmac::verify`] to ensure the message has not been tampered with and comes from a trusted source.
-```rust,edition2018
+```rust,edition2021
use ring::{hmac, rand};
use ring::rand::SecureRandom;
use ring::error::Unspecified;
diff --git a/src/cryptography/hashing/sha-digest.md b/src/cryptography/hashing/sha-digest.md
index 14fca973..fb9a60c8 100644
--- a/src/cryptography/hashing/sha-digest.md
+++ b/src/cryptography/hashing/sha-digest.md
@@ -5,19 +5,12 @@
Writes some data to a file, then calculates the SHA-256 [`digest::Digest`] of
the file's contents using [`digest::Context`].
-```rust,edition2018
-# use error_chain::error_chain;
-use data_encoding::HEXUPPER;
+```rust,edition2021
+use anyhow::Result;
use ring::digest::{Context, Digest, SHA256};
+use data_encoding::HEXUPPER;
use std::fs::File;
use std::io::{BufReader, Read, Write};
-#
-# error_chain! {
-# foreign_links {
-# Io(std::io::Error);
-# Decode(data_encoding::DecodeError);
-# }
-# }
fn sha256_digest(mut reader: R) -> Result {
let mut context = Context::new(&SHA256);
diff --git a/src/data_structures/bitfield/bitfield.md b/src/data_structures/bitfield/bitfield.md
index 4c62a7d2..df4bfadf 100644
--- a/src/data_structures/bitfield/bitfield.md
+++ b/src/data_structures/bitfield/bitfield.md
@@ -2,35 +2,66 @@
[![bitflags-badge]][bitflags] [![cat-no-std-badge]][cat-no-std]
-Creates type safe bitfield type `MyFlags` with help of [`bitflags!`] macro
-and implements elementary `clear` operation as well as [`Display`] trait for it.
+Creates type safe bitfield type `MyFlags` with elementary `clear` operation as well as [`Display`] trait for it.
Subsequently, shows basic bitwise operations and formatting.
```rust,edition2018
-use bitflags::bitflags;
use std::fmt;
-bitflags! {
- struct MyFlags: u32 {
- const FLAG_A = 0b00000001;
- const FLAG_B = 0b00000010;
- const FLAG_C = 0b00000100;
- const FLAG_ABC = Self::FLAG_A.bits
- | Self::FLAG_B.bits
- | Self::FLAG_C.bits;
- }
-}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+struct MyFlags(u32);
impl MyFlags {
+ const FLAG_A: MyFlags = MyFlags(0b00000001);
+ const FLAG_B: MyFlags = MyFlags(0b00000010);
+ const FLAG_C: MyFlags = MyFlags(0b00000100);
+ const FLAG_ABC: MyFlags = MyFlags(Self::FLAG_A.0 | Self::FLAG_B.0 | Self::FLAG_C.0);
+
+ fn empty() -> Self {
+ MyFlags(0)
+ }
+
+ fn bits(&self) -> u32 {
+ self.0
+ }
+
pub fn clear(&mut self) -> &mut MyFlags {
- self.bits = 0;
+ *self = MyFlags::empty();
self
}
}
+impl std::ops::BitOr for MyFlags {
+ type Output = Self;
+ fn bitor(self, rhs: Self) -> Self {
+ MyFlags(self.0 | rhs.0)
+ }
+}
+
+impl std::ops::BitAnd for MyFlags {
+ type Output = Self;
+ fn bitand(self, rhs: Self) -> Self {
+ MyFlags(self.0 & rhs.0)
+ }
+}
+
+impl std::ops::Sub for MyFlags {
+ type Output = Self;
+ fn sub(self, rhs: Self) -> Self {
+ MyFlags(self.0 & !rhs.0)
+ }
+}
+
+impl std::ops::Not for MyFlags {
+ type Output = Self;
+ fn not(self) -> Self {
+ MyFlags(!self.0 & 0b00000111) // Only consider defined flags
+ }
+}
+
impl fmt::Display for MyFlags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{:032b}", self.bits)
+ write!(f, "{:032b}", self.bits())
}
}
@@ -45,10 +76,6 @@ fn main() {
let mut flags = MyFlags::FLAG_ABC;
assert_eq!(format!("{}", flags), "00000000000000000000000000000111");
assert_eq!(format!("{}", flags.clear()), "00000000000000000000000000000000");
- assert_eq!(format!("{:?}", MyFlags::FLAG_B), "FLAG_B");
- assert_eq!(format!("{:?}", MyFlags::FLAG_A | MyFlags::FLAG_B), "FLAG_A | FLAG_B");
+ assert_eq!(format!("{:?}", MyFlags::FLAG_B), "MyFlags(2)");
+ assert_eq!(format!("{:?}", MyFlags::FLAG_A | MyFlags::FLAG_B), "MyFlags(3)");
}
-```
-
-[`bitflags!`]: https://docs.rs/bitflags/*/bitflags/macro.bitflags.html
-[`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
diff --git a/src/database/postgres/aggregate_data.md b/src/database/postgres/aggregate_data.md
index 8d799d0d..f216c330 100644
--- a/src/database/postgres/aggregate_data.md
+++ b/src/database/postgres/aggregate_data.md
@@ -2,9 +2,9 @@
[![postgres-badge]][postgres] [![cat-database-badge]][cat-database]
-This recipe lists the nationalities of the first 7999 artists in the database of the [`Museum of Modern Art`] in descending order.
+This recipe lists the nationalities of the first 7999 artists in the database of the [Museum of Modern Art] in descending order.
-```rust,edition2018,no_run
+```rust,edition2021,no_run
use postgres::{Client, Error, NoTls};
struct Nation {
@@ -40,4 +40,4 @@ fn main() -> Result<(), Error> {
}
```
-[`Museum of Modern Art`]: https://github.com/MuseumofModernArt/collection/blob/main/Artists.csv
+[Museum of Modern Art]: https://github.com/MuseumofModernArt/collection/blob/main/Artists.csv
diff --git a/src/database/postgres/create_tables.md b/src/database/postgres/create_tables.md
index 393fdd82..568c4778 100644
--- a/src/database/postgres/create_tables.md
+++ b/src/database/postgres/create_tables.md
@@ -6,7 +6,7 @@ Use the [`postgres`] crate to create tables in a Postgres database.
[`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`.
-```rust,edition2018,no_run
+```rust,edition2021,no_run
use postgres::{Client, NoTls, Error};
fn main() -> Result<(), Error> {
diff --git a/src/database/postgres/insert_query_data.md b/src/database/postgres/insert_query_data.md
index da1e320d..6da267d9 100644
--- a/src/database/postgres/insert_query_data.md
+++ b/src/database/postgres/insert_query_data.md
@@ -5,7 +5,7 @@
The recipe inserts data into the `author` table using [`execute`] method of `Client`. Then, displays the data from the `author` table using [`query`] method of `Client`.
-```rust,edition2018,no_run
+```rust,edition2021,no_run
use postgres::{Client, NoTls, Error};
use std::collections::HashMap;
diff --git a/src/database/sqlite/initialization.md b/src/database/sqlite/initialization.md
index 1e957470..099dc045 100644
--- a/src/database/sqlite/initialization.md
+++ b/src/database/sqlite/initialization.md
@@ -7,7 +7,7 @@ Use the `rusqlite` crate to open SQLite databases. See
[`Connection::open`] will create the database if it doesn't already exist.
-```rust,edition2024,no_run
+```rust,edition2021,no_run
use rusqlite::{Connection, Result};
fn main() -> Result<()> {
diff --git a/src/database/sqlite/insert_select.md b/src/database/sqlite/insert_select.md
index 30a7d9d9..37568949 100644
--- a/src/database/sqlite/insert_select.md
+++ b/src/database/sqlite/insert_select.md
@@ -5,8 +5,7 @@
[`Connection::open`] will open the database `cats` created in the earlier recipe.
This recipe inserts data into `cat_colors` and `cats` tables using the [`execute`] method of `Connection`. First, the data is inserted into the `cat_colors` table. After a record for a color is inserted, [`last_insert_rowid`] method of `Connection` is used to get `id` of the last color inserted. This `id` is used while inserting data into the `cats` table. Then, the select query is prepared using the [`prepare`] method which gives a [`statement`] struct. Then, query is executed using [`query_map`] method of [`statement`].
-```rust,edition2024,no_run
-
+```rust,edition2021,no_run
use rusqlite::{params, Connection, Result};
use std::collections::HashMap;
diff --git a/src/database/sqlite/transactions.md b/src/database/sqlite/transactions.md
index 22f1c6c4..f087bcc6 100644
--- a/src/database/sqlite/transactions.md
+++ b/src/database/sqlite/transactions.md
@@ -12,7 +12,7 @@ a unique constraint on the color name. When an attempt to insert
a duplicate color is made, the transaction rolls back.
-```rust,edition2024,no_run
+```rust,edition2021,no_run
use rusqlite::{Connection, Result};
fn main() -> Result<()> {
diff --git a/src/datetime/duration/timezone.md b/src/datetime/duration/timezone.md
index 58387c65..c35f5972 100644
--- a/src/datetime/duration/timezone.md
+++ b/src/datetime/duration/timezone.md
@@ -5,7 +5,6 @@
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.
```rust,edition2018
-
use chrono::{DateTime, FixedOffset, Local, Utc};
fn main() {
diff --git a/src/datetime/parse/timestamp.md b/src/datetime/parse/timestamp.md
index 3dcc8820..bf50ab5d 100644
--- a/src/datetime/parse/timestamp.md
+++ b/src/datetime/parse/timestamp.md
@@ -7,7 +7,6 @@ Then it calculates what was the date after one billion seconds
since January 1, 1970 0:00:00 UTC, using [`NaiveDateTime::from_timestamp`].
```rust,edition2018
-
use chrono::{NaiveDate, NaiveDateTime};
fn main() {
diff --git a/src/development_tools/debugging/config_log/log-custom.md b/src/development_tools/debugging/config_log/log-custom.md
index 5ebac32b..e75064b0 100644
--- a/src/development_tools/debugging/config_log/log-custom.md
+++ b/src/development_tools/debugging/config_log/log-custom.md
@@ -12,20 +12,11 @@ Assigns the configuration to [`log4rs::config::Config`] and sets the default
[`log::LevelFilter`].
```rust,edition2018,no_run
-# use error_chain::error_chain;
-
+use anyhow::Result;
use log::LevelFilter;
use log4rs::append::file::FileAppender;
use log4rs::encode::pattern::PatternEncoder;
use log4rs::config::{Appender, Config, Root};
-#
-# error_chain! {
-# foreign_links {
-# Io(std::io::Error);
-# LogConfig(log4rs::config::Errors);
-# SetLogger(log::SetLoggerError);
-# }
-# }
fn main() -> Result<()> {
let logfile = FileAppender::builder()
diff --git a/src/development_tools/debugging/config_log/log-mod.md b/src/development_tools/debugging/config_log/log-mod.md
index 87bd6591..e8e655d0 100644
--- a/src/development_tools/debugging/config_log/log-mod.md
+++ b/src/development_tools/debugging/config_log/log-mod.md
@@ -6,7 +6,6 @@ Creates two modules `foo` and nested `foo::bar` with logging directives
controlled separately with [`RUST_LOG`] environmental variable.
```rust,edition2018
-
mod foo {
mod bar {
pub fn run() {
diff --git a/src/development_tools/debugging/log/log-debug.md b/src/development_tools/debugging/log/log-debug.md
index 28e0a2ec..6626b396 100644
--- a/src/development_tools/debugging/log/log-debug.md
+++ b/src/development_tools/debugging/log/log-debug.md
@@ -7,7 +7,6 @@ logging via an environment variable. The [`log::debug!`] macro works like other
[`std::fmt`] formatted strings.
```rust,edition2018
-
fn execute_query(query: &str) {
log::debug!("Executing query: {}", query);
}
diff --git a/src/development_tools/debugging/log/log-error.md b/src/development_tools/debugging/log/log-error.md
index a30c1f4e..073b8f0b 100644
--- a/src/development_tools/debugging/log/log-error.md
+++ b/src/development_tools/debugging/log/log-error.md
@@ -6,7 +6,6 @@ Proper error handling considers exceptions exceptional. Here, an error logs
to stderr with `log`'s convenience macro [`log::error!`].
```rust,edition2018
-
fn execute_query(_query: &str) -> Result<(), &'static str> {
Err("I'm afraid I can't do that")
}
diff --git a/src/development_tools/debugging/log/log-stdout.md b/src/development_tools/debugging/log/log-stdout.md
index 9203d381..c8d1415c 100644
--- a/src/development_tools/debugging/log/log-stdout.md
+++ b/src/development_tools/debugging/log/log-stdout.md
@@ -5,7 +5,6 @@
Creates a custom logger configuration using the [`Builder::target`] to set the target of the log output to [`Target::Stdout`].
```rust,edition2018
-
use env_logger::{Builder, Target};
fn main() {
diff --git a/src/development_tools/versioning/semver-command.md b/src/development_tools/versioning/semver-command.md
index c5c52749..1813ca6c 100644
--- a/src/development_tools/versioning/semver-command.md
+++ b/src/development_tools/versioning/semver-command.md
@@ -8,19 +8,9 @@ Runs `git --version` using [`Command`], then parses the version number into a
"git version x.y.z".
```rust,edition2018,no_run
-# use error_chain::error_chain;
-
+use anyhow::{Result, anyhow};
use std::process::Command;
use semver::{Version, VersionReq};
-#
-# error_chain! {
-# foreign_links {
-# Io(std::io::Error);
-# Utf8(std::string::FromUtf8Error);
-# SemVer(semver::SemVerError);
-# SemVerReq(semver::ReqParseError);
-# }
-# }
fn main() -> Result<()> {
let version_constraint = "> 1.12.0";
@@ -28,18 +18,18 @@ fn main() -> Result<()> {
let output = Command::new("git").arg("--version").output()?;
if !output.status.success() {
- error_chain::bail!("Command executed with failing error code");
+ return Err(anyhow!("Command executed with failing error code"));
}
let stdout = String::from_utf8(output.stdout)?;
let version = stdout.split(" ").last().ok_or_else(|| {
- "Invalid command output"
+ anyhow!("Invalid command output")
})?;
let parsed_version = Version::parse(version)?;
if !version_test.matches(&parsed_version) {
- error_chain::bail!("Command version lower than minimum supported version (found {}, need {})",
- parsed_version, version_constraint);
+ return Err(anyhow!("Command version lower than minimum supported version (found {}, need {})",
+ parsed_version, version_constraint));
}
Ok(())
diff --git a/src/development_tools/versioning/semver-complex.md b/src/development_tools/versioning/semver-complex.md
index 5903a374..20e9b581 100644
--- a/src/development_tools/versioning/semver-complex.md
+++ b/src/development_tools/versioning/semver-complex.md
@@ -9,26 +9,17 @@ Note that, in accordance with the Specification, build metadata is parsed but no
comparing versions. In other words, two versions may be equal even if their build strings differ.
```rust,edition2018
-use semver::{Identifier, Version, SemVerError};
+use semver::{Version, Prerelease, BuildMetadata, Error};
-fn main() -> Result<(), SemVerError> {
+fn main() -> Result<(), Error> {
let version_str = "1.0.49-125+g72ee7853";
let parsed_version = Version::parse(version_str)?;
- assert_eq!(
- parsed_version,
- Version {
- major: 1,
- minor: 0,
- patch: 49,
- pre: vec![Identifier::Numeric(125)],
- build: vec![],
- }
- );
- assert_eq!(
- parsed_version.build,
- vec![Identifier::AlphaNumeric(String::from("g72ee7853"))]
- );
+ assert_eq!(parsed_version.major, 1);
+ assert_eq!(parsed_version.minor, 0);
+ assert_eq!(parsed_version.patch, 49);
+ assert_eq!(parsed_version.pre, Prerelease::new("125")?);
+ assert_eq!(parsed_version.build, BuildMetadata::new("g72ee7853")?);
let serialized_version = parsed_version.to_string();
assert_eq!(&serialized_version, version_str);
diff --git a/src/development_tools/versioning/semver-increment.md b/src/development_tools/versioning/semver-increment.md
index de4f7f04..4c5ff314 100644
--- a/src/development_tools/versioning/semver-increment.md
+++ b/src/development_tools/versioning/semver-increment.md
@@ -11,31 +11,28 @@ incrementing the major version number resets both the minor and patch version
numbers to 0.
```rust,edition2018
-use semver::{Version, SemVerError};
+use semver::{Version, Error as SemVerError};
fn main() -> Result<(), SemVerError> {
let mut parsed_version = Version::parse("0.2.6")?;
assert_eq!(
parsed_version,
- Version {
- major: 0,
- minor: 2,
- patch: 6,
- pre: vec![],
- build: vec![],
- }
+ Version::new(0, 2, 6)
);
- parsed_version.increment_patch();
+ parsed_version.patch += 1;
assert_eq!(parsed_version.to_string(), "0.2.7");
println!("New patch release: v{}", parsed_version);
- parsed_version.increment_minor();
+ parsed_version.minor += 1;
+ parsed_version.patch = 0;
assert_eq!(parsed_version.to_string(), "0.3.0");
println!("New minor release: v{}", parsed_version);
- parsed_version.increment_major();
+ parsed_version.major += 1;
+ parsed_version.minor = 0;
+ parsed_version.patch = 0;
assert_eq!(parsed_version.to_string(), "1.0.0");
println!("New major release: v{}", parsed_version);
diff --git a/src/development_tools/versioning/semver-latest.md b/src/development_tools/versioning/semver-latest.md
index daab5eeb..f0b8d622 100644
--- a/src/development_tools/versioning/semver-latest.md
+++ b/src/development_tools/versioning/semver-latest.md
@@ -7,16 +7,8 @@ Given a list of version &strs, finds the latest [`semver::Version`].
Also demonstrates `semver` pre-release preferences.
```rust,edition2018
-# use error_chain::error_chain;
-
+use anyhow::Result;
use semver::{Version, VersionReq};
-#
-# error_chain! {
-# foreign_links {
-# SemVer(semver::SemVerError);
-# SemVerReq(semver::ReqParseError);
-# }
-# }
fn find_max_matching_version<'a, I>(version_req_str: &str, iterable: I) -> Result