Update some crates.

Patch-level changes only.

async-trait = "=0.1.76"
camino = "=1.1.9"
combine = "=4.6.7"
crossbeam-channel = "=0.5.13"
darling_core = "=0.20.10"
darling_macro = "=0.20.10"
der_derive = "=0.7.3"
displaydoc = "=0.2.5"
document-features = "=0.2.10"
downcast-rs = "=1.2.1"
enumn = "=0.1.12"
strsim = "=0.11.1"

Bug: http://b/339424309
Test: treehugger
Change-Id: I508b7aaa8a949ba3e16bb0746264b4431f60a11d
diff --git a/crates/async-trait/.cargo-checksum.json b/crates/async-trait/.cargo-checksum.json
index 94d79ae..da14fa8 100644
--- a/crates/async-trait/.cargo-checksum.json
+++ b/crates/async-trait/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"d2e4c5dc8ec7e68d2efdedf30334f48cd31a6e4c7b7acd4c6fbb8da28588ae4c","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5b94948e52c1410eae55fb8e4084e8837d0f8eb0c000698dc13fac591c70dc1b","build.rs":"ad9da6073db9c5c1e1128aed696590ab10f1ad6a46dee4499d20c7ed60127093","src/args.rs":"6eed5497db91752b3aae597943c39e769f60406b37055304e69e4699f1f87b15","src/bound.rs":"ea6a8d0c1a33521163e5546463f68f6dbda0d35a59e75597be6bf04e0b7b23ad","src/expand.rs":"2d0b0f122c3ec393ce67db6fa177626d8fca0c4f5558b42f4fee219f31b97f9e","src/lib.rs":"3b381b9c34d6d7134e499bbb491c4fb64f0a6b871367fe72c3046a7d40bfc848","src/lifetime.rs":"e5ccfba2fa7ecb226cba247286c661f20a84e9a0ad2d789bdfee166cd5250160","src/parse.rs":"cd9032fe2c6dcf41050b3a59b9fb98eb9700a29bbe2fa011ee2854014c1666b7","src/receiver.rs":"356b4ac3e45607d041927799b12c1390c28e6333079343a38799d31ff5dfbe33","src/verbatim.rs":"45d0b691fab21f20d3414733f00d82845442d23b6f2547f8d6880a709d0d3b2a","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/executor/mod.rs":"3cf48614288715f625514a73ae642f649c2635a402a3ad90278bbee116a7234c","tests/test.rs":"203646366ce6959bf7e727372eaaf16c8f6e7b7c6c7cc5e12c259244d7254550","tests/ui/arg-implementation-detail.rs":"7199aba887dd0a8a14c86ec16542a73a70244930f8202940f43e40a62f72d200","tests/ui/arg-implementation-detail.stderr":"c3ff1a2a9a9ca4368cb8719e2a035a6d2d45b367212bec2b1fe2712fcfbbbe5d","tests/ui/bare-trait-object.rs":"4546e8bd6682de11920fa4c768295fed61954484ef0550dfadbc5677b77f29a5","tests/ui/bare-trait-object.stderr":"0e1d5902f1ed99a60c6126416806b7c40f4ac9bdd78f26d8e6d866738cc332df","tests/ui/consider-restricting.rs":"bff794222d9324241155568d541e7beac0238b66ce14039b242d4392f4e531b6","tests/ui/consider-restricting.stderr":"a8f7f45aa196febb5d7550597f47b72ba0176d05599260e56a438148b42de840","tests/ui/delimiter-span.rs":"f4fd804223ce3be0d4eecdfd222afdd835c5393e2473ff4932116163943c0bc9","tests/ui/delimiter-span.stderr":"7b5bbe4be3be533d31d1302649b317465bc28cc7f042b98ec78e8b9a82828155","tests/ui/lifetime-defined-here.rs":"3139a3d92cf787c43afd93da2d967ee80d114ee3a0b9c924da9601b5c6614ef5","tests/ui/lifetime-defined-here.stderr":"0d4236821e0f43e5ae38a99319a64020576e78a49a71d8c94eb8a486d384308c","tests/ui/lifetime-span.rs":"bbcaa92c2bc08e18cf0c7e9ca1f0bd8080772ebde8b067d819eb2fd662e47b3b","tests/ui/lifetime-span.stderr":"db67c5078ab66725227b8f4c612ff97b39cb45d5d6b7a4191766a34a6c711547","tests/ui/missing-async-in-impl.rs":"5a5538d08d11c145211a92af0d8973eee8b21f33b90adda85430805bd3dbbc83","tests/ui/missing-async-in-impl.stderr":"2916bc8a51e25f4dd18eaf433b916d533943eac2c1afbee64e9a89e7b928040d","tests/ui/missing-async-in-trait.rs":"dc67241593f270233ba885df92e59164126416e68d49d8d62edc251666b5db6e","tests/ui/missing-async-in-trait.stderr":"67e66e7b19358830deff3ba01f5d701a9ae05c4e6fa9c081c49c1c75efbb7ade","tests/ui/missing-body.rs":"d06c0da8c6044e7c790b924136f167e2edc0d0d3fa01f23521f3f08ca605929b","tests/ui/missing-body.stderr":"e5ee994398bf8294324d61df02467a4229f68f4113bf5acc004851c03d66ec6a","tests/ui/must-use.rs":"75090c7df984df0996464337f60371d198bd0caf3f9f44b10d1e131f15fd4fca","tests/ui/must-use.stderr":"e9989ec6ae4e87f117cd9ffd73e774b5477eb28c9df5b508dbd3654b783e5bf4","tests/ui/no-attribute-macro.rs":"99aaad298a8ef366029e53b6d320b14f18e04057a117ff58a0aebad65f01e22f","tests/ui/no-attribute-macro.stderr":"48dc13503b181f36271f5632ca835ea9e8d977d9dfcbe786f64a6633f3bb9b6b","tests/ui/self-span.rs":"67ddde05907d7014bfb3f2c63d427b1d72d6c4369a9108a4335dac6bee5832b2","tests/ui/self-span.stderr":"016ef4f29156250f073f4f6cd3096d2889325709bd693938e0d368077b752551","tests/ui/send-not-implemented.rs":"affbbe8bc9c3501d3db3a024e06daa9d076f1d142dba290c7aa1ea119daebd19","tests/ui/send-not-implemented.stderr":"b2cd38ce3cadda8f9e641b98e37db51afba47eab21d29cbfc47a90c8a444aa27","tests/ui/unreachable.rs":"be0aa7cc129fe42a1fbd85e36b3f08c6a2bd16c90ed2e33fc4c50e40ce085bcd","tests/ui/unreachable.stderr":"73beb71cb74076f2cb45485271de31658cf59f4143e62daa34b9f2a8980ddfcd","tests/ui/unsupported-self.rs":"f7855bc39dab1fd2f533fb2e873a27c3757dcb9fb57001e4b19f58d3dda36d01","tests/ui/unsupported-self.stderr":"64fc5d45cb51330f0a1e85e69a28b69ddda12a109aa6a8ba3eaee1ac58d93b5f"},"package":"a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"}
\ No newline at end of file
+{"files":{"Cargo.toml":"50a9b38138b59e83657f65ec43fd3b81a80f265cb6b090bf15db297a02ee7bc9","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"caa22edc176059d74c0ad5b7266fd8e8d4164f67b597164c9aa41244a9f08df3","build.rs":"9f9975151b7e9cae692471ff00059392207d8bd66ed51a4d1de61f85693e8e3c","src/args.rs":"6eed5497db91752b3aae597943c39e769f60406b37055304e69e4699f1f87b15","src/bound.rs":"ea6a8d0c1a33521163e5546463f68f6dbda0d35a59e75597be6bf04e0b7b23ad","src/expand.rs":"2d0b0f122c3ec393ce67db6fa177626d8fca0c4f5558b42f4fee219f31b97f9e","src/lib.rs":"ccb898d8c251de8040b04b421c4f44d9b3632908cf8ae73fedee03a37db54b45","src/lifetime.rs":"e5ccfba2fa7ecb226cba247286c661f20a84e9a0ad2d789bdfee166cd5250160","src/parse.rs":"cd9032fe2c6dcf41050b3a59b9fb98eb9700a29bbe2fa011ee2854014c1666b7","src/receiver.rs":"356b4ac3e45607d041927799b12c1390c28e6333079343a38799d31ff5dfbe33","src/verbatim.rs":"45d0b691fab21f20d3414733f00d82845442d23b6f2547f8d6880a709d0d3b2a","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/executor/mod.rs":"3cf48614288715f625514a73ae642f649c2635a402a3ad90278bbee116a7234c","tests/test.rs":"2eba31217eeff7f67e786f4c279d1168385204c07c4b28b607a29ce9ede9d86a","tests/ui/arg-implementation-detail.rs":"7199aba887dd0a8a14c86ec16542a73a70244930f8202940f43e40a62f72d200","tests/ui/arg-implementation-detail.stderr":"c3ff1a2a9a9ca4368cb8719e2a035a6d2d45b367212bec2b1fe2712fcfbbbe5d","tests/ui/bare-trait-object.rs":"4546e8bd6682de11920fa4c768295fed61954484ef0550dfadbc5677b77f29a5","tests/ui/bare-trait-object.stderr":"0e1d5902f1ed99a60c6126416806b7c40f4ac9bdd78f26d8e6d866738cc332df","tests/ui/consider-restricting.rs":"bff794222d9324241155568d541e7beac0238b66ce14039b242d4392f4e531b6","tests/ui/consider-restricting.stderr":"a8f7f45aa196febb5d7550597f47b72ba0176d05599260e56a438148b42de840","tests/ui/delimiter-span.rs":"f4fd804223ce3be0d4eecdfd222afdd835c5393e2473ff4932116163943c0bc9","tests/ui/delimiter-span.stderr":"7b5bbe4be3be533d31d1302649b317465bc28cc7f042b98ec78e8b9a82828155","tests/ui/lifetime-defined-here.rs":"3139a3d92cf787c43afd93da2d967ee80d114ee3a0b9c924da9601b5c6614ef5","tests/ui/lifetime-defined-here.stderr":"0d4236821e0f43e5ae38a99319a64020576e78a49a71d8c94eb8a486d384308c","tests/ui/lifetime-span.rs":"bbcaa92c2bc08e18cf0c7e9ca1f0bd8080772ebde8b067d819eb2fd662e47b3b","tests/ui/lifetime-span.stderr":"db67c5078ab66725227b8f4c612ff97b39cb45d5d6b7a4191766a34a6c711547","tests/ui/missing-async-in-impl.rs":"5a5538d08d11c145211a92af0d8973eee8b21f33b90adda85430805bd3dbbc83","tests/ui/missing-async-in-impl.stderr":"2916bc8a51e25f4dd18eaf433b916d533943eac2c1afbee64e9a89e7b928040d","tests/ui/missing-async-in-trait.rs":"dc67241593f270233ba885df92e59164126416e68d49d8d62edc251666b5db6e","tests/ui/missing-async-in-trait.stderr":"67e66e7b19358830deff3ba01f5d701a9ae05c4e6fa9c081c49c1c75efbb7ade","tests/ui/missing-body.rs":"d06c0da8c6044e7c790b924136f167e2edc0d0d3fa01f23521f3f08ca605929b","tests/ui/missing-body.stderr":"e5ee994398bf8294324d61df02467a4229f68f4113bf5acc004851c03d66ec6a","tests/ui/must-use.rs":"75090c7df984df0996464337f60371d198bd0caf3f9f44b10d1e131f15fd4fca","tests/ui/must-use.stderr":"3f4c30eb0234da366b6dc360b0ff85ef5f621003055fb64a0e1fc18d4a0e244f","tests/ui/no-attribute-macro.rs":"99aaad298a8ef366029e53b6d320b14f18e04057a117ff58a0aebad65f01e22f","tests/ui/no-attribute-macro.stderr":"a6ae9bb5914777c780021e223877bc21f38e7716d351ab98aef668dc349bd3ab","tests/ui/self-span.rs":"67ddde05907d7014bfb3f2c63d427b1d72d6c4369a9108a4335dac6bee5832b2","tests/ui/self-span.stderr":"016ef4f29156250f073f4f6cd3096d2889325709bd693938e0d368077b752551","tests/ui/send-not-implemented.rs":"affbbe8bc9c3501d3db3a024e06daa9d076f1d142dba290c7aa1ea119daebd19","tests/ui/send-not-implemented.stderr":"b2cd38ce3cadda8f9e641b98e37db51afba47eab21d29cbfc47a90c8a444aa27","tests/ui/unreachable.rs":"be0aa7cc129fe42a1fbd85e36b3f08c6a2bd16c90ed2e33fc4c50e40ce085bcd","tests/ui/unreachable.stderr":"73beb71cb74076f2cb45485271de31658cf59f4143e62daa34b9f2a8980ddfcd","tests/ui/unsupported-self.rs":"f7855bc39dab1fd2f533fb2e873a27c3757dcb9fb57001e4b19f58d3dda36d01","tests/ui/unsupported-self.stderr":"64fc5d45cb51330f0a1e85e69a28b69ddda12a109aa6a8ba3eaee1ac58d93b5f"},"package":"531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514"}
\ No newline at end of file
diff --git a/crates/async-trait/Android.bp b/crates/async-trait/Android.bp
index d963e0b..625feec 100644
--- a/crates/async-trait/Android.bp
+++ b/crates/async-trait/Android.bp
@@ -17,7 +17,7 @@
     name: "libasync_trait",
     crate_name: "async_trait",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.1.74",
+    cargo_pkg_version: "0.1.76",
     crate_root: "src/lib.rs",
     edition: "2021",
     rustlibs: [
diff --git a/crates/async-trait/Cargo.toml b/crates/async-trait/Cargo.toml
index 0bb7764..7f3101d 100644
--- a/crates/async-trait/Cargo.toml
+++ b/crates/async-trait/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2021"
 rust-version = "1.56"
 name = "async-trait"
-version = "0.1.74"
+version = "0.1.76"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 description = "Type erasure for async trait methods"
 documentation = "https://docs.rs/async-trait"
@@ -47,16 +47,16 @@
 ]
 
 [dev-dependencies.futures]
-version = "0.3.28"
+version = "0.3.30"
 
 [dev-dependencies.rustversion]
 version = "1.0.13"
 
 [dev-dependencies.tracing]
-version = "0.1.37"
+version = "0.1.40"
 
 [dev-dependencies.tracing-attributes]
-version = "0.1.26"
+version = "0.1.27"
 
 [dev-dependencies.trybuild]
 version = "1.0.81"
diff --git a/crates/async-trait/METADATA b/crates/async-trait/METADATA
index 704eda5..7aa80ed 100644
--- a/crates/async-trait/METADATA
+++ b/crates/async-trait/METADATA
@@ -1,17 +1,17 @@
 name: "async-trait"
 description: "Type erasure for async trait methods"
 third_party {
-  version: "0.1.74"
+  version: "0.1.76"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2023
-    month: 11
-    day: 24
+    year: 2024
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/async-trait"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/async-trait/async-trait-0.1.74.crate"
-    version: "0.1.74"
+    value: "https://static.crates.io/crates/async-trait/async-trait-0.1.76.crate"
+    version: "0.1.76"
   }
 }
diff --git a/crates/async-trait/README.md b/crates/async-trait/README.md
index 39e368b..97dbac9 100644
--- a/crates/async-trait/README.md
+++ b/crates/async-trait/README.md
@@ -6,29 +6,43 @@
 [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-async--trait-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/async-trait)
 [<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/async-trait/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/async-trait/actions?query=branch%3Amaster)
 
-The initial round of stabilizations for the async/await language feature in Rust
-1.39 did not include support for async fn in traits. Trying to include an async
-fn in a trait produces the following error:
+The stabilization of async functions in traits in Rust 1.75 did not include
+support for using traits containing async functions as `dyn Trait`. Trying to
+use dyn with an async trait produces the following error:
 
 ```rust
-trait MyTrait {
-    async fn f() {}
+pub trait Trait {
+    async fn f(&self);
+}
+
+pub fn make() -> Box<dyn Trait> {
+    unimplemented!()
 }
 ```
 
 ```console
-error[E0706]: trait fns cannot be declared `async`
- --> src/main.rs:4:5
+error[E0038]: the trait `Trait` cannot be made into an object
+ --> src/main.rs:5:22
   |
-4 |     async fn f() {}
-  |     ^^^^^^^^^^^^^^^
+5 | pub fn make() -> Box<dyn Trait> {
+  |                      ^^^^^^^^^ `Trait` cannot be made into an object
+  |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+ --> src/main.rs:2:14
+  |
+1 | pub trait Trait {
+  |           ----- this trait cannot be made into an object...
+2 |     async fn f(&self);
+  |              ^ ...because method `f` is `async`
+  = help: consider moving `f` to another trait
 ```
 
-This crate provides an attribute macro to make async fn in traits work.
+This crate provides an attribute macro to make async fn in traits work with dyn
+traits.
 
 Please refer to [*why async fn in traits are hard*][hard] for a deeper analysis
-of how this implementation differs from what the compiler and language hope to
-deliver in the future.
+of how this implementation differs from what the compiler and language deliver
+natively.
 
 [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
 
@@ -40,7 +54,9 @@
 using async fn in a trait.
 
 The only thing to notice here is that we write an `#[async_trait]` macro on top
-of traits and trait impls that contain async fn, and then they work.
+of traits and trait impls that contain async fn, and then they work. We get to
+have `Vec<Box<dyn Advertisement + Sync>>` or `&[&dyn Advertisement]`, for
+example.
 
 ```rust
 use async_trait::async_trait;
@@ -95,15 +111,14 @@
 - &#128077;&ensp;Associated types;
 - &#128077;&ensp;Having async and non-async functions in the same trait;
 - &#128077;&ensp;Default implementations provided by the trait;
-- &#128077;&ensp;Elided lifetimes;
-- &#128077;&ensp;Dyn-capable traits.
+- &#128077;&ensp;Elided lifetimes.
 
 <br>
 
 ## Explanation
 
 Async fns get transformed into methods that return `Pin<Box<dyn Future + Send +
-'async_trait>>` and delegate to a private async freestanding function.
+'async_trait>>` and delegate to an async block.
 
 For example the `impl Advertisement for AutoplayingVideo` above would be
 expanded as:
@@ -116,11 +131,9 @@
     where
         Self: Sync + 'async_trait,
     {
-        async fn run(_self: &AutoplayingVideo) {
+        Box::pin(async move {
             /* the original method body */
-        }
-
-        Box::pin(run(self))
+        })
     }
 }
 ```
diff --git a/crates/async-trait/build.rs b/crates/async-trait/build.rs
index f25fb0a..db7c5f0 100644
--- a/crates/async-trait/build.rs
+++ b/crates/async-trait/build.rs
@@ -17,10 +17,6 @@
     if compiler < 47 {
         println!("cargo:rustc-cfg=self_span_hack");
     }
-
-    if compiler >= 75 && env::var_os("DOCS_RS").is_none() {
-        println!("cargo:rustc-cfg=native_async_fn_in_trait");
-    }
 }
 
 fn rustc_minor_version() -> Option<u32> {
diff --git a/crates/async-trait/src/lib.rs b/crates/async-trait/src/lib.rs
index 435d508..708b870 100644
--- a/crates/async-trait/src/lib.rs
+++ b/crates/async-trait/src/lib.rs
@@ -6,32 +6,45 @@
 //!
 //! <br>
 //!
-//! <h5>Type erasure for async trait methods</h5>
+//! <h4>Type erasure for async trait methods</h4>
 //!
-//! The initial round of stabilizations for the async/await language feature in
-//! Rust 1.39 did not include support for async fn in traits. Trying to include
-//! an async fn in a trait produces the following error:
+//! The stabilization of async functions in traits in Rust 1.75 did not include
+//! support for using traits containing async functions as `dyn Trait`. Trying
+//! to use dyn with an async trait produces the following error:
 //!
-#![cfg_attr(not(native_async_fn_in_trait), doc = "```compile_fail")]
-#![cfg_attr(native_async_fn_in_trait, doc = "```")]
-//! trait MyTrait {
-//!     async fn f() {}
+//! ```compile_fail
+//! pub trait Trait {
+//!     async fn f(&self);
 //! }
-#![doc = "```"]
 //!
-//! ```text
-//! error[E0706]: trait fns cannot be declared `async`
-//!  --> src/main.rs:4:5
-//!   |
-//! 4 |     async fn f() {}
-//!   |     ^^^^^^^^^^^^^^^
+//! pub fn make() -> Box<dyn Trait> {
+//!     unimplemented!()
+//! }
 //! ```
 //!
-//! This crate provides an attribute macro to make async fn in traits work.
+//! ```text
+//! error[E0038]: the trait `Trait` cannot be made into an object
+//!  --> src/main.rs:5:22
+//!   |
+//! 5 | pub fn make() -> Box<dyn Trait> {
+//!   |                      ^^^^^^^^^ `Trait` cannot be made into an object
+//!   |
+//! note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+//!  --> src/main.rs:2:14
+//!   |
+//! 1 | pub trait Trait {
+//!   |           ----- this trait cannot be made into an object...
+//! 2 |     async fn f(&self);
+//!   |              ^ ...because method `f` is `async`
+//!   = help: consider moving `f` to another trait
+//! ```
+//!
+//! This crate provides an attribute macro to make async fn in traits work with
+//! dyn traits.
 //!
 //! Please refer to [*why async fn in traits are hard*][hard] for a deeper
 //! analysis of how this implementation differs from what the compiler and
-//! language hope to deliver in the future.
+//! language deliver natively.
 //!
 //! [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
 //!
@@ -43,7 +56,9 @@
 //! using async fn in a trait.
 //!
 //! The only thing to notice here is that we write an `#[async_trait]` macro on
-//! top of traits and trait impls that contain async fn, and then they work.
+//! top of traits and trait impls that contain async fn, and then they work. We
+//! get to have `Vec<Box<dyn Advertisement + Sync>>` or `&[&dyn Advertisement]`,
+//! for example.
 //!
 //! ```
 //! use async_trait::async_trait;
@@ -111,15 +126,14 @@
 //! > &#9745;&emsp;Associated types;<br>
 //! > &#9745;&emsp;Having async and non-async functions in the same trait;<br>
 //! > &#9745;&emsp;Default implementations provided by the trait;<br>
-//! > &#9745;&emsp;Elided lifetimes;<br>
-//! > &#9745;&emsp;Dyn-capable traits.<br>
+//! > &#9745;&emsp;Elided lifetimes.<br>
 //!
 //! <br>
 //!
 //! # Explanation
 //!
 //! Async fns get transformed into methods that return `Pin<Box<dyn Future +
-//! Send + 'async_trait>>` and delegate to a private async freestanding function.
+//! Send + 'async_trait>>` and delegate to an async block.
 //!
 //! For example the `impl Advertisement for AutoplayingVideo` above would be
 //! expanded as:
@@ -133,11 +147,9 @@
 //!     where
 //!         Self: Sync + 'async_trait,
 //!     {
-//!         async fn run(_self: &AutoplayingVideo) {
+//!         Box::pin(async move {
 //!             /* the original method body */
-//!         }
-//!
-//!         Box::pin(run(self))
+//!         })
 //!     }
 //! }
 //! # };
@@ -304,7 +316,7 @@
 //! let object = &value as &dyn ObjectSafe;
 //! ```
 
-#![doc(html_root_url = "https://docs.rs/async-trait/0.1.74")]
+#![doc(html_root_url = "https://docs.rs/async-trait/0.1.76")]
 #![allow(
     clippy::default_trait_access,
     clippy::doc_markdown,
diff --git a/crates/async-trait/tests/test.rs b/crates/async-trait/tests/test.rs
index 650959c..b78c9ff 100644
--- a/crates/async-trait/tests/test.rs
+++ b/crates/async-trait/tests/test.rs
@@ -620,7 +620,6 @@
     }
 
     #[test]
-    #[cfg_attr(miri, ignore)] // https://github.com/matklad/once_cell/pull/185
     fn tracing() {
         // Create the future outside of the subscriber, as no call to tracing
         // should be made until the future is polled.
diff --git a/crates/async-trait/tests/ui/must-use.stderr b/crates/async-trait/tests/ui/must-use.stderr
index 9b71d10..79e0a7a 100644
--- a/crates/async-trait/tests/ui/must-use.stderr
+++ b/crates/async-trait/tests/ui/must-use.stderr
@@ -1,14 +1,22 @@
+error: unused pinned boxed `Future` trait object that must be used
+  --> tests/ui/must-use.rs:18:5
+   |
+18 |     Thing.f();
+   |     ^^^^^^^^^
+   |
+   = note: futures do nothing unless you `.await` or poll them
+note: the lint level is defined here
+  --> tests/ui/must-use.rs:1:9
+   |
+1  | #![deny(unused_must_use)]
+   |         ^^^^^^^^^^^^^^^
+
 error: unused return value of `Interface::f` that must be used
   --> tests/ui/must-use.rs:18:5
    |
 18 |     Thing.f();
    |     ^^^^^^^^^
    |
-note: the lint level is defined here
-  --> tests/ui/must-use.rs:1:9
-   |
-1  | #![deny(unused_must_use)]
-   |         ^^^^^^^^^^^^^^^
 help: use `let _ = ...` to ignore the resulting value
    |
 18 |     let _ = Thing.f();
diff --git a/crates/async-trait/tests/ui/no-attribute-macro.stderr b/crates/async-trait/tests/ui/no-attribute-macro.stderr
index 35d8d5a..cb15522 100644
--- a/crates/async-trait/tests/ui/no-attribute-macro.stderr
+++ b/crates/async-trait/tests/ui/no-attribute-macro.stderr
@@ -12,3 +12,5 @@
 2  |     async fn method(&self);
    |              ^^^^^^ ...because method `method` is `async`
    = help: consider moving `method` to another trait
+   = help: only type `Struct` is seen to implement the trait in this crate, consider using it directly instead
+   = note: `Trait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type
diff --git a/crates/camino/.cargo-checksum.json b/crates/camino/.cargo-checksum.json
index ded873d..cee1b42 100644
--- a/crates/camino/.cargo-checksum.json
+++ b/crates/camino/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"979191a4e606b72622b6049da05e14190e5d36379f517a167ffc79d8d0846ede","Cargo.toml":"c1a6ba7fa2cef4385fdff5bfddcf8702defce109ed2b73d33e95f1b0d0661cbd","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"4ca8f827ccdad7459c2b7524587a25523a857f3ff4bbb11d569e666118806f49","build.rs":"a57fc77ab3880126e9d83088eff56dea7a7cfee9c18a920c244a724ad89b164d","clippy.toml":"818cba7332cc56b019d59e09805a3498f523da788f51454742905f1987c0b563","release.toml":"287514631fde7a1d29a8e8027bc37c585c7e30c173c8254f551b042e38f4bb81","rustfmt.toml":"bf9776adb152b3fdc0d75c0929ede148c3e28c58f909a7d052865bc332e8958f","src/lib.rs":"19a145d12c9935ffb80cc084fd580806c622a3068b53d2792532c440460be732","src/proptest_impls.rs":"4f36f5804bd3cbbf65177db4b20d808ed56405388b552bad375aab308a535236","src/serde_impls.rs":"981f529290f18445a9814c46ae57c9e5ab390a361fb7eb1dd4f4ed7a3f94fc03","src/tests.rs":"2cb79e032972ca5eccd9ad95bed1e0314b15e5e7eaa84ecb53acc37636598afe","tests/integration_tests.rs":"56aa396a173d0c255369159b57e4a7db294e607aa6cfb65efebd95d79cc51a04"},"package":"c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"0fb29afffbea75302d61bcf9cd0ab4d9ab3906741815bf0af5e2540780fa4a46","Cargo.lock.rust134":"a8e33cd142a8f15eefc414cc0d8dae0f9ed63bc9c36a142205e572b148f7bc43","Cargo.toml":"36d66ff21614abccf9753c9729ab99a3eda9681169a1d94d4e4b594299849ea3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"701f0714f4a103cd2f4387709563efad803a246e3a06eec85bf8be416ac3916a","build.rs":"cbdfaa56ff8e211896e75fc7867e3230aa8aa09fdda901111db957c65306f1d8","clippy.toml":"818cba7332cc56b019d59e09805a3498f523da788f51454742905f1987c0b563","release.toml":"287514631fde7a1d29a8e8027bc37c585c7e30c173c8254f551b042e38f4bb81","rustfmt.toml":"bf9776adb152b3fdc0d75c0929ede148c3e28c58f909a7d052865bc332e8958f","src/lib.rs":"07875714e5f7a59c1d66c3c19ab93558bbd50565ca854df554fcaa5e0a3ac533","src/proptest_impls.rs":"a731e50f156421647a5d780d261f387857cf1b8d82004539b74b4071e58bd82e","src/serde_impls.rs":"981f529290f18445a9814c46ae57c9e5ab390a361fb7eb1dd4f4ed7a3f94fc03","src/tests.rs":"2cb79e032972ca5eccd9ad95bed1e0314b15e5e7eaa84ecb53acc37636598afe","tests/integration_tests.rs":"56aa396a173d0c255369159b57e4a7db294e607aa6cfb65efebd95d79cc51a04"},"package":"8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"}
\ No newline at end of file
diff --git a/crates/camino/Android.bp b/crates/camino/Android.bp
index 7301b3f..a8c76f8 100644
--- a/crates/camino/Android.bp
+++ b/crates/camino/Android.bp
@@ -18,7 +18,7 @@
     host_supported: true,
     crate_name: "camino",
     cargo_env_compat: true,
-    cargo_pkg_version: "1.1.6",
+    cargo_pkg_version: "1.1.9",
     crate_root: "src/lib.rs",
     edition: "2018",
     apex_available: [
diff --git a/crates/camino/CHANGELOG.md b/crates/camino/CHANGELOG.md
index 7558c70..455e8d2 100644
--- a/crates/camino/CHANGELOG.md
+++ b/crates/camino/CHANGELOG.md
@@ -3,6 +3,25 @@
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [1.1.9] - 2024-08-17
+
+### Added
+
+- Top-level function `absolute_utf8` wraps `std::path::absolute`, converting paths to UTF-8.
+  Requires Rust 1.79 and above.
+
+## [1.1.8] - 2024-08-15
+
+### Changed
+
+- Use `OsStr::as_encoded_bytes` on Rust 1.74 and above, making conversions from `OsStr` to `str` virtually free ([#93](https://github.com/camino-rs/camino/pull/93)). Thanks [@h-a-n-a](https://github.com/h-a-n-a) for your first contribution!
+
+## [1.1.7] - 2024-05-14
+
+### Fixed
+
+- Resolve `unexpected_cfg` warnings.
+
 ## [1.1.6] - 2023-07-11
 
 ### Added
@@ -63,7 +82,7 @@
 - New methods `canonicalize_utf8`, `read_link_utf8` and `read_dir_utf8` return `Utf8PathBuf`s, erroring out if a resulting path is not valid UTF-8.
 - New feature `proptest1` introduces proptest `Arbitrary` impls for `Utf8PathBuf` and
   `Box<Utf8Path>` ([#18], thanks [mcronce](https://github.com/mcronce) for your first contribution!)
-  
+
 [#18]: https://github.com/camino-rs/camino/pull/18
 
 ## [1.0.7] - 2022-01-16
@@ -130,6 +149,9 @@
 
 Initial release.
 
+[1.1.9]: https://github.com/camino-rs/camino/releases/tag/camino-1.1.9
+[1.1.8]: https://github.com/camino-rs/camino/releases/tag/camino-1.1.8
+[1.1.7]: https://github.com/camino-rs/camino/releases/tag/camino-1.1.7
 [1.1.6]: https://github.com/camino-rs/camino/releases/tag/camino-1.1.6
 [1.1.5]: https://github.com/camino-rs/camino/releases/tag/camino-1.1.5
 [1.1.4]: https://github.com/camino-rs/camino/releases/tag/camino-1.1.4
diff --git a/crates/camino/Cargo.lock.rust134 b/crates/camino/Cargo.lock.rust134
new file mode 100644
index 0000000..0562bef
--- /dev/null
+++ b/crates/camino/Cargo.lock.rust134
@@ -0,0 +1,553 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "anyhow"
+version = "1.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.152 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "bit-set"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bit-vec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "byteorder"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "camino"
+version = "1.1.6"
+dependencies = [
+ "bincode 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proptest 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_bytes 0.11.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "camino-examples"
+version = "0.1.0"
+dependencies = [
+ "anyhow 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
+ "camino 1.1.6",
+ "clap 3.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "clap"
+version = "3.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap_derive 3.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap_lex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "indexmap 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "once_cell 1.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termcolor 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "textwrap 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "clap_derive"
+version = "3.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "heck 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro-error 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.109 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "os_str_bytes 6.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "fastrand"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "instant 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "getrandom"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.152 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.152 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hashbrown 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.2.152"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "num-traits"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "os_str_bytes"
+version = "6.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro-error-attr 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.109 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-ident 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proptest"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bit-set 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quick-error 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_chacha 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_xorshift 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rusty-fork 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "quick-error"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.152 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_chacha 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ppv-lite86 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "getrandom 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ucd-util 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rusty-fork"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.109 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "itoa 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ryu 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-ident 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fastrand 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.152 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-util 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "ucd-util"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.152 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum anyhow 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
+"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+"checksum autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+"checksum bincode 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+"checksum bit-set 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
+"checksum bit-vec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
+"checksum bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
+"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+"checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+"checksum clap 3.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
+"checksum clap_derive 3.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008"
+"checksum clap_lex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+"checksum fastrand 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+"checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+"checksum getrandom 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4"
+"checksum hashbrown 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+"checksum heck 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+"checksum hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+"checksum indexmap 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+"checksum instant 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+"checksum itoa 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
+"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+"checksum libc 0.2.152 (registry+https://github.com/rust-lang/crates.io-index)" = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
+"checksum num-traits 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+"checksum once_cell 1.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+"checksum os_str_bytes 6.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
+"checksum ppv-lite86 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+"checksum proc-macro-error 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+"checksum proc-macro-error-attr 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+"checksum proc-macro2 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b"
+"checksum proptest 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5"
+"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+"checksum quick-error 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
+"checksum quote 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+"checksum rand 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a76330fb486679b4ace3670f117bbc9e16204005c4bde9c4bd372f45bed34f12"
+"checksum rand_chacha 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+"checksum rand_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
+"checksum rand_xorshift 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
+"checksum redox_syscall 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48"
+"checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+"checksum rusty-fork 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
+"checksum ryu 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+"checksum serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a"
+"checksum serde_bytes 0.11.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f3c5113243e4a3a1c96587342d067f3e6b0f50790b6cf40d2868eb647a3eef0e"
+"checksum serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "11e410fde43e157d789fc290d26bc940778ad0fdd47836426fbac36573710dbb"
+"checksum serde_json 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
+"checksum strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+"checksum syn 1.0.109 (registry+https://github.com/rust-lang/crates.io-index)" = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+"checksum tempfile 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
+"checksum termcolor 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+"checksum textwrap 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
+"checksum ucd-util 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "abd2fc5d32b590614af8b0a20d837f32eca055edd0bbead59a9cfe80858be003"
+"checksum unicode-ident 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+"checksum version_check 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+"checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
+"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-util 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/crates/camino/Cargo.toml b/crates/camino/Cargo.toml
index b0bfabd..66b9a87 100644
--- a/crates/camino/Cargo.toml
+++ b/crates/camino/Cargo.toml
@@ -11,18 +11,24 @@
 
 [package]
 edition = "2018"
+rust-version = "1.34.0"
 name = "camino"
-version = "1.1.6"
+version = "1.1.9"
 authors = [
     "Without Boats <saoirse@without.boats>",
     "Ashley Williams <ashley666ashley@gmail.com>",
     "Steve Klabnik <steve@steveklabnik.com>",
     "Rain <rain@sunshowers.io>",
 ]
+build = "build.rs"
 exclude = [
     ".cargo/**/*",
     ".github/**/*",
 ]
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
 description = "UTF-8 paths"
 documentation = "https://docs.rs/camino"
 readme = "README.md"
@@ -44,6 +50,14 @@
 all-features = true
 rustdoc-args = ["--cfg=doc_cfg"]
 
+[lib]
+name = "camino"
+path = "src/lib.rs"
+
+[[test]]
+name = "integration_tests"
+path = "tests/integration_tests.rs"
+
 [dependencies.proptest]
 version = "1.0.0"
 optional = true
diff --git a/crates/camino/METADATA b/crates/camino/METADATA
index c29323e..12a2800 100644
--- a/crates/camino/METADATA
+++ b/crates/camino/METADATA
@@ -1,17 +1,17 @@
 name: "camino"
 description: "UTF-8 paths"
 third_party {
-  version: "1.1.6"
+  version: "1.1.9"
   license_type: NOTICE
   last_upgrade_date {
     year: 2024
-    month: 3
-    day: 21
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/camino"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/camino/camino-1.1.6.crate"
-    version: "1.1.6"
+    value: "https://static.crates.io/crates/camino/camino-1.1.9.crate"
+    version: "1.1.9"
   }
 }
diff --git a/crates/camino/README.md b/crates/camino/README.md
index 82c03e4..78cb788 100644
--- a/crates/camino/README.md
+++ b/crates/camino/README.md
@@ -13,31 +13,32 @@
 ## What is camino?
 
 `camino`'s [`Utf8PathBuf`] and [`Utf8Path`] types are like the standard library's [`PathBuf`] and [`Path`] types, except
-they  are guaranteed to only contain UTF-8 encoded data. Therefore, they expose the ability to get their
+they are guaranteed to only contain UTF-8 encoded data. Therefore, they expose the ability to get their
 contents as strings, they implement `Display`, etc.
 
 The `std::path` types are not guaranteed to be valid UTF-8. This is the right decision for the standard library,
 since it must be as general as possible. However, on all platforms, non-Unicode paths are vanishingly uncommon for a
 number of reasons:
-* Unicode won. There are still some legacy codebases that store paths in encodings like [Shift JIS], but most
+
+- Unicode won. There are still some legacy codebases that store paths in encodings like [Shift JIS], but most
   have been converted to Unicode at this point.
-* Unicode is the common subset of supported paths across Windows and Unix platforms. (On Windows, Rust stores paths
+- Unicode is the common subset of supported paths across Windows and Unix platforms. (On Windows, Rust stores paths
   as [an extension to UTF-8](https://simonsapin.github.io/wtf-8/), and converts them to UTF-16 at Win32
   API boundaries.)
-* There are already many systems, such as Cargo, that only support UTF-8 paths. If your own tool interacts with any such
+- There are already many systems, such as Cargo, that only support UTF-8 paths. If your own tool interacts with any such
   system, you can assume that paths are valid UTF-8 without creating any additional burdens on consumers.
-* The ["makefile problem"](https://www.mercurial-scm.org/wiki/EncodingStrategy#The_.22makefile_problem.22) asks: given a
+- The ["makefile problem"](https://www.mercurial-scm.org/wiki/EncodingStrategy#The_.22makefile_problem.22) asks: given a
   Makefile or other metadata file (such as `Cargo.toml`) that lists the names of other files, how should the names in
-  the Makefile be matched with the ones on disk? This has *no general, cross-platform solution* in systems that support
+  the Makefile be matched with the ones on disk? This has _no general, cross-platform solution_ in systems that support
   non-UTF-8 paths. However, restricting paths to UTF-8 eliminates this problem.
 
 [Shift JIS]: https://en.wikipedia.org/wiki/Shift_JIS
 
-Therefore, many programs that want to manipulate paths *do* assume they contain UTF-8 data, and convert them to `str`s
-as  necessary. However, because this invariant is not encoded in the `Path` type, conversions such as
+Therefore, many programs that want to manipulate paths _do_ assume they contain UTF-8 data, and convert them to `str`s
+as necessary. However, because this invariant is not encoded in the `Path` type, conversions such as
 `path.to_str().unwrap()` need to be repeated again and again, creating a frustrating experience.
 
-Instead, `camino` allows you to check that your paths are UTF-8 *once*, and then manipulate them
+Instead, `camino` allows you to check that your paths are UTF-8 _once_, and then manipulate them
 as valid UTF-8 from there on, avoiding repeated lossy and confusing conversions.
 
 ## Examples
@@ -52,9 +53,10 @@
 for [`Path`] and [`PathBuf`].
 
 Most APIs are the same, but those at the boundary with `str` are different. Some examples:
-* `Path::to_str() -> Option<&str>` has been renamed to `Utf8Path::as_str() -> &str`.
-* [`Utf8Path`] implements `Display`, and `Path::display()` has been removed.
-* Iterating over a [`Utf8Path`] returns `&str`, not `&OsStr`.
+
+- `Path::to_str() -> Option<&str>` has been renamed to `Utf8Path::as_str() -> &str`.
+- [`Utf8Path`] implements `Display`, and `Path::display()` has been removed.
+- Iterating over a [`Utf8Path`] returns `&str`, not `&OsStr`.
 
 Every [`Utf8Path`] is a valid [`Path`], so [`Utf8Path`] implements `AsRef<Path>`. Any APIs that accept `impl AsRef<Path>`
 will continue to work with [`Utf8Path`] instances.
@@ -64,27 +66,27 @@
 `camino` trades off some utility for a great deal of simplicity. Whether `camino` is appropriate for a project or not
 is ultimately a case-by-case decision. Here are some general guidelines that may help.
 
-*You should consider using camino if...*
+_You should consider using camino if..._
 
-* **You're building portable, cross-platform software.** While both Unix and Windows platforms support different kinds
+- **You're building portable, cross-platform software.** While both Unix and Windows platforms support different kinds
   of non-Unicode paths, Unicode is the common subset that's supported across them.
-* **Your system has files that contain the names of other files.** If you don't use UTF-8 paths, you will run into the
+- **Your system has files that contain the names of other files.** If you don't use UTF-8 paths, you will run into the
   makefile problem described above, which has no general, cross-platform solution.
-* **You're interacting with existing systems that already assume UTF-8 paths.** In that case you won't be adding any new
+- **You're interacting with existing systems that already assume UTF-8 paths.** In that case you won't be adding any new
   burdens on downstream consumers.
-* **You're building something brand new and are willing to ask your users to rename their paths if necessary.** Projects
+- **You're building something brand new and are willing to ask your users to rename their paths if necessary.** Projects
   that don't have to worry about legacy compatibility have more flexibility in choosing what paths they support.
-  
+
 In general, using camino is the right choice for most projects.
 
-*You should **NOT** use camino, if...*
+_You should **NOT** use camino, if..._
 
-* **You're writing a core system utility.** If you're writing, say, an `mv` or `cat` replacement, you should
+- **You're writing a core system utility.** If you're writing, say, an `mv` or `cat` replacement, you should
   **not** use camino. Instead, use [`std::path::Path`] and add extensive tests for non-UTF-8 paths.
-* **You have legacy compatibility constraints.** For example, Git supports non-UTF-8 paths. If your tool needs to handle
-  arbitrary Git repositories, it should use its own path type that's a wrapper around `Vec<u8>`. 
-  * [`std::path::Path`] supports arbitrary bytestrings [on Unix] but not on Windows.
-* **There's some other reason you need to support non-UTF-8 paths.** Some tools like disk recovery utilities need to
+- **You have legacy compatibility constraints.** For example, Git supports non-UTF-8 paths. If your tool needs to handle
+  arbitrary Git repositories, it should use its own path type that's a wrapper around `Vec<u8>`.
+  - [`std::path::Path`] supports arbitrary bytestrings [on Unix] but not on Windows.
+- **There's some other reason you need to support non-UTF-8 paths.** Some tools like disk recovery utilities need to
   handle potentially corrupt filenames: only being able to handle UTF-8 paths would greatly diminish their utility.
 
 [on Unix]: https://doc.rust-lang.org/std/os/unix/ffi/index.html
@@ -93,18 +95,22 @@
 
 By default, `camino` has **no dependencies** other than `std`. There are some optional features that enable
 dependencies:
-* `serde1` adds serde [`Serialize`] and [`Deserialize`] impls for [`Utf8PathBuf`] and [`Utf8Path`]
+
+- `serde1` adds serde [`Serialize`] and [`Deserialize`] impls for [`Utf8PathBuf`] and [`Utf8Path`]
   (zero-copy).
-* `proptest1` adds [proptest](https://altsysrq.github.io/proptest-book/) [`Arbitrary`]
+- `proptest1` adds [proptest](https://altsysrq.github.io/proptest-book/) [`Arbitrary`]
   implementations for [`Utf8PathBuf`] and `Box<Utf8Path>`.
 
+> NOTE: Enabling the `serde` or `proptest` features will not do anything. You must enable the `serde1` and `proptest1` features, respectively.
+
 ## Rust version support
 
 The minimum supported Rust version (MSRV) for `camino` with default features is **1.34**. This project is tested in CI
 against the latest stable version of Rust and the MSRV.
-* *Stable APIs* added in later Rust versions are supported either through conditional compilation in `build.rs`, or through backfills that also work on older versions.
-* *Deprecations* are kept in sync with the version of Rust they're added in.
-* *Unstable APIs* are currently not supported. Please
+
+- _Stable APIs_ added in later Rust versions are supported either through conditional compilation in `build.rs`, or through backfills that also work on older versions.
+- _Deprecations_ are kept in sync with the version of Rust they're added in.
+- _Unstable APIs_ are currently not supported. Please
   [file an issue on GitHub](https://github.com/camino-rs/camino/issues/new) if you need an unstable API.
 
 `camino` is designed to be a core library and has a conservative MSRV policy. MSRV increases will only happen for
diff --git a/crates/camino/build.rs b/crates/camino/build.rs
index c24fc8e..ea64c14 100644
--- a/crates/camino/build.rs
+++ b/crates/camino/build.rs
@@ -10,6 +10,17 @@
 // opening a GitHub issue if your build environment requires some way to enable
 // these cfgs other than by executing our build script.
 fn main() {
+    println!("cargo:rerun-if-changed=build.rs");
+
+    // Required by Rust 1.79+.
+    println!("cargo:rustc-check-cfg=cfg(doc_cfg)");
+    println!("cargo:rustc-check-cfg=cfg(path_buf_deref_mut)");
+    println!("cargo:rustc-check-cfg=cfg(path_buf_capacity)");
+    println!("cargo:rustc-check-cfg=cfg(shrink_to)");
+    println!("cargo:rustc-check-cfg=cfg(try_reserve_2)");
+    println!("cargo:rustc-check-cfg=cfg(os_str_bytes)");
+    println!("cargo:rustc-check-cfg=cfg(absolute_path)");
+
     let compiler = match rustc_version() {
         Some(compiler) => compiler,
         None => return,
@@ -40,6 +51,31 @@
     {
         println!("cargo:rustc-cfg=path_buf_deref_mut");
     }
+    // os_str_bytes was added in 1.74.
+    if (compiler.minor >= 74 && compiler.channel == ReleaseChannel::Stable) || compiler.minor >= 75
+    {
+        println!("cargo:rustc-cfg=os_str_bytes");
+    }
+    // absolute_path was added in 1.79.
+    if (compiler.minor >= 79 && compiler.channel == ReleaseChannel::Stable) || compiler.minor >= 80
+    {
+        println!("cargo:rustc-cfg=absolute_path");
+    }
+
+    // Catch situations where the actual features aren't enabled. Currently, they're only shown with
+    // `-vv` output, but maybe that will be noticed.
+    #[cfg(all(feature = "proptest", not(feature = "proptest1")))]
+    {
+        println!(
+            "cargo:warning=proptest feature is enabled, but proptest1 isn't -- this won't do anything"
+        );
+    }
+    #[cfg(all(feature = "serde", not(feature = "serde1")))]
+    {
+        println!(
+            "cargo:warning=serde feature is enabled, but serde1 isn't -- this won't do anything"
+        );
+    }
 }
 
 struct Compiler {
diff --git a/crates/camino/src/lib.rs b/crates/camino/src/lib.rs
index 7a5c61c..2b71e18 100644
--- a/crates/camino/src/lib.rs
+++ b/crates/camino/src/lib.rs
@@ -33,6 +33,9 @@
 //! Instead, `camino` allows you to check that your paths are UTF-8 *once*, and then manipulate them
 //! as valid UTF-8 from there on, avoiding repeated lossy and confusing conversions.
 
+// General note: we use #[allow(clippy::incompatible_msrv)] for code that's already guarded by a
+// version-specific cfg conditional.
+
 use std::{
     borrow::{Borrow, Cow},
     cmp::Ordering,
@@ -204,6 +207,7 @@
     ///
     /// [`with_capacity`]: PathBuf::with_capacity
     #[cfg(path_buf_capacity)]
+    #[allow(clippy::incompatible_msrv)]
     #[must_use]
     pub fn with_capacity(capacity: usize) -> Utf8PathBuf {
         Utf8PathBuf(PathBuf::with_capacity(capacity))
@@ -391,6 +395,7 @@
     ///
     /// [`capacity`]: PathBuf::capacity
     #[cfg(path_buf_capacity)]
+    #[allow(clippy::incompatible_msrv)]
     #[must_use]
     pub fn capacity(&self) -> usize {
         self.0.capacity()
@@ -402,6 +407,7 @@
     ///
     /// [`clear`]: PathBuf::clear
     #[cfg(path_buf_capacity)]
+    #[allow(clippy::incompatible_msrv)]
     pub fn clear(&mut self) {
         self.0.clear()
     }
@@ -412,6 +418,7 @@
     ///
     /// [`reserve`]: PathBuf::reserve
     #[cfg(path_buf_capacity)]
+    #[allow(clippy::incompatible_msrv)]
     pub fn reserve(&mut self, additional: usize) {
         self.0.reserve(additional)
     }
@@ -422,6 +429,7 @@
     ///
     /// [`try_reserve`]: PathBuf::try_reserve
     #[cfg(try_reserve_2)]
+    #[allow(clippy::incompatible_msrv)]
     #[inline]
     pub fn try_reserve(
         &mut self,
@@ -436,6 +444,7 @@
     ///
     /// [`reserve_exact`]: PathBuf::reserve_exact
     #[cfg(path_buf_capacity)]
+    #[allow(clippy::incompatible_msrv)]
     pub fn reserve_exact(&mut self, additional: usize) {
         self.0.reserve_exact(additional)
     }
@@ -446,6 +455,7 @@
     ///
     /// [`try_reserve_exact`]: PathBuf::try_reserve_exact
     #[cfg(try_reserve_2)]
+    #[allow(clippy::incompatible_msrv)]
     #[inline]
     pub fn try_reserve_exact(
         &mut self,
@@ -460,6 +470,7 @@
     ///
     /// [`shrink_to_fit`]: PathBuf::shrink_to_fit
     #[cfg(path_buf_capacity)]
+    #[allow(clippy::incompatible_msrv)]
     pub fn shrink_to_fit(&mut self) {
         self.0.shrink_to_fit()
     }
@@ -470,6 +481,7 @@
     ///
     /// [`shrink_to`]: PathBuf::shrink_to
     #[cfg(shrink_to)]
+    #[allow(clippy::incompatible_msrv)]
     #[inline]
     pub fn shrink_to(&mut self, min_capacity: usize) {
         self.0.shrink_to(min_capacity)
@@ -486,6 +498,7 @@
 
 /// *Requires Rust 1.68 or newer.*
 #[cfg(path_buf_deref_mut)]
+#[allow(clippy::incompatible_msrv)]
 impl std::ops::DerefMut for Utf8PathBuf {
     fn deref_mut(&mut self) -> &mut Self::Target {
         unsafe { Utf8Path::assume_utf8_mut(&mut self.0) }
@@ -578,7 +591,9 @@
     /// Returns `None` if the path is not valid UTF-8.
     ///
     /// For a version that returns a type that implements [`std::error::Error`], use the
-    /// `TryFrom<&Path>` impl.
+    /// [`TryFrom<&Path>`][tryfrom] impl.
+    ///
+    /// [tryfrom]: #impl-TryFrom<%26'a+Path>-for-%26'a+Utf8Path
     ///
     /// # Examples
     ///
@@ -622,6 +637,7 @@
     /// let new_utf8_path = Utf8Path::from_path(std_path).unwrap();
     /// assert_eq!(new_utf8_path, "foo.txt");
     /// ```
+    #[inline]
     pub fn as_std_path(&self) -> &Path {
         self.as_ref()
     }
@@ -641,10 +657,11 @@
     /// ```
     ///
     /// [`str`]: str
+    #[inline]
     #[must_use]
     pub fn as_str(&self) -> &str {
         // SAFETY: every Utf8Path constructor ensures that self is valid UTF-8
-        unsafe { assume_utf8(self.as_os_str()) }
+        unsafe { str_assume_utf8(self.as_os_str()) }
     }
 
     /// Yields the underlying [`OsStr`] slice.
@@ -657,6 +674,7 @@
     /// let os_str = Utf8Path::new("foo.txt").as_os_str();
     /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt"));
     /// ```
+    #[inline]
     #[must_use]
     pub fn as_os_str(&self) -> &OsStr {
         self.0.as_os_str()
@@ -672,6 +690,7 @@
     /// let path_buf = Utf8Path::new("foo.txt").to_path_buf();
     /// assert_eq!(path_buf, Utf8PathBuf::from("foo.txt"));
     /// ```
+    #[inline]
     #[must_use = "this returns the result of the operation, \
                   without modifying the original"]
     pub fn to_path_buf(&self) -> Utf8PathBuf {
@@ -682,10 +701,10 @@
     /// the current directory.
     ///
     /// * On Unix, a path is absolute if it starts with the root, so
-    /// `is_absolute` and [`has_root`] are equivalent.
+    ///   `is_absolute` and [`has_root`] are equivalent.
     ///
     /// * On Windows, a path is absolute if it has a prefix and starts with the
-    /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not.
+    ///   root: `c:\windows` is absolute, while `c:temp` and `\temp` are not.
     ///
     /// # Examples
     ///
@@ -696,6 +715,7 @@
     /// ```
     ///
     /// [`has_root`]: Utf8Path::has_root
+    #[inline]
     #[must_use]
     pub fn is_absolute(&self) -> bool {
         self.0.is_absolute()
@@ -714,6 +734,7 @@
     /// ```
     ///
     /// [`is_absolute`]: Utf8Path::is_absolute
+    #[inline]
     #[must_use]
     pub fn is_relative(&self) -> bool {
         self.0.is_relative()
@@ -735,6 +756,7 @@
     ///
     /// assert!(Utf8Path::new("/etc/passwd").has_root());
     /// ```
+    #[inline]
     #[must_use]
     pub fn has_root(&self) -> bool {
         self.0.has_root()
@@ -757,6 +779,7 @@
     /// assert_eq!(grand_parent, Utf8Path::new("/"));
     /// assert_eq!(grand_parent.parent(), None);
     /// ```
+    #[inline]
     #[must_use]
     pub fn parent(&self) -> Option<&Utf8Path> {
         self.0.parent().map(|path| {
@@ -793,6 +816,7 @@
     /// ```
     ///
     /// [`parent`]: Utf8Path::parent
+    #[inline]
     pub fn ancestors(&self) -> Utf8Ancestors<'_> {
         Utf8Ancestors(self.0.ancestors())
     }
@@ -816,11 +840,12 @@
     /// assert_eq!(None, Utf8Path::new("foo.txt/..").file_name());
     /// assert_eq!(None, Utf8Path::new("/").file_name());
     /// ```
+    #[inline]
     #[must_use]
     pub fn file_name(&self) -> Option<&str> {
         self.0.file_name().map(|s| {
             // SAFETY: self is valid UTF-8, so file_name is valid UTF-8 as well
-            unsafe { assume_utf8(s) }
+            unsafe { str_assume_utf8(s) }
         })
     }
 
@@ -852,6 +877,7 @@
     /// let prefix = Utf8PathBuf::from("/test/");
     /// assert_eq!(path.strip_prefix(prefix), Ok(Utf8Path::new("haha/foo.txt")));
     /// ```
+    #[inline]
     pub fn strip_prefix(&self, base: impl AsRef<Path>) -> Result<&Utf8Path, StripPrefixError> {
         self.0.strip_prefix(base).map(|path| {
             // SAFETY: self is valid UTF-8, and strip_prefix returns a part of self (or an empty
@@ -882,6 +908,7 @@
     ///
     /// assert!(!Utf8Path::new("/etc/foo.rs").starts_with("/etc/foo"));
     /// ```
+    #[inline]
     #[must_use]
     pub fn starts_with(&self, base: impl AsRef<Path>) -> bool {
         self.0.starts_with(base)
@@ -905,6 +932,7 @@
     /// assert!(!path.ends_with("/resolv.conf"));
     /// assert!(!path.ends_with("conf")); // use .extension() instead
     /// ```
+    #[inline]
     #[must_use]
     pub fn ends_with(&self, base: impl AsRef<Path>) -> bool {
         self.0.ends_with(base)
@@ -929,11 +957,12 @@
     /// assert_eq!("foo", Utf8Path::new("foo.rs").file_stem().unwrap());
     /// assert_eq!("foo.tar", Utf8Path::new("foo.tar.gz").file_stem().unwrap());
     /// ```
+    #[inline]
     #[must_use]
     pub fn file_stem(&self) -> Option<&str> {
         self.0.file_stem().map(|s| {
             // SAFETY: self is valid UTF-8, so file_stem is valid UTF-8 as well
-            unsafe { assume_utf8(s) }
+            unsafe { str_assume_utf8(s) }
         })
     }
 
@@ -956,11 +985,12 @@
     /// assert_eq!("rs", Utf8Path::new("foo.rs").extension().unwrap());
     /// assert_eq!("gz", Utf8Path::new("foo.tar.gz").extension().unwrap());
     /// ```
+    #[inline]
     #[must_use]
     pub fn extension(&self) -> Option<&str> {
         self.0.extension().map(|s| {
             // SAFETY: self is valid UTF-8, so extension is valid UTF-8 as well
-            unsafe { assume_utf8(s) }
+            unsafe { str_assume_utf8(s) }
         })
     }
 
@@ -975,6 +1005,7 @@
     ///
     /// assert_eq!(Utf8Path::new("/etc").join("passwd"), Utf8PathBuf::from("/etc/passwd"));
     /// ```
+    #[inline]
     #[must_use]
     pub fn join(&self, path: impl AsRef<Utf8Path>) -> Utf8PathBuf {
         Utf8PathBuf(self.0.join(&path.as_ref().0))
@@ -992,6 +1023,7 @@
     ///
     /// assert_eq!(Utf8Path::new("/etc").join_os("passwd"), PathBuf::from("/etc/passwd"));
     /// ```
+    #[inline]
     #[must_use]
     pub fn join_os(&self, path: impl AsRef<Path>) -> PathBuf {
         self.0.join(path)
@@ -1012,6 +1044,7 @@
     /// let path = Utf8Path::new("/tmp");
     /// assert_eq!(path.with_file_name("var"), Utf8PathBuf::from("/var"));
     /// ```
+    #[inline]
     #[must_use]
     pub fn with_file_name(&self, file_name: impl AsRef<str>) -> Utf8PathBuf {
         Utf8PathBuf(self.0.with_file_name(file_name.as_ref()))
@@ -1034,6 +1067,7 @@
     /// assert_eq!(path.with_extension("xz"), Utf8PathBuf::from("foo.tar.xz"));
     /// assert_eq!(path.with_extension("").with_extension("txt"), Utf8PathBuf::from("foo.txt"));
     /// ```
+    #[inline]
     pub fn with_extension(&self, extension: impl AsRef<str>) -> Utf8PathBuf {
         Utf8PathBuf(self.0.with_extension(extension.as_ref()))
     }
@@ -1070,6 +1104,7 @@
     /// ```
     ///
     /// [`CurDir`]: Utf8Component::CurDir
+    #[inline]
     pub fn components(&self) -> Utf8Components {
         Utf8Components(self.0.components())
     }
@@ -1093,6 +1128,7 @@
     /// assert_eq!(it.next(), Some("foo.txt"));
     /// assert_eq!(it.next(), None)
     /// ```
+    #[inline]
     pub fn iter(&self) -> Iter<'_> {
         Iter {
             inner: self.components(),
@@ -1115,6 +1151,7 @@
     /// let metadata = path.metadata().expect("metadata call failed");
     /// println!("{:?}", metadata.file_type());
     /// ```
+    #[inline]
     pub fn metadata(&self) -> io::Result<fs::Metadata> {
         self.0.metadata()
     }
@@ -1132,6 +1169,7 @@
     /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
     /// println!("{:?}", metadata.file_type());
     /// ```
+    #[inline]
     pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
         self.0.symlink_metadata()
     }
@@ -1154,6 +1192,7 @@
     /// let path = Utf8Path::new("/foo/test/../test/bar.rs");
     /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
     /// ```
+    #[inline]
     pub fn canonicalize(&self) -> io::Result<PathBuf> {
         self.0.canonicalize()
     }
@@ -1203,6 +1242,7 @@
     /// let path = Utf8Path::new("/laputa/sky_castle.rs");
     /// let path_link = path.read_link().expect("read_link call failed");
     /// ```
+    #[inline]
     pub fn read_link(&self) -> io::Result<PathBuf> {
         self.0.read_link()
     }
@@ -1253,6 +1293,7 @@
     ///     }
     /// }
     /// ```
+    #[inline]
     pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
         self.0.read_dir()
     }
@@ -1313,6 +1354,7 @@
     ///
     /// [`try_exists()`]: Self::try_exists
     #[must_use]
+    #[inline]
     pub fn exists(&self) -> bool {
         self.0.exists()
     }
@@ -1383,6 +1425,7 @@
     /// a Unix-like system for example. See [`fs::File::open`] or
     /// [`fs::OpenOptions::open`] for more information.
     #[must_use]
+    #[inline]
     pub fn is_file(&self) -> bool {
         self.0.is_file()
     }
@@ -1409,6 +1452,7 @@
     /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
     /// [`fs::Metadata::is_dir`] if it was [`Ok`].
     #[must_use]
+    #[inline]
     pub fn is_dir(&self) -> bool {
         self.0.is_dir()
     }
@@ -1448,6 +1492,7 @@
 
     /// Converts a `Box<Utf8Path>` into a [`Utf8PathBuf`] without copying or allocating.
     #[must_use = "`self` will be dropped if the result is not used"]
+    #[inline]
     pub fn into_path_buf(self: Box<Utf8Path>) -> Utf8PathBuf {
         let ptr = Box::into_raw(self) as *mut Path;
         // SAFETY:
@@ -1460,6 +1505,7 @@
     }
 
     // invariant: Path must be guaranteed to be utf-8 data
+    #[inline]
     unsafe fn assume_utf8(path: &Path) -> &Utf8Path {
         // SAFETY: Utf8Path is marked as #[repr(transparent)] so the conversion from a
         // *const Path to a *const Utf8Path is valid.
@@ -1467,6 +1513,7 @@
     }
 
     #[cfg(path_buf_deref_mut)]
+    #[inline]
     unsafe fn assume_utf8_mut(path: &mut Path) -> &mut Utf8Path {
         &mut *(path as *mut Path as *mut Utf8Path)
     }
@@ -1529,6 +1576,7 @@
 impl<'a> Iterator for Utf8Ancestors<'a> {
     type Item = &'a Utf8Path;
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.0.next().map(|path| {
             // SAFETY: Utf8Ancestors was constructed from a Utf8Path, so it is guaranteed to
@@ -1577,6 +1625,7 @@
     /// assert_eq!(Utf8Path::new("foo/bar.txt"), components.as_path());
     /// ```
     #[must_use]
+    #[inline]
     pub fn as_path(&self) -> &'a Utf8Path {
         // SAFETY: Utf8Components was constructed from a Utf8Path, so it is guaranteed to be valid
         // UTF-8
@@ -1587,6 +1636,7 @@
 impl<'a> Iterator for Utf8Components<'a> {
     type Item = Utf8Component<'a>;
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.0.next().map(|component| {
             // SAFETY: Utf8Component was constructed from a Utf8Path, so it is guaranteed to be
@@ -1599,6 +1649,7 @@
 impl<'a> FusedIterator for Utf8Components<'a> {}
 
 impl<'a> DoubleEndedIterator for Utf8Components<'a> {
+    #[inline]
     fn next_back(&mut self) -> Option<Self::Item> {
         self.0.next_back().map(|component| {
             // SAFETY: Utf8Component was constructed from a Utf8Path, so it is guaranteed to be
@@ -1615,24 +1666,28 @@
 }
 
 impl AsRef<Utf8Path> for Utf8Components<'_> {
+    #[inline]
     fn as_ref(&self) -> &Utf8Path {
         self.as_path()
     }
 }
 
 impl AsRef<Path> for Utf8Components<'_> {
+    #[inline]
     fn as_ref(&self) -> &Path {
         self.as_path().as_ref()
     }
 }
 
 impl AsRef<str> for Utf8Components<'_> {
+    #[inline]
     fn as_ref(&self) -> &str {
         self.as_path().as_ref()
     }
 }
 
 impl AsRef<OsStr> for Utf8Components<'_> {
+    #[inline]
     fn as_ref(&self) -> &OsStr {
         self.as_path().as_os_str()
     }
@@ -1681,30 +1736,35 @@
     /// assert_eq!(Utf8Path::new("foo/bar.txt"), iter.as_path());
     /// ```
     #[must_use]
+    #[inline]
     pub fn as_path(&self) -> &'a Utf8Path {
         self.inner.as_path()
     }
 }
 
 impl AsRef<Utf8Path> for Iter<'_> {
+    #[inline]
     fn as_ref(&self) -> &Utf8Path {
         self.as_path()
     }
 }
 
 impl AsRef<Path> for Iter<'_> {
+    #[inline]
     fn as_ref(&self) -> &Path {
         self.as_path().as_ref()
     }
 }
 
 impl AsRef<str> for Iter<'_> {
+    #[inline]
     fn as_ref(&self) -> &str {
         self.as_path().as_ref()
     }
 }
 
 impl AsRef<OsStr> for Iter<'_> {
+    #[inline]
     fn as_ref(&self) -> &OsStr {
         self.as_path().as_os_str()
     }
@@ -1713,12 +1773,14 @@
 impl<'a> Iterator for Iter<'a> {
     type Item = &'a str;
 
+    #[inline]
     fn next(&mut self) -> Option<&'a str> {
         self.inner.next().map(|component| component.as_str())
     }
 }
 
 impl<'a> DoubleEndedIterator for Iter<'a> {
+    #[inline]
     fn next_back(&mut self) -> Option<&'a str> {
         self.inner.next_back().map(|component| component.as_str())
     }
@@ -1783,7 +1845,7 @@
             Component::RootDir => Utf8Component::RootDir,
             Component::CurDir => Utf8Component::CurDir,
             Component::ParentDir => Utf8Component::ParentDir,
-            Component::Normal(s) => Utf8Component::Normal(assume_utf8(s)),
+            Component::Normal(s) => Utf8Component::Normal(str_assume_utf8(s)),
         }
     }
 
@@ -1799,10 +1861,11 @@
     /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
     /// ```
     #[must_use]
+    #[inline]
     pub fn as_str(&self) -> &'a str {
         // SAFETY: Utf8Component was constructed from a Utf8Path, so it is guaranteed to be
         // valid UTF-8
-        unsafe { assume_utf8(self.as_os_str()) }
+        unsafe { str_assume_utf8(self.as_os_str()) }
     }
 
     /// Extracts the underlying [`OsStr`] slice.
@@ -1841,24 +1904,28 @@
 }
 
 impl AsRef<Utf8Path> for Utf8Component<'_> {
+    #[inline]
     fn as_ref(&self) -> &Utf8Path {
         self.as_str().as_ref()
     }
 }
 
 impl AsRef<Path> for Utf8Component<'_> {
+    #[inline]
     fn as_ref(&self) -> &Path {
         self.as_os_str().as_ref()
     }
 }
 
 impl AsRef<str> for Utf8Component<'_> {
+    #[inline]
     fn as_ref(&self) -> &str {
         self.as_str()
     }
 }
 
 impl AsRef<OsStr> for Utf8Component<'_> {
+    #[inline]
     fn as_ref(&self) -> &OsStr {
         self.as_os_str()
     }
@@ -2004,17 +2071,17 @@
         // SAFETY for all the below unsafe blocks: the path self was originally constructed from was
         // UTF-8 so any parts of it are valid UTF-8
         match self.0.kind() {
-            Prefix::Verbatim(prefix) => Utf8Prefix::Verbatim(unsafe { assume_utf8(prefix) }),
+            Prefix::Verbatim(prefix) => Utf8Prefix::Verbatim(unsafe { str_assume_utf8(prefix) }),
             Prefix::VerbatimUNC(server, share) => {
-                let server = unsafe { assume_utf8(server) };
-                let share = unsafe { assume_utf8(share) };
+                let server = unsafe { str_assume_utf8(server) };
+                let share = unsafe { str_assume_utf8(share) };
                 Utf8Prefix::VerbatimUNC(server, share)
             }
             Prefix::VerbatimDisk(drive) => Utf8Prefix::VerbatimDisk(drive),
-            Prefix::DeviceNS(prefix) => Utf8Prefix::DeviceNS(unsafe { assume_utf8(prefix) }),
+            Prefix::DeviceNS(prefix) => Utf8Prefix::DeviceNS(unsafe { str_assume_utf8(prefix) }),
             Prefix::UNC(server, share) => {
-                let server = unsafe { assume_utf8(server) };
-                let share = unsafe { assume_utf8(share) };
+                let server = unsafe { str_assume_utf8(server) };
+                let share = unsafe { str_assume_utf8(share) };
                 Utf8Prefix::UNC(server, share)
             }
             Prefix::Disk(drive) => Utf8Prefix::Disk(drive),
@@ -2023,14 +2090,16 @@
 
     /// Returns the [`str`] slice for this prefix.
     #[must_use]
+    #[inline]
     pub fn as_str(&self) -> &'a str {
         // SAFETY: Utf8PrefixComponent was constructed from a Utf8Path, so it is guaranteed to be
         // valid UTF-8
-        unsafe { assume_utf8(self.as_os_str()) }
+        unsafe { str_assume_utf8(self.as_os_str()) }
     }
 
     /// Returns the raw [`OsStr`] slice for this prefix.
     #[must_use]
+    #[inline]
     pub fn as_os_str(&self) -> &'a OsStr {
         self.0.as_os_str()
     }
@@ -2453,6 +2522,31 @@
     }
 }
 
+/// Converts a [`Path`] to a [`Utf8Path`].
+///
+/// Returns [`FromPathError`] if the path is not valid UTF-8.
+///
+/// # Examples
+///
+/// ```
+/// use camino::Utf8Path;
+/// use std::convert::TryFrom;
+/// use std::ffi::OsStr;
+/// # #[cfg(unix)]
+/// use std::os::unix::ffi::OsStrExt;
+/// use std::path::Path;
+///
+/// let unicode_path = Path::new("/valid/unicode");
+/// <&Utf8Path>::try_from(unicode_path).expect("valid Unicode path succeeded");
+///
+/// // Paths on Unix can be non-UTF-8.
+/// # #[cfg(unix)]
+/// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
+/// # #[cfg(unix)]
+/// let non_unicode_path = Path::new(non_unicode_str);
+/// # #[cfg(unix)]
+/// assert!(<&Utf8Path>::try_from(non_unicode_path).is_err(), "non-Unicode path failed");
+/// ```
 impl<'a> TryFrom<&'a Path> for &'a Utf8Path {
     type Error = FromPathError;
 
@@ -2499,11 +2593,13 @@
 
 impl FromPathBufError {
     /// Returns the [`Path`] slice that was attempted to be converted to [`Utf8PathBuf`].
+    #[inline]
     pub fn as_path(&self) -> &Path {
         &self.path
     }
 
     /// Returns the [`PathBuf`] that was attempted to be converted to [`Utf8PathBuf`].
+    #[inline]
     pub fn into_path_buf(self) -> PathBuf {
         self.path
     }
@@ -2512,6 +2608,7 @@
     ///
     /// At the moment this struct does not contain any additional information, but is provided for
     /// completeness.
+    #[inline]
     pub fn from_path_error(&self) -> FromPathError {
         self.error
     }
@@ -2600,60 +2697,70 @@
 // ---
 
 impl AsRef<Utf8Path> for Utf8Path {
+    #[inline]
     fn as_ref(&self) -> &Utf8Path {
         self
     }
 }
 
 impl AsRef<Utf8Path> for Utf8PathBuf {
+    #[inline]
     fn as_ref(&self) -> &Utf8Path {
         self.as_path()
     }
 }
 
 impl AsRef<Utf8Path> for str {
+    #[inline]
     fn as_ref(&self) -> &Utf8Path {
         Utf8Path::new(self)
     }
 }
 
 impl AsRef<Utf8Path> for String {
+    #[inline]
     fn as_ref(&self) -> &Utf8Path {
         Utf8Path::new(self)
     }
 }
 
 impl AsRef<Path> for Utf8Path {
+    #[inline]
     fn as_ref(&self) -> &Path {
         &self.0
     }
 }
 
 impl AsRef<Path> for Utf8PathBuf {
+    #[inline]
     fn as_ref(&self) -> &Path {
         &self.0
     }
 }
 
 impl AsRef<str> for Utf8Path {
+    #[inline]
     fn as_ref(&self) -> &str {
         self.as_str()
     }
 }
 
 impl AsRef<str> for Utf8PathBuf {
+    #[inline]
     fn as_ref(&self) -> &str {
         self.as_str()
     }
 }
 
 impl AsRef<OsStr> for Utf8Path {
+    #[inline]
     fn as_ref(&self) -> &OsStr {
         self.as_os_str()
     }
 }
 
 impl AsRef<OsStr> for Utf8PathBuf {
+    #[inline]
     fn as_ref(&self) -> &OsStr {
         self.as_os_str()
     }
@@ -2664,6 +2771,7 @@
 // ---
 
 impl Borrow<Utf8Path> for Utf8PathBuf {
+    #[inline]
     fn borrow(&self) -> &Utf8Path {
         self.as_path()
     }
@@ -2672,6 +2780,7 @@
 impl ToOwned for Utf8Path {
     type Owned = Utf8PathBuf;
 
+    #[inline]
     fn to_owned(&self) -> Utf8PathBuf {
         self.to_path_buf()
     }
@@ -2690,6 +2799,7 @@
 // ---
 
 impl PartialEq for Utf8PathBuf {
+    #[inline]
     fn eq(&self, other: &Utf8PathBuf) -> bool {
         self.components() == other.components()
     }
@@ -2698,14 +2808,16 @@
 impl Eq for Utf8PathBuf {}
 
 impl Hash for Utf8PathBuf {
+    #[inline]
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.as_path().hash(state)
     }
 }
 
 impl PartialOrd for Utf8PathBuf {
+    #[inline]
     fn partial_cmp(&self, other: &Utf8PathBuf) -> Option<Ordering> {
-        self.components().partial_cmp(other.components())
+        Some(self.cmp(other))
     }
 }
 
@@ -2716,6 +2828,7 @@
 }
 
 impl PartialEq for Utf8Path {
+    #[inline]
     fn eq(&self, other: &Utf8Path) -> bool {
         self.components().eq(other.components())
     }
@@ -2732,8 +2845,9 @@
 }
 
 impl PartialOrd for Utf8Path {
+    #[inline]
     fn partial_cmp(&self, other: &Utf8Path) -> Option<Ordering> {
-        self.components().partial_cmp(other.components())
+        Some(self.cmp(other))
     }
 }
 
@@ -2746,6 +2860,7 @@
 impl<'a> IntoIterator for &'a Utf8PathBuf {
     type Item = &'a str;
     type IntoIter = Iter<'a>;
+    #[inline]
     fn into_iter(self) -> Iter<'a> {
         self.iter()
     }
@@ -2754,6 +2869,7 @@
 impl<'a> IntoIterator for &'a Utf8Path {
     type Item = &'a str;
     type IntoIter = Iter<'a>;
+    #[inline]
     fn into_iter(self) -> Iter<'a> {
         self.iter()
     }
@@ -2948,7 +3064,110 @@
 impl_cmp_os_str!(&'a Utf8Path, OsString);
 // NOTE: impls for Cow<'a, Utf8Path> cannot be defined because of the orphan rule (E0117)
 
+/// Makes the path absolute without accessing the filesystem, converting it to a [`Utf8PathBuf`].
+///
+/// If the path is relative, the current directory is used as the base directory. All intermediate
+/// components will be resolved according to platform-specific rules, but unlike
+/// [`canonicalize`][Utf8Path::canonicalize] or [`canonicalize_utf8`](Utf8Path::canonicalize_utf8),
+/// this does not resolve symlinks and may succeed even if the path does not exist.
+///
+/// *Requires Rust 1.79 or newer.*
+///
+/// # Errors
+///
+/// Errors if:
+///
+/// * The path is empty.
+/// * The [current directory][std::env::current_dir] cannot be determined.
+/// * The path is not valid UTF-8.
+///
+/// # Examples
+///
+/// ## POSIX paths
+///
+/// ```
+/// # #[cfg(unix)]
+/// fn main() -> std::io::Result<()> {
+///     use camino::Utf8Path;
+///
+///     // Relative to absolute
+///     let absolute = camino::absolute_utf8("foo/./bar")?;
+///     assert!(absolute.ends_with("foo/bar"));
+///
+///     // Absolute to absolute
+///     let absolute = camino::absolute_utf8("/foo//test/.././bar.rs")?;
+///     assert_eq!(absolute, Utf8Path::new("/foo/test/../bar.rs"));
+///     Ok(())
+/// }
+/// # #[cfg(not(unix))]
+/// # fn main() {}
+/// ```
+///
+/// The path is resolved using [POSIX semantics][posix-semantics] except that it stops short of
+/// resolving symlinks. This means it will keep `..` components and trailing slashes.
+///
+/// ## Windows paths
+///
+/// ```
+/// # #[cfg(windows)]
+/// fn main() -> std::io::Result<()> {
+///     use camino::Utf8Path;
+///
+///     // Relative to absolute
+///     let absolute = camino::absolute_utf8("foo/./bar")?;
+///     assert!(absolute.ends_with(r"foo\bar"));
+///
+///     // Absolute to absolute
+///     let absolute = camino::absolute_utf8(r"C:\foo//test\..\./bar.rs")?;
+///
+///     assert_eq!(absolute, Utf8Path::new(r"C:\foo\bar.rs"));
+///     Ok(())
+/// }
+/// # #[cfg(not(windows))]
+/// # fn main() {}
+/// ```
+///
+/// For verbatim paths this will simply return the path as given. For other paths this is currently
+/// equivalent to calling [`GetFullPathNameW`][windows-path].
+///
+/// Note that this [may change in the future][changes].
+///
+/// [changes]: io#platform-specific-behavior
+/// [posix-semantics]:
+///     https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+/// [windows-path]:
+///     https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
+#[cfg(absolute_path)]
+pub fn absolute_utf8<P: AsRef<Path>>(path: P) -> io::Result<Utf8PathBuf> {
+    // Note that even if the passed in path is valid UTF-8, it is not guaranteed that the absolute
+    // path will be valid UTF-8. For example, the current directory may not be valid UTF-8.
+    //
+    // That's why we take `AsRef<Path>` instead of `AsRef<Utf8Path>` here -- we have to pay the cost
+    // of checking for valid UTF-8 anyway.
+    let path = path.as_ref();
+    #[allow(clippy::incompatible_msrv)]
+    Utf8PathBuf::try_from(std::path::absolute(path)?).map_err(|error| error.into_io_error())
+}
+
 // invariant: OsStr must be guaranteed to be utf8 data
-unsafe fn assume_utf8(string: &OsStr) -> &str {
-    &*(string as *const OsStr as *const str)
+#[inline]
+unsafe fn str_assume_utf8(string: &OsStr) -> &str {
+    #[cfg(os_str_bytes)]
+    {
+        // SAFETY: OsStr is guaranteed to be utf8 data from the invariant
+        unsafe {
+            std::str::from_utf8_unchecked(
+                #[allow(clippy::incompatible_msrv)]
+                string.as_encoded_bytes(),
+            )
+        }
+    }
+    #[cfg(not(os_str_bytes))]
+    {
+        // Adapted from the source code for Option::unwrap_unchecked.
+        match string.to_str() {
+            Some(val) => val,
+            None => std::hint::unreachable_unchecked(),
+        }
+    }
 }
diff --git a/crates/camino/src/proptest_impls.rs b/crates/camino/src/proptest_impls.rs
index 81776f2..22ca63a 100644
--- a/crates/camino/src/proptest_impls.rs
+++ b/crates/camino/src/proptest_impls.rs
@@ -30,12 +30,12 @@
             prop::collection::vec(any_with::<String>(args), 0..8),
         )
             .prop_map(|(is_relative, components)| {
-                let initial_component =
-                    is_relative.then(|| format!("{}", std::path::MAIN_SEPARATOR));
-                initial_component
-                    .into_iter()
-                    .chain(components.into_iter())
-                    .collect()
+                let initial_component = if is_relative {
+                    Some(format!("{}", std::path::MAIN_SEPARATOR))
+                } else {
+                    None
+                };
+                initial_component.into_iter().chain(components).collect()
             })
             .boxed()
     }
diff --git a/crates/combine/.cargo-checksum.json b/crates/combine/.cargo-checksum.json
index 30b5d4f..cfd4200 100644
--- a/crates/combine/.cargo-checksum.json
+++ b/crates/combine/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"7dab0114f84bb28550f20945fb19bc8eb3ee126eeedb407a239d83e81d63859a","Cargo.lock":"3713ec3427674be7496e2c7db7acbbed5d2e5b3f43e096e11f5b4aa97333524d","Cargo.toml":"73714151a0740300247529d7f567d07a002338b0668c5d8b0dbb9a39d34f1de3","LICENSE":"9bbc1b3dc4674a9ebb12c2a62f54fe3c08672539717f8d05828f684b6cc419a3","README.md":"d3d266598879fc406ace5808319886714a33191e63134cd569e9959403cca4b2","benches/data.json":"dfececbeb40e51033d9437fcb955c524fe31fd1b1734ad0e069b134d5bffd9dd","benches/http-requests.txt":"6c5d29174cc9d5c1064282e6e68d55ba5759ff9d9fac2e9b952822ba64fa6fa1","benches/http.rs":"876e8d2a7b1d2eaa4108726f180b6de1cda1afb8ba44f657352d42df81acace0","benches/json.rs":"1c1aa94308b77afdf4d7ebdbaa1aab8d3084b475ee157629b011fd3ab1fc7526","benches/mp4.rs":"3354bd947d5f66e568b3e26a4813dceedd2ccce1615a7aacf11298fad5c1640a","ci.sh":"b3a050d17575ba7a8e955dbc0272e9325d6d52dbbf88143b59d407c7f462c657","examples/async.rs":"251eae98979e5c62ea5f39a7178b261b7c4dc9568b287b8c93ecb5fd136a0ec3","examples/date.rs":"2f425a752d9f3af90055fe0a165a04827200c30f856f7768fcfc0983962bb871","examples/ini.rs":"66390952233fd7a9b882c03d7c41bb5499f76449a121ed7b7df79425cb412224","examples/number.rs":"46423aad5aac010bf779641cd53ca300faba4c920dffb27039b89c628d6f5ead","examples/readme.rs":"c156719ca4b1cca31841578a899d164561a4f151ab3be7e2fc47ed3f82a0db00","release.sh":"f4dc049059df5ba4fcf068330b7c81162fb7738f43c1473f4360444910fcf539","rustfmt.toml":"d8e7f616455a670ba75e3e94bf6f88f4c168c481664d12501820c7dfff5c3cc2","src/error.rs":"e39cbb9d7c227b5fd34df6181ecbec6c39ef11a15f9169b5cd7ef3109887dd33","src/future_ext.rs":"f6879b2adc93d8c5d1048bd0b4bdd6e8e4ceb7cb7fcdaa1f80c5688fb8a6f07c","src/lib.rs":"f69da4ca547bc158bafff17b4147de9bfc83ca5da2ffa5458c715f3e1f7dda06","src/parser/byte.rs":"d351e504d6e53d743bdbd57ad6b9cb001b7aa634835bd8d20ce9e368d3b97692","src/parser/char.rs":"0eb363e996448515d5e7b55117bcb86e45a71525500c9bdfe45a04eb4ef3e4ae","src/parser/choice.rs":"2bf4b728cb9a008b77b694b4b4bc2785ac6fb3bf9856d4e50c58c335f2d60d62","src/parser/combinator.rs":"ecc1828beab9d172d5afd2cbf54a0658499ff8f5d1729eb4c490fbabd68a6738","src/parser/error.rs":"669917e75241fb23cf5b6b3d80e123cfa60d21adb229be58e5264aa3673ba81f","src/parser/function.rs":"fbee0ddb23061e5de6c9bc65882fece14f82a7b978a0d195935f3bca3ea032f5","src/parser/mod.rs":"3d0fcb0a7435670870ad28fd58746ef0d4c11ecc5bb13165ada0f9b09df84864","src/parser/range.rs":"84691cd0ea409f42395c0c261076341b1e5c3a83b87f9495da9ab775525a3816","src/parser/regex.rs":"ca3e46d645c35deee8c995e99e958910aba84a78e14d1e57f35da44fddbb65b0","src/parser/repeat.rs":"dbea60a343481c879073a0a60a13802d7f6acccfb975b86207d07f4911985c57","src/parser/sequence.rs":"130ac0a907ced01ae0629fb3c4bcfceb124a51e14d6557c40d679d2c278f3e93","src/parser/token.rs":"2500adb7e8541ed83e5aa9777952920c0169923acf06e32ef48069031697dbbc","src/stream/buf_reader.rs":"b12708b236585b5cbf3f808b2b63ac8b1ba5f7f284af818dc739652d1322c30a","src/stream/buffered.rs":"75df0dcd053a96b893fedbc393d11fa1c4a56ead450b28d847e443a04c688db2","src/stream/decoder.rs":"b23859913cf7e704b0e1f1477260f2c92be7163fba0b038d42d4245fc0011d46","src/stream/easy.rs":"2097cba05a8d1bf72c540649ef685847fc7ab9a57661fb9b98bad6baa6af1ff4","src/stream/mod.rs":"89f42cce96587d978f23f7cfcc45f2ef83e778ef5f2914e145eb1b391db70d26","src/stream/position.rs":"7408c9d892acda501d1e29bd2b44783071a7990f51088db2445bfb36a369d00b","src/stream/read.rs":"b7b732ac41bf6692334746610d9912bc5c8354dd5136e4e27cc78a6224f6dfde","src/stream/span.rs":"e229ca993efc243888c9c7ddbad60273c16a5b7b1212624c34f8f0186f2c97b7","src/stream/state.rs":"21107661c102b39653a2b90728c23087d30d2b105bd4ac518b6faaea1c098794","tests/async.rs":"0c00ec8ab58ea341657915afefad02056e17bbebfb1cd59968249ffd5a4a3a4f","tests/buffered_stream.rs":"26fdcec1c13cf0504dadbd37044ebc4dcbba34485fbfda0d262233517e71a9c0","tests/parser.rs":"73d91daca1a5a43c48d41a875bc3e4e9035c8981e26669f03db6487241da4c6e","tests/parser_macro.rs":"4cad91d583cf60f1e917c1f79aeb3701d5a746928c518ec6f2d61c3a3becdea4","tests/support/mod.rs":"9e375de8c6b66d2a40b9f14443bb8c153691afa6e5d8d3061aefa709187ed3d8"},"package":"35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"2e1470226ebc52eda98ebd2051d9fd8b14eda6e77b78bef529f12f09548f6629","Cargo.lock":"a7a18d65585f2d008512efbd0f6e10b326cf1867928405060bb2cf368438982d","Cargo.toml":"7e755c2622b7a6ee59bd8c21c0e6c98df1f6f30c3f416c6632684a0117dec49a","LICENSE":"9bbc1b3dc4674a9ebb12c2a62f54fe3c08672539717f8d05828f684b6cc419a3","README.md":"426950cd2e2cf23e05859d7e227282c1fbee83e19e7e005138094bb66af49529","benches/buffers.rs":"879f6fb830e844f74f07b4815ea1173e984ab6f364fb8e4db2789cced28d7506","benches/data.json":"dfececbeb40e51033d9437fcb955c524fe31fd1b1734ad0e069b134d5bffd9dd","benches/http-requests.txt":"6c5d29174cc9d5c1064282e6e68d55ba5759ff9d9fac2e9b952822ba64fa6fa1","benches/http.rs":"5570b535a78e2817badcfd573876d846518ed49bdaf043c508bfe047b4bcae39","benches/json.rs":"969e5161f6e89f3f260b498310571533e0505dcb8aeac39f57f81186fbd88158","benches/mp4.rs":"3354bd947d5f66e568b3e26a4813dceedd2ccce1615a7aacf11298fad5c1640a","ci.sh":"b3a050d17575ba7a8e955dbc0272e9325d6d52dbbf88143b59d407c7f462c657","examples/async.rs":"f1c829e3f398ea3a50d74f9246e8ca1a0e6434d4c1346bb88a53f262827dc070","examples/date.rs":"7333b021cc7cc39ce7d3cd0bd603f0b36c64f1695c710be73c3f22206fe5bdd2","examples/ini.rs":"7793257a38aaff7968f0d3c5cb679d6d1d3fd384a2f2091733a74e3f2a8c2022","examples/number.rs":"46423aad5aac010bf779641cd53ca300faba4c920dffb27039b89c628d6f5ead","examples/readme.rs":"c156719ca4b1cca31841578a899d164561a4f151ab3be7e2fc47ed3f82a0db00","release.sh":"f4dc049059df5ba4fcf068330b7c81162fb7738f43c1473f4360444910fcf539","rustfmt.toml":"d8e7f616455a670ba75e3e94bf6f88f4c168c481664d12501820c7dfff5c3cc2","src/error.rs":"2aef1615bb4c83f06a2d23d273febe2b4d4d9a4f7b0747845168e30795a7b35e","src/future_ext.rs":"f6879b2adc93d8c5d1048bd0b4bdd6e8e4ceb7cb7fcdaa1f80c5688fb8a6f07c","src/lib.rs":"9dbda93f6ada241035f6f47dd487644e0cf3b729626cc70265edd5e9468c064a","src/parser/byte.rs":"39a6b430805f9745abe449b80e65e5a3cefbad7db7da7bf767f116203520bbcc","src/parser/char.rs":"36d002702baa2c66fc13a27b89ab0f05244a16b2c8c2ddc68e8972d983d4f93b","src/parser/choice.rs":"2bf4b728cb9a008b77b694b4b4bc2785ac6fb3bf9856d4e50c58c335f2d60d62","src/parser/combinator.rs":"1b4f22777b01ae9314087444158325178a7f42c3fcd69c62322255440cbedeb9","src/parser/error.rs":"669917e75241fb23cf5b6b3d80e123cfa60d21adb229be58e5264aa3673ba81f","src/parser/function.rs":"32c49be9b8f66c41879e25744ed7b93da4740f87d27d14a187101878a203dd39","src/parser/mod.rs":"3d0fcb0a7435670870ad28fd58746ef0d4c11ecc5bb13165ada0f9b09df84864","src/parser/range.rs":"84691cd0ea409f42395c0c261076341b1e5c3a83b87f9495da9ab775525a3816","src/parser/regex.rs":"ca3e46d645c35deee8c995e99e958910aba84a78e14d1e57f35da44fddbb65b0","src/parser/repeat.rs":"dbea60a343481c879073a0a60a13802d7f6acccfb975b86207d07f4911985c57","src/parser/sequence.rs":"cbcbc2f9bb76ffa4a0486779f788ef46f95f3e056673d505dcdf8c59fa443c84","src/parser/token.rs":"2500adb7e8541ed83e5aa9777952920c0169923acf06e32ef48069031697dbbc","src/stream/buf_reader.rs":"c3b89f9658f6a83f2050ae3ae87d7e6821f6016d5a747f0f51f4a35d70ab007b","src/stream/buffered.rs":"75df0dcd053a96b893fedbc393d11fa1c4a56ead450b28d847e443a04c688db2","src/stream/decoder.rs":"b23859913cf7e704b0e1f1477260f2c92be7163fba0b038d42d4245fc0011d46","src/stream/easy.rs":"2097cba05a8d1bf72c540649ef685847fc7ab9a57661fb9b98bad6baa6af1ff4","src/stream/mod.rs":"b7a3a887ea27143818986772b3957f9cc578a0b35dc1dcf5592d206296ea4b36","src/stream/position.rs":"08025dc42db27437cf69ca931178cd2949402913b501f4387fcabc1a3e5c03f9","src/stream/read.rs":"b7b732ac41bf6692334746610d9912bc5c8354dd5136e4e27cc78a6224f6dfde","src/stream/span.rs":"e229ca993efc243888c9c7ddbad60273c16a5b7b1212624c34f8f0186f2c97b7","src/stream/state.rs":"21107661c102b39653a2b90728c23087d30d2b105bd4ac518b6faaea1c098794","tests/async.rs":"6d64fcb32850f173470f89fea95503aa5bf2f6f9d0ef231b32ae4cc7afbd5dd2","tests/buffered_stream.rs":"26fdcec1c13cf0504dadbd37044ebc4dcbba34485fbfda0d262233517e71a9c0","tests/parser.rs":"73d91daca1a5a43c48d41a875bc3e4e9035c8981e26669f03db6487241da4c6e","tests/parser_macro.rs":"4cad91d583cf60f1e917c1f79aeb3701d5a746928c518ec6f2d61c3a3becdea4","tests/support/mod.rs":"9e375de8c6b66d2a40b9f14443bb8c153691afa6e5d8d3061aefa709187ed3d8"},"package":"ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"}
\ No newline at end of file
diff --git a/crates/combine/Android.bp b/crates/combine/Android.bp
index 6e4b10c..f6024ae 100644
--- a/crates/combine/Android.bp
+++ b/crates/combine/Android.bp
@@ -18,7 +18,7 @@
     host_supported: true,
     crate_name: "combine",
     cargo_env_compat: true,
-    cargo_pkg_version: "4.6.6",
+    cargo_pkg_version: "4.6.7",
     crate_root: "src/lib.rs",
     edition: "2018",
     features: [
diff --git a/crates/combine/CHANGELOG.md b/crates/combine/CHANGELOG.md
index a2bf60d..bbda468 100644
--- a/crates/combine/CHANGELOG.md
+++ b/crates/combine/CHANGELOG.md
@@ -1,5 +1,10 @@
-<a name="v4.6.5"></a>
-### v4.6.5 (2022-08-09)
+<a name="v4.6.7"></a>
+### v4.6.7 (2024-04-10)
+
+* perf: avoid initializing huge buffers in the stream decoder
+
+<a name="v4.6.6"></a>
+### v4.6.6 (2022-08-09)
 
 * memchr: use non deprecated feature `std` instead of `use_std`
 
diff --git a/crates/combine/Cargo.lock b/crates/combine/Cargo.lock
index 1900e9c..e617874 100644
--- a/crates/combine/Cargo.lock
+++ b/crates/combine/Cargo.lock
@@ -3,114 +3,162 @@
 version = 3
 
 [[package]]
-name = "aho-corasick"
-version = "0.7.18"
+name = "addr2line"
+version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "async-channel"
-version = "1.6.1"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319"
+checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
 dependencies = [
  "concurrent-queue",
- "event-listener",
+ "event-listener 2.5.3",
  "futures-core",
 ]
 
 [[package]]
-name = "async-executor"
-version = "1.4.1"
+name = "async-channel"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965"
+checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c"
 dependencies = [
+ "concurrent-queue",
+ "event-listener 4.0.0",
+ "event-listener-strategy",
+ "futures-core",
+ "pin-project-lite 0.2.13",
+]
+
+[[package]]
+name = "async-executor"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c"
+dependencies = [
+ "async-lock 3.2.0",
  "async-task",
  "concurrent-queue",
- "fastrand",
- "futures-lite",
- "once_cell",
+ "fastrand 2.0.1",
+ "futures-lite 2.1.0",
  "slab",
 ]
 
 [[package]]
 name = "async-global-executor"
-version = "2.0.2"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6"
+checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
 dependencies = [
- "async-channel",
+ "async-channel 2.1.1",
  "async-executor",
- "async-io",
- "async-mutex",
+ "async-io 2.2.2",
+ "async-lock 3.2.0",
  "blocking",
- "futures-lite",
- "num_cpus",
+ "futures-lite 2.1.0",
  "once_cell",
 ]
 
 [[package]]
 name = "async-io"
-version = "1.6.0"
+version = "1.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b"
+checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
 dependencies = [
+ "async-lock 2.8.0",
+ "autocfg",
+ "cfg-if 1.0.0",
  "concurrent-queue",
- "futures-lite",
- "libc",
+ "futures-lite 1.13.0",
  "log",
- "once_cell",
  "parking",
- "polling",
+ "polling 2.8.0",
+ "rustix 0.37.27",
  "slab",
  "socket2",
  "waker-fn",
- "winapi 0.3.9",
+]
+
+[[package]]
+name = "async-io"
+version = "2.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6afaa937395a620e33dc6a742c593c01aced20aa376ffb0f628121198578ccc7"
+dependencies = [
+ "async-lock 3.2.0",
+ "cfg-if 1.0.0",
+ "concurrent-queue",
+ "futures-io",
+ "futures-lite 2.1.0",
+ "parking",
+ "polling 3.3.1",
+ "rustix 0.38.28",
+ "slab",
+ "tracing",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "async-lock"
-version = "2.4.0"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b"
+checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
 dependencies = [
- "event-listener",
+ "event-listener 2.5.3",
 ]
 
 [[package]]
-name = "async-mutex"
-version = "1.4.0"
+name = "async-lock"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e"
+checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c"
 dependencies = [
- "event-listener",
+ "event-listener 4.0.0",
+ "event-listener-strategy",
+ "pin-project-lite 0.2.13",
 ]
 
 [[package]]
 name = "async-std"
-version = "1.10.0"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952"
+checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
 dependencies = [
- "async-channel",
+ "async-channel 1.9.0",
  "async-global-executor",
- "async-io",
- "async-lock",
+ "async-io 1.13.0",
+ "async-lock 2.8.0",
  "crossbeam-utils",
  "futures-channel",
  "futures-core",
  "futures-io",
- "futures-lite",
+ "futures-lite 1.13.0",
  "gloo-timers",
  "kv-log-macro",
  "log",
  "memchr",
- "num_cpus",
  "once_cell",
- "pin-project-lite 0.2.7",
+ "pin-project-lite 0.2.13",
  "pin-utils",
  "slab",
  "wasm-bindgen-futures",
@@ -118,15 +166,15 @@
 
 [[package]]
 name = "async-task"
-version = "4.0.3"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0"
+checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1"
 
 [[package]]
 name = "atomic-waker"
-version = "1.0.0"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
 
 [[package]]
 name = "atty"
@@ -134,16 +182,31 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.1.19",
  "libc",
  "winapi 0.3.9",
 ]
 
 [[package]]
 name = "autocfg"
-version = "1.0.1"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "backtrace"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if 1.0.0",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
 
 [[package]]
 name = "bitflags"
@@ -152,42 +215,38 @@
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
-name = "blocking"
-version = "1.0.2"
+name = "bitflags"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9"
-dependencies = [
- "async-channel",
- "async-task",
- "atomic-waker",
- "fastrand",
- "futures-lite",
- "once_cell",
-]
+checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
 
 [[package]]
-name = "bstr"
-version = "0.2.17"
+name = "blocking"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118"
 dependencies = [
- "lazy_static",
- "memchr",
- "regex-automata",
- "serde",
+ "async-channel 2.1.1",
+ "async-lock 3.2.0",
+ "async-task",
+ "fastrand 2.0.1",
+ "futures-io",
+ "futures-lite 2.1.0",
+ "piper",
+ "tracing",
 ]
 
 [[package]]
 name = "bumpalo"
-version = "3.8.0"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
 
 [[package]]
 name = "byteorder"
-version = "1.4.3"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
@@ -207,30 +266,24 @@
 
 [[package]]
 name = "bytes"
-version = "1.1.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
-
-[[package]]
-name = "cache-padded"
-version = "1.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
 
 [[package]]
 name = "cast"
-version = "0.2.7"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
-dependencies = [
- "rustc_version",
-]
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.0.71"
+version = "1.0.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
 
 [[package]]
 name = "cfg-if"
@@ -246,53 +299,53 @@
 
 [[package]]
 name = "clap"
-version = "2.33.3"
+version = "2.34.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
 dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
  "textwrap",
  "unicode-width",
 ]
 
 [[package]]
 name = "combine"
-version = "4.6.6"
+version = "4.6.7"
 dependencies = [
  "async-std",
  "bytes 0.5.6",
- "bytes 1.1.0",
+ "bytes 1.5.0",
  "criterion",
- "futures 0.3.17",
+ "futures 0.3.29",
  "futures-core",
  "futures-io",
  "memchr",
  "once_cell",
  "partial-io",
- "pin-project-lite 0.2.7",
+ "pin-project-lite 0.2.13",
  "quick-error",
  "quickcheck",
  "regex",
  "tokio 0.2.25",
  "tokio 0.3.7",
- "tokio 1.12.0",
+ "tokio 1.35.0",
  "tokio-util",
 ]
 
 [[package]]
 name = "concurrent-queue"
-version = "1.2.2"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
+checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363"
 dependencies = [
- "cache-padded",
+ "crossbeam-utils",
 ]
 
 [[package]]
 name = "criterion"
-version = "0.3.5"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
+checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
 dependencies = [
  "atty",
  "cast",
@@ -316,29 +369,19 @@
 
 [[package]]
 name = "criterion-plot"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
+checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
 dependencies = [
  "cast",
  "itertools",
 ]
 
 [[package]]
-name = "crossbeam-channel"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
-dependencies = [
- "cfg-if 1.0.0",
- "crossbeam-utils",
-]
-
-[[package]]
 name = "crossbeam-deque"
-version = "0.8.1"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
 dependencies = [
  "cfg-if 1.0.0",
  "crossbeam-epoch",
@@ -347,34 +390,32 @@
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.5"
+version = "0.9.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
+checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
 dependencies = [
+ "autocfg",
  "cfg-if 1.0.0",
  "crossbeam-utils",
- "lazy_static",
  "memoffset",
  "scopeguard",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.5"
+version = "0.8.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
+checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
 dependencies = [
  "cfg-if 1.0.0",
- "lazy_static",
 ]
 
 [[package]]
 name = "csv"
-version = "1.1.6"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
+checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
 dependencies = [
- "bstr",
  "csv-core",
  "itoa",
  "ryu",
@@ -383,28 +424,18 @@
 
 [[package]]
 name = "csv-core"
-version = "0.1.10"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
+checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
-name = "ctor"
-version = "0.1.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa"
-dependencies = [
- "quote",
- "syn",
-]
-
-[[package]]
 name = "either"
-version = "1.6.1"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
 
 [[package]]
 name = "env_logger"
@@ -420,21 +451,58 @@
 ]
 
 [[package]]
-name = "event-listener"
-version = "2.5.1"
+name = "errno"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "event-listener"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
+
+[[package]]
+name = "event-listener"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite 0.2.13",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
+dependencies = [
+ "event-listener 4.0.0",
+ "pin-project-lite 0.2.13",
+]
 
 [[package]]
 name = "fastrand"
-version = "1.5.0"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
 dependencies = [
  "instant",
 ]
 
 [[package]]
+name = "fastrand"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
+
+[[package]]
 name = "fuchsia-cprng"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -446,7 +514,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
 dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
  "fuchsia-zircon-sys",
 ]
 
@@ -464,9 +532,9 @@
 
 [[package]]
 name = "futures"
-version = "0.3.17"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca"
+checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -479,9 +547,9 @@
 
 [[package]]
 name = "futures-channel"
-version = "0.3.17"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
+checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -489,15 +557,15 @@
 
 [[package]]
 name = "futures-core"
-version = "0.3.17"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
+checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.17"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c"
+checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -506,57 +574,67 @@
 
 [[package]]
 name = "futures-io"
-version = "0.3.17"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377"
+checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
 
 [[package]]
 name = "futures-lite"
-version = "1.12.0"
+version = "1.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
+checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
 dependencies = [
- "fastrand",
+ "fastrand 1.9.0",
  "futures-core",
  "futures-io",
  "memchr",
  "parking",
- "pin-project-lite 0.2.7",
+ "pin-project-lite 0.2.13",
  "waker-fn",
 ]
 
 [[package]]
-name = "futures-macro"
-version = "0.3.17"
+name = "futures-lite"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb"
+checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143"
 dependencies = [
- "autocfg",
- "proc-macro-hack",
+ "fastrand 2.0.1",
+ "futures-core",
+ "futures-io",
+ "parking",
+ "pin-project-lite 0.2.13",
+]
+
+[[package]]
+name = "futures-macro"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
+dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.40",
 ]
 
 [[package]]
 name = "futures-sink"
-version = "0.3.17"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11"
+checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
 
 [[package]]
 name = "futures-task"
-version = "0.3.17"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
+checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
 
 [[package]]
 name = "futures-util"
-version = "0.3.17"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
+checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
 dependencies = [
- "autocfg",
  "futures-channel",
  "futures-core",
  "futures-io",
@@ -564,24 +642,27 @@
  "futures-sink",
  "futures-task",
  "memchr",
- "pin-project-lite 0.2.7",
+ "pin-project-lite 0.2.13",
  "pin-utils",
- "proc-macro-hack",
- "proc-macro-nested",
  "slab",
 ]
 
 [[package]]
-name = "gloo-timers"
-version = "0.2.1"
+name = "gimli"
+version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+
+[[package]]
+name = "gloo-timers"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
 dependencies = [
  "futures-channel",
  "futures-core",
  "js-sys",
  "wasm-bindgen",
- "web-sys",
 ]
 
 [[package]]
@@ -600,6 +681,12 @@
 ]
 
 [[package]]
+name = "hermit-abi"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
+
+[[package]]
 name = "humantime"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -618,6 +705,17 @@
 ]
 
 [[package]]
+name = "io-lifetimes"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+dependencies = [
+ "hermit-abi 0.3.3",
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
 name = "iovec"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -628,24 +726,24 @@
 
 [[package]]
 name = "itertools"
-version = "0.10.1"
+version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
 dependencies = [
  "either",
 ]
 
 [[package]]
 name = "itoa"
-version = "0.4.8"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
+checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
 
 [[package]]
 name = "js-sys"
-version = "0.3.55"
+version = "0.3.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
+checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -677,36 +775,56 @@
 
 [[package]]
 name = "libc"
-version = "0.2.105"
+version = "0.2.151"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
+checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
 
 [[package]]
 name = "log"
-version = "0.4.14"
+version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 dependencies = [
- "cfg-if 1.0.0",
  "value-bag",
 ]
 
 [[package]]
 name = "memchr"
-version = "2.4.1"
+version = "2.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
 
 [[package]]
 name = "memoffset"
-version = "0.6.4"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
+checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
+name = "miniz_oxide"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+dependencies = [
+ "adler",
+]
+
+[[package]]
 name = "mio"
 version = "0.6.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -739,9 +857,9 @@
 
 [[package]]
 name = "net2"
-version = "0.2.37"
+version = "0.2.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
+checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac"
 dependencies = [
  "cfg-if 0.1.10",
  "libc",
@@ -750,28 +868,37 @@
 
 [[package]]
 name = "num-traits"
-version = "0.2.14"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "num_cpus"
-version = "1.13.0"
+version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.3.3",
  "libc",
 ]
 
 [[package]]
-name = "once_cell"
-version = "1.8.0"
+name = "object"
+version = "0.32.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
+checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
 name = "oorandom"
@@ -781,9 +908,9 @@
 
 [[package]]
 name = "parking"
-version = "2.0.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
+checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
 
 [[package]]
 name = "partial-io"
@@ -804,9 +931,9 @@
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.7"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
 
 [[package]]
 name = "pin-utils"
@@ -815,10 +942,21 @@
 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
-name = "plotters"
-version = "0.3.1"
+name = "piper"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
+checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4"
+dependencies = [
+ "atomic-waker",
+ "fastrand 2.0.1",
+ "futures-io",
+]
+
+[[package]]
+name = "plotters"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
 dependencies = [
  "num-traits",
  "plotters-backend",
@@ -829,51 +967,56 @@
 
 [[package]]
 name = "plotters-backend"
-version = "0.3.2"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
+checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
 
 [[package]]
 name = "plotters-svg"
-version = "0.3.1"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9"
+checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
 dependencies = [
  "plotters-backend",
 ]
 
 [[package]]
 name = "polling"
-version = "2.1.0"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92341d779fa34ea8437ef4d82d440d5e1ce3f3ff7f824aa64424cd481f9a1f25"
+checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
 dependencies = [
+ "autocfg",
+ "bitflags 1.3.2",
  "cfg-if 1.0.0",
+ "concurrent-queue",
  "libc",
  "log",
- "wepoll-ffi",
- "winapi 0.3.9",
+ "pin-project-lite 0.2.13",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
-name = "proc-macro-hack"
-version = "0.5.19"
+name = "polling"
+version = "3.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
-
-[[package]]
-name = "proc-macro-nested"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
+checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e"
+dependencies = [
+ "cfg-if 1.0.0",
+ "concurrent-queue",
+ "pin-project-lite 0.2.13",
+ "rustix 0.38.28",
+ "tracing",
+ "windows-sys 0.52.0",
+]
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.32"
+version = "1.0.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
+checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
 dependencies = [
- "unicode-xid",
+ "unicode-ident",
 ]
 
 [[package]]
@@ -895,9 +1038,9 @@
 
 [[package]]
 name = "quote"
-version = "1.0.10"
+version = "1.0.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 dependencies = [
  "proc-macro2",
 ]
@@ -932,27 +1075,22 @@
 
 [[package]]
 name = "rayon"
-version = "1.5.1"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
+checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
 dependencies = [
- "autocfg",
- "crossbeam-deque",
  "either",
  "rayon-core",
 ]
 
 [[package]]
 name = "rayon-core"
-version = "1.9.1"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
+checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
 dependencies = [
- "crossbeam-channel",
  "crossbeam-deque",
  "crossbeam-utils",
- "lazy_static",
- "num_cpus",
 ]
 
 [[package]]
@@ -966,9 +1104,21 @@
 
 [[package]]
 name = "regex"
-version = "1.5.4"
+version = "1.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -976,31 +1126,49 @@
 ]
 
 [[package]]
-name = "regex-automata"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
-
-[[package]]
 name = "regex-syntax"
-version = "0.6.25"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
 
 [[package]]
-name = "rustc_version"
-version = "0.4.0"
+name = "rustc-demangle"
+version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
+[[package]]
+name = "rustix"
+version = "0.37.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
 dependencies = [
- "semver",
+ "bitflags 1.3.2",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys 0.3.8",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
+dependencies = [
+ "bitflags 2.4.1",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.12",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "ryu"
-version = "1.0.5"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
 
 [[package]]
 name = "same-file"
@@ -1013,21 +1181,18 @@
 
 [[package]]
 name = "scopeguard"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
-
-[[package]]
-name = "semver"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "serde"
-version = "1.0.130"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
+dependencies = [
+ "serde_derive",
+]
 
 [[package]]
 name = "serde_cbor"
@@ -1041,20 +1206,20 @@
 
 [[package]]
 name = "serde_derive"
-version = "1.0.130"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.40",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.68"
+version = "1.0.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
 dependencies = [
  "itoa",
  "ryu",
@@ -1063,15 +1228,18 @@
 
 [[package]]
 name = "slab"
-version = "0.4.5"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
 
 [[package]]
 name = "socket2"
-version = "0.4.2"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516"
+checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
 dependencies = [
  "libc",
  "winapi 0.3.9",
@@ -1079,20 +1247,31 @@
 
 [[package]]
 name = "syn"
-version = "1.0.81"
+version = "1.0.109"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
 dependencies = [
  "proc-macro2",
  "quote",
- "unicode-xid",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
 ]
 
 [[package]]
 name = "termcolor"
-version = "1.1.2"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
 dependencies = [
  "winapi-util",
 ]
@@ -1139,23 +1318,22 @@
 dependencies = [
  "autocfg",
  "num_cpus",
- "pin-project-lite 0.2.7",
+ "pin-project-lite 0.2.13",
  "slab",
  "tokio-macros 0.3.2",
 ]
 
 [[package]]
 name = "tokio"
-version = "1.12.0"
+version = "1.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc"
+checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c"
 dependencies = [
- "autocfg",
- "bytes 1.1.0",
- "memchr",
+ "backtrace",
+ "bytes 1.5.0",
  "num_cpus",
- "pin-project-lite 0.2.7",
- "tokio-macros 1.5.0",
+ "pin-project-lite 0.2.13",
+ "tokio-macros 2.2.0",
 ]
 
 [[package]]
@@ -1177,7 +1355,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -1188,84 +1366,92 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "1.5.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2dd85aeaba7b68df939bd357c6afb36c87951be9e80bf9c859f2fc3e9fca0fd"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.40",
 ]
 
 [[package]]
 name = "tokio-util"
-version = "0.7.0"
+version = "0.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64910e1b9c1901aaf5375561e35b9c057d95ff41a44ede043a03e09279eabaf1"
+checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
 dependencies = [
- "bytes 1.1.0",
+ "bytes 1.5.0",
  "futures-core",
  "futures-sink",
- "log",
- "pin-project-lite 0.2.7",
- "tokio 1.12.0",
+ "pin-project-lite 0.2.13",
+ "tokio 1.35.0",
+ "tracing",
 ]
 
 [[package]]
+name = "tracing"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+dependencies = [
+ "pin-project-lite 0.2.13",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
 name = "unicode-width"
-version = "0.1.9"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
 
 [[package]]
 name = "value-bag"
-version = "1.0.0-alpha.8"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f"
-dependencies = [
- "ctor",
- "version_check",
-]
-
-[[package]]
-name = "version_check"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+checksum = "4a72e1902dde2bd6441347de2b70b7f5d59bf157c6c62f0c44572607a1d55bbe"
 
 [[package]]
 name = "waker-fn"
-version = "1.1.0"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
+checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690"
 
 [[package]]
 name = "walkdir"
-version = "2.3.2"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
 dependencies = [
  "same-file",
- "winapi 0.3.9",
  "winapi-util",
 ]
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.78"
+version = "0.2.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
+checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
 dependencies = [
  "cfg-if 1.0.0",
  "wasm-bindgen-macro",
@@ -1273,24 +1459,24 @@
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.78"
+version = "0.2.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
+checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
 dependencies = [
  "bumpalo",
- "lazy_static",
  "log",
+ "once_cell",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.40",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.28"
+version = "0.4.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39"
+checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
 dependencies = [
  "cfg-if 1.0.0",
  "js-sys",
@@ -1300,9 +1486,9 @@
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.78"
+version = "0.2.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
+checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -1310,43 +1496,34 @@
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.78"
+version = "0.2.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
+checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.40",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.78"
+version = "0.2.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
+checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
 
 [[package]]
 name = "web-sys"
-version = "0.3.55"
+version = "0.3.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
+checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
 ]
 
 [[package]]
-name = "wepoll-ffi"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb"
-dependencies = [
- "cc",
-]
-
-[[package]]
 name = "winapi"
 version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1376,9 +1553,9 @@
 
 [[package]]
 name = "winapi-util"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
 dependencies = [
  "winapi 0.3.9",
 ]
@@ -1390,6 +1567,138 @@
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.0",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.0",
+ "windows_aarch64_msvc 0.52.0",
+ "windows_i686_gnu 0.52.0",
+ "windows_i686_msvc 0.52.0",
+ "windows_x86_64_gnu 0.52.0",
+ "windows_x86_64_gnullvm 0.52.0",
+ "windows_x86_64_msvc 0.52.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+
+[[package]]
 name = "ws2_32-sys"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/crates/combine/Cargo.toml b/crates/combine/Cargo.toml
index b4e5996..27622ab 100644
--- a/crates/combine/Cargo.toml
+++ b/crates/combine/Cargo.toml
@@ -12,7 +12,7 @@
 [package]
 edition = "2018"
 name = "combine"
-version = "4.6.6"
+version = "4.6.7"
 authors = ["Markus Westerlind <marwes91@gmail.com>"]
 description = "Fast parser combinators on arbitrary streams with zero-copy support."
 documentation = "https://docs.rs/combine"
@@ -29,7 +29,6 @@
 ]
 license = "MIT"
 repository = "https://github.com/Marwes/combine"
-resolver = "1"
 
 [package.metadata.docs.rs]
 all-features = true
@@ -87,6 +86,11 @@
 harness = false
 required-features = ["mp4"]
 
+[[bench]]
+name = "buffers"
+harness = false
+required-features = ["std"]
+
 [dependencies.bytes]
 version = "1"
 optional = true
diff --git a/crates/combine/METADATA b/crates/combine/METADATA
index ede2263..73bf60c 100644
--- a/crates/combine/METADATA
+++ b/crates/combine/METADATA
@@ -1,17 +1,17 @@
 name: "combine"
 description: "Fast parser combinators on arbitrary streams with zero-copy support."
 third_party {
-  version: "4.6.6"
+  version: "4.6.7"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2022
-    month: 12
-    day: 8
+    year: 2024
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/combine"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/combine/combine-4.6.6.crate"
-    version: "4.6.6"
+    value: "https://static.crates.io/crates/combine/combine-4.6.7.crate"
+    version: "4.6.7"
   }
 }
diff --git a/crates/combine/README.md b/crates/combine/README.md
index 5d67f1c..795af3a 100644
--- a/crates/combine/README.md
+++ b/crates/combine/README.md
@@ -1,6 +1,5 @@
 # combine
 [![Build Status](https://travis-ci.org/Marwes/combine.svg?branch=master)](https://travis-ci.org/Marwes/combine)
-[![Docs v3](https://docs.rs/combine/badge.svg?version=^3)](https://docs.rs/combine/^3)
 [![Docs](https://docs.rs/combine/badge.svg)](https://docs.rs/combine)
 [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Marwes/combine?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
 
@@ -48,15 +47,15 @@
 
 ## Features
 
-* __Parse arbitrary streams__ - Combine can parse anything from `&[u8]` and `&str` to iterators and `Read` instances. If none of the builtin streams fit your use case you can even implement a couple traits your self to create your own custom [stream](https://docs.rs/combine/3.*/combine/stream/index.html)!
+* __Parse arbitrary streams__ - Combine can parse anything from `&[u8]` and `&str` to iterators and `Read` instances. If none of the builtin streams fit your use case you can even implement a couple traits your self to create your own custom [stream](https://docs.rs/combine/*/combine/stream/index.html)!
 
-* __zero-copy parsing__ - When parsing in memory data, combine can parse without copying. See the [range module](https://docs.rs/combine/3.*/combine/parser/range/index.html) for parsers specialized for zero-copy parsing.
+* __zero-copy parsing__ - When parsing in memory data, combine can parse without copying. See the [range module](https://docs.rs/combine/*/combine/parser/range/index.html) for parsers specialized for zero-copy parsing.
 
 * __partial parsing__ - Combine parsers can be stopped at any point during parsing and later be resumed without losing any progress. This makes it possible to start parsing partial data coming from an io device such as a socket without worrying about if enough data is present to complete the parse. If more data is needed the parser will stop and may be resumed at the same point once more data is available. See the [async example](https://github.com/Marwes/combine/blob/master/examples/async.rs) for an example and [this post](https://marwes.github.io/2018/02/08/combine-3.html) for an introduction.
 
 ## About
 
-A parser combinator is, broadly speaking, a function which takes several parsers as arguments and returns a new parser, created by combining those parsers. For instance, the [many](https://docs.rs/combine/*/combine/fn.many.html) parser takes one parser, `p`, as input and returns a new parser which applies `p` zero or more times. Thanks to the modularity that parser combinators gives it is possible to define parsers for a wide range of tasks without needing to implement the low level plumbing while still having the full power of Rust when you need it. 
+A parser combinator is, broadly speaking, a function which takes several parsers as arguments and returns a new parser, created by combining those parsers. For instance, the [many](https://docs.rs/combine/*/combine/fn.many.html) parser takes one parser, `p`, as input and returns a new parser which applies `p` zero or more times. Thanks to the modularity that parser combinators gives it is possible to define parsers for a wide range of tasks without needing to implement the low level plumbing while still having the full power of Rust when you need it.
 
 The library adheres to [semantic versioning](https://semver.org/).
 
@@ -98,13 +97,9 @@
 
 There is an additional crate which has parsers to lex and parse programming languages in [combine-language](https://github.com/Marwes/combine-language).
 
-You can find older versions of combine (parser-combinators) [here](https://crates.io/crates/parser-combinators).
 
 ## Contributing
 
-Current master is the 3.0.0 branch. If you want to submit a fix or feature to the 2.x version of combine then
-do so to the 2.x branch or submit the PR to master and request that it be backported.
-
 The easiest way to contribute is to just open an issue about any problems you encounter using combine but if you are interested in adding something to the library here is a list of some of the easier things to work on to get started.
 
 * __Add additional parsers__ If you have a suggestion for another parser just open an issue or a PR with an implementation.
diff --git a/crates/combine/benches/buffers.rs b/crates/combine/benches/buffers.rs
new file mode 100644
index 0000000..6716cf1
--- /dev/null
+++ b/crates/combine/benches/buffers.rs
@@ -0,0 +1,86 @@
+#![cfg(feature = "std")]
+
+use {
+    combine::{
+        parser::{
+            byte::take_until_bytes,
+            combinator::{any_send_sync_partial_state, recognize, AnySendSyncPartialState},
+        },
+        Parser, RangeStream,
+    },
+    criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion},
+    partial_io::{PartialOp, PartialRead},
+    std::io::Cursor,
+};
+
+fn test_data() -> Vec<u8> {
+    let mut input = vec![b' '; 5_000_000];
+    input.push(b'1');
+
+    input
+}
+
+fn parser<'a, I>() -> impl combine::Parser<I, Output = usize, PartialState = AnySendSyncPartialState>
+where
+    I: RangeStream<Token = u8, Range = &'a [u8]>,
+    I::Error: combine::ParseError<u8, &'a [u8], I::Position>,
+{
+    any_send_sync_partial_state(
+        recognize(take_until_bytes(&b"1"[..])).map(|spaces: Vec<u8>| spaces.len()),
+    )
+}
+
+fn bench_small_buf(bencher: &mut Bencher<'_>) {
+    let input = test_data();
+    let mut decoder = combine::stream::decoder::Decoder::new();
+
+    bencher.iter(|| {
+        let cursor = Cursor::new(&input);
+        let mut partial_read =
+            PartialRead::new(cursor, std::iter::repeat(PartialOp::Limited(1000)));
+        let mut ref_decoder = &mut decoder;
+
+        let result = combine::decode!(ref_decoder, partial_read, parser(), |input, _position| {
+            combine::easy::Stream::from(input)
+        },);
+
+        match result {
+            Ok(usize) => black_box(usize),
+            Err(err) => {
+                println!("{:?}", err);
+                panic!();
+            }
+        };
+    });
+}
+
+fn bench_big_buf(bencher: &mut Bencher<'_>) {
+    let input = test_data();
+    let mut decoder = combine::stream::decoder::Decoder::new();
+
+    bencher.iter(|| {
+        let cursor = Cursor::new(&input);
+        let mut partial_read = PartialRead::new(cursor, std::iter::repeat(PartialOp::Unlimited));
+        let mut ref_decoder = &mut decoder;
+
+        let result = combine::decode!(ref_decoder, partial_read, parser(), |input, _position| {
+            combine::easy::Stream::from(input)
+        },);
+
+        match result {
+            Ok(usize) => black_box(usize),
+            Err(err) => {
+                println!("{:?}", err);
+                panic!();
+            }
+        };
+    });
+}
+
+fn bench(c: &mut Criterion) {
+    c.bench_function("buffers_small", bench_small_buf);
+    c.bench_function("buffers_big", bench_big_buf);
+}
+
+criterion_group!(buffers, bench);
+criterion_main!(buffers);
diff --git a/crates/combine/benches/http.rs b/crates/combine/benches/http.rs
index e08e973..187b4eb 100644
--- a/crates/combine/benches/http.rs
+++ b/crates/combine/benches/http.rs
@@ -74,7 +74,6 @@
 fn end_of_line<'a, Input>() -> impl Parser<Input, Output = u8>
 where
     Input: RangeStream<Token = u8, Range = &'a [u8]>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     (token(b'\r'), token(b'\n')).map(|_| b'\r').or(token(b'\n'))
 }
@@ -82,7 +81,6 @@
 fn message_header<'a, Input>() -> impl Parser<Input, Output = Header<'a>>
 where
     Input: RangeStream<Token = u8, Range = &'a [u8]>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     let message_header_line = (
         take_while1(is_horizontal_space),
@@ -103,7 +101,6 @@
 fn parse_http_request<'a, Input>(input: Input) -> Result<(HttpRequest<'a>, Input), Input::Error>
 where
     Input: RangeStream<Token = u8, Range = &'a [u8]>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     let http_version = range(&b"HTTP/"[..]).with(take_while1(is_http_version));
 
@@ -155,7 +152,7 @@
 fn http_requests_bench<'a, Input>(b: &mut Bencher<'_>, buffer: Input)
 where
     Input: RangeStream<Token = u8, Range = &'a [u8]> + Clone,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position> + fmt::Debug,
+    Input::Error: fmt::Debug,
 {
     b.iter(|| {
         let mut buf = black_box(buffer.clone());
diff --git a/crates/combine/benches/json.rs b/crates/combine/benches/json.rs
index 56add8e..c277260 100644
--- a/crates/combine/benches/json.rs
+++ b/crates/combine/benches/json.rs
@@ -1,6 +1,3 @@
-// `impl Trait` is not required for this parser but we use to to show that it can be used to
-// significantly simplify things
-
 #![cfg(feature = "std")]
 
 #[macro_use]
@@ -58,7 +55,6 @@
 fn integer<Input>() -> impl Parser<Input, Output = i64>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     lex(many1(digit()))
         .map(|s: String| {
@@ -74,7 +70,6 @@
 fn number<Input>() -> impl Parser<Input, Output = f64>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     let i = char('0').map(|_| 0.0).or(integer().map(|x| x as f64));
     let fractional = many(digit()).map(|digits: String| {
@@ -108,7 +103,6 @@
 fn json_char<Input>() -> impl Parser<Input, Output = char>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     parser(|input: &mut Input| {
         let (c, committed) = any().parse_lazy(input).into_result()?;
@@ -136,7 +130,6 @@
 fn json_string<Input>() -> impl Parser<Input, Output = String>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     between(char('"'), lex(char('"')), many(json_char())).expected("string")
 }
@@ -144,7 +137,6 @@
 fn object<Input>() -> impl Parser<Input, Output = Value>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     let field = (json_string(), lex(char(':')), json_value()).map(|t| (t.0, t.2));
     let fields = sep_by(field, lex(char(',')));
@@ -157,7 +149,6 @@
 fn json_value<Input>() -> impl Parser<Input, Output = Value>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     json_value_()
 }
diff --git a/crates/combine/examples/async.rs b/crates/combine/examples/async.rs
index 909ca2c..75153a3 100644
--- a/crates/combine/examples/async.rs
+++ b/crates/combine/examples/async.rs
@@ -56,8 +56,6 @@
 ) -> impl Parser<Input, Output = Vec<u8>, PartialState = AnyPartialState> + 'a
 where
     Input: RangeStream<Token = u8, Range = &'a [u8]> + 'a,
-    // Necessary due to rust-lang/rust#24159
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     let content_length = range(&b"Content-Length: "[..])
         .with(recognize(skip_many1(digit())).and_then(|digits: &[u8]| {
diff --git a/crates/combine/examples/date.rs b/crates/combine/examples/date.rs
index 3daaa72..8645b52 100644
--- a/crates/combine/examples/date.rs
+++ b/crates/combine/examples/date.rs
@@ -9,7 +9,6 @@
 
 use combine::{
     choice,
-    error::ParseError,
     many, optional,
     parser::char::{char, digit},
     stream::position,
@@ -63,8 +62,6 @@
 fn two_digits<Input>() -> impl Parser<Input, Output = i32>
 where
     Input: Stream<Token = char>,
-    // Necessary due to rust-lang/rust#24159
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     (digit(), digit()).map(|(x, y): (char, char)| {
         let x = x.to_digit(10).expect("digit");
@@ -81,7 +78,6 @@
 fn time_zone<Input>() -> impl Parser<Input, Output = i32>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     let utc = char('Z').map(|_| 0);
     let offset = (
@@ -106,7 +102,6 @@
 fn date<Input>() -> impl Parser<Input, Output = Date>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     (
         many::<String, _, _>(digit()),
@@ -130,7 +125,6 @@
 fn time<Input>() -> impl Parser<Input, Output = Time>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     (
         two_digits(),
@@ -156,7 +150,6 @@
 fn date_time<Input>() -> impl Parser<Input, Output = DateTime>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     (date(), char('T'), time()).map(|(date, _, time)| DateTime { date, time })
 }
diff --git a/crates/combine/examples/ini.rs b/crates/combine/examples/ini.rs
index 2d41619..2ef43e4 100644
--- a/crates/combine/examples/ini.rs
+++ b/crates/combine/examples/ini.rs
@@ -41,8 +41,6 @@
 fn property<Input>() -> impl Parser<Input, Output = (String, String)>
 where
     Input: Stream<Token = char>,
-    // Necessary due to rust-lang/rust#24159
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     (
         many1(satisfy(|c| c != '=' && c != '[' && c != ';')),
@@ -56,7 +54,6 @@
 fn whitespace<Input>() -> impl Parser<Input>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     let comment = (token(';'), skip_many(satisfy(|c| c != '\n'))).map(|_| ());
     // Wrap the `spaces().or(comment)` in `skip_many` so that it skips alternating whitespace and
@@ -67,7 +64,6 @@
 fn properties<Input>() -> impl Parser<Input, Output = HashMap<String, String>>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     // After each property we skip any whitespace that followed it
     many(property().skip(whitespace()))
@@ -76,7 +72,6 @@
 fn section<Input>() -> impl Parser<Input, Output = (String, HashMap<String, String>)>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     (
         between(token('['), token(']'), many(satisfy(|c| c != ']'))),
@@ -90,7 +85,6 @@
 fn ini<Input>() -> impl Parser<Input, Output = Ini>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     (whitespace(), properties(), many(section()))
         .map(|(_, global, sections)| Ini { global, sections })
diff --git a/crates/combine/src/error.rs b/crates/combine/src/error.rs
index 23326c7..f403521 100644
--- a/crates/combine/src/error.rs
+++ b/crates/combine/src/error.rs
@@ -296,7 +296,6 @@
     /// //and " respectively
     /// fn char<Input>(input: &mut Input) -> StdParseResult<char, Input>
     ///     where Input: Stream<Token = char>,
-    ///           Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
     /// {
     ///     let (c, committed) = satisfy(|c| c != '"').parse_stream(input).into_result()?;
     ///     match c {
diff --git a/crates/combine/src/lib.rs b/crates/combine/src/lib.rs
index 77e3e23..04faeda 100644
--- a/crates/combine/src/lib.rs
+++ b/crates/combine/src/lib.rs
@@ -84,10 +84,10 @@
 //! If we need a parser that is mutually recursive or if we want to export a reusable parser the
 //! [`parser!`] macro can be used. In effect it makes it possible to return a parser without naming
 //! the type of the parser (which can be very large due to combine's trait based approach). While
-//! it is possible to do avoid naming the type without the macro those solutions require either allocation
-//! (`Box<dyn Parser< Input, Output = O, PartialState = P>>`) or nightly rust via `impl Trait`. The
-//! macro thus threads the needle and makes it possible to have non-allocating, anonymous parsers
-//! on stable rust.
+//! it is possible to do avoid naming the type without the macro those solutions require either
+//! allocation (`Box<dyn Parser< Input, Output = O, PartialState = P>>`) or via `impl Trait` in the
+//! return position. The macro thus threads the needle and makes it possible to have
+//! non-allocating, anonymous parsers on stable rust.
 //!
 //! ```
 //! #[macro_use]
@@ -108,8 +108,6 @@
 //! // `impl Parser` can be used to create reusable parsers with zero overhead
 //! fn expr_<Input>() -> impl Parser< Input, Output = Expr>
 //!     where Input: Stream<Token = char>,
-//!           // Necessary due to rust-lang/rust#24159
-//!           Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 //! {
 //!     let word = many1(letter());
 //!
@@ -241,8 +239,8 @@
 /// The expression which creates the parser should have no side effects as it may be called
 /// multiple times even during a single parse attempt.
 ///
-/// NOTE: If you are using rust nightly you can use `impl Trait` instead. See the [json parser][] for
-/// an example.
+/// NOTE: You can use `impl Trait` in the return position instead. See the [json parser][] for an
+/// example.
 ///
 /// [json parser]:https://github.com/Marwes/combine/blob/master/benches/json.rs
 ///
@@ -259,7 +257,6 @@
 ///     fn integer[Input]()(Input) -> i32
 ///     where [
 ///         Input: Stream<Token = char>,
-///         Input::Error: ParseError<char, Input::Range, Input::Position>,
 ///         <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError:
 ///             From<::std::num::ParseIntError>,
 ///     ]
@@ -283,7 +280,6 @@
 ///     pub fn integer_or_string[Input]()(Input) -> IntOrString
 ///     where [
 ///         Input: Stream<Token = char>,
-///         Input::Error: ParseError<char, Input::Range, Input::Position>,
 ///         <Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError:
 ///             From<::std::num::ParseIntError>,
 ///     ]
@@ -709,7 +705,6 @@
     fn integer<Input>(input: &mut Input) -> StdParseResult<i64, Input>
     where
         Input: Stream<Token = char>,
-        Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
     {
         let (s, input) = many1::<String, _, _>(digit())
             .expected("integer")
@@ -834,7 +829,6 @@
     fn term<Input>(input: &mut Input) -> StdParseResult<Expr, Input>
     where
         Input: Stream<Token = char>,
-        Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
     {
         fn times(l: Expr, r: Expr) -> Expr {
             Expr::Times(Box::new(l), Box::new(r))
diff --git a/crates/combine/src/parser/byte.rs b/crates/combine/src/parser/byte.rs
index c70769d..4132912 100644
--- a/crates/combine/src/parser/byte.rs
+++ b/crates/combine/src/parser/byte.rs
@@ -1,7 +1,7 @@
 //! Module containing parsers specialized on byte streams.
 
 use crate::{
-    error::{self, ParseError, ParseResult::*},
+    error::{self, ParseResult::*},
     parser::{
         combinator::no_partial,
         range::{take_fn, TakeRange},
@@ -24,7 +24,6 @@
 pub fn byte<Input>(c: u8) -> Token<Input>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     token(c)
 }
@@ -51,7 +50,6 @@
 pub fn digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     byte_parser!(digit, Digit, is_ascii_digit())
 }
@@ -69,7 +67,6 @@
 pub fn space<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     byte_parser!(space, Space, is_ascii_whitespace)
 }
@@ -87,7 +84,6 @@
 pub fn spaces<Input>() -> impl Parser<Input, Output = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     skip_many(space()).expected("whitespaces")
 }
@@ -103,7 +99,6 @@
 pub fn newline<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch: u8| ch == b'\n').expected("lf newline")
 }
@@ -120,7 +115,6 @@
 pub fn crlf<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     no_partial(satisfy(|ch: u8| ch == b'\r').with(newline())).expected("crlf newline")
 }
@@ -136,7 +130,6 @@
 pub fn tab<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch| ch == b'\t').expected("tab")
 }
@@ -152,7 +145,6 @@
 pub fn upper<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     byte_parser!(upper, Upper, is_ascii_uppercase)
 }
@@ -168,7 +160,6 @@
 pub fn lower<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     byte_parser!(lower, Lower, is_ascii_lowercase)
 }
@@ -185,7 +176,6 @@
 pub fn alpha_num<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     byte_parser!(alpha_num, AlphaNum, is_ascii_alphanumeric)
 }
@@ -202,7 +192,6 @@
 pub fn letter<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     byte_parser!(letter, Letter, is_ascii_alphabetic)
 }
@@ -218,7 +207,6 @@
 pub fn oct_digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch| (b'0'..=b'7').contains(&ch)).expected("octal digit")
 }
@@ -234,7 +222,6 @@
 pub fn hex_digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
 where
     Input: Stream<Token = u8>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     byte_parser!(hex_digit, HexDigit, is_ascii_hexdigit())
 }
@@ -262,7 +249,6 @@
 pub fn bytes['a, 'b, Input](s: &'static [u8])(Input) -> &'a [u8]
 where [
     Input: Stream<Token = u8, Range = &'b [u8]>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 ]
 {
     bytes_cmp(s, |l: u8, r: u8| l == r)
@@ -293,7 +279,6 @@
 where [
     C: FnMut(u8, u8) -> bool,
     Input: Stream<Token = u8, Range = &'b [u8]>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 ]
 {
     let s = *s;
@@ -457,7 +442,6 @@
             pub fn $be_name<'a, Input>() -> impl Parser<Input, Output = $output_type, PartialState = ()>
             where
                 Input: Stream<Token = u8>,
-                Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
             {
                 parser(|input: &mut Input| {
                     let checkpoint = input.checkpoint();
@@ -479,7 +463,6 @@
             pub fn $le_name<'a, Input>() -> impl Parser<Input, Output = $output_type, PartialState = ()>
             where
                 Input: Stream<Token = u8>,
-                Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
             {
                 parser(|input: &mut Input| {
                     let checkpoint = input.checkpoint();
diff --git a/crates/combine/src/parser/char.rs b/crates/combine/src/parser/char.rs
index e93b446..0f673c0 100644
--- a/crates/combine/src/parser/char.rs
+++ b/crates/combine/src/parser/char.rs
@@ -1,7 +1,6 @@
 //! Module containing parsers specialized on character streams.
 
 use crate::{
-    error::ParseError,
     parser::{
         combinator::no_partial,
         repeat::skip_many,
@@ -22,7 +21,6 @@
 pub fn char<Input>(c: char) -> Token<Input>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     token(c)
 }
@@ -63,7 +61,6 @@
 pub fn space<Input>() -> impl Parser<Input, Output = char, PartialState = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     let f: fn(char) -> bool = char::is_whitespace;
     satisfy(f).expected("whitespace")
@@ -84,7 +81,6 @@
 pub fn spaces<Input>() -> impl Parser<Input, Output = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     skip_many(space()).expected("whitespaces")
 }
@@ -100,7 +96,6 @@
 pub fn newline<Input>() -> impl Parser<Input, Output = char, PartialState = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch: char| ch == '\n').expected("lf newline")
 }
@@ -117,7 +112,6 @@
 pub fn crlf<Input>() -> impl Parser<Input, Output = char, PartialState = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     no_partial(satisfy(|ch: char| ch == '\r').with(newline())).expected("crlf newline")
 }
@@ -133,7 +127,6 @@
 pub fn tab<Input>() -> impl Parser<Input, Output = char, PartialState = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch: char| ch == '\t').expected("tab")
 }
@@ -151,7 +144,6 @@
 pub fn upper<Input>() -> impl Parser<Input, Output = char, PartialState = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch: char| ch.is_uppercase()).expected("uppercase letter")
 }
@@ -169,7 +161,6 @@
 pub fn lower<Input>() -> impl Parser<Input, Output = char, PartialState = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch: char| ch.is_lowercase()).expected("lowercase letter")
 }
@@ -188,7 +179,6 @@
 pub fn alpha_num<Input>() -> impl Parser<Input, Output = char, PartialState = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch: char| ch.is_alphanumeric()).expected("letter or digit")
 }
@@ -207,7 +197,6 @@
 pub fn letter<Input>() -> impl Parser<Input, Output = char, PartialState = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch: char| ch.is_alphabetic()).expected("letter")
 }
@@ -223,7 +212,6 @@
 pub fn oct_digit<Input>() -> impl Parser<Input, Output = char, PartialState = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch: char| ch.is_digit(8)).expected("octal digit")
 }
@@ -239,7 +227,6 @@
 pub fn hex_digit<Input>() -> impl Parser<Input, Output = char, PartialState = ()>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     satisfy(|ch: char| ch.is_digit(0x10)).expected("hexadecimal digit")
 }
@@ -260,7 +247,6 @@
 pub fn string<'a, Input>(s: &'static str) -> impl Parser<Input, Output = &'a str>
 where
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     string_cmp(s, |l, r| l == r)
 }
@@ -282,7 +268,6 @@
 where
     C: FnMut(char, char) -> bool,
     Input: Stream<Token = char>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     tokens_cmp(s.chars(), cmp).map(move |_| s).expected(s)
 }
diff --git a/crates/combine/src/parser/combinator.rs b/crates/combine/src/parser/combinator.rs
index bb06b89..e7a7ba1 100644
--- a/crates/combine/src/parser/combinator.rs
+++ b/crates/combine/src/parser/combinator.rs
@@ -360,7 +360,6 @@
     P: Parser<Input>,
     F: FnMut(P::Output) -> Result<O, E>,
     E: Into<<Input::Error as ParseError<Input::Token, Input::Range, Input::Position>>::StreamError>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     type Output = O;
     type PartialState = P::PartialState;
@@ -1002,7 +1001,6 @@
 /// fn example<Input>() -> impl Parser<Input, Output = (char, char), PartialState = AnySendSyncPartialState>
 /// where
 ///     Input: Stream<Token = char>,
-///     Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 /// {
 ///     any_send_sync_partial_state((letter(), letter()))
 /// }
@@ -1374,7 +1372,6 @@
 /// fn expr<Input>() -> FnOpaque<Input, Expr>
 /// where
 ///     Input: Stream<Token = char>,
-///     Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 /// {
 ///     opaque!(
 ///         // `no_partial` disables partial parsing and replaces the partial state with `()`,
@@ -1517,7 +1514,6 @@
 where
     P: Parser<Input>,
     Input: Stream<Position = Span<Q>>,
-    Input::Error: ParseError<Input::Token, Input::Range, Span<Q>>,
     Q: Ord + Clone,
 {
     type Output = P::Output;
diff --git a/crates/combine/src/parser/function.rs b/crates/combine/src/parser/function.rs
index 45258d4..4d93b4a 100644
--- a/crates/combine/src/parser/function.rs
+++ b/crates/combine/src/parser/function.rs
@@ -144,7 +144,6 @@
 /// impl Interner {
 ///     fn string<Input>(&self, input: &mut Input) -> StdParseResult<u32, Input>
 ///         where Input: Stream<Token = char>,
-///               Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 ///     {
 ///         many(letter())
 ///             .map(|s: String| self.0.get(&s).cloned().unwrap_or(0))
diff --git a/crates/combine/src/parser/sequence.rs b/crates/combine/src/parser/sequence.rs
index 166b89d..8e0ecc9 100644
--- a/crates/combine/src/parser/sequence.rs
+++ b/crates/combine/src/parser/sequence.rs
@@ -109,7 +109,6 @@
                 $h: &mut $h $(, $id : &mut $id )*
             ) -> ParseResult<($h::Output, $($id::Output),*), <Input as StreamOnce>::Error>
                 where Input: Stream,
-                      Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
                       $h: Parser<Input>,
                       $($id: Parser<Input>),*
             {
@@ -143,7 +142,6 @@
         #[allow(non_snake_case)]
         impl <Input: Stream, $h:, $($id:),*> Parser<Input> for ($h, $($id),*)
             where Input: Stream,
-                  Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
                   $h: Parser<Input>,
                   $($id: Parser<Input>),*
         {
diff --git a/crates/combine/src/stream/buf_reader.rs b/crates/combine/src/stream/buf_reader.rs
index fa7b928..e6c2762 100644
--- a/crates/combine/src/stream/buf_reader.rs
+++ b/crates/combine/src/stream/buf_reader.rs
@@ -8,11 +8,7 @@
 ))]
 use std::pin::Pin;
 
-#[cfg(any(
-    feature = "futures-03",
-    feature = "tokio-02",
-    feature = "tokio-03"
-))]
+#[cfg(any(feature = "futures-03", feature = "tokio-02", feature = "tokio-03"))]
 use std::mem::MaybeUninit;
 
 #[cfg(feature = "futures-core-03")]
@@ -361,14 +357,17 @@
 where
     R: Read,
 {
+    let size = 8 * 1024;
     if !buf.has_remaining_mut() {
-        buf.reserve(8 * 1024);
+        buf.reserve(size);
     }
 
     // Copy of tokio's poll_read_buf method (but it has to force initialize the buffer)
     let n = {
         let bs = buf.chunk_mut();
 
+        let initial_size = bs.len().min(size);
+        let bs = &mut bs[..initial_size];
         for i in 0..bs.len() {
             bs.write_byte(i, 0);
         }
diff --git a/crates/combine/src/stream/mod.rs b/crates/combine/src/stream/mod.rs
index b1f3d07..a395612 100644
--- a/crates/combine/src/stream/mod.rs
+++ b/crates/combine/src/stream/mod.rs
@@ -165,7 +165,6 @@
 impl<Input> Stream for Input
 where
     Input: StreamOnce + Positioned + ResetStream,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
 }
 
@@ -1401,7 +1400,7 @@
 ///         },
 ///         |input, _position| combine::easy::Stream::from(input),
 ///     ).map_err(combine::easy::Errors::<u8, &[u8], _>::from),
-///     Ok(824),
+///     Ok(773),
 /// );
 /// ```
 #[cfg(feature = "std")]
@@ -1497,7 +1496,7 @@
 ///             },
 ///             |input, _position| combine::easy::Stream::from(input),
 ///         ).map_err(combine::easy::Errors::<u8, &[u8], _>::from),
-///         Ok(824),
+///         Ok(773),
 ///     );
 /// }
 /// ```
@@ -1591,7 +1590,7 @@
 ///             },
 ///             |input, _position| combine::easy::Stream::from(input),
 ///         ).map_err(combine::easy::Errors::<u8, &[u8], _>::from),
-///         Ok(824),
+///         Ok(773),
 ///     );
 /// }
 /// ```
@@ -1687,7 +1686,7 @@
 ///             },
 ///             |input, _position| combine::easy::Stream::from(input),
 ///         ).map_err(combine::easy::Errors::<u8, &[u8], _>::from),
-///         Ok(824),
+///         Ok(773),
 ///     );
 /// }
 /// ```
@@ -1783,7 +1782,7 @@
 ///             },
 ///             |input, _position| combine::easy::Stream::from(input),
 ///         ).map_err(combine::easy::Errors::<u8, &[u8], _>::from),
-///         Ok(824),
+///         Ok(773),
 ///     );
 /// }
 /// ```
diff --git a/crates/combine/src/stream/position.rs b/crates/combine/src/stream/position.rs
index 137b05e..1712e50 100644
--- a/crates/combine/src/stream/position.rs
+++ b/crates/combine/src/stream/position.rs
@@ -111,13 +111,13 @@
     }
 }
 
-impl<Input, X, E> Positioned for Stream<Input, X>
+impl<Input, X, S> Positioned for Stream<Input, X>
 where
     Input: StreamOnce,
     X: Positioner<Input::Token>,
-    E: StreamError<Input::Token, Input::Range>,
-    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = E>,
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = E>,
+    S: StreamError<Input::Token, Input::Range>,
+    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
+    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
 {
     #[inline]
     fn position(&self) -> Self::Position {
@@ -130,8 +130,8 @@
     Input: StreamOnce,
     X: Positioner<Input::Token>,
     S: StreamError<Input::Token, Input::Range>,
-    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>
-        + ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
+    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
+    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
 {
     type Token = Input::Token;
     type Range = Input::Range;
diff --git a/crates/combine/tests/async.rs b/crates/combine/tests/async.rs
index bedaa72..e523d3d 100644
--- a/crates/combine/tests/async.rs
+++ b/crates/combine/tests/async.rs
@@ -277,8 +277,6 @@
 ) -> impl Parser<Input, Output = String, PartialState = AnySendPartialState> + 'a
 where
     Input: RangeStream<Token = char, Range = &'a str> + 'a,
-    // Necessary due to rust-lang/rust#24159
-    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
 {
     let content_length = range("Content-Length: ").with(
         range::recognize(skip_many1(digit())).and_then(|digits: &str| {
@@ -634,7 +632,7 @@
     assert_eq!(result.unwrap(), [""]);
 }
 
-const WORDS_IN_README: usize = 824;
+const WORDS_IN_README: usize = 773;
 
 #[test]
 fn decode_std() {
@@ -850,5 +848,5 @@
             }
         }
     }
-    assert_eq!(824, count);
+    assert_eq!(WORDS_IN_README, count);
 }
diff --git a/crates/crossbeam-channel/.cargo-checksum.json b/crates/crossbeam-channel/.cargo-checksum.json
index a9bfaf1..6784db9 100644
--- a/crates/crossbeam-channel/.cargo-checksum.json
+++ b/crates/crossbeam-channel/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"2817250fc57879a0bef77761f50ec7a6a6b77888c6159bc4a1207f23a1a1980d","Cargo.lock":"7f969ed9666d57717d774f3b9d8147d4532e2a020d25876c42657f1bace44a1a","Cargo.toml":"482924c4a945cbb5e3f47cf30405f5baecededde7018cd1423f20b3159e48a26","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"b16db96b93b1d7cf7bea533f572091ec6bca3234fbe0a83038be772ff391a44c","README.md":"5dfb91ebb498dec49948a440a53977109ec532388170e567c3c2a0339589aa4c","benches/crossbeam.rs":"96cb1abd23cac3ef8a7174a802e94609926b555bb02c9658c78723d433f1dd92","examples/fibonacci.rs":"4e88fa40048cdc31e9c7bb60347d46f92543d7ddf39cab3b52bfe44affdb6a02","examples/matching.rs":"63c250e164607a7a9f643d46f107bb5da846d49e89cf9069909562d20e530f71","examples/stopwatch.rs":"d02121258f08d56f1eb7997e19bcb9bacb6836cfa0abbba90a9e59d8a50ae5cf","src/channel.rs":"13fbbe12d4ec361855af1c3587fc80aea5f537db8dc44dd4f66c9e2b4ae9f5c1","src/context.rs":"ff4d39639ddf16aaab582d4a5f3d10ef2c71afe1abbf4e60f3d9d2ddbd72c230","src/counter.rs":"c49a9f44587888850edeb62f7c8ecd1acecb39c836834254ff3ac934c478440a","src/err.rs":"44cb2024ee6b0cd6fd24996430e53720769f64b4ac35016bc3e05cb9db48681d","src/flavors/array.rs":"04839c29b0adcc50c0af6882b9bd68b42ffa7fdaa435ce01bc636c694f33c613","src/flavors/at.rs":"04e07861534f2f7d5b5f884f2f5bc9c008427e6d0afa1c8ad401e1d7e54b57eb","src/flavors/list.rs":"9c32d8da8e232eee0f2c62df57d379dd95a17dbe69f7eada01a657d21743090f","src/flavors/mod.rs":"3d9d43bc38b0adb18c96c995c2bd3421d8e33ab6c30b20c3c467d21d48e485dc","src/flavors/never.rs":"747da857aa1a7601641f23f4930e6ad00ebaf50456d9be5c7aa270e2ecc24dcb","src/flavors/tick.rs":"0916ca3faef30b8cc591137701c456d5fc5b5b49cb1edad1e3a80d35bae222bb","src/flavors/zero.rs":"7458eb0ece475dc5093b4f2cde13f6de57e4f70291258850de4fa3c951c8f594","src/lib.rs":"06b3ce0105b1260ae218ed1865b09f20a8235d63c73c0e613f08806bc868eac3","src/select.rs":"966fb1abb05f900b84a00ff2bd99b4934aafc793d9083ad4f31c551cc9f6aa5f","src/select_macro.rs":"8e77a560081dc2cddfc9523889e0d2bfa6ef34edf85c145792c2287d80b4bb7c","src/utils.rs":"639015cb52a2e5990e830d7be8bff899fad81b30f4b2089ad9c3fd920bec7b31","src/waker.rs":"6839108d1c9357b3c0c1c162c8b4633ff5ac4f756e95e677ac1293e7df942635","tests/after.rs":"0154a8e152880db17a20514ecdd49dabc361d3629858d119b9746b5e932c780c","tests/array.rs":"a57ae6264e676f573d7adb5c4b024994e98bc6811352516adb3444f880f7125e","tests/golang.rs":"7b2ef219ba8a21841c133512f3a540f8279a2458304e9bbed7da81d6091ecd82","tests/iter.rs":"25dc02135bbae9d47a30f9047661648e66bdc134e40ba78bc2fbacbb8b3819bc","tests/list.rs":"3d1a4ae23bb6b4767242b8109a8efda26f1d3b28c0f90da3368f8eb9ca0eee37","tests/mpsc.rs":"b982bcae005e8ecc4fac7477d41c83f998ad21793a2fc2097370dbe48dc26889","tests/never.rs":"ee40c4fc4dd5af4983fae8de6927f52b81174d222c162f745b26c4a6c7108e4f","tests/ready.rs":"4361352fa94254041e6c73e97b13be032c2d51c741f2a50519efe3000cf4dc28","tests/same_channel.rs":"2bab761443671e841e1b2476bd8082d75533a2f6be7946f5dbcee67cdc82dccb","tests/select.rs":"101ea8afd9a40d24c2d2aec29e5f2fdc4faac51aa1d7c9fe077b364f12edd206","tests/select_macro.rs":"25c43b7705f45f882b0d939b149119dbf2f833abecdc21c13df2e9bf8eeae114","tests/thread_locals.rs":"f42fcddca959b3b44cd545b92949d65e33a54332b27f490ec92f9f29b7f8290c","tests/tick.rs":"5f697bd14c48505d932e82065b5302ef668e1cc19cac18e8ac22e0c83c221c1d","tests/zero.rs":"9c5af802d5efb2c711f8242b8905ed29cc2601e48dbd95e41c7e6fbfe2918398"},"package":"176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"6b520b783f5e0c17c6caa975defb9ed6e0ae1254a6a41a9bcd03d249bc942289","Cargo.lock":"605ed4a922e22b42c8a7b75624dfd55d6f0bc96bf76bbf016b003a2c44ddc29a","Cargo.toml":"0f7a8020ede552c5370c101973e8b77cdf5ce6d41f4b6f7b1420b97491fd1e24","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"b16db96b93b1d7cf7bea533f572091ec6bca3234fbe0a83038be772ff391a44c","README.md":"5dfb91ebb498dec49948a440a53977109ec532388170e567c3c2a0339589aa4c","benches/crossbeam.rs":"96cb1abd23cac3ef8a7174a802e94609926b555bb02c9658c78723d433f1dd92","examples/fibonacci.rs":"4e88fa40048cdc31e9c7bb60347d46f92543d7ddf39cab3b52bfe44affdb6a02","examples/matching.rs":"63c250e164607a7a9f643d46f107bb5da846d49e89cf9069909562d20e530f71","examples/stopwatch.rs":"d02121258f08d56f1eb7997e19bcb9bacb6836cfa0abbba90a9e59d8a50ae5cf","src/channel.rs":"13fbbe12d4ec361855af1c3587fc80aea5f537db8dc44dd4f66c9e2b4ae9f5c1","src/context.rs":"477cc2b7bac7502fd2459288a58cc76f015b1ec8e87b853cda77ccb1808c6334","src/counter.rs":"b8f1e48ec634a7dab8e04c485209161587ecbbd2d57b0825467164d4554c6249","src/err.rs":"44cb2024ee6b0cd6fd24996430e53720769f64b4ac35016bc3e05cb9db48681d","src/flavors/array.rs":"79bc219187c9f40b156b9fe551c1176b66bf73e6d48905b23a2d74c6366a2205","src/flavors/at.rs":"04e07861534f2f7d5b5f884f2f5bc9c008427e6d0afa1c8ad401e1d7e54b57eb","src/flavors/list.rs":"280f55b51cefe9351a52c8d2186de368b688ad06885d083efe7e831726846520","src/flavors/mod.rs":"3d9d43bc38b0adb18c96c995c2bd3421d8e33ab6c30b20c3c467d21d48e485dc","src/flavors/never.rs":"747da857aa1a7601641f23f4930e6ad00ebaf50456d9be5c7aa270e2ecc24dcb","src/flavors/tick.rs":"0916ca3faef30b8cc591137701c456d5fc5b5b49cb1edad1e3a80d35bae222bb","src/flavors/zero.rs":"f9cbc9e035fadce808a4af86a223cfded89990ba1e9acfe731fb17a7fe12b432","src/lib.rs":"5b1c406fd1ce6140feae9000be361858da2aabe7fc9fffd0eafcb88020d2b268","src/select.rs":"7aa8addb82427141b0a4afa16fa4d23a02becab115a0a5a6d6d327728fd0672f","src/select_macro.rs":"522cfc8155825c1f260922c17ea6ef8ae672cf94863750c1a6115db2cbc9fc18","src/utils.rs":"9bd81aeb385a81409a63f4b9edc35444c7fd1d2724725f9c34ad7ca39dd69a18","src/waker.rs":"017f87a120d945502701c0dba79062c7fe55d44e5907cc6f8605b4510c90d529","tests/after.rs":"0154a8e152880db17a20514ecdd49dabc361d3629858d119b9746b5e932c780c","tests/array.rs":"a57ae6264e676f573d7adb5c4b024994e98bc6811352516adb3444f880f7125e","tests/golang.rs":"7b2ef219ba8a21841c133512f3a540f8279a2458304e9bbed7da81d6091ecd82","tests/iter.rs":"25dc02135bbae9d47a30f9047661648e66bdc134e40ba78bc2fbacbb8b3819bc","tests/list.rs":"3d1a4ae23bb6b4767242b8109a8efda26f1d3b28c0f90da3368f8eb9ca0eee37","tests/mpsc.rs":"5fbb5342fa7c9e4bcda5545255e0979dc6b9ba638edee127acf75372c18c925f","tests/never.rs":"ee40c4fc4dd5af4983fae8de6927f52b81174d222c162f745b26c4a6c7108e4f","tests/ready.rs":"4361352fa94254041e6c73e97b13be032c2d51c741f2a50519efe3000cf4dc28","tests/same_channel.rs":"2bab761443671e841e1b2476bd8082d75533a2f6be7946f5dbcee67cdc82dccb","tests/select.rs":"101ea8afd9a40d24c2d2aec29e5f2fdc4faac51aa1d7c9fe077b364f12edd206","tests/select_macro.rs":"4d6d52ad48f385c5b8f5023a590e00e7a4b632e80bd929b6fc89a53f5faee515","tests/thread_locals.rs":"f42fcddca959b3b44cd545b92949d65e33a54332b27f490ec92f9f29b7f8290c","tests/tick.rs":"5f697bd14c48505d932e82065b5302ef668e1cc19cac18e8ac22e0c83c221c1d","tests/zero.rs":"9c5af802d5efb2c711f8242b8905ed29cc2601e48dbd95e41c7e6fbfe2918398"},"package":"33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"}
\ No newline at end of file
diff --git a/crates/crossbeam-channel/Android.bp b/crates/crossbeam-channel/Android.bp
index 395febf..407bdf1 100644
--- a/crates/crossbeam-channel/Android.bp
+++ b/crates/crossbeam-channel/Android.bp
@@ -18,7 +18,7 @@
     host_supported: true,
     crate_name: "crossbeam_channel",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.5.11",
+    cargo_pkg_version: "0.5.13",
     crate_root: "src/lib.rs",
     edition: "2021",
     features: [
diff --git a/crates/crossbeam-channel/CHANGELOG.md b/crates/crossbeam-channel/CHANGELOG.md
index 2f172fb..4d7fa0f 100644
--- a/crates/crossbeam-channel/CHANGELOG.md
+++ b/crates/crossbeam-channel/CHANGELOG.md
@@ -1,3 +1,11 @@
+# Version 0.5.13
+
+- Add `select_biased!` macro. (#1040)
+
+# Version 0.5.12
+
+- Fix memory leak in unbounded channel. (#1084)
+
 # Version 0.5.11
 
 - Remove dependency on `cfg-if`. (#1072)
diff --git a/crates/crossbeam-channel/Cargo.lock b/crates/crossbeam-channel/Cargo.lock
index 051ab47..ec55f94 100644
--- a/crates/crossbeam-channel/Cargo.lock
+++ b/crates/crossbeam-channel/Cargo.lock
@@ -10,7 +10,7 @@
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.11"
+version = "0.5.13"
 dependencies = [
  "crossbeam-utils",
  "num_cpus",
@@ -20,18 +20,15 @@
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.18"
+version = "0.8.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
-dependencies = [
- "cfg-if",
-]
+checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
 
 [[package]]
 name = "getrandom"
-version = "0.2.11"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
@@ -40,15 +37,15 @@
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.3"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
 
 [[package]]
 name = "libc"
-version = "0.2.152"
+version = "0.2.154"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
+checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
 
 [[package]]
 name = "num_cpus"
@@ -108,9 +105,9 @@
 
 [[package]]
 name = "signal-hook-registry"
-version = "1.4.1"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
 dependencies = [
  "libc",
 ]
diff --git a/crates/crossbeam-channel/Cargo.toml b/crates/crossbeam-channel/Cargo.toml
index 8b64867..fb617f0 100644
--- a/crates/crossbeam-channel/Cargo.toml
+++ b/crates/crossbeam-channel/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2021"
 rust-version = "1.60"
 name = "crossbeam-channel"
-version = "0.5.11"
+version = "0.5.13"
 description = "Multi-producer multi-consumer channels for message passing"
 homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel"
 readme = "README.md"
@@ -48,3 +48,7 @@
 [features]
 default = ["std"]
 std = ["crossbeam-utils/std"]
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+priority = 0
diff --git a/crates/crossbeam-channel/METADATA b/crates/crossbeam-channel/METADATA
index 2197697..d213f47 100644
--- a/crates/crossbeam-channel/METADATA
+++ b/crates/crossbeam-channel/METADATA
@@ -1,17 +1,17 @@
 name: "crossbeam-channel"
 description: "Multi-producer multi-consumer channels for message passing"
 third_party {
-  version: "0.5.11"
+  version: "0.5.13"
   license_type: NOTICE
   last_upgrade_date {
     year: 2024
-    month: 2
-    day: 1
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/crossbeam-channel"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/crossbeam-channel/crossbeam-channel-0.5.11.crate"
-    version: "0.5.11"
+    value: "https://static.crates.io/crates/crossbeam-channel/crossbeam-channel-0.5.13.crate"
+    version: "0.5.13"
   }
 }
diff --git a/crates/crossbeam-channel/src/context.rs b/crates/crossbeam-channel/src/context.rs
index 7467b80..4230027 100644
--- a/crates/crossbeam-channel/src/context.rs
+++ b/crates/crossbeam-channel/src/context.rs
@@ -41,7 +41,7 @@
     where
         F: FnOnce(&Context) -> R,
     {
-        thread_local! {
+        std::thread_local! {
             /// Cached thread-local context.
             static CONTEXT: Cell<Option<Context>> = Cell::new(Some(Context::new()));
         }
diff --git a/crates/crossbeam-channel/src/counter.rs b/crates/crossbeam-channel/src/counter.rs
index 2c27f7c..f8e8b37 100644
--- a/crates/crossbeam-channel/src/counter.rs
+++ b/crates/crossbeam-channel/src/counter.rs
@@ -1,5 +1,6 @@
 //! Reference counter for channels.
 
+use std::boxed::Box;
 use std::isize;
 use std::ops;
 use std::process;
diff --git a/crates/crossbeam-channel/src/flavors/array.rs b/crates/crossbeam-channel/src/flavors/array.rs
index ccc47b5..4087c05 100644
--- a/crates/crossbeam-channel/src/flavors/array.rs
+++ b/crates/crossbeam-channel/src/flavors/array.rs
@@ -8,6 +8,7 @@
 //!   - <http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue>
 //!   - <https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub>
 
+use std::boxed::Box;
 use std::cell::UnsafeCell;
 use std::mem::{self, MaybeUninit};
 use std::ptr;
@@ -242,7 +243,7 @@
             let slot = unsafe { self.buffer.get_unchecked(index) };
             let stamp = slot.stamp.load(Ordering::Acquire);
 
-            // If the the stamp is ahead of the head by 1, we may attempt to pop.
+            // If the stamp is ahead of the head by 1, we may attempt to pop.
             if head + 1 == stamp {
                 let new = if index + 1 < self.cap {
                     // Same lap, incremented index.
diff --git a/crates/crossbeam-channel/src/flavors/list.rs b/crates/crossbeam-channel/src/flavors/list.rs
index 638d6c2..e7fb615 100644
--- a/crates/crossbeam-channel/src/flavors/list.rs
+++ b/crates/crossbeam-channel/src/flavors/list.rs
@@ -1,5 +1,6 @@
 //! Unbounded channel implemented as a linked list.
 
+use std::boxed::Box;
 use std::cell::UnsafeCell;
 use std::marker::PhantomData;
 use std::mem::MaybeUninit;
@@ -582,7 +583,10 @@
         }
 
         let mut head = self.head.index.load(Ordering::Acquire);
-        let mut block = self.head.block.load(Ordering::Acquire);
+        // The channel may be uninitialized, so we have to swap to avoid overwriting any sender's attempts
+        // to initialize the first block before noticing that the receivers disconnected. Late allocations
+        // will be deallocated by the sender in Drop
+        let mut block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel);
 
         // If we're going to be dropping messages we need to synchronize with initialization
         if head >> SHIFT != tail >> SHIFT {
@@ -595,6 +599,7 @@
                 block = self.head.block.load(Ordering::Acquire);
             }
         }
+
         unsafe {
             // Drop all messages between head and tail and deallocate the heap-allocated blocks.
             while head >> SHIFT != tail >> SHIFT {
@@ -622,7 +627,6 @@
             }
         }
         head &= !MARK_BIT;
-        self.head.block.store(ptr::null_mut(), Ordering::Release);
         self.head.index.store(head, Ordering::Release);
     }
 
diff --git a/crates/crossbeam-channel/src/flavors/zero.rs b/crates/crossbeam-channel/src/flavors/zero.rs
index aae2ea3..feaaca1 100644
--- a/crates/crossbeam-channel/src/flavors/zero.rs
+++ b/crates/crossbeam-channel/src/flavors/zero.rs
@@ -2,6 +2,7 @@
 //!
 //! This kind of channel is also known as *rendezvous* channel.
 
+use std::boxed::Box;
 use std::cell::UnsafeCell;
 use std::marker::PhantomData;
 use std::sync::atomic::{AtomicBool, Ordering};
diff --git a/crates/crossbeam-channel/src/lib.rs b/crates/crossbeam-channel/src/lib.rs
index 0bb98a2..93e190b 100644
--- a/crates/crossbeam-channel/src/lib.rs
+++ b/crates/crossbeam-channel/src/lib.rs
@@ -321,6 +321,7 @@
 //! [`iter`]: Receiver::iter
 //! [`try_iter`]: Receiver::try_iter
 
+#![no_std]
 #![doc(test(
     no_crate_inject,
     attr(
@@ -334,7 +335,9 @@
     rust_2018_idioms,
     unreachable_pub
 )]
-#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(feature = "std")]
+extern crate std;
 
 #[cfg(feature = "std")]
 mod channel;
diff --git a/crates/crossbeam-channel/src/select.rs b/crates/crossbeam-channel/src/select.rs
index 3eb0b97..4bfa65c 100644
--- a/crates/crossbeam-channel/src/select.rs
+++ b/crates/crossbeam-channel/src/select.rs
@@ -4,6 +4,7 @@
 use std::marker::PhantomData;
 use std::mem;
 use std::time::{Duration, Instant};
+use std::vec::Vec;
 
 use crossbeam_utils::Backoff;
 
@@ -176,6 +177,7 @@
 fn run_select(
     handles: &mut [(&dyn SelectHandle, usize, *const u8)],
     timeout: Timeout,
+    is_biased: bool,
 ) -> Option<(Token, usize, *const u8)> {
     if handles.is_empty() {
         // Wait until the timeout and return.
@@ -192,8 +194,10 @@
         }
     }
 
-    // Shuffle the operations for fairness.
-    utils::shuffle(handles);
+    if !is_biased {
+        // Shuffle the operations for fairness.
+        utils::shuffle(handles);
+    }
 
     // Create a token, which serves as a temporary variable that gets initialized in this function
     // and is later used by a call to `channel::read()` or `channel::write()` that completes the
@@ -324,6 +328,7 @@
 fn run_ready(
     handles: &mut [(&dyn SelectHandle, usize, *const u8)],
     timeout: Timeout,
+    is_biased: bool,
 ) -> Option<usize> {
     if handles.is_empty() {
         // Wait until the timeout and return.
@@ -340,8 +345,10 @@
         }
     }
 
-    // Shuffle the operations for fairness.
-    utils::shuffle(handles);
+    if !is_biased {
+        // Shuffle the operations for fairness.
+        utils::shuffle(handles);
+    }
 
     loop {
         let backoff = Backoff::new();
@@ -449,8 +456,9 @@
 #[inline]
 pub fn try_select<'a>(
     handles: &mut [(&'a dyn SelectHandle, usize, *const u8)],
+    is_biased: bool,
 ) -> Result<SelectedOperation<'a>, TrySelectError> {
-    match run_select(handles, Timeout::Now) {
+    match run_select(handles, Timeout::Now, is_biased) {
         None => Err(TrySelectError),
         Some((token, index, ptr)) => Ok(SelectedOperation {
             token,
@@ -466,12 +474,13 @@
 #[inline]
 pub fn select<'a>(
     handles: &mut [(&'a dyn SelectHandle, usize, *const u8)],
+    is_biased: bool,
 ) -> SelectedOperation<'a> {
     if handles.is_empty() {
         panic!("no operations have been added to `Select`");
     }
 
-    let (token, index, ptr) = run_select(handles, Timeout::Never).unwrap();
+    let (token, index, ptr) = run_select(handles, Timeout::Never, is_biased).unwrap();
     SelectedOperation {
         token,
         index,
@@ -486,10 +495,11 @@
 pub fn select_timeout<'a>(
     handles: &mut [(&'a dyn SelectHandle, usize, *const u8)],
     timeout: Duration,
+    is_biased: bool,
 ) -> Result<SelectedOperation<'a>, SelectTimeoutError> {
     match Instant::now().checked_add(timeout) {
-        Some(deadline) => select_deadline(handles, deadline),
-        None => Ok(select(handles)),
+        Some(deadline) => select_deadline(handles, deadline, is_biased),
+        None => Ok(select(handles, is_biased)),
     }
 }
 
@@ -498,8 +508,9 @@
 pub(crate) fn select_deadline<'a>(
     handles: &mut [(&'a dyn SelectHandle, usize, *const u8)],
     deadline: Instant,
+    is_biased: bool,
 ) -> Result<SelectedOperation<'a>, SelectTimeoutError> {
-    match run_select(handles, Timeout::At(deadline)) {
+    match run_select(handles, Timeout::At(deadline), is_biased) {
         None => Err(SelectTimeoutError),
         Some((token, index, ptr)) => Ok(SelectedOperation {
             token,
@@ -763,7 +774,7 @@
     /// }
     /// ```
     pub fn try_select(&mut self) -> Result<SelectedOperation<'a>, TrySelectError> {
-        try_select(&mut self.handles)
+        try_select(&mut self.handles, false)
     }
 
     /// Blocks until one of the operations becomes ready and selects it.
@@ -810,7 +821,7 @@
     /// }
     /// ```
     pub fn select(&mut self) -> SelectedOperation<'a> {
-        select(&mut self.handles)
+        select(&mut self.handles, false)
     }
 
     /// Blocks for a limited time until one of the operations becomes ready and selects it.
@@ -860,7 +871,7 @@
         &mut self,
         timeout: Duration,
     ) -> Result<SelectedOperation<'a>, SelectTimeoutError> {
-        select_timeout(&mut self.handles, timeout)
+        select_timeout(&mut self.handles, timeout, false)
     }
 
     /// Blocks until a given deadline, or until one of the operations becomes ready and selects it.
@@ -912,7 +923,7 @@
         &mut self,
         deadline: Instant,
     ) -> Result<SelectedOperation<'a>, SelectTimeoutError> {
-        select_deadline(&mut self.handles, deadline)
+        select_deadline(&mut self.handles, deadline, false)
     }
 
     /// Attempts to find a ready operation without blocking.
@@ -951,7 +962,7 @@
     /// }
     /// ```
     pub fn try_ready(&mut self) -> Result<usize, TryReadyError> {
-        match run_ready(&mut self.handles, Timeout::Now) {
+        match run_ready(&mut self.handles, Timeout::Now, false) {
             None => Err(TryReadyError),
             Some(index) => Ok(index),
         }
@@ -1004,7 +1015,7 @@
             panic!("no operations have been added to `Select`");
         }
 
-        run_ready(&mut self.handles, Timeout::Never).unwrap()
+        run_ready(&mut self.handles, Timeout::Never, false).unwrap()
     }
 
     /// Blocks for a limited time until one of the operations becomes ready.
@@ -1097,7 +1108,7 @@
     /// }
     /// ```
     pub fn ready_deadline(&mut self, deadline: Instant) -> Result<usize, ReadyTimeoutError> {
-        match run_ready(&mut self.handles, Timeout::At(deadline)) {
+        match run_ready(&mut self.handles, Timeout::At(deadline), false) {
             None => Err(ReadyTimeoutError),
             Some(index) => Ok(index),
         }
diff --git a/crates/crossbeam-channel/src/select_macro.rs b/crates/crossbeam-channel/src/select_macro.rs
index 43932a6..e109404 100644
--- a/crates/crossbeam-channel/src/select_macro.rs
+++ b/crates/crossbeam-channel/src/select_macro.rs
@@ -750,7 +750,7 @@
         $cases:tt
     ) => {{
         let _oper: $crate::SelectedOperation<'_> = {
-            let _oper = $crate::internal::select(&mut $sel);
+            let _oper = $crate::internal::select(&mut $sel, _IS_BIASED);
 
             // Erase the lifetime so that `sel` can be dropped early even without NLL.
             unsafe { ::std::mem::transmute(_oper) }
@@ -772,7 +772,7 @@
         $cases:tt
     ) => {{
         let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = {
-            let _oper = $crate::internal::try_select(&mut $sel);
+            let _oper = $crate::internal::try_select(&mut $sel, _IS_BIASED);
 
             // Erase the lifetime so that `sel` can be dropped early even without NLL.
             unsafe { ::std::mem::transmute(_oper) }
@@ -802,7 +802,7 @@
         $cases:tt
     ) => {{
         let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = {
-            let _oper = $crate::internal::select_timeout(&mut $sel, $timeout);
+            let _oper = $crate::internal::select_timeout(&mut $sel, $timeout, _IS_BIASED);
 
             // Erase the lifetime so that `sel` can be dropped early even without NLL.
             unsafe { ::std::mem::transmute(_oper) }
@@ -985,7 +985,8 @@
 ///
 /// This macro allows you to define a set of channel operations, wait until any one of them becomes
 /// ready, and finally execute it. If multiple operations are ready at the same time, a random one
-/// among them is selected.
+/// among them is selected (i.e. the unbiased selection). Use `select_biased!` for the biased
+/// selection.
 ///
 /// It is also possible to define a `default` case that gets executed if none of the operations are
 /// ready, either right away or for a certain duration of time.
@@ -1109,8 +1110,33 @@
 #[macro_export]
 macro_rules! select {
     ($($tokens:tt)*) => {
-        $crate::crossbeam_channel_internal!(
-            $($tokens)*
-        )
+        {
+            const _IS_BIASED: bool = false;
+
+            $crate::crossbeam_channel_internal!(
+                $($tokens)*
+            )
+        }
+    };
+}
+
+/// Selects from a set of channel operations.
+///
+/// This macro allows you to define a list of channel operations, wait until any one of them
+/// becomes ready, and finally execute it. If multiple operations are ready at the same time, the
+/// operation nearest to the front of the list is always selected (i.e. the biased selection). Use
+/// [`select!`] for the unbiased selection.
+///
+/// Otherwise, this macro's functionality is identical to [`select!`]. Refer to it for the syntax.
+#[macro_export]
+macro_rules! select_biased {
+    ($($tokens:tt)*) => {
+        {
+            const _IS_BIASED: bool = true;
+
+            $crate::crossbeam_channel_internal!(
+                $($tokens)*
+            )
+        }
     };
 }
diff --git a/crates/crossbeam-channel/src/utils.rs b/crates/crossbeam-channel/src/utils.rs
index 705ca1a..a425d96 100644
--- a/crates/crossbeam-channel/src/utils.rs
+++ b/crates/crossbeam-channel/src/utils.rs
@@ -12,7 +12,7 @@
         return;
     }
 
-    thread_local! {
+    std::thread_local! {
         static RNG: Cell<Wrapping<u32>> = const { Cell::new(Wrapping(1_406_868_647)) };
     }
 
diff --git a/crates/crossbeam-channel/src/waker.rs b/crates/crossbeam-channel/src/waker.rs
index 7eb58ba..a6db927 100644
--- a/crates/crossbeam-channel/src/waker.rs
+++ b/crates/crossbeam-channel/src/waker.rs
@@ -4,6 +4,7 @@
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Mutex;
 use std::thread::{self, ThreadId};
+use std::vec::Vec;
 
 use crate::context::Context;
 use crate::select::{Operation, Selected};
@@ -275,7 +276,7 @@
 /// Returns the id of the current thread.
 #[inline]
 fn current_thread_id() -> ThreadId {
-    thread_local! {
+    std::thread_local! {
         /// Cached thread-local id.
         static THREAD_ID: ThreadId = thread::current().id();
     }
diff --git a/crates/crossbeam-channel/tests/mpsc.rs b/crates/crossbeam-channel/tests/mpsc.rs
index 0cea233..3e96946 100644
--- a/crates/crossbeam-channel/tests/mpsc.rs
+++ b/crates/crossbeam-channel/tests/mpsc.rs
@@ -176,6 +176,8 @@
     (
         $($name:pat = $rx:ident.$meth:ident() => $code:expr),+
     ) => ({
+        const _IS_BIASED: bool = false;
+
         cc::crossbeam_channel_internal! {
             $(
                 $meth(($rx).inner) -> res => {
@@ -193,7 +195,7 @@
 
     use std::env;
     use std::thread;
-    use std::time::{Duration, Instant};
+    use std::time::Instant;
 
     pub fn stress_factor() -> usize {
         match env::var("RUST_TEST_STRESS") {
@@ -969,7 +971,6 @@
 
     use std::env;
     use std::thread;
-    use std::time::Duration;
 
     pub fn stress_factor() -> usize {
         match env::var("RUST_TEST_STRESS") {
diff --git a/crates/crossbeam-channel/tests/select_macro.rs b/crates/crossbeam-channel/tests/select_macro.rs
index c480809..794e026 100644
--- a/crates/crossbeam-channel/tests/select_macro.rs
+++ b/crates/crossbeam-channel/tests/select_macro.rs
@@ -9,7 +9,7 @@
 use std::thread;
 use std::time::{Duration, Instant};
 
-use crossbeam_channel::{after, bounded, never, select, tick, unbounded};
+use crossbeam_channel::{after, bounded, never, select, select_biased, tick, unbounded};
 use crossbeam_channel::{Receiver, RecvError, SendError, Sender, TryRecvError};
 use crossbeam_utils::thread::scope;
 
@@ -943,7 +943,122 @@
     assert!(hits.iter().all(|x| *x >= COUNT / 4));
 }
 
-#[allow(clippy::or_fun_call)] // This is intentional.
+#[test]
+fn unfairness() {
+    #[cfg(miri)]
+    const COUNT: usize = 100;
+    #[cfg(not(miri))]
+    const COUNT: usize = 10_000;
+
+    let (s1, r1) = unbounded::<()>();
+    let (s2, r2) = unbounded::<()>();
+    let (s3, r3) = unbounded::<()>();
+
+    for _ in 0..COUNT {
+        s1.send(()).unwrap();
+        s2.send(()).unwrap();
+    }
+    s3.send(()).unwrap();
+
+    let mut hits = [0usize; 3];
+    for _ in 0..COUNT {
+        select_biased! {
+            recv(r1) -> _ => hits[0] += 1,
+            recv(r2) -> _ => hits[1] += 1,
+            recv(r3) -> _ => hits[2] += 1,
+        }
+    }
+    assert_eq!(hits, [COUNT, 0, 0]);
+
+    for _ in 0..COUNT {
+        select_biased! {
+            recv(r1) -> _ => hits[0] += 1,
+            recv(r2) -> _ => hits[1] += 1,
+            recv(r3) -> _ => hits[2] += 1,
+        }
+    }
+    assert_eq!(hits, [COUNT, COUNT, 0]);
+}
+
+#[test]
+fn unfairness_timeout() {
+    #[cfg(miri)]
+    const COUNT: usize = 100;
+    #[cfg(not(miri))]
+    const COUNT: usize = 10_000;
+
+    let (s1, r1) = unbounded::<()>();
+    let (s2, r2) = unbounded::<()>();
+    let (s3, r3) = unbounded::<()>();
+
+    for _ in 0..COUNT {
+        s1.send(()).unwrap();
+        s2.send(()).unwrap();
+    }
+    s3.send(()).unwrap();
+
+    let mut hits = [0usize; 3];
+    for _ in 0..COUNT {
+        select_biased! {
+            recv(r1) -> _ => hits[0] += 1,
+            recv(r2) -> _ => hits[1] += 1,
+            recv(r3) -> _ => hits[2] += 1,
+            default(ms(1000)) => unreachable!(),
+        }
+    }
+    assert_eq!(hits, [COUNT, 0, 0]);
+
+    for _ in 0..COUNT {
+        select_biased! {
+            recv(r1) -> _ => hits[0] += 1,
+            recv(r2) -> _ => hits[1] += 1,
+            recv(r3) -> _ => hits[2] += 1,
+            default(ms(1000)) => unreachable!(),
+        }
+    }
+    assert_eq!(hits, [COUNT, COUNT, 0]);
+}
+
+#[test]
+fn unfairness_try() {
+    #[cfg(miri)]
+    const COUNT: usize = 100;
+    #[cfg(not(miri))]
+    const COUNT: usize = 10_000;
+
+    let (s1, r1) = unbounded::<()>();
+    let (s2, r2) = unbounded::<()>();
+    let (s3, r3) = unbounded::<()>();
+
+    for _ in 0..COUNT {
+        s1.send(()).unwrap();
+        s2.send(()).unwrap();
+    }
+    s3.send(()).unwrap();
+
+    let mut hits = [0usize; 3];
+    for _ in 0..COUNT {
+        select_biased! {
+            recv(r1) -> _ => hits[0] += 1,
+            recv(r2) -> _ => hits[1] += 1,
+            recv(r3) -> _ => hits[2] += 1,
+            default() => unreachable!(),
+        }
+    }
+    assert_eq!(hits, [COUNT, 0, 0]);
+
+    for _ in 0..COUNT {
+        select_biased! {
+            recv(r1) -> _ => hits[0] += 1,
+            recv(r2) -> _ => hits[1] += 1,
+            recv(r3) -> _ => hits[2] += 1,
+            default() => unreachable!(),
+        }
+    }
+    assert_eq!(hits, [COUNT, COUNT, 0]);
+}
+
+#[allow(clippy::or_fun_call, clippy::unnecessary_literal_unwrap)] // This is intentional.
 #[test]
 fn references() {
     let (s, r) = unbounded::<i32>();
diff --git a/crates/darling_core/.cargo-checksum.json b/crates/darling_core/.cargo-checksum.json
index de78f2e..1013c26 100644
--- a/crates/darling_core/.cargo-checksum.json
+++ b/crates/darling_core/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"67bd66e46716e4dbf28b03d7155a13a1a53a8f462270d4c30821fd97b09f77bb","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","src/ast/data.rs":"0ad320af548cbf3c5e86c933c80f2b4ca9748ba915b5a289ab95ddb658ca259d","src/ast/generics.rs":"5a9c30068cd39c59c42c1bb494a1fe6680714798f10ca952abc8b0dabd9152ad","src/ast/mod.rs":"58a58eeb1db7682e5994732cc8eb04088f6ca662805460ef443cf089e5c24e2c","src/codegen/attr_extractor.rs":"c719060d5791ecee53087bb940b5f5d133f6dd1cae2c06801d422fffe4e7201b","src/codegen/attrs_field.rs":"5ae91e1fcdb27b6e2263b4f5e0f46354208325524e59d85834eb665e64798052","src/codegen/default_expr.rs":"5486c8dc264e3bb8be2a871f3258f56ed2812ae39b1eb9f0d16006605407027f","src/codegen/error.rs":"4ef086317234a161bec493413ba38d842cbbecd0b9610dad0a25fe8883c75d3b","src/codegen/field.rs":"5ec800d5cadbae155d877805bd746a5850e390778755b3659ab95843ae2f3ecf","src/codegen/from_attributes_impl.rs":"b6ebc26fd8fd9737e525b5a00e48c8cc647538d5eee3b5df0e24b5a5bd55430f","src/codegen/from_derive_impl.rs":"441edc764793d2a9abc99e389dc3948cd3dbd2376dfca9f233900df979533632","src/codegen/from_field.rs":"db02f06c26451bed298fe5ab27be56f519c97e47381614bfe3806d3f908f1349","src/codegen/from_meta_impl.rs":"9180f209332226100cdbe257480edcc4a2c2689ecd9e5e1e71e8b65bd9023098","src/codegen/from_type_param.rs":"319dafb7c13e6d01dd4477098139a2d6c8eb0b5770a4278c32fe41d3b144fc2a","src/codegen/from_variant_impl.rs":"bd5162bc9bafab396adc1a1c29c7a2c22888650f20057370103e6a18eab77543","src/codegen/mod.rs":"38ee48646cf768b02199f52695515d9d43ae8e1d23cc3455b39eb8d50540dce3","src/codegen/outer_from_impl.rs":"e47548abfa3542ba13c75873c9d0f7b6a7581fec1a433ae5fd79f3d4d9da6a09","src/codegen/postfix_transform.rs":"41c84a239c15671e5a9cb8ce9fbb1b907f20aebe30d5dea4f04f004e3aa584c1","src/codegen/trait_impl.rs":"3a84ad91b399acdc04fa3b53502105f1ba9d2af058aae609b01cb361e514d6c4","src/codegen/variant.rs":"b2bc0feb6b05c7397f0908654303cae6996153f1e00d35dcfff9b35e13079ae5","src/codegen/variant_data.rs":"0cd8c404d8cb4228a15139938ff4af90b629cec4ccf78caff3ecbf40a252d2cd","src/derive.rs":"d35f35233eea28bc66bf6f738358415d650741560ca56f8deaee9465b3e88b2a","src/error/child.rs":"a6cc6e21b3a424150a764b2b9a8ffbc525722ccb4c372e197ded5a39021439fc","src/error/kind.rs":"e0490ba6a0085335565d529d53b9f0eee98c00b3c082d5def2b3f93ccdc605c4","src/error/mod.rs":"dc209381fb6fe5f2ba697752265d494f0fa0954d4ac0bcececf3b5fcca2d2ec5","src/from_attributes.rs":"9c98a34eccdb66526711793d6d00bd5216de1d0e9d3755133996242a27efe272","src/from_derive_input.rs":"a60aba72ebd4deddd6bb9919995652f90aafdf88f6109c00c1a1c4459e439049","src/from_field.rs":"1e22b7750843b6a018fe75ae1510fb9252343be99ab02d2093881421e87d867d","src/from_generic_param.rs":"bdabc80f49212501e6e3574c7e6c03b4e453d0fe241ac46d465a5f004381f4c9","src/from_generics.rs":"b0a156179b2d1d88467183649afc97405403b01a7fdae39e4df8392f6b9f500c","src/from_meta.rs":"181e37b5a4c4606877313480aefefff6dca26279477908d253da14d72cc42e05","src/from_type_param.rs":"0c8930a42e1f0720429aa968f97f938e207460232dd2169cbf8efec12e7c6f5a","src/from_variant.rs":"dd27ffef65ceea0e68809afde7df82d3751cdedc248773062637aa8c146da6e7","src/lib.rs":"b066b0747dcec5150d6962a80850a8fb7690b24700f62537893ebb2d4c88a4a8","src/macros_private.rs":"4373c36e75d516c340fc9b13c52b471d823fff9997cb7faeeb5f93b11d40d0b4","src/macros_public.rs":"7d2ce0c5026227ef7854db11d7a885ad891255438b2e49bbdfda56fa2f92feec","src/options/core.rs":"2942b4c2a2bf34ecf7d10d70425ed582d4d9c064b5ca6e3300f2f301fdfd3b87","src/options/forward_attrs.rs":"9f98e9f15fe9ff14cdf5b93b23c6a897e15f2b8ba365972b9a6af6c2c9fbf900","src/options/from_attributes.rs":"f6920790402d1b85c0122dab2b67b38a5026ac535ae1b75128e612b28d651577","src/options/from_derive.rs":"6aba3b984c009539d5c91a8e69ee2d0b47b232d54fb85dc93844a3d7a88c22ed","src/options/from_field.rs":"84e601fd11bd5e06fafee2bc0b86c79e9b42d6a62dfab40d343e76a4af560594","src/options/from_meta.rs":"77ab7106b571a48d4830c06dcf6e5c75fa9edab5013e6678a659d8ad8d084fb5","src/options/from_type_param.rs":"2e6b380dd217c6051e2abbb365ff499b56e4943e01ba4d586c552af4587adfcb","src/options/from_variant.rs":"ec6fafc77e5bee9f77a3173e9757ec7e4b6f37d66809261f3f9dd7461e29ea93","src/options/input_field.rs":"7233974b2eb905c47559d800d67b6cc5248f4e0ff5b8d7aac6ad9d7c3ebe72af","src/options/input_variant.rs":"b4e3d647fe90869ceff6a03a133132b1fd2b31611e49bd401246fa165a8b99b3","src/options/mod.rs":"a91a8419f9f9e7759a4a55a751b03771dfdd7a13511d6748c36f1304ec8aaa81","src/options/outer_from.rs":"e10ea61f56e188b1af77cfe29101e2a0e22280fb5c7ad76b5df42669cac84d48","src/options/shape.rs":"4e676e0fce9c0cec625fcb391897dfc6b7cfc338912b76ff72cd6179affb836d","src/usage/generics_ext.rs":"b2d15e2ff75c47f43f3ce305b2108e800dd3d89e3a21fadf82bda455837b8090","src/usage/ident_set.rs":"30edb2f0a599284967e3c6b579da31e5f9b15f3dd67bc9a82d6335eb44133df0","src/usage/lifetimes.rs":"f3dcb3fab5370c07ddb19fa04079f8da1f035d671930d987ab3980f77ae7f3cc","src/usage/mod.rs":"e49adadfa8ffed27299d5bbf3c33e68e2c8c7411f89aef655f77e158be9dd642","src/usage/options.rs":"0491c995aad0d55783b24cce8a4e40f0f4435988c54ce2ded34763ac9b199fcf","src/usage/type_params.rs":"e009419b102ad56878706d411b44cb89f5a497e8d0abbb6769bcd2d4af53c90b","src/util/flag.rs":"b2ac32e1a140d2fd9e02d84c73e5db3807b52419841fb293d3144b8e8a847a44","src/util/ident_string.rs":"2a2d32f9ba3a5b46ddcf430891d62f47d0a65782b592cccbfd0e88bb1361cbc9","src/util/ignored.rs":"099c015023b9be0870fb1c4c44ad00f87789ea13da25e2ca952132443e497214","src/util/mod.rs":"2412be5a804685b2570a7e4e42e595566dab7b52a595fd74ecb50453687aae5f","src/util/over_ride.rs":"5cf502315b3aea1a2820d5b39ce5123c1b8a41a0182f119c34154d5209d47108","src/util/parse_attribute.rs":"82f897215865475ab3fc1ea2036e5bb29e02cee677aa2f05949b3abb4c3d814a","src/util/parse_expr.rs":"71d7eb900ec5460934ff2f1770e85acb68c7a2c317b1e2f9776b4f4d7258f9fa","src/util/path_list.rs":"939d0035b09ef7b361e654271f0eafde93be8208f6fb9a1caef9a3ee9e7e337d","src/util/path_to_string.rs":"c093354f91ab45e0be3c50d2d4356408f415c910f1569fb9275c5087110736f6","src/util/shape.rs":"dda17aa8a063b5023ae1f055bec2859f984ec32633f6cc55938a442252f07204","src/util/spanned_value.rs":"3a7efefb4085a52d8483ad29b8535633342c8c029354da9a41124ff9c44823ea","src/util/with_original.rs":"56ea20c03d07ebe1a8bc0ed220258f6cee5a3cf7192c0e07601fafda99404062"},"package":"9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"}
\ No newline at end of file
+{"files":{"Cargo.toml":"d566f8998134a7647338af18d9eae4fa1fffb200dabb0eb45ed22c2f9bf404d7","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","src/ast/data.rs":"dd7c64af33afd0224d06367fc8fefa2e8e25ed7edfb6f9e5d8dc02e4baca0fdb","src/ast/generics.rs":"f58bc7cf6be6aabde290f965018bdea236fc40c3b3d234b1f47a101f3d286179","src/ast/mod.rs":"58a58eeb1db7682e5994732cc8eb04088f6ca662805460ef443cf089e5c24e2c","src/codegen/attr_extractor.rs":"9ec3e79a7659bdff066bf1b9ac92e2c8ef63e901e5ba98ab35d7eacf6f0dd7dc","src/codegen/attrs_field.rs":"e06e0830edb63315b40e139c5b99d49429f0949b4fc9ee7c6e20219189e13ffb","src/codegen/default_expr.rs":"5486c8dc264e3bb8be2a871f3258f56ed2812ae39b1eb9f0d16006605407027f","src/codegen/error.rs":"4ef086317234a161bec493413ba38d842cbbecd0b9610dad0a25fe8883c75d3b","src/codegen/field.rs":"15e812bf5f97117ec5108552d89b5ec0b77a6465fcc2f4a3bd9e0ed2236f6902","src/codegen/from_attributes_impl.rs":"07f4eed890028df8f83e1f068eacfddd8a5464159c02b52832f9b811eeaf3524","src/codegen/from_derive_impl.rs":"2a0c8140653f5ef4542406e053ab263e33ab01750d8e8fd415d32c38b7fe747e","src/codegen/from_field.rs":"8e7cd4bb41908ea4c2f2bff119cb8e965303c2eb892ef8c518db2d0e78ed8852","src/codegen/from_meta_impl.rs":"9180f209332226100cdbe257480edcc4a2c2689ecd9e5e1e71e8b65bd9023098","src/codegen/from_type_param.rs":"97c4cb643681a9268d41e8e87114427e6561f58a22ec31c6acac47c26a220346","src/codegen/from_variant_impl.rs":"3530dbe1d6187e65f1fdbcfbeb79eb2838b6940614de912b5e06c2a35aa9f747","src/codegen/mod.rs":"38ee48646cf768b02199f52695515d9d43ae8e1d23cc3455b39eb8d50540dce3","src/codegen/outer_from_impl.rs":"b1e63838daed79c8d1c024ca4c88388f32b51454c5a86241717d68d3c3c92414","src/codegen/postfix_transform.rs":"41c84a239c15671e5a9cb8ce9fbb1b907f20aebe30d5dea4f04f004e3aa584c1","src/codegen/trait_impl.rs":"5b1d706d0c7a2ad99508fe143e1204306742bd1c21cbc1a7f73614f11ddbf8e8","src/codegen/variant.rs":"0050d5d37196e283b78a327782cbac9efce314f42cd4d0840f70a72fc9d8a515","src/codegen/variant_data.rs":"0cd8c404d8cb4228a15139938ff4af90b629cec4ccf78caff3ecbf40a252d2cd","src/derive.rs":"d35f35233eea28bc66bf6f738358415d650741560ca56f8deaee9465b3e88b2a","src/error/child.rs":"a6cc6e21b3a424150a764b2b9a8ffbc525722ccb4c372e197ded5a39021439fc","src/error/kind.rs":"26957bf705802c29fdaa004ee86d6ccaa758070f1355aa4abe42156618c39ea8","src/error/mod.rs":"0aba7222de6316b2dad32e8128b77eb7241e597b8f03811f8fe410af7a7670dc","src/from_attributes.rs":"9c98a34eccdb66526711793d6d00bd5216de1d0e9d3755133996242a27efe272","src/from_derive_input.rs":"a60aba72ebd4deddd6bb9919995652f90aafdf88f6109c00c1a1c4459e439049","src/from_field.rs":"1e22b7750843b6a018fe75ae1510fb9252343be99ab02d2093881421e87d867d","src/from_generic_param.rs":"bdabc80f49212501e6e3574c7e6c03b4e453d0fe241ac46d465a5f004381f4c9","src/from_generics.rs":"b0a156179b2d1d88467183649afc97405403b01a7fdae39e4df8392f6b9f500c","src/from_meta.rs":"b4ca7c37bdfeac60c2a40979796d4373493705f73d316eb29d769f84632604a8","src/from_type_param.rs":"0c8930a42e1f0720429aa968f97f938e207460232dd2169cbf8efec12e7c6f5a","src/from_variant.rs":"dd27ffef65ceea0e68809afde7df82d3751cdedc248773062637aa8c146da6e7","src/lib.rs":"34808fd70c0c871c1eba5636530ebc5792788a1141999aa7165edabe66cfe9e8","src/macros_private.rs":"4373c36e75d516c340fc9b13c52b471d823fff9997cb7faeeb5f93b11d40d0b4","src/macros_public.rs":"7d2ce0c5026227ef7854db11d7a885ad891255438b2e49bbdfda56fa2f92feec","src/options/core.rs":"41936931c0b505663d577bc2a0338295e86ed29e1082dd0d4f21fe1da6084b24","src/options/forward_attrs.rs":"9f98e9f15fe9ff14cdf5b93b23c6a897e15f2b8ba365972b9a6af6c2c9fbf900","src/options/from_attributes.rs":"b82356ab9a31dac1d4e2b12b02966ac068fa48df1b3492f889d45769c8b8dde3","src/options/from_derive.rs":"1e257762d1599df45ecc38112274ced0dbbe5e3faa76971b8bea75dad14763fb","src/options/from_field.rs":"93d025e43c8dba21e0e21d40ad8c0d9814eadb95b1ad3b2738156b1699f7e218","src/options/from_meta.rs":"77ab7106b571a48d4830c06dcf6e5c75fa9edab5013e6678a659d8ad8d084fb5","src/options/from_type_param.rs":"d8f68a9927c57321b3e4d717d15fe917ffa91ee561d7e298625bcaf25441d849","src/options/from_variant.rs":"104565175aeb238edf9ee68f7ffe2a665620796c50f7f9f3e1e3ef23751214aa","src/options/input_field.rs":"7233974b2eb905c47559d800d67b6cc5248f4e0ff5b8d7aac6ad9d7c3ebe72af","src/options/input_variant.rs":"b4e3d647fe90869ceff6a03a133132b1fd2b31611e49bd401246fa165a8b99b3","src/options/mod.rs":"a91a8419f9f9e7759a4a55a751b03771dfdd7a13511d6748c36f1304ec8aaa81","src/options/outer_from.rs":"ddc5ada98b5b5afc54ca42d8daba809b26ea58c13bd1b61b0a4d51a751193225","src/options/shape.rs":"4e676e0fce9c0cec625fcb391897dfc6b7cfc338912b76ff72cd6179affb836d","src/usage/generics_ext.rs":"b2d15e2ff75c47f43f3ce305b2108e800dd3d89e3a21fadf82bda455837b8090","src/usage/ident_set.rs":"30edb2f0a599284967e3c6b579da31e5f9b15f3dd67bc9a82d6335eb44133df0","src/usage/lifetimes.rs":"f3dcb3fab5370c07ddb19fa04079f8da1f035d671930d987ab3980f77ae7f3cc","src/usage/mod.rs":"e49adadfa8ffed27299d5bbf3c33e68e2c8c7411f89aef655f77e158be9dd642","src/usage/options.rs":"0491c995aad0d55783b24cce8a4e40f0f4435988c54ce2ded34763ac9b199fcf","src/usage/type_params.rs":"e009419b102ad56878706d411b44cb89f5a497e8d0abbb6769bcd2d4af53c90b","src/util/flag.rs":"b2ac32e1a140d2fd9e02d84c73e5db3807b52419841fb293d3144b8e8a847a44","src/util/ident_string.rs":"5e91c4e7f97fd02b114b56b9b77527fc0a00970954ed12dfb9c75adfeab59c82","src/util/ignored.rs":"099c015023b9be0870fb1c4c44ad00f87789ea13da25e2ca952132443e497214","src/util/mod.rs":"2412be5a804685b2570a7e4e42e595566dab7b52a595fd74ecb50453687aae5f","src/util/over_ride.rs":"b917e68750c898cba6159db98362bf1226ca856c8a0919ad9d3920ed82b76f54","src/util/parse_attribute.rs":"202b9c05b818caa3d54c05d9dc34a52c7f46c87996a65865c1623084b4fb8eb7","src/util/parse_expr.rs":"71d7eb900ec5460934ff2f1770e85acb68c7a2c317b1e2f9776b4f4d7258f9fa","src/util/path_list.rs":"939d0035b09ef7b361e654271f0eafde93be8208f6fb9a1caef9a3ee9e7e337d","src/util/path_to_string.rs":"c093354f91ab45e0be3c50d2d4356408f415c910f1569fb9275c5087110736f6","src/util/shape.rs":"dda17aa8a063b5023ae1f055bec2859f984ec32633f6cc55938a442252f07204","src/util/spanned_value.rs":"3a7efefb4085a52d8483ad29b8535633342c8c029354da9a41124ff9c44823ea","src/util/with_original.rs":"56ea20c03d07ebe1a8bc0ed220258f6cee5a3cf7192c0e07601fafda99404062"},"package":"95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"}
\ No newline at end of file
diff --git a/crates/darling_core/Android.bp b/crates/darling_core/Android.bp
index 0142198..1891a5b 100644
--- a/crates/darling_core/Android.bp
+++ b/crates/darling_core/Android.bp
@@ -18,9 +18,9 @@
     host_cross_supported: false,
     crate_name: "darling_core",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.20.8",
+    cargo_pkg_version: "0.20.10",
     crate_root: "src/lib.rs",
-    edition: "2018",
+    edition: "2021",
     rustlibs: [
         "libfnv",
         "libident_case",
diff --git a/crates/darling_core/Cargo.toml b/crates/darling_core/Cargo.toml
index 2ad8f1d..292a037 100644
--- a/crates/darling_core/Cargo.toml
+++ b/crates/darling_core/Cargo.toml
@@ -10,9 +10,10 @@
 # See Cargo.toml.orig for the original contents.
 
 [package]
-edition = "2018"
+edition = "2021"
+rust-version = "1.56"
 name = "darling_core"
-version = "0.20.8"
+version = "0.20.10"
 authors = ["Ted Driggs <ted.driggs@outlook.com>"]
 description = """
 Helper crate for proc-macro library for reading attributes into structs when
@@ -34,7 +35,7 @@
 version = "1.0.18"
 
 [dependencies.strsim]
-version = "0.10.0"
+version = "0.11.1"
 optional = true
 
 [dependencies.syn]
diff --git a/crates/darling_core/METADATA b/crates/darling_core/METADATA
index fd866e5..813bde3 100644
--- a/crates/darling_core/METADATA
+++ b/crates/darling_core/METADATA
@@ -1,17 +1,17 @@
 name: "darling_core"
 description: "()"
 third_party {
-  version: "0.20.8"
+  version: "0.20.10"
   license_type: NOTICE
   last_upgrade_date {
     year: 2024
-    month: 3
-    day: 6
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/darling_core"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/darling_core/darling_core-0.20.8.crate"
-    version: "0.20.8"
+    value: "https://static.crates.io/crates/darling_core/darling_core-0.20.10.crate"
+    version: "0.20.10"
   }
 }
diff --git a/crates/darling_core/src/ast/data.rs b/crates/darling_core/src/ast/data.rs
index 4b91595..03036d8 100644
--- a/crates/darling_core/src/ast/data.rs
+++ b/crates/darling_core/src/ast/data.rs
@@ -244,7 +244,7 @@
         }
     }
 
-    pub fn iter(&self) -> slice::Iter<T> {
+    pub fn iter(&self) -> slice::Iter<'_, T> {
         self.fields.iter()
     }
 
@@ -428,7 +428,7 @@
 }
 
 impl syn::parse::Parse for NestedMeta {
-    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
         if input.peek(syn::Lit) && !(input.peek(syn::LitBool) && input.peek2(Token![=])) {
             input.parse().map(NestedMeta::Lit)
         } else if input.peek(syn::Ident::peek_any)
diff --git a/crates/darling_core/src/ast/generics.rs b/crates/darling_core/src/ast/generics.rs
index d4bf0c9..8e9798b 100644
--- a/crates/darling_core/src/ast/generics.rs
+++ b/crates/darling_core/src/ast/generics.rs
@@ -158,7 +158,7 @@
     }
 }
 
-pub struct TypeParams<'a, P: 'a>(Iter<'a, P>);
+pub struct TypeParams<'a, P>(Iter<'a, P>);
 
 impl<'a, P: GenericParamExt> Iterator for TypeParams<'a, P> {
     type Item = &'a <P as GenericParamExt>::TypeParam;
diff --git a/crates/darling_core/src/codegen/attr_extractor.rs b/crates/darling_core/src/codegen/attr_extractor.rs
index 612c28f..2491599 100644
--- a/crates/darling_core/src/codegen/attr_extractor.rs
+++ b/crates/darling_core/src/codegen/attr_extractor.rs
@@ -13,7 +13,7 @@
     /// Gets the list of attribute names that should be parsed by the extractor.
     fn attr_names(&self) -> &PathList;
 
-    fn forward_attrs(&self) -> &ForwardAttrs;
+    fn forward_attrs(&self) -> &ForwardAttrs<'_>;
 
     /// Gets the name used by the generated impl to return to the `syn` item passed as input.
     fn param_name(&self) -> TokenStream;
diff --git a/crates/darling_core/src/codegen/attrs_field.rs b/crates/darling_core/src/codegen/attrs_field.rs
index bbd43f8..8b21267 100644
--- a/crates/darling_core/src/codegen/attrs_field.rs
+++ b/crates/darling_core/src/codegen/attrs_field.rs
@@ -21,23 +21,23 @@
     }
 
     /// Get the field declarations to support attribute forwarding
-    pub fn as_declaration(&self) -> Option<Declaration> {
+    pub fn as_declaration(&self) -> Option<Declaration<'_>> {
         self.field.map(Declaration)
     }
 
     /// Get the match arms for attribute matching
-    pub fn as_match_arms(&self) -> MatchArms {
+    pub fn as_match_arms(&self) -> MatchArms<'_> {
         MatchArms(self)
     }
 
     /// Get the statement that will try to transform forwarded attributes into
     /// the result expected by the receiver field.
-    pub fn as_value_populator(&self) -> Option<ValuePopulator> {
+    pub fn as_value_populator(&self) -> Option<ValuePopulator<'_>> {
         self.field.map(ValuePopulator)
     }
 
     /// Get the field initializer for use when building the deriving struct.
-    pub fn as_initializer(&self) -> Option<Initializer> {
+    pub fn as_initializer(&self) -> Option<Initializer<'_>> {
         self.field.map(Initializer)
     }
 }
diff --git a/crates/darling_core/src/codegen/field.rs b/crates/darling_core/src/codegen/field.rs
index 51020a9..d4f9369 100644
--- a/crates/darling_core/src/codegen/field.rs
+++ b/crates/darling_core/src/codegen/field.rs
@@ -86,7 +86,7 @@
 
 impl<'a> ToTokens for Declaration<'a> {
     fn to_tokens(&self, tokens: &mut TokenStream) {
-        let field: &Field = self.0;
+        let field = self.0;
         let ident = field.ident;
         let ty = field.ty;
 
@@ -146,7 +146,7 @@
 
 impl<'a> ToTokens for MatchArm<'a> {
     fn to_tokens(&self, tokens: &mut TokenStream) {
-        let field: &Field = self.0;
+        let field = self.0;
 
         // Skipped and flattened fields cannot be populated by a meta
         // with their name, so they do not have a match arm.
@@ -211,7 +211,7 @@
 
 impl<'a> ToTokens for Initializer<'a> {
     fn to_tokens(&self, tokens: &mut TokenStream) {
-        let field: &Field = self.0;
+        let field = self.0;
         let ident = field.ident;
         tokens.append_all(if field.multiple {
             if let Some(ref expr) = field.default_expression {
diff --git a/crates/darling_core/src/codegen/from_attributes_impl.rs b/crates/darling_core/src/codegen/from_attributes_impl.rs
index 72da349..1e40c26 100644
--- a/crates/darling_core/src/codegen/from_attributes_impl.rs
+++ b/crates/darling_core/src/codegen/from_attributes_impl.rs
@@ -38,6 +38,7 @@
             }
         }
 
+        let passed_attrs = self.forward_attrs.as_initializer();
         let inits = self.base.initializers();
         let default = self.base.fallback_decl();
 
@@ -61,6 +62,7 @@
                     #default
 
                     ::darling::export::Ok(#ty_ident {
+                        #passed_attrs
                         #inits
                     }) #post_transform
                 }
@@ -79,7 +81,7 @@
         self.attr_names
     }
 
-    fn forward_attrs(&self) -> &super::ForwardAttrs {
+    fn forward_attrs(&self) -> &super::ForwardAttrs<'_> {
         &self.forward_attrs
     }
 
diff --git a/crates/darling_core/src/codegen/from_derive_impl.rs b/crates/darling_core/src/codegen/from_derive_impl.rs
index d64d9e2..8016ca8 100644
--- a/crates/darling_core/src/codegen/from_derive_impl.rs
+++ b/crates/darling_core/src/codegen/from_derive_impl.rs
@@ -116,7 +116,7 @@
         self.attr_names
     }
 
-    fn forward_attrs(&self) -> &ForwardAttrs {
+    fn forward_attrs(&self) -> &ForwardAttrs<'_> {
         &self.forward_attrs
     }
 
diff --git a/crates/darling_core/src/codegen/from_field.rs b/crates/darling_core/src/codegen/from_field.rs
index 5bd7350..d29b77d 100644
--- a/crates/darling_core/src/codegen/from_field.rs
+++ b/crates/darling_core/src/codegen/from_field.rs
@@ -82,7 +82,7 @@
         self.attr_names
     }
 
-    fn forward_attrs(&self) -> &super::ForwardAttrs {
+    fn forward_attrs(&self) -> &super::ForwardAttrs<'_> {
         &self.forward_attrs
     }
 
diff --git a/crates/darling_core/src/codegen/from_type_param.rs b/crates/darling_core/src/codegen/from_type_param.rs
index d44e8eb..5f356fd 100644
--- a/crates/darling_core/src/codegen/from_type_param.rs
+++ b/crates/darling_core/src/codegen/from_type_param.rs
@@ -79,7 +79,7 @@
         self.attr_names
     }
 
-    fn forward_attrs(&self) -> &ForwardAttrs {
+    fn forward_attrs(&self) -> &ForwardAttrs<'_> {
         &self.forward_attrs
     }
 
diff --git a/crates/darling_core/src/codegen/from_variant_impl.rs b/crates/darling_core/src/codegen/from_variant_impl.rs
index a835b13..6febde0 100644
--- a/crates/darling_core/src/codegen/from_variant_impl.rs
+++ b/crates/darling_core/src/codegen/from_variant_impl.rs
@@ -106,7 +106,7 @@
         self.attr_names
     }
 
-    fn forward_attrs(&self) -> &ForwardAttrs {
+    fn forward_attrs(&self) -> &ForwardAttrs<'_> {
         &self.forward_attrs
     }
 
diff --git a/crates/darling_core/src/codegen/outer_from_impl.rs b/crates/darling_core/src/codegen/outer_from_impl.rs
index 79c5c68..5e266ef 100644
--- a/crates/darling_core/src/codegen/outer_from_impl.rs
+++ b/crates/darling_core/src/codegen/outer_from_impl.rs
@@ -28,6 +28,7 @@
 
         tokens.append_all(quote!(
             #[automatically_derived]
+            #[allow(clippy::manual_unwrap_or_default)]
             impl #impl_generics #trayt for #ty_ident #ty_generics
                 #where_clause
             {
diff --git a/crates/darling_core/src/codegen/trait_impl.rs b/crates/darling_core/src/codegen/trait_impl.rs
index 2f358db..1dab56f 100644
--- a/crates/darling_core/src/codegen/trait_impl.rs
+++ b/crates/darling_core/src/codegen/trait_impl.rs
@@ -1,6 +1,6 @@
 use proc_macro2::TokenStream;
 use quote::quote;
-use syn::{Generics, Ident, WherePredicate};
+use syn::{Generics, Ident};
 
 use crate::ast::{Data, Fields};
 use crate::codegen::{
@@ -16,7 +16,6 @@
     pub data: Data<Variant<'a>, Field<'a>>,
     pub default: Option<DefaultExpression<'a>>,
     pub post_transform: Option<&'a PostfixTransform>,
-    pub bound: Option<&'a [WherePredicate]>,
     pub allow_unknown_fields: bool,
 }
 
@@ -38,8 +37,8 @@
 
     fn type_params_matching<F, V>(&self, field_filter: F, variant_filter: V) -> IdentSet
     where
-        F: Fn(&&Field) -> bool,
-        V: Fn(&&Variant) -> bool,
+        F: Fn(&&Field<'_>) -> bool,
+        V: Fn(&&Variant<'_>) -> bool,
     {
         let declared = self.declared_type_params();
         match self.data {
@@ -67,7 +66,7 @@
         declared: &IdentSet,
     ) -> IdentSet
     where
-        F: Fn(&&'b Field) -> bool,
+        F: Fn(&&'b Field<'_>) -> bool,
     {
         fields
             .iter()
@@ -83,7 +82,7 @@
     }
 
     /// Gets the check which performs an early return if errors occurred during parsing.
-    pub fn check_errors(&self) -> ErrorCheck {
+    pub fn check_errors(&self) -> ErrorCheck<'_> {
         ErrorCheck::default()
     }
 
diff --git a/crates/darling_core/src/codegen/variant.rs b/crates/darling_core/src/codegen/variant.rs
index 2a55780..9ce643f 100644
--- a/crates/darling_core/src/codegen/variant.rs
+++ b/crates/darling_core/src/codegen/variant.rs
@@ -82,6 +82,12 @@
 
         let name_in_attr = &val.name_in_attr;
 
+        let unsupported_format_error = || {
+            quote!(::darling::export::Err(
+                ::darling::Error::unsupported_format("literal")
+            ))
+        };
+
         if val.data.is_unit() {
             let variant_ident = val.variant_ident;
             let ty_ident = val.ty_ident;
@@ -89,9 +95,29 @@
             tokens.append_all(quote!(
                 #name_in_attr => ::darling::export::Ok(#ty_ident::#variant_ident),
             ));
+        } else if val.data.is_newtype() {
+            let field = val
+                .data
+                .fields
+                .first()
+                .expect("Newtype should have exactly one field");
+            let field_ty = field.ty;
+            let ty_ident = val.ty_ident;
+            let variant_ident = val.variant_ident;
+            let unsupported_format = unsupported_format_error();
+
+            tokens.append_all(quote!{
+                #name_in_attr => {
+                    match <#field_ty as ::darling::FromMeta>::from_none() {
+                        ::darling::export::Some(__value) => ::darling::export::Ok(#ty_ident::#variant_ident(__value)),
+                        ::darling::export::None => #unsupported_format,
+                    }
+                }
+            })
         } else {
+            let unsupported_format = unsupported_format_error();
             tokens.append_all(quote!(
-                #name_in_attr => ::darling::export::Err(::darling::Error::unsupported_format("literal")),
+                #name_in_attr => #unsupported_format,
             ));
         }
     }
diff --git a/crates/darling_core/src/error/kind.rs b/crates/darling_core/src/error/kind.rs
index 1254f67..6d5ef8a 100644
--- a/crates/darling_core/src/error/kind.rs
+++ b/crates/darling_core/src/error/kind.rs
@@ -64,7 +64,7 @@
 }
 
 impl fmt::Display for ErrorKind {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use self::ErrorKind::*;
 
         match *self {
@@ -191,7 +191,7 @@
 }
 
 impl fmt::Display for ErrorUnknownField {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "Unknown field: `{}`", self.name)?;
 
         if let Some((_, ref did_you_mean)) = self.did_you_mean {
diff --git a/crates/darling_core/src/error/mod.rs b/crates/darling_core/src/error/mod.rs
index 3c22d4c..5ce2ef1 100644
--- a/crates/darling_core/src/error/mod.rs
+++ b/crates/darling_core/src/error/mod.rs
@@ -634,7 +634,7 @@
 }
 
 impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", self.kind)?;
         if !self.locations.is_empty() {
             write!(f, " at {}", self.locations.join("/"))?;
diff --git a/crates/darling_core/src/from_meta.rs b/crates/darling_core/src/from_meta.rs
index 7e50e4e..dd3a2b0 100644
--- a/crates/darling_core/src/from_meta.rs
+++ b/crates/darling_core/src/from_meta.rs
@@ -3,6 +3,7 @@
 use std::collections::hash_map::HashMap;
 use std::collections::HashSet;
 use std::hash::BuildHasher;
+use std::num;
 use std::rc::Rc;
 use std::sync::atomic::AtomicBool;
 use std::sync::Arc;
@@ -219,7 +220,7 @@
 /// Generate an impl of `FromMeta` that will accept strings which parse to numbers or
 /// integer literals.
 macro_rules! from_meta_num {
-    ($ty:ident) => {
+    ($ty:path) => {
         impl FromMeta for $ty {
             fn from_string(s: &str) -> Result<Self> {
                 s.parse().map_err(|_| Error::unknown_value(s))
@@ -228,7 +229,7 @@
             fn from_value(value: &Lit) -> Result<Self> {
                 (match *value {
                     Lit::Str(ref s) => Self::from_string(&s.value()),
-                    Lit::Int(ref s) => Ok(s.base10_parse::<$ty>().unwrap()),
+                    Lit::Int(ref s) => s.base10_parse::<$ty>().map_err(Error::from),
                     _ => Err(Error::unexpected_lit_type(value)),
                 })
                 .map_err(|e| e.with_span(value))
@@ -249,6 +250,18 @@
 from_meta_num!(i64);
 from_meta_num!(i128);
 from_meta_num!(isize);
+from_meta_num!(num::NonZeroU8);
+from_meta_num!(num::NonZeroU16);
+from_meta_num!(num::NonZeroU32);
+from_meta_num!(num::NonZeroU64);
+from_meta_num!(num::NonZeroU128);
+from_meta_num!(num::NonZeroUsize);
+from_meta_num!(num::NonZeroI8);
+from_meta_num!(num::NonZeroI16);
+from_meta_num!(num::NonZeroI32);
+from_meta_num!(num::NonZeroI64);
+from_meta_num!(num::NonZeroI128);
+from_meta_num!(num::NonZeroIsize);
 
 /// Generate an impl of `FromMeta` that will accept strings which parse to floats or
 /// float literals.
@@ -262,7 +275,7 @@
             fn from_value(value: &Lit) -> Result<Self> {
                 (match *value {
                     Lit::Str(ref s) => Self::from_string(&s.value()),
-                    Lit::Float(ref s) => Ok(s.base10_parse::<$ty>().unwrap()),
+                    Lit::Float(ref s) => s.base10_parse::<$ty>().map_err(Error::from),
                     _ => Err(Error::unexpected_lit_type(value)),
                 })
                 .map_err(|e| e.with_span(value))
@@ -596,26 +609,50 @@
     }
 }
 
-impl<T: FromMeta> FromMeta for Box<T> {
-    fn from_none() -> Option<Self> {
-        T::from_none().map(Box::new)
-    }
-
-    fn from_meta(item: &Meta) -> Result<Self> {
-        FromMeta::from_meta(item).map(Box::new)
-    }
-}
-
 impl<T: FromMeta> FromMeta for Result<T> {
     fn from_none() -> Option<Self> {
         T::from_none().map(Ok)
     }
 
+    // `#[darling(flatten)]` forwards directly to this method, so it's
+    // necessary to declare it to avoid getting an unsupported format
+    // error if it's invoked directly.
+    fn from_list(items: &[NestedMeta]) -> Result<Self> {
+        Ok(FromMeta::from_list(items))
+    }
+
     fn from_meta(item: &Meta) -> Result<Self> {
         Ok(FromMeta::from_meta(item))
     }
 }
 
+/// Create an impl that forwards to an inner type `T` for parsing.
+macro_rules! smart_pointer_t {
+    ($ty:path, $map_fn:path) => {
+        impl<T: FromMeta> FromMeta for $ty {
+            fn from_none() -> Option<Self> {
+                T::from_none().map($map_fn)
+            }
+
+            // `#[darling(flatten)]` forwards directly to this method, so it's
+            // necessary to declare it to avoid getting an unsupported format
+            // error if it's invoked directly.
+            fn from_list(items: &[NestedMeta]) -> Result<Self> {
+                FromMeta::from_list(items).map($map_fn)
+            }
+
+            fn from_meta(item: &Meta) -> Result<Self> {
+                FromMeta::from_meta(item).map($map_fn)
+            }
+        }
+    };
+}
+
+smart_pointer_t!(Box<T>, Box::new);
+smart_pointer_t!(Rc<T>, Rc::new);
+smart_pointer_t!(Arc<T>, Arc::new);
+smart_pointer_t!(RefCell<T>, RefCell::new);
+
 /// Parses the meta-item, and in case of error preserves a copy of the input for
 /// later analysis.
 impl<T: FromMeta> FromMeta for ::std::result::Result<T, Meta> {
@@ -626,36 +663,6 @@
     }
 }
 
-impl<T: FromMeta> FromMeta for Rc<T> {
-    fn from_none() -> Option<Self> {
-        T::from_none().map(Rc::new)
-    }
-
-    fn from_meta(item: &Meta) -> Result<Self> {
-        FromMeta::from_meta(item).map(Rc::new)
-    }
-}
-
-impl<T: FromMeta> FromMeta for Arc<T> {
-    fn from_none() -> Option<Self> {
-        T::from_none().map(Arc::new)
-    }
-
-    fn from_meta(item: &Meta) -> Result<Self> {
-        FromMeta::from_meta(item).map(Arc::new)
-    }
-}
-
-impl<T: FromMeta> FromMeta for RefCell<T> {
-    fn from_none() -> Option<Self> {
-        T::from_none().map(RefCell::new)
-    }
-
-    fn from_meta(item: &Meta) -> Result<Self> {
-        FromMeta::from_meta(item).map(RefCell::new)
-    }
-}
-
 /// Trait to convert from a path into an owned key for a map.
 trait KeyFromPath: Sized {
     fn from_path(path: &syn::Path) -> Result<Self>;
@@ -787,6 +794,8 @@
 /// it should not be considered by the parsing.
 #[cfg(test)]
 mod tests {
+    use std::num::{NonZeroU32, NonZeroU64};
+
     use proc_macro2::TokenStream;
     use quote::quote;
     use syn::parse_quote;
@@ -859,6 +868,20 @@
         assert_eq!(fm::<f64>(quote!(ignore = "1.4e10")), 1.4e10);
     }
 
+    #[should_panic(expected = "UnknownValue(\"0\")")]
+    #[test]
+    fn nonzero_number_fails() {
+        fm::<NonZeroU64>(quote!(ignore = "0"));
+    }
+
+    #[test]
+    fn nonzero_number_succeeds() {
+        assert_eq!(
+            fm::<NonZeroU32>(quote!(ignore = "2")),
+            NonZeroU32::new(2).unwrap()
+        );
+    }
+
     #[test]
     fn int_without_quotes() {
         assert_eq!(fm::<u8>(quote!(ignore = 2)), 2u8);
@@ -884,6 +907,11 @@
     }
 
     #[test]
+    fn too_large_int_produces_error() {
+        assert!(fm::<Result<u8>>(quote!(ignore = 2000)).is_err());
+    }
+
+    #[test]
     fn meta_succeeds() {
         use syn::Meta;
 
diff --git a/crates/darling_core/src/lib.rs b/crates/darling_core/src/lib.rs
index bf2050c..7915458 100644
--- a/crates/darling_core/src/lib.rs
+++ b/crates/darling_core/src/lib.rs
@@ -1,5 +1,6 @@
 #![recursion_limit = "256"]
 #![cfg_attr(feature = "diagnostics", feature(proc_macro_diagnostic))]
+#![warn(rust_2018_idioms)]
 
 #[cfg(feature = "diagnostics")]
 extern crate proc_macro;
diff --git a/crates/darling_core/src/options/core.rs b/crates/darling_core/src/options/core.rs
index de8bdb0..3eef3f8 100644
--- a/crates/darling_core/src/options/core.rs
+++ b/crates/darling_core/src/options/core.rs
@@ -191,7 +191,6 @@
                 .map_enum_variants(|variant| variant.as_codegen_variant(&v.ident)),
             default: v.as_codegen_default(),
             post_transform: v.post_transform.as_ref(),
-            bound: v.bound.as_deref(),
             allow_unknown_fields: v.allow_unknown_fields.unwrap_or_default(),
         }
     }
diff --git a/crates/darling_core/src/options/from_attributes.rs b/crates/darling_core/src/options/from_attributes.rs
index dc11b29..d642291 100644
--- a/crates/darling_core/src/options/from_attributes.rs
+++ b/crates/darling_core/src/options/from_attributes.rs
@@ -62,7 +62,7 @@
         FromAttributesImpl {
             base: (&v.base.container).into(),
             attr_names: &v.base.attr_names,
-            forward_attrs: Default::default(),
+            forward_attrs: v.base.as_forward_attrs(),
         }
     }
 }
diff --git a/crates/darling_core/src/options/from_derive.rs b/crates/darling_core/src/options/from_derive.rs
index eb27641..3f371b3 100644
--- a/crates/darling_core/src/options/from_derive.rs
+++ b/crates/darling_core/src/options/from_derive.rs
@@ -54,15 +54,15 @@
     fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
         match field.ident.as_ref().map(|v| v.to_string()).as_deref() {
             Some("vis") => {
-                self.vis = field.ident.clone();
+                self.vis.clone_from(&field.ident);
                 Ok(())
             }
             Some("data") => {
-                self.data = field.ident.clone();
+                self.data.clone_from(&field.ident);
                 Ok(())
             }
             Some("generics") => {
-                self.generics = field.ident.clone();
+                self.generics.clone_from(&field.ident);
                 Ok(())
             }
             _ => self.base.parse_field(field),
diff --git a/crates/darling_core/src/options/from_field.rs b/crates/darling_core/src/options/from_field.rs
index 6dcd0f6..00eec5e 100644
--- a/crates/darling_core/src/options/from_field.rs
+++ b/crates/darling_core/src/options/from_field.rs
@@ -39,11 +39,11 @@
     fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
         match field.ident.as_ref().map(|v| v.to_string()).as_deref() {
             Some("vis") => {
-                self.vis = field.ident.clone();
+                self.vis.clone_from(&field.ident);
                 Ok(())
             }
             Some("ty") => {
-                self.ty = field.ident.clone();
+                self.ty.clone_from(&field.ident);
                 Ok(())
             }
             _ => self.base.parse_field(field),
diff --git a/crates/darling_core/src/options/from_type_param.rs b/crates/darling_core/src/options/from_type_param.rs
index e14de99..a7bcb6f 100644
--- a/crates/darling_core/src/options/from_type_param.rs
+++ b/crates/darling_core/src/options/from_type_param.rs
@@ -39,11 +39,11 @@
     fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
         match field.ident.as_ref().map(|v| v.to_string()).as_deref() {
             Some("bounds") => {
-                self.bounds = field.ident.clone();
+                self.bounds.clone_from(&field.ident);
                 Ok(())
             }
             Some("default") => {
-                self.default = field.ident.clone();
+                self.default.clone_from(&field.ident);
                 Ok(())
             }
             _ => self.base.parse_field(field),
diff --git a/crates/darling_core/src/options/from_variant.rs b/crates/darling_core/src/options/from_variant.rs
index c3223c5..79a34b3 100644
--- a/crates/darling_core/src/options/from_variant.rs
+++ b/crates/darling_core/src/options/from_variant.rs
@@ -59,11 +59,11 @@
     fn parse_field(&mut self, field: &Field) -> Result<()> {
         match field.ident.as_ref().map(|v| v.to_string()).as_deref() {
             Some("discriminant") => {
-                self.discriminant = field.ident.clone();
+                self.discriminant.clone_from(&field.ident);
                 Ok(())
             }
             Some("fields") => {
-                self.fields = field.ident.clone();
+                self.fields.clone_from(&field.ident);
                 Ok(())
             }
             _ => self.base.parse_field(field),
diff --git a/crates/darling_core/src/options/outer_from.rs b/crates/darling_core/src/options/outer_from.rs
index da97b47..20bac5d 100644
--- a/crates/darling_core/src/options/outer_from.rs
+++ b/crates/darling_core/src/options/outer_from.rs
@@ -43,7 +43,7 @@
         })
     }
 
-    pub fn as_forward_attrs(&self) -> ForwardAttrs {
+    pub fn as_forward_attrs(&self) -> ForwardAttrs<'_> {
         ForwardAttrs {
             field: self.attrs.as_ref(),
             filter: self.forward_attrs.as_ref(),
@@ -78,7 +78,7 @@
     fn parse_field(&mut self, field: &Field) -> Result<()> {
         match field.ident.as_ref().map(|v| v.to_string()).as_deref() {
             Some("ident") => {
-                self.ident = field.ident.clone();
+                self.ident.clone_from(&field.ident);
                 Ok(())
             }
             Some("attrs") => {
diff --git a/crates/darling_core/src/util/ident_string.rs b/crates/darling_core/src/util/ident_string.rs
index 937d1a6..3b926cd 100644
--- a/crates/darling_core/src/util/ident_string.rs
+++ b/crates/darling_core/src/util/ident_string.rs
@@ -118,13 +118,13 @@
 }
 
 impl fmt::Debug for IdentString {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{:?}", self.ident)
     }
 }
 
 impl fmt::Display for IdentString {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", self.ident)
     }
 }
diff --git a/crates/darling_core/src/util/over_ride.rs b/crates/darling_core/src/util/over_ride.rs
index 0b52dd8..620cc5f 100644
--- a/crates/darling_core/src/util/over_ride.rs
+++ b/crates/darling_core/src/util/over_ride.rs
@@ -126,7 +126,7 @@
 }
 
 impl<T: fmt::Display> fmt::Display for Override<T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             Inherit => write!(f, "Inherit"),
             Explicit(ref val) => write!(f, "Explicit `{}`", val),
diff --git a/crates/darling_core/src/util/parse_attribute.rs b/crates/darling_core/src/util/parse_attribute.rs
index 747c30d..48d6329 100644
--- a/crates/darling_core/src/util/parse_attribute.rs
+++ b/crates/darling_core/src/util/parse_attribute.rs
@@ -35,7 +35,7 @@
 struct DisplayPath<'a>(&'a Path);
 
 impl fmt::Display for DisplayPath<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let path = self.0;
         if path.leading_colon.is_some() {
             write!(f, "::")?;
diff --git a/crates/darling_macro/.cargo-checksum.json b/crates/darling_macro/.cargo-checksum.json
index 7c85ef6..a0d8fa7 100644
--- a/crates/darling_macro/.cargo-checksum.json
+++ b/crates/darling_macro/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"e3bf0c57ff7ad1e7456607dd30f48d7b01ee7f0cce626506ec1c75e74411954a","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","src/lib.rs":"728be3bb12c9cdaaf0520bce87e489a0820e436c78fa3627e238fc1acc11dd7f"},"package":"a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"}
\ No newline at end of file
+{"files":{"Cargo.toml":"b79ce73433e4a17b2f24ce9a3bae7f2c17714e10805653863c50d42532b1128c","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","src/lib.rs":"728be3bb12c9cdaaf0520bce87e489a0820e436c78fa3627e238fc1acc11dd7f"},"package":"d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"}
\ No newline at end of file
diff --git a/crates/darling_macro/Android.bp b/crates/darling_macro/Android.bp
index a9dabbf..067bd7f 100644
--- a/crates/darling_macro/Android.bp
+++ b/crates/darling_macro/Android.bp
@@ -17,9 +17,9 @@
     name: "libdarling_macro",
     crate_name: "darling_macro",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.20.8",
+    cargo_pkg_version: "0.20.10",
     crate_root: "src/lib.rs",
-    edition: "2018",
+    edition: "2021",
     rustlibs: [
         "libdarling_core",
         "libquote",
diff --git a/crates/darling_macro/Cargo.toml b/crates/darling_macro/Cargo.toml
index 779f3b1..01133bb 100644
--- a/crates/darling_macro/Cargo.toml
+++ b/crates/darling_macro/Cargo.toml
@@ -10,9 +10,10 @@
 # See Cargo.toml.orig for the original contents.
 
 [package]
-edition = "2018"
+edition = "2021"
+rust-version = "1.56"
 name = "darling_macro"
-version = "0.20.8"
+version = "0.20.10"
 authors = ["Ted Driggs <ted.driggs@outlook.com>"]
 description = """
 Internal support for a proc-macro library for reading attributes into structs when
@@ -25,7 +26,7 @@
 proc-macro = true
 
 [dependencies.darling_core]
-version = "=0.20.8"
+version = "=0.20.10"
 
 [dependencies.quote]
 version = "1.0.18"
diff --git a/crates/darling_macro/METADATA b/crates/darling_macro/METADATA
index 63ba03d..ce04771 100644
--- a/crates/darling_macro/METADATA
+++ b/crates/darling_macro/METADATA
@@ -1,17 +1,17 @@
 name: "darling_macro"
 description: "()"
 third_party {
-  version: "0.20.8"
+  version: "0.20.10"
   license_type: NOTICE
   last_upgrade_date {
     year: 2024
-    month: 3
-    day: 6
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/darling_macro"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/darling_macro/darling_macro-0.20.8.crate"
-    version: "0.20.8"
+    value: "https://static.crates.io/crates/darling_macro/darling_macro-0.20.10.crate"
+    version: "0.20.10"
   }
 }
diff --git a/crates/der_derive/.cargo-checksum.json b/crates/der_derive/.cargo-checksum.json
index 2786d74..4061000 100644
--- a/crates/der_derive/.cargo-checksum.json
+++ b/crates/der_derive/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"87f531146a92caab6fa3ca3ea06f11020a715c2d1230aabba4dd02f277d5a6be","Cargo.toml":"1ea70d9ef1ccf1e682c0e76102fd555819a600ed7ec90f0a6c6a63fa5985912e","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"bada9e7ed8dc00d63502053c455d7c8d7575dfb7e8277a2a832531844d900682","README.md":"3ce01127caaece7ffed43cb0cf72c1c0d26f257e0b17e05151f159ab86a1960a","src/asn1_type.rs":"fd069c7d014e2ccca9870a5eb38996ec5c53735122534c104f4184ed4ca1816a","src/attributes.rs":"fe488ebe8bab405307394fe2a7a76e33bbe88abe2c11b494fcd4ca7ddc967f61","src/choice.rs":"5d3ae12877795ef8f2329160d2c991b05078a6d3addc807d418adcddefb47ef4","src/choice/variant.rs":"473f2bd3b9f6456381324e2dc86ca1e5f42089d27c43458559b232c1410b3895","src/enumerated.rs":"2f914d0c630aa583af5f723e7dd18596f6a7a15e947b2862f928560a62fcc970","src/lib.rs":"211cf61053dd2cfced08ac612e1c76be7500966538b5b650ec620a56fe7c5bc0","src/sequence.rs":"f89aef12f4ebf9693910e26543f208163fcc82710a96a5a6d92a77bbc77d014c","src/sequence/field.rs":"de00c30192afea7e7d0befe736a82b46f55ecfac31069b221704df8c9558eed4","src/tag.rs":"8f16997917e2a77813410eadf71d76427c0813a4a7f0832fea86f24f6be93173","src/value_ord.rs":"d3d107012f74fd7ad80d2d730e357e305adaf28b665de564c9d8ec36eef53ccc"},"package":"5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"a105f6f6aa23249c6aa14058900253b11445909da976a3dfbaa2f28ba58bc5f0","Cargo.toml":"a500496532a6fa4aabd03078b38d8ad56355bd178a438bd4ba03799cddc18311","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"bada9e7ed8dc00d63502053c455d7c8d7575dfb7e8277a2a832531844d900682","README.md":"3ce01127caaece7ffed43cb0cf72c1c0d26f257e0b17e05151f159ab86a1960a","src/asn1_type.rs":"fd069c7d014e2ccca9870a5eb38996ec5c53735122534c104f4184ed4ca1816a","src/attributes.rs":"fe488ebe8bab405307394fe2a7a76e33bbe88abe2c11b494fcd4ca7ddc967f61","src/choice.rs":"5d3ae12877795ef8f2329160d2c991b05078a6d3addc807d418adcddefb47ef4","src/choice/variant.rs":"473f2bd3b9f6456381324e2dc86ca1e5f42089d27c43458559b232c1410b3895","src/enumerated.rs":"2f914d0c630aa583af5f723e7dd18596f6a7a15e947b2862f928560a62fcc970","src/lib.rs":"211cf61053dd2cfced08ac612e1c76be7500966538b5b650ec620a56fe7c5bc0","src/sequence.rs":"f89aef12f4ebf9693910e26543f208163fcc82710a96a5a6d92a77bbc77d014c","src/sequence/field.rs":"634a67a56a30ae49732d8940a5c318801618ccb034751e45b70fc35d39964a25","src/tag.rs":"8f16997917e2a77813410eadf71d76427c0813a4a7f0832fea86f24f6be93173","src/value_ord.rs":"d3d107012f74fd7ad80d2d730e357e305adaf28b665de564c9d8ec36eef53ccc"},"package":"8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18"}
\ No newline at end of file
diff --git a/crates/der_derive/Android.bp b/crates/der_derive/Android.bp
index bb09e46..c302e1c 100644
--- a/crates/der_derive/Android.bp
+++ b/crates/der_derive/Android.bp
@@ -17,7 +17,7 @@
     name: "libder_derive",
     crate_name: "der_derive",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.7.2",
+    cargo_pkg_version: "0.7.3",
     crate_root: "src/lib.rs",
     edition: "2021",
     rustlibs: [
diff --git a/crates/der_derive/CHANGELOG.md b/crates/der_derive/CHANGELOG.md
index 194f7af..a9dc9cd 100644
--- a/crates/der_derive/CHANGELOG.md
+++ b/crates/der_derive/CHANGELOG.md
@@ -4,6 +4,12 @@
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## 0.7.3 (2024-07-09)
+### Changed
+- avoid type inference when using default ([#1443])
+
+[#1443]: https://github.com/RustCrypto/formats/pull/1443
+
 ## 0.7.2 (2023-08-07)
 ### Changed
 - fix doc typo and use a valid tag number ([#1184])
diff --git a/crates/der_derive/Cargo.toml b/crates/der_derive/Cargo.toml
index 3d86ca3..fdfebaa 100644
--- a/crates/der_derive/Cargo.toml
+++ b/crates/der_derive/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2021"
 rust-version = "1.65"
 name = "der_derive"
-version = "0.7.2"
+version = "0.7.3"
 authors = ["RustCrypto Developers"]
 description = "Custom derive support for the `der` crate's `Choice` and `Sequence` traits"
 documentation = "https://docs.rs/der"
diff --git a/crates/der_derive/METADATA b/crates/der_derive/METADATA
index a9e8811..ff4016e 100644
--- a/crates/der_derive/METADATA
+++ b/crates/der_derive/METADATA
@@ -1,17 +1,17 @@
 name: "der_derive"
 description: "Custom derive support for the `der` crate\'s `Choice` and `Sequence` traits"
 third_party {
-  version: "0.7.2"
+  version: "0.7.3"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2023
-    month: 12
-    day: 15
+    year: 2024
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/der_derive"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/der_derive/der_derive-0.7.2.crate"
-    version: "0.7.2"
+    value: "https://static.crates.io/crates/der_derive/der_derive-0.7.3.crate"
+    version: "0.7.3"
   }
 }
diff --git a/crates/der_derive/src/sequence/field.rs b/crates/der_derive/src/sequence/field.rs
index 3fb1832..d91599c 100644
--- a/crates/der_derive/src/sequence/field.rs
+++ b/crates/der_derive/src/sequence/field.rs
@@ -97,7 +97,7 @@
                 !attrs.optional,
                 "`default`, and `optional` are mutually exclusive"
             );
-            lowerer.apply_default(&self.ident, default);
+            lowerer.apply_default(&self.ident, default, &self.field_type);
         }
 
         lowerer.into_tokens()
@@ -189,14 +189,17 @@
     }
 
     /// Handle default value for a type.
-    fn apply_default(&mut self, ident: &Ident, default: &Path) {
+    fn apply_default(&mut self, ident: &Ident, default: &Path, field_type: &Type) {
         let encoder = &self.encoder;
 
         self.encoder = quote! {
-            if &self.#ident == &#default() {
-                None
-            } else {
-                Some(#encoder)
+            {
+                let default_value: #field_type = #default();
+                if &self.#ident == &default_value {
+                    None
+                } else {
+                    Some(#encoder)
+                }
             }
         };
     }
diff --git a/crates/displaydoc/.cargo-checksum.json b/crates/displaydoc/.cargo-checksum.json
index a1f0964..ddbf7a3 100644
--- a/crates/displaydoc/.cargo-checksum.json
+++ b/crates/displaydoc/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"ac4b11a820a3251453aa5eed99f2e34758281c4794234376532ab1686fc4092e","Cargo.lock":"764c7f380095ccd0c22e10470ed71a1c38899a502943f70baf1b0641f30d61a9","Cargo.toml":"6eac127183532630ea388e11f07a33c1a8537175d4f1269290eacd0b5010b41d","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"60628c334f71eba035e7ba4d5ba4df966c9de953260f9d1f28b0141ad06a07a8","README.tpl":"a8b023f5f39b795ef553c2b75551d6ad42db6597362c8909101f4bc8c8994bcc","examples/simple.rs":"dd37ed49175e86124cf58aba6fdcf4b4c2adc13a2414d4a2ba31cfab21638415","src/attr.rs":"1aeaf46ea739f63bf7eca5a575ca4345ff325c16e959fb59b5671b9a338d5ddc","src/expand.rs":"a0e6c062e00b9e68a0811a7d4d739e7572cd4a5dd962dc3519c0c8bfa1e84d8b","src/fmt.rs":"9734d3b51206f73ca8d9a513bee46d72215ff877797500887d43bc64af639c37","src/lib.rs":"de304b1de4a60700c0a031c6bd568da7ed24f5169edcfc16b7009e9e9494daed","tests/compile_tests.rs":"6cd211e343c42873a287b02581bd342b09ae508022fc82022714ebdc625935aa","tests/happy.rs":"ebd93ca6cea7c2ab77c59f990335ca34714e19365fddd40a6eca5f180bf7cb75","tests/no_std/enum_prefix.rs":"fd2a565ceddffe0433f83c6d0c9b15bc1db96fbf952f222ff04bc0dc1ea34d41","tests/no_std/enum_prefix_missing.rs":"4ed8aaef3d9274b377837b90fb9a80315df502b1c569de3213b7a2e7fa613322","tests/no_std/enum_prefix_missing.stderr":"add42a5efa90502483b2fcd0152289b62c1d5b790faf9e46d8d930e4e474b781","tests/no_std/multi_line.rs":"6ce3c1554f8bffa409f42a12517f2ef79e884ce22c79d2514455263a9254ae10","tests/no_std/multi_line.stderr":"ee076d8d02e187fe9651429a755599752b82be5910aa19e9312cf678779b2c03","tests/no_std/multi_line_allow.rs":"ef1f5a6b551e81ec6405626c939d81fe6db279bd5c2c66a2c5cc6e30a318cdbe","tests/no_std/with.rs":"3607edede6069527e792e000bfe0062f539ec342048aa2b2322556f6d6462bcc","tests/no_std/without.rs":"518cd04d73bd950e70f2d515d2cdae48b0f409fbefa2132b4d9a1b97e9c0a406","tests/no_std/without.stderr":"b3ade743ec5597f433cfb6ac378db239207d349bc99b21d9f75399a8df6ec4ae","tests/num_in_field.rs":"cd83f7d79ae065a97dcb53b2e92dc57e2f269e12433d1cd4644cb0ec6b2a4d0f","tests/std/enum_prefix.rs":"fd2a565ceddffe0433f83c6d0c9b15bc1db96fbf952f222ff04bc0dc1ea34d41","tests/std/enum_prefix_missing.rs":"4ed8aaef3d9274b377837b90fb9a80315df502b1c569de3213b7a2e7fa613322","tests/std/enum_prefix_missing.stderr":"ac4b4ac371b6e134bc1781854e3bc4df2afecdb29182a9c8328ee1d37c0fef3d","tests/std/multi_line.rs":"86726db8140e5bf9f690ac3f2d607a7a9d74b9b79fae7945480cff62cf3e8700","tests/std/multi_line.stderr":"ed9de88820f5a0cacdf26f955790b1c433c784a432cf723a963211011e1ccd7b","tests/std/multi_line_allow.rs":"ef1f5a6b551e81ec6405626c939d81fe6db279bd5c2c66a2c5cc6e30a318cdbe","tests/std/multiple.rs":"a4194da6b5bef919bb0107ddb91c548421ef9812d69894bef5e5b6f316af8eee","tests/std/without.rs":"80a59e296ee3c205960b9e8dd18c1d2b210d8fd096e89652d482b963010f340b","tests/std/without.stderr":"fc699e263f1148b1db7f5ea63f0d952c74f997c8155578ff4efaf1cd9f8db8d4","tests/variantless.rs":"84495a36014bdc090b8e5d97442bcfd3229d07f0d40579e450e71596ef9a7b50","update-readme.sh":"794668cc4eb58da01049effb0370db4799e7a70a9db777edfba83d92c33e821a"},"package":"487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"9aadbd7c8b22fa4574b2080d0baaa908f43b5ed2c320c64ec88476cbf739871b","Cargo.lock":"53ebb1c438812bf2e049126afd9bb833d02278416d49ed436d67b4c5c03f21b1","Cargo.toml":"c6f12ae2dd031cf599ec131d3b6b89fb5de66edc4416b4a8f2f06b3fda889620","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"4e230c5596f208b8b752edaa1ff3ace5b1508da61f2069129fa5a6fbda6f4834","README.tpl":"974701ae7f6d238bd325dd32104a5265841e79a9b79a595f7fdd964711c0cd19","examples/simple.rs":"bca524b36621ac56044cbe3eebf8892f7a3b398fd8f257fc67b17b26ae34bfbf","src/attr.rs":"10b31136a5d46066066ea3988f8b857b554fa62b3737988967ae7c2aaa97a58b","src/expand.rs":"6d201ddf75b065875131f437d5a911bb4b2d3e9fe385eebbfc61101d790549dd","src/fmt.rs":"9c13cbcd337066614bc26ecfd36ea9730c9b8099083a9a7ffd79f8dc17e414f1","src/lib.rs":"01b770363022045aa8de41548b20764db7278ae90add903642312eaa4408d467","tests/compile_tests.rs":"935609d68eaa52e0ce9f29b3dae649787cd1f540f9b4bbadcbefcb8a0febcfc8","tests/happy.rs":"1b4c119184ca3914684c1cafaa25a8fbb9e60ef45eb257ad7ac86b8b2d7a3856","tests/no_std/enum_prefix.rs":"386e18cd6b6d35df0a864473a820aa05872f2f7f8364793adae784203946eb82","tests/no_std/enum_prefix_missing.rs":"f60100eac4b3a0f86c57b2082ee52e94b3fa0b5029e535fd3fd55cc1aeaf308c","tests/no_std/enum_prefix_missing.stderr":"e0e98f4dfc21f8cb133519ff98f10b08d8c76219b54cfbc6436c46ba9c601ead","tests/no_std/multi_line.rs":"b0c0cdc7631234a9b7a49205bb1d6824821153001ab30ddad1948deaaaa363c3","tests/no_std/multi_line.stderr":"08cba6ace9ac1938ea8fe18ed4a536b861ad48a9f9d646b4a7ebfe4bf5da438c","tests/no_std/multi_line_allow.rs":"7f7b300db1336b5d9487f82e10deee6a22a7d749ae3698e13e45455540ed5742","tests/no_std/with.rs":"ba96ba70da11f7d5afb5b43a23d8f1d7d28b1eceda8c84c1595006145b8e15fd","tests/no_std/without.rs":"fa2d73e9d6b3bff8073bc95296aeef69e4e8c20a8e6666c239041564877cfec9","tests/no_std/without.stderr":"be00cd4dd7396f324c1cb6283d02a38ad55e3b4d2684e7a4b6bbd43ed937c7f2","tests/num_in_field.rs":"d0bc3ba7f9aea17d3abee4ac05afe6d4a0112d3527698791e1eeaa3464e2b1d4","tests/std/enum_prefix.rs":"baab2132d9468ec167423048ba5244394238e488523214b9e50adee46920f700","tests/std/enum_prefix_missing.rs":"58c8f7c9d851689ca59caf475c0e5f12674f5a58ecbb025cac232acc68eec8aa","tests/std/enum_prefix_missing.stderr":"a26fa36de033d2b032a1e6475cb8d89ee1266e15647bcfaf192931188b38445b","tests/std/multi_line.rs":"b0c0cdc7631234a9b7a49205bb1d6824821153001ab30ddad1948deaaaa363c3","tests/std/multi_line.stderr":"02ca7d07ae4f72c726457c918506ed38873b5085af53c5b60090b53cf5ae46b0","tests/std/multi_line_allow.rs":"ecacc0120aa127dc289d6333348ab357c74d6cb49851de43e7cf3984facf0abc","tests/std/multiple.rs":"b8dc9939c41b2655600ba1b698dbdbbef6e907bff533b6f2cbc315134013fc84","tests/std/without.rs":"fa2d73e9d6b3bff8073bc95296aeef69e4e8c20a8e6666c239041564877cfec9","tests/std/without.stderr":"606a9470520b99eb17c1e609e1074b3765ccd3ab4f1d0b3c3cc2bda9811884de","tests/variantless.rs":"af6930daa15f488fcc00fd2a623a2662ddb86d071ffe698bd97c13c65b9b50a3","update-readme.sh":"7885d60cba79c3dc2b779b9805d520960cc7d8b82d7f1d0c59deff4140ac857b"},"package":"97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"}
\ No newline at end of file
diff --git a/crates/displaydoc/Android.bp b/crates/displaydoc/Android.bp
index ec998e0..3757e33 100644
--- a/crates/displaydoc/Android.bp
+++ b/crates/displaydoc/Android.bp
@@ -17,9 +17,9 @@
     name: "libdisplaydoc",
     crate_name: "displaydoc",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.2.4",
+    cargo_pkg_version: "0.2.5",
     crate_root: "src/lib.rs",
-    edition: "2018",
+    edition: "2021",
     features: [
         "default",
         "std",
diff --git a/crates/displaydoc/CHANGELOG.md b/crates/displaydoc/CHANGELOG.md
index 4513b4a..b4d6cad 100644
--- a/crates/displaydoc/CHANGELOG.md
+++ b/crates/displaydoc/CHANGELOG.md
@@ -1,50 +1,58 @@
-# Changelog

-All notable changes to this project will be documented in this file.

-

-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

-

-<!-- next-header -->

-

-## [Unreleased] - ReleaseDate

-

-# [0.2.4] - 2022-05-02

-

-## Added

-- Updated `syn` dependency to 2.0

-- Support for empty enums

-- Implicitly require fmt::Display on all type parameters unless overridden

-

-## Changed

-- Bumped MSRV to 1.56

-

-# [0.2.3] - 2021-07-16

-## Added

-- Added `#[displaydoc("..")]` attribute for overriding a doc comment

-

-# [0.2.2] - 2021-07-01

-## Added

-- Added prefix feature to use the doc comment from an enum and prepend it

-  before the error message from each variant.

-

-# [0.2.1] - 2021-03-26

-## Added

-- Added opt in support for ignoring extra doc attributes

-

-# [0.2.0] - 2021-03-16

-## Changed

-

-- (BREAKING) disallow multiple `doc` attributes in display impl

-  [https://github.com/yaahc/displaydoc/pull/22]. Allowing and ignoring extra

-  doc attributes made it too easy to accidentally create a broken display

-  implementation with missing context without realizing it, this change turns

-  that into a hard error and directs users towards block comments if multiple

-  lines are needed.

-

-<!-- next-url -->

-[Unreleased]: https://github.com/yaahc/displaydoc/compare/v0.2.4...HEAD

-[0.2.4]: https://github.com/yaahc/displaydoc/compare/v0.2.3...v0.2.4

-[0.2.3]: https://github.com/yaahc/displaydoc/compare/v0.2.2...v0.2.3

-[0.2.2]: https://github.com/yaahc/displaydoc/compare/v0.2.1...v0.2.2

-[0.2.1]: https://github.com/yaahc/displaydoc/compare/v0.2.0...v0.2.1

-[0.2.0]: https://github.com/yaahc/displaydoc/releases/tag/v0.2.0

+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+<!-- next-header -->
+
+## [Unreleased] - ReleaseDate
+
+# [0.2.5] - 2024-06-20
+
+# Changed
+ - Don't name the output of the const block to work around `non_local_definitions` error (#47)
+ - Reference the `core` crate correctly to avoid clashes with modules named `core` (#45)
+ - Explicitly list MSRV in Cargo.toml (#51)
+ - Bump edition to 2021 (#51)
+
+# [0.2.4] - 2022-05-02
+
+## Added
+- Updated `syn` dependency to 2.0
+- Support for empty enums
+- Implicitly require fmt::Display on all type parameters unless overridden
+
+## Changed
+- Bumped MSRV to 1.56
+
+# [0.2.3] - 2021-07-16
+## Added
+- Added `#[displaydoc("..")]` attribute for overriding a doc comment
+
+# [0.2.2] - 2021-07-01
+## Added
+- Added prefix feature to use the doc comment from an enum and prepend it
+  before the error message from each variant.
+
+# [0.2.1] - 2021-03-26
+## Added
+- Added opt in support for ignoring extra doc attributes
+
+# [0.2.0] - 2021-03-16
+## Changed
+
+- (BREAKING) disallow multiple `doc` attributes in display impl
+  [https://github.com/yaahc/displaydoc/pull/22]. Allowing and ignoring extra
+  doc attributes made it too easy to accidentally create a broken display
+  implementation with missing context without realizing it, this change turns
+  that into a hard error and directs users towards block comments if multiple
+  lines are needed.
+
+<!-- next-url -->
+[Unreleased]: https://github.com/yaahc/displaydoc/compare/v0.2.4...HEAD
+[0.2.4]: https://github.com/yaahc/displaydoc/compare/v0.2.3...v0.2.4
+[0.2.3]: https://github.com/yaahc/displaydoc/compare/v0.2.2...v0.2.3
+[0.2.2]: https://github.com/yaahc/displaydoc/compare/v0.2.1...v0.2.2
+[0.2.1]: https://github.com/yaahc/displaydoc/compare/v0.2.0...v0.2.1
+[0.2.0]: https://github.com/yaahc/displaydoc/releases/tag/v0.2.0
diff --git a/crates/displaydoc/Cargo.lock b/crates/displaydoc/Cargo.lock
index 30580d9..5e313d2 100644
--- a/crates/displaydoc/Cargo.lock
+++ b/crates/displaydoc/Cargo.lock
@@ -12,15 +12,6 @@
 ]
 
 [[package]]
-name = "basic-toml"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1"
-dependencies = [
- "serde",
-]
-
-[[package]]
 name = "ctor"
 version = "0.1.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -38,7 +29,7 @@
 
 [[package]]
 name = "displaydoc"
-version = "0.2.4"
+version = "0.2.5"
 dependencies = [
  "libc",
  "pretty_assertions",
@@ -46,34 +37,56 @@
  "quote",
  "rustversion",
  "static_assertions",
- "syn 2.0.15",
+ "syn 2.0.66",
  "thiserror",
  "trybuild",
 ]
 
 [[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
 name = "glob"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
 
 [[package]]
-name = "itoa"
-version = "1.0.6"
+name = "hashbrown"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "indexmap"
+version = "2.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "libc"
-version = "0.2.142"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
-name = "once_cell"
-version = "1.17.1"
+name = "memchr"
+version = "2.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "output_vt100"
@@ -98,56 +111,59 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.56"
+version = "1.0.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
+checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.26"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "rustversion"
-version = "1.0.12"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
+checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
 
 [[package]]
 name = "ryu"
-version = "1.0.13"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "serde"
-version = "1.0.160"
+version = "1.0.203"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
+checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
+dependencies = [
+ "serde_derive",
+]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.160"
+version = "1.0.203"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
+checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.15",
+ "syn 2.0.66",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.96"
+version = "1.0.117"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
+checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
 dependencies = [
  "itoa",
  "ryu",
@@ -155,6 +171,15 @@
 ]
 
 [[package]]
+name = "serde_spanned"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
+dependencies = [
+ "serde",
+]
+
+[[package]]
 name = "static_assertions"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -173,9 +198,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.15"
+version = "2.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -184,53 +209,86 @@
 
 [[package]]
 name = "termcolor"
-version = "1.2.0"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
 dependencies = [
  "winapi-util",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.40"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
+checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.40"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
+checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.15",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
 ]
 
 [[package]]
 name = "trybuild"
-version = "1.0.80"
+version = "1.0.96"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "501dbdbb99861e4ab6b60eb6a7493956a9defb644fd034bc4a5ef27c693c8a3a"
+checksum = "33a5f13f11071020bb12de7a16b925d2d58636175c20c11dc5f96cb64bb6c9b3"
 dependencies = [
- "basic-toml",
  "glob",
- "once_cell",
  "serde",
  "serde_derive",
  "serde_json",
  "termcolor",
+ "toml",
 ]
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.8"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "winapi"
@@ -250,11 +308,11 @@
 
 [[package]]
 name = "winapi-util"
-version = "0.1.5"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
 dependencies = [
- "winapi",
+ "windows-sys",
 ]
 
 [[package]]
@@ -262,3 +320,85 @@
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+
+[[package]]
+name = "winnow"
+version = "0.6.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
+dependencies = [
+ "memchr",
+]
diff --git a/crates/displaydoc/Cargo.toml b/crates/displaydoc/Cargo.toml
index 1affcca..0202d99 100644
--- a/crates/displaydoc/Cargo.toml
+++ b/crates/displaydoc/Cargo.toml
@@ -10,9 +10,10 @@
 # See Cargo.toml.orig for the original contents.
 
 [package]
-edition = "2018"
+edition = "2021"
+rust-version = "1.56.0"
 name = "displaydoc"
-version = "0.2.4"
+version = "0.2.5"
 authors = ["Jane Lusby <jlusby@yaah.dev>"]
 description = """
 A derive macro for implementing the display Trait via a doc comment and string interpolation
@@ -40,42 +41,42 @@
 
 [[package.metadata.release.pre-release-replacements]]
 file = "CHANGELOG.md"
-search = "Unreleased"
 replace = "{{version}}"
+search = "Unreleased"
 
 [[package.metadata.release.pre-release-replacements]]
-file = "src/lib.rs"
-search = '#!\[doc\(html_root_url.*'
-replace = "#![doc(html_root_url = \"https://docs.rs/{{crate_name}}/{{version}}\")]"
 exactly = 1
+file = "src/lib.rs"
+replace = "#![doc(html_root_url = \"https://docs.rs/{{crate_name}}/{{version}}\")]"
+search = '#!\[doc\(html_root_url.*'
 
 [[package.metadata.release.pre-release-replacements]]
 file = "CHANGELOG.md"
-search = "ReleaseDate"
 replace = "{{date}}"
+search = "ReleaseDate"
 
 [[package.metadata.release.pre-release-replacements]]
+exactly = 1
 file = "CHANGELOG.md"
-search = "<!-- next-header -->"
 replace = """
 <!-- next-header -->
 
 # [Unreleased] - ReleaseDate"""
-exactly = 1
+search = "<!-- next-header -->"
 
 [[package.metadata.release.pre-release-replacements]]
+exactly = 1
 file = "CHANGELOG.md"
-search = '\.\.\.HEAD'
 replace = "...{{tag_name}}"
-exactly = 1
+search = '\.\.\.HEAD'
 
 [[package.metadata.release.pre-release-replacements]]
+exactly = 1
 file = "CHANGELOG.md"
-search = "<!-- next-url -->"
 replace = """
 <!-- next-url -->
 [Unreleased]: https://github.com/yaahc/{{crate_name}}/compare/{{tag_name}}...HEAD"""
-exactly = 1
+search = "<!-- next-url -->"
 
 [lib]
 path = "src/lib.rs"
diff --git a/crates/displaydoc/LICENSE-APACHE b/crates/displaydoc/LICENSE-APACHE
index f47c941..16fe87b 100644
--- a/crates/displaydoc/LICENSE-APACHE
+++ b/crates/displaydoc/LICENSE-APACHE
@@ -1,201 +1,201 @@
-                              Apache License

-                        Version 2.0, January 2004

-                     http://www.apache.org/licenses/

-

-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

-1. Definitions.

-

-   "License" shall mean the terms and conditions for use, reproduction,

-   and distribution as defined by Sections 1 through 9 of this document.

-

-   "Licensor" shall mean the copyright owner or entity authorized by

-   the copyright owner that is granting the License.

-

-   "Legal Entity" shall mean the union of the acting entity and all

-   other entities that control, are controlled by, or are under common

-   control with that entity. For the purposes of this definition,

-   "control" means (i) the power, direct or indirect, to cause the

-   direction or management of such entity, whether by contract or

-   otherwise, or (ii) ownership of fifty percent (50%) or more of the

-   outstanding shares, or (iii) beneficial ownership of such entity.

-

-   "You" (or "Your") shall mean an individual or Legal Entity

-   exercising permissions granted by this License.

-

-   "Source" form shall mean the preferred form for making modifications,

-   including but not limited to software source code, documentation

-   source, and configuration files.

-

-   "Object" form shall mean any form resulting from mechanical

-   transformation or translation of a Source form, including but

-   not limited to compiled object code, generated documentation,

-   and conversions to other media types.

-

-   "Work" shall mean the work of authorship, whether in Source or

-   Object form, made available under the License, as indicated by a

-   copyright notice that is included in or attached to the work

-   (an example is provided in the Appendix below).

-

-   "Derivative Works" shall mean any work, whether in Source or Object

-   form, that is based on (or derived from) the Work and for which the

-   editorial revisions, annotations, elaborations, or other modifications

-   represent, as a whole, an original work of authorship. For the purposes

-   of this License, Derivative Works shall not include works that remain

-   separable from, or merely link (or bind by name) to the interfaces of,

-   the Work and Derivative Works thereof.

-

-   "Contribution" shall mean any work of authorship, including

-   the original version of the Work and any modifications or additions

-   to that Work or Derivative Works thereof, that is intentionally

-   submitted to Licensor for inclusion in the Work by the copyright owner

-   or by an individual or Legal Entity authorized to submit on behalf of

-   the copyright owner. For the purposes of this definition, "submitted"

-   means any form of electronic, verbal, or written communication sent

-   to the Licensor or its representatives, including but not limited to

-   communication on electronic mailing lists, source code control systems,

-   and issue tracking systems that are managed by, or on behalf of, the

-   Licensor for the purpose of discussing and improving the Work, but

-   excluding communication that is conspicuously marked or otherwise

-   designated in writing by the copyright owner as "Not a Contribution."

-

-   "Contributor" shall mean Licensor and any individual or Legal Entity

-   on behalf of whom a Contribution has been received by Licensor and

-   subsequently incorporated within the Work.

-

-2. Grant of Copyright License. Subject to the terms and conditions of

-   this License, each Contributor hereby grants to You a perpetual,

-   worldwide, non-exclusive, no-charge, royalty-free, irrevocable

-   copyright license to reproduce, prepare Derivative Works of,

-   publicly display, publicly perform, sublicense, and distribute the

-   Work and such Derivative Works in Source or Object form.

-

-3. Grant of Patent License. Subject to the terms and conditions of

-   this License, each Contributor hereby grants to You a perpetual,

-   worldwide, non-exclusive, no-charge, royalty-free, irrevocable

-   (except as stated in this section) patent license to make, have made,

-   use, offer to sell, sell, import, and otherwise transfer the Work,

-   where such license applies only to those patent claims licensable

-   by such Contributor that are necessarily infringed by their

-   Contribution(s) alone or by combination of their Contribution(s)

-   with the Work to which such Contribution(s) was submitted. If You

-   institute patent litigation against any entity (including a

-   cross-claim or counterclaim in a lawsuit) alleging that the Work

-   or a Contribution incorporated within the Work constitutes direct

-   or contributory patent infringement, then any patent licenses

-   granted to You under this License for that Work shall terminate

-   as of the date such litigation is filed.

-

-4. Redistribution. You may reproduce and distribute copies of the

-   Work or Derivative Works thereof in any medium, with or without

-   modifications, and in Source or Object form, provided that You

-   meet the following conditions:

-

-   (a) You must give any other recipients of the Work or

-       Derivative Works a copy of this License; and

-

-   (b) You must cause any modified files to carry prominent notices

-       stating that You changed the files; and

-

-   (c) You must retain, in the Source form of any Derivative Works

-       that You distribute, all copyright, patent, trademark, and

-       attribution notices from the Source form of the Work,

-       excluding those notices that do not pertain to any part of

-       the Derivative Works; and

-

-   (d) If the Work includes a "NOTICE" text file as part of its

-       distribution, then any Derivative Works that You distribute must

-       include a readable copy of the attribution notices contained

-       within such NOTICE file, excluding those notices that do not

-       pertain to any part of the Derivative Works, in at least one

-       of the following places: within a NOTICE text file distributed

-       as part of the Derivative Works; within the Source form or

-       documentation, if provided along with the Derivative Works; or,

-       within a display generated by the Derivative Works, if and

-       wherever such third-party notices normally appear. The contents

-       of the NOTICE file are for informational purposes only and

-       do not modify the License. You may add Your own attribution

-       notices within Derivative Works that You distribute, alongside

-       or as an addendum to the NOTICE text from the Work, provided

-       that such additional attribution notices cannot be construed

-       as modifying the License.

-

-   You may add Your own copyright statement to Your modifications and

-   may provide additional or different license terms and conditions

-   for use, reproduction, or distribution of Your modifications, or

-   for any such Derivative Works as a whole, provided Your use,

-   reproduction, and distribution of the Work otherwise complies with

-   the conditions stated in this License.

-

-5. Submission of Contributions. Unless You explicitly state otherwise,

-   any Contribution intentionally submitted for inclusion in the Work

-   by You to the Licensor shall be under the terms and conditions of

-   this License, without any additional terms or conditions.

-   Notwithstanding the above, nothing herein shall supersede or modify

-   the terms of any separate license agreement you may have executed

-   with Licensor regarding such Contributions.

-

-6. Trademarks. This License does not grant permission to use the trade

-   names, trademarks, service marks, or product names of the Licensor,

-   except as required for reasonable and customary use in describing the

-   origin of the Work and reproducing the content of the NOTICE file.

-

-7. Disclaimer of Warranty. Unless required by applicable law or

-   agreed to in writing, Licensor provides the Work (and each

-   Contributor provides its Contributions) on an "AS IS" BASIS,

-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or

-   implied, including, without limitation, any warranties or conditions

-   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A

-   PARTICULAR PURPOSE. You are solely responsible for determining the

-   appropriateness of using or redistributing the Work and assume any

-   risks associated with Your exercise of permissions under this License.

-

-8. Limitation of Liability. In no event and under no legal theory,

-   whether in tort (including negligence), contract, or otherwise,

-   unless required by applicable law (such as deliberate and grossly

-   negligent acts) or agreed to in writing, shall any Contributor be

-   liable to You for damages, including any direct, indirect, special,

-   incidental, or consequential damages of any character arising as a

-   result of this License or out of the use or inability to use the

-   Work (including but not limited to damages for loss of goodwill,

-   work stoppage, computer failure or malfunction, or any and all

-   other commercial damages or losses), even if such Contributor

-   has been advised of the possibility of such damages.

-

-9. Accepting Warranty or Additional Liability. While redistributing

-   the Work or Derivative Works thereof, You may choose to offer,

-   and charge a fee for, acceptance of support, warranty, indemnity,

-   or other liability obligations and/or rights consistent with this

-   License. However, in accepting such obligations, You may act only

-   on Your own behalf and on Your sole responsibility, not on behalf

-   of any other Contributor, and only if You agree to indemnify,

-   defend, and hold each Contributor harmless for any liability

-   incurred by, or claims asserted against, such Contributor by reason

-   of your accepting any such warranty or additional liability.

-

-END OF TERMS AND CONDITIONS

-

-APPENDIX: How to apply the Apache License to your work.

-

-   To apply the Apache License to your work, attach the following

-   boilerplate notice, with the fields enclosed by brackets "[]"

-   replaced with your own identifying information. (Don't include

-   the brackets!)  The text should be enclosed in the appropriate

-   comment syntax for the file format. We also recommend that a

-   file or class name and description of purpose be included on the

-   same "printed page" as the copyright notice for easier

-   identification within third-party archives.

-

-Copyright [yyyy] [name of copyright owner]

-

-Licensed under the Apache License, Version 2.0 (the "License");

-you may not use this file except in compliance with the License.

-You may obtain a copy of the License at

-

-	http://www.apache.org/licenses/LICENSE-2.0

-

-Unless required by applicable law or agreed to in writing, software

-distributed under the License is distributed on an "AS IS" BASIS,

-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-See the License for the specific language governing permissions and

-limitations under the License.

+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/crates/displaydoc/LICENSE-MIT b/crates/displaydoc/LICENSE-MIT
index 458723b..31aa793 100644
--- a/crates/displaydoc/LICENSE-MIT
+++ b/crates/displaydoc/LICENSE-MIT
@@ -1,23 +1,23 @@
-Permission is hereby granted, free of charge, to any

-person obtaining a copy of this software and associated

-documentation files (the "Software"), to deal in the

-Software without restriction, including without

-limitation the rights to use, copy, modify, merge,

-publish, distribute, sublicense, and/or sell copies of

-the Software, and to permit persons to whom the Software

-is furnished to do so, subject to the following

-conditions:

-

-The above copyright notice and this permission notice

-shall be included in all copies or substantial portions

-of the Software.

-

-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF

-ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED

-TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A

-PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT

-SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY

-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION

-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR

-IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER

-DEALINGS IN THE SOFTWARE.

+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/crates/displaydoc/METADATA b/crates/displaydoc/METADATA
index db5e3a1..53d29c6 100644
--- a/crates/displaydoc/METADATA
+++ b/crates/displaydoc/METADATA
@@ -1,17 +1,17 @@
 name: "displaydoc"
 description: "()"
 third_party {
-  version: "0.2.4"
+  version: "0.2.5"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2023
-    month: 11
-    day: 21
+    year: 2024
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/displaydoc"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/displaydoc/displaydoc-0.2.4.crate"
-    version: "0.2.4"
+    value: "https://static.crates.io/crates/displaydoc/displaydoc-0.2.5.crate"
+    version: "0.2.5"
   }
 }
diff --git a/crates/displaydoc/README.md b/crates/displaydoc/README.md
index b8fa091..a609b0f 100644
--- a/crates/displaydoc/README.md
+++ b/crates/displaydoc/README.md
@@ -1,115 +1,115 @@
-derive(Display) /// `From<docs>`

-===============

-

-[![Latest Version](https://img.shields.io/crates/v/displaydoc.svg)](https://crates.io/crates/displaydoc)

-[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/displaydoc)

-

-This library provides a convenient derive macro for the standard library's

-[`core::fmt::Display`] trait.

-

-[`core::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html

-

-```toml

-[dependencies]

-displaydoc = "0.2"

-```

-

-*Compiler support: requires rustc 1.56+*

-

-<br>

-

-### Example

-

-*Demonstration alongside the [`Error`][std::error::Error] derive macro from [`thiserror`](https://docs.rs/thiserror/1.0.25/thiserror/index.html),

-to propagate source locations from [`io::Error`][std::io::Error] with the `#[source]` attribute:*

-```rust

-use std::io;

-use displaydoc::Display;

-use thiserror::Error;

-

-#[derive(Display, Error, Debug)]

-pub enum DataStoreError {

-    /// data store disconnected

-    Disconnect(#[source] io::Error),

-    /// the data for key `{0}` is not available

-    Redaction(String),

-    /// invalid header (expected {expected:?}, found {found:?})

-    InvalidHeader {

-        expected: String,

-        found: String,

-    },

-    /// unknown data store error

-    Unknown,

-}

-

-let error = DataStoreError::Redaction("CLASSIFIED CONTENT".to_string());

-assert!("the data for key `CLASSIFIED CONTENT` is not available" == &format!("{}", error));

-```

-*Note that although [`io::Error`][std::io::Error] implements `Display`, we do not add it to the

-generated message for `DataStoreError::Disconnect`, since it is already made available via

-`#[source]`. See further context on avoiding duplication in error reports at the rust blog

-[here](https://github.com/yaahc/blog.rust-lang.org/blob/master/posts/inside-rust/2021-05-15-What-the-error-handling-project-group-is-working-towards.md#duplicate-information-issue).*

-

-<br>

-

-### Details

-

-- A `fmt::Display` impl is generated for your enum if you provide

-  a docstring comment on each variant as shown above in the example. The

-  `Display` derive macro supports a shorthand for interpolating fields from

-  the error:

-    - `/// {var}` ⟶ `write!("{}", self.var)`

-    - `/// {0}` ⟶ `write!("{}", self.0)`

-    - `/// {var:?}` ⟶ `write!("{:?}", self.var)`

-    - `/// {0:?}` ⟶ `write!("{:?}", self.0)`

-- This also works with structs and [generic types][crate::Display#generic-type-parameters]:

-```rust

-/// oh no, an error: {0}

-#[derive(Display)]

-pub struct Error<E>(pub E);

-

-let error: Error<&str> = Error("muahaha i am an error");

-assert!("oh no, an error: muahaha i am an error" == &format!("{}", error));

-```

-

-- Two optional attributes can be added to your types next to the derive:

-

-    - `#[ignore_extra_doc_attributes]` makes the macro ignore any doc

-      comment attributes (or `///` lines) after the first. Multi-line

-      comments using `///` are otherwise treated as an error, so use this

-      attribute or consider switching to block doc comments (`/** */`).

-

-    - `#[prefix_enum_doc_attributes]` combines the doc comment message on

-      your enum itself with the messages for each variant, in the format

-      “enum: variant”. When added to an enum, the doc comment on the enum

-      becomes mandatory. When added to any other type, it has no effect.

-

-- In case you want to have an independent doc comment, the

-  `#[displaydoc("...")` atrribute may be used on the variant or struct to

-  override it.

-

-<br>

-

-### FAQ

-

-1. **Is this crate `no_std` compatible?**

-    * Yes! This crate implements the [`core::fmt::Display`] trait, not the [`std::fmt::Display`] trait, so it should work in `std` and `no_std` environments. Just add `default-features = false`.

-

-2. **Does this crate work with `Path` and `PathBuf` via the `Display` trait?**

-    * Yuuup. This crate uses @dtolnay's [autoref specialization technique](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md) to add a special trait for types to get the display impl. It then specializes for `Path` and `PathBuf`, and when either of these types are found, it calls `self.display()` to get a `std::path::Display<'_>` type which can be used with the `Display` format specifier!

-

-

-#### License

-

-<sup>

-Licensed under either of <a href="LICENSE-APACHE">Apache License, Version

-2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.

-</sup>

-

-<br>

-

-<sub>

-Unless you explicitly state otherwise, any contribution intentionally submitted

-for inclusion in this crate by you, as defined in the Apache-2.0 license, shall

-be dual licensed as above, without any additional terms or conditions.

-</sub>

+derive(Display) /// `From<docs>`
+===============
+
+[![Latest Version](https://img.shields.io/crates/v/displaydoc.svg)](https://crates.io/crates/displaydoc)
+[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/displaydoc)
+
+This library provides a convenient derive macro for the standard library's
+[`core::fmt::Display`] trait.
+
+[`core::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
+
+```toml
+[dependencies]
+displaydoc = "0.2"
+```
+
+*Compiler support: requires rustc 1.56+*
+
+<br>
+
+### Example
+
+*Demonstration alongside the [`Error`][std::error::Error] derive macro from [`thiserror`](https://docs.rs/thiserror/1.0.25/thiserror/index.html),
+to propagate source locations from [`io::Error`][std::io::Error] with the `#[source]` attribute:*
+```rust
+use std::io;
+use displaydoc::Display;
+use thiserror::Error;
+
+#[derive(Display, Error, Debug)]
+pub enum DataStoreError {
+    /// data store disconnected
+    Disconnect(#[source] io::Error),
+    /// the data for key `{0}` is not available
+    Redaction(String),
+    /// invalid header (expected {expected:?}, found {found:?})
+    InvalidHeader {
+        expected: String,
+        found: String,
+    },
+    /// unknown data store error
+    Unknown,
+}
+
+let error = DataStoreError::Redaction("CLASSIFIED CONTENT".to_string());
+assert!("the data for key `CLASSIFIED CONTENT` is not available" == &format!("{}", error));
+```
+*Note that although [`io::Error`][std::io::Error] implements `Display`, we do not add it to the
+generated message for `DataStoreError::Disconnect`, since it is already made available via
+`#[source]`. See further context on avoiding duplication in error reports at the rust blog
+[here](https://github.com/yaahc/blog.rust-lang.org/blob/master/posts/inside-rust/2021-05-15-What-the-error-handling-project-group-is-working-towards.md#duplicate-information-issue).*
+
+<br>
+
+### Details
+
+- A `fmt::Display` impl is generated for your enum if you provide
+  a docstring comment on each variant as shown above in the example. The
+  `Display` derive macro supports a shorthand for interpolating fields from
+  the error:
+    - `/// {var}` ⟶ `write!("{}", self.var)`
+    - `/// {0}` ⟶ `write!("{}", self.0)`
+    - `/// {var:?}` ⟶ `write!("{:?}", self.var)`
+    - `/// {0:?}` ⟶ `write!("{:?}", self.0)`
+- This also works with structs and [generic types][crate::Display#generic-type-parameters]:
+```rust
+/// oh no, an error: {0}
+#[derive(Display)]
+pub struct Error<E>(pub E);
+
+let error: Error<&str> = Error("muahaha i am an error");
+assert!("oh no, an error: muahaha i am an error" == &format!("{}", error));
+```
+
+- Two optional attributes can be added to your types next to the derive:
+
+    - `#[ignore_extra_doc_attributes]` makes the macro ignore any doc
+      comment attributes (or `///` lines) after the first. Multi-line
+      comments using `///` are otherwise treated as an error, so use this
+      attribute or consider switching to block doc comments (`/** */`).
+
+    - `#[prefix_enum_doc_attributes]` combines the doc comment message on
+      your enum itself with the messages for each variant, in the format
+      “enum: variant”. When added to an enum, the doc comment on the enum
+      becomes mandatory. When added to any other type, it has no effect.
+
+- In case you want to have an independent doc comment, the
+  `#[displaydoc("...")` atrribute may be used on the variant or struct to
+  override it.
+
+<br>
+
+### FAQ
+
+1. **Is this crate `no_std` compatible?**
+    * Yes! This crate implements the [`core::fmt::Display`] trait, not the [`std::fmt::Display`] trait, so it should work in `std` and `no_std` environments. Just add `default-features = false`.
+
+2. **Does this crate work with `Path` and `PathBuf` via the `Display` trait?**
+    * Yuuup. This crate uses @dtolnay's [autoref specialization technique](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md) to add a special trait for types to get the display impl. It then specializes for `Path` and `PathBuf`, and when either of these types are found, it calls `self.display()` to get a `std::path::Display<'_>` type which can be used with the `Display` format specifier!
+
+
+#### License
+
+<sup>
+Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
+2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
+</sup>
+
+<br>
+
+<sub>
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+</sub>
diff --git a/crates/displaydoc/README.tpl b/crates/displaydoc/README.tpl
index b131fb8..6206a9e 100644
--- a/crates/displaydoc/README.tpl
+++ b/crates/displaydoc/README.tpl
@@ -1,23 +1,23 @@
-derive(Display) /// `From<docs>`

-===============

-

-[![Latest Version](https://img.shields.io/crates/v/displaydoc.svg)](https://crates.io/crates/displaydoc)

-[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/displaydoc)

-

-{{readme}}

-

-

-#### License

-

-<sup>

-Licensed under either of <a href="LICENSE-APACHE">Apache License, Version

-2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.

-</sup>

-

-<br>

-

-<sub>

-Unless you explicitly state otherwise, any contribution intentionally submitted

-for inclusion in this crate by you, as defined in the Apache-2.0 license, shall

-be dual licensed as above, without any additional terms or conditions.

-</sub>

+derive(Display) /// `From<docs>`
+===============
+
+[![Latest Version](https://img.shields.io/crates/v/displaydoc.svg)](https://crates.io/crates/displaydoc)
+[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/displaydoc)
+
+{{readme}}
+
+
+#### License
+
+<sup>
+Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
+2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
+</sup>
+
+<br>
+
+<sub>
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+</sub>
diff --git a/crates/displaydoc/examples/simple.rs b/crates/displaydoc/examples/simple.rs
index 1f9fd11..f4aad21 100644
--- a/crates/displaydoc/examples/simple.rs
+++ b/crates/displaydoc/examples/simple.rs
@@ -1,36 +1,36 @@
-use displaydoc::Display;

-

-#[derive(Debug, Display)]

-pub enum DataStoreError {

-    /// data store disconnected

-    Disconnect,

-    /// the data for key `{0}` is not available

-    Redaction(String),

-    /// invalid header (expected {expected:?}, found {found:?})

-    InvalidHeader { expected: String, found: String },

-    /// unknown data store error

-    Unknown,

-}

-

-fn main() {

-    let disconnect = DataStoreError::Disconnect;

-    println!(

-        "Enum value `Disconnect` should be printed as:\n\t{}",

-        disconnect

-    );

-

-    let redaction = DataStoreError::Redaction(String::from("Dummy"));

-    println!(

-        "Enum value `Redaction` should be printed as:\n\t{}",

-        redaction

-    );

-

-    let invalid_header = DataStoreError::InvalidHeader {

-        expected: String::from("https"),

-        found: String::from("http"),

-    };

-    println!(

-        "Enum value `InvalidHeader` should be printed as:\n\t{}",

-        invalid_header

-    );

-}

+use displaydoc::Display;
+
+#[derive(Debug, Display)]
+pub enum DataStoreError {
+    /// data store disconnected
+    Disconnect,
+    /// the data for key `{0}` is not available
+    Redaction(String),
+    /// invalid header (expected {expected:?}, found {found:?})
+    InvalidHeader { expected: String, found: String },
+    /// unknown data store error
+    Unknown,
+}
+
+fn main() {
+    let disconnect = DataStoreError::Disconnect;
+    println!(
+        "Enum value `Disconnect` should be printed as:\n\t{}",
+        disconnect
+    );
+
+    let redaction = DataStoreError::Redaction(String::from("Dummy"));
+    println!(
+        "Enum value `Redaction` should be printed as:\n\t{}",
+        redaction
+    );
+
+    let invalid_header = DataStoreError::InvalidHeader {
+        expected: String::from("https"),
+        found: String::from("http"),
+    };
+    println!(
+        "Enum value `InvalidHeader` should be printed as:\n\t{}",
+        invalid_header
+    );
+}
diff --git a/crates/displaydoc/src/attr.rs b/crates/displaydoc/src/attr.rs
index a965d04..afda4b9 100644
--- a/crates/displaydoc/src/attr.rs
+++ b/crates/displaydoc/src/attr.rs
@@ -1,137 +1,137 @@
-use proc_macro2::TokenStream;

-use quote::{quote, ToTokens};

-use syn::{Attribute, LitStr, Meta, Result};

-

-#[derive(Clone)]

-pub(crate) struct Display {

-    pub(crate) fmt: LitStr,

-    pub(crate) args: TokenStream,

-}

-

-pub(crate) struct VariantDisplay {

-    pub(crate) r#enum: Option<Display>,

-    pub(crate) variant: Display,

-}

-

-impl ToTokens for Display {

-    fn to_tokens(&self, tokens: &mut TokenStream) {

-        let fmt = &self.fmt;

-        let args = &self.args;

-        tokens.extend(quote! {

-            write!(formatter, #fmt #args)

-        });

-    }

-}

-

-impl ToTokens for VariantDisplay {

-    fn to_tokens(&self, tokens: &mut TokenStream) {

-        if let Some(ref r#enum) = self.r#enum {

-            r#enum.to_tokens(tokens);

-            tokens.extend(quote! { ?; write!(formatter, ": ")?; });

-        }

-        self.variant.to_tokens(tokens);

-    }

-}

-

-pub(crate) struct AttrsHelper {

-    ignore_extra_doc_attributes: bool,

-    prefix_enum_doc_attributes: bool,

-}

-

-impl AttrsHelper {

-    pub(crate) fn new(attrs: &[Attribute]) -> Self {

-        let ignore_extra_doc_attributes = attrs

-            .iter()

-            .any(|attr| attr.path().is_ident("ignore_extra_doc_attributes"));

-        let prefix_enum_doc_attributes = attrs

-            .iter()

-            .any(|attr| attr.path().is_ident("prefix_enum_doc_attributes"));

-

-        Self {

-            ignore_extra_doc_attributes,

-            prefix_enum_doc_attributes,

-        }

-    }

-

-    pub(crate) fn display(&self, attrs: &[Attribute]) -> Result<Option<Display>> {

-        let displaydoc_attr = attrs.iter().find(|attr| attr.path().is_ident("displaydoc"));

-

-        if let Some(displaydoc_attr) = displaydoc_attr {

-            let lit = displaydoc_attr

-                .parse_args()

-                .expect("#[displaydoc(\"foo\")] must contain string arguments");

-            let mut display = Display {

-                fmt: lit,

-                args: TokenStream::new(),

-            };

-

-            display.expand_shorthand();

-            return Ok(Some(display));

-        }

-

-        let num_doc_attrs = attrs

-            .iter()

-            .filter(|attr| attr.path().is_ident("doc"))

-            .count();

-

-        if !self.ignore_extra_doc_attributes && num_doc_attrs > 1 {

-            panic!("Multi-line comments are disabled by default by displaydoc. Please consider using block doc comments (/** */) or adding the #[ignore_extra_doc_attributes] attribute to your type next to the derive.");

-        }

-

-        for attr in attrs {

-            if attr.path().is_ident("doc") {

-                let lit = match &attr.meta {

-                    Meta::NameValue(syn::MetaNameValue {

-                        value:

-                            syn::Expr::Lit(syn::ExprLit {

-                                lit: syn::Lit::Str(lit),

-                                ..

-                            }),

-                        ..

-                    }) => lit,

-                    _ => unimplemented!(),

-                };

-

-                // Make an attempt at cleaning up multiline doc comments.

-                let doc_str = lit

-                    .value()

-                    .lines()

-                    .map(|line| line.trim().trim_start_matches('*').trim())

-                    .collect::<Vec<&str>>()

-                    .join("\n");

-

-                let lit = LitStr::new(doc_str.trim(), lit.span());

-

-                let mut display = Display {

-                    fmt: lit,

-                    args: TokenStream::new(),

-                };

-

-                display.expand_shorthand();

-                return Ok(Some(display));

-            }

-        }

-

-        Ok(None)

-    }

-

-    pub(crate) fn display_with_input(

-        &self,

-        r#enum: &[Attribute],

-        variant: &[Attribute],

-    ) -> Result<Option<VariantDisplay>> {

-        let r#enum = if self.prefix_enum_doc_attributes {

-            let result = self

-                .display(r#enum)?

-                .expect("Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself.");

-

-            Some(result)

-        } else {

-            None

-        };

-

-        Ok(self

-            .display(variant)?

-            .map(|variant| VariantDisplay { r#enum, variant }))

-    }

-}

+use proc_macro2::TokenStream;
+use quote::{quote, ToTokens};
+use syn::{Attribute, LitStr, Meta, Result};
+
+#[derive(Clone)]
+pub(crate) struct Display {
+    pub(crate) fmt: LitStr,
+    pub(crate) args: TokenStream,
+}
+
+pub(crate) struct VariantDisplay {
+    pub(crate) r#enum: Option<Display>,
+    pub(crate) variant: Display,
+}
+
+impl ToTokens for Display {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let fmt = &self.fmt;
+        let args = &self.args;
+        tokens.extend(quote! {
+            write!(formatter, #fmt #args)
+        });
+    }
+}
+
+impl ToTokens for VariantDisplay {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        if let Some(ref r#enum) = self.r#enum {
+            r#enum.to_tokens(tokens);
+            tokens.extend(quote! { ?; write!(formatter, ": ")?; });
+        }
+        self.variant.to_tokens(tokens);
+    }
+}
+
+pub(crate) struct AttrsHelper {
+    ignore_extra_doc_attributes: bool,
+    prefix_enum_doc_attributes: bool,
+}
+
+impl AttrsHelper {
+    pub(crate) fn new(attrs: &[Attribute]) -> Self {
+        let ignore_extra_doc_attributes = attrs
+            .iter()
+            .any(|attr| attr.path().is_ident("ignore_extra_doc_attributes"));
+        let prefix_enum_doc_attributes = attrs
+            .iter()
+            .any(|attr| attr.path().is_ident("prefix_enum_doc_attributes"));
+
+        Self {
+            ignore_extra_doc_attributes,
+            prefix_enum_doc_attributes,
+        }
+    }
+
+    pub(crate) fn display(&self, attrs: &[Attribute]) -> Result<Option<Display>> {
+        let displaydoc_attr = attrs.iter().find(|attr| attr.path().is_ident("displaydoc"));
+
+        if let Some(displaydoc_attr) = displaydoc_attr {
+            let lit = displaydoc_attr
+                .parse_args()
+                .expect("#[displaydoc(\"foo\")] must contain string arguments");
+            let mut display = Display {
+                fmt: lit,
+                args: TokenStream::new(),
+            };
+
+            display.expand_shorthand();
+            return Ok(Some(display));
+        }
+
+        let num_doc_attrs = attrs
+            .iter()
+            .filter(|attr| attr.path().is_ident("doc"))
+            .count();
+
+        if !self.ignore_extra_doc_attributes && num_doc_attrs > 1 {
+            panic!("Multi-line comments are disabled by default by displaydoc. Please consider using block doc comments (/** */) or adding the #[ignore_extra_doc_attributes] attribute to your type next to the derive.");
+        }
+
+        for attr in attrs {
+            if attr.path().is_ident("doc") {
+                let lit = match &attr.meta {
+                    Meta::NameValue(syn::MetaNameValue {
+                        value:
+                            syn::Expr::Lit(syn::ExprLit {
+                                lit: syn::Lit::Str(lit),
+                                ..
+                            }),
+                        ..
+                    }) => lit,
+                    _ => unimplemented!(),
+                };
+
+                // Make an attempt at cleaning up multiline doc comments.
+                let doc_str = lit
+                    .value()
+                    .lines()
+                    .map(|line| line.trim().trim_start_matches('*').trim())
+                    .collect::<Vec<&str>>()
+                    .join("\n");
+
+                let lit = LitStr::new(doc_str.trim(), lit.span());
+
+                let mut display = Display {
+                    fmt: lit,
+                    args: TokenStream::new(),
+                };
+
+                display.expand_shorthand();
+                return Ok(Some(display));
+            }
+        }
+
+        Ok(None)
+    }
+
+    pub(crate) fn display_with_input(
+        &self,
+        r#enum: &[Attribute],
+        variant: &[Attribute],
+    ) -> Result<Option<VariantDisplay>> {
+        let r#enum = if self.prefix_enum_doc_attributes {
+            let result = self
+                .display(r#enum)?
+                .expect("Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself.");
+
+            Some(result)
+        } else {
+            None
+        };
+
+        Ok(self
+            .display(variant)?
+            .map(|variant| VariantDisplay { r#enum, variant }))
+    }
+}
diff --git a/crates/displaydoc/src/expand.rs b/crates/displaydoc/src/expand.rs
index 8a84390..3b146f8 100644
--- a/crates/displaydoc/src/expand.rs
+++ b/crates/displaydoc/src/expand.rs
@@ -1,410 +1,409 @@
-use super::attr::AttrsHelper;

-use proc_macro2::{Span, TokenStream};

-use quote::{format_ident, quote};

-use syn::{

-    punctuated::Punctuated,

-    token::{Colon, Comma, PathSep, Plus, Where},

-    Data, DataEnum, DataStruct, DeriveInput, Error, Fields, Generics, Ident, Path, PathArguments,

-    PathSegment, PredicateType, Result, TraitBound, TraitBoundModifier, Type, TypeParam,

-    TypeParamBound, TypePath, WhereClause, WherePredicate,

-};

-

-use std::collections::HashMap;

-

-pub(crate) fn derive(input: &DeriveInput) -> Result<TokenStream> {

-    let impls = match &input.data {

-        Data::Struct(data) => impl_struct(input, data),

-        Data::Enum(data) => impl_enum(input, data),

-        Data::Union(_) => Err(Error::new_spanned(input, "Unions are not supported")),

-    }?;

-

-    let helpers = specialization();

-    let dummy_const = format_ident!("_DERIVE_Display_FOR_{}", input.ident);

-    Ok(quote! {

-        #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]

-        const #dummy_const: () = {

-            #helpers

-            #impls

-        };

-    })

-}

-

-#[cfg(feature = "std")]

-fn specialization() -> TokenStream {

-    quote! {

-        trait DisplayToDisplayDoc {

-            fn __displaydoc_display(&self) -> Self;

-        }

-

-        impl<T: core::fmt::Display> DisplayToDisplayDoc for &T {

-            fn __displaydoc_display(&self) -> Self {

-                self

-            }

-        }

-

-        // If the `std` feature gets enabled we want to ensure that any crate

-        // using displaydoc can still reference the std crate, which is already

-        // being compiled in by whoever enabled the `std` feature in

-        // `displaydoc`, even if the crates using displaydoc are no_std.

-        extern crate std;

-

-        trait PathToDisplayDoc {

-            fn __displaydoc_display(&self) -> std::path::Display<'_>;

-        }

-

-        impl PathToDisplayDoc for std::path::Path {

-            fn __displaydoc_display(&self) -> std::path::Display<'_> {

-                self.display()

-            }

-        }

-

-        impl PathToDisplayDoc for std::path::PathBuf {

-            fn __displaydoc_display(&self) -> std::path::Display<'_> {

-                self.display()

-            }

-        }

-    }

-}

-

-#[cfg(not(feature = "std"))]

-fn specialization() -> TokenStream {

-    quote! {}

-}

-

-fn impl_struct(input: &DeriveInput, data: &DataStruct) -> Result<TokenStream> {

-    let ty = &input.ident;

-    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

-    let where_clause = generate_where_clause(&input.generics, where_clause);

-

-    let helper = AttrsHelper::new(&input.attrs);

-

-    let display = helper.display(&input.attrs)?.map(|display| {

-        let pat = match &data.fields {

-            Fields::Named(fields) => {

-                let var = fields.named.iter().map(|field| &field.ident);

-                quote!(Self { #(#var),* })

-            }

-            Fields::Unnamed(fields) => {

-                let var = (0..fields.unnamed.len()).map(|i| format_ident!("_{}", i));

-                quote!(Self(#(#var),*))

-            }

-            Fields::Unit => quote!(_),

-        };

-        quote! {

-            impl #impl_generics core::fmt::Display for #ty #ty_generics #where_clause {

-                fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {

-                    // NB: This destructures the fields of `self` into named variables (for unnamed

-                    // fields, it uses _0, _1, etc as above). The `#[allow(unused_variables)]`

-                    // section means it doesn't have to parse the individual field references out of

-                    // the docstring.

-                    #[allow(unused_variables)]

-                    let #pat = self;

-                    #display

-                }

-            }

-        }

-    });

-

-    Ok(quote! { #display })

-}

-

-/// Create a `where` predicate for `ident`, without any [bound][TypeParamBound]s yet.

-fn new_empty_where_type_predicate(ident: Ident) -> PredicateType {

-    let mut path_segments = Punctuated::<PathSegment, PathSep>::new();

-    path_segments.push_value(PathSegment {

-        ident,

-        arguments: PathArguments::None,

-    });

-    PredicateType {

-        lifetimes: None,

-        bounded_ty: Type::Path(TypePath {

-            qself: None,

-            path: Path {

-                leading_colon: None,

-                segments: path_segments,

-            },

-        }),

-        colon_token: Colon {

-            spans: [Span::call_site()],

-        },

-        bounds: Punctuated::<TypeParamBound, Plus>::new(),

-    }

-}

-

-/// Create a `where` clause that we can add [WherePredicate]s to.

-fn new_empty_where_clause() -> WhereClause {

-    WhereClause {

-        where_token: Where {

-            span: Span::call_site(),

-        },

-        predicates: Punctuated::<WherePredicate, Comma>::new(),

-    }

-}

-

-enum UseGlobalPrefix {

-    LeadingColon,

-    #[allow(dead_code)]

-    NoLeadingColon,

-}

-

-/// Create a path with segments composed of [Idents] *without* any [PathArguments].

-fn join_paths(name_segments: &[&str], use_global_prefix: UseGlobalPrefix) -> Path {

-    let mut segments = Punctuated::<PathSegment, PathSep>::new();

-    assert!(!name_segments.is_empty());

-    segments.push_value(PathSegment {

-        ident: Ident::new(name_segments[0], Span::call_site()),

-        arguments: PathArguments::None,

-    });

-    for name in name_segments[1..].iter() {

-        segments.push_punct(PathSep {

-            spans: [Span::call_site(), Span::mixed_site()],

-        });

-        segments.push_value(PathSegment {

-            ident: Ident::new(name, Span::call_site()),

-            arguments: PathArguments::None,

-        });

-    }

-    Path {

-        leading_colon: match use_global_prefix {

-            UseGlobalPrefix::LeadingColon => Some(PathSep {

-                spans: [Span::call_site(), Span::mixed_site()],

-            }),

-            UseGlobalPrefix::NoLeadingColon => None,

-        },

-        segments,

-    }

-}

-

-/// Push `new_type_predicate` onto the end of `where_clause`.

-fn append_where_clause_type_predicate(

-    where_clause: &mut WhereClause,

-    new_type_predicate: PredicateType,

-) {

-    // Push a comma at the end if there are already any `where` predicates.

-    if !where_clause.predicates.is_empty() {

-        where_clause.predicates.push_punct(Comma {

-            spans: [Span::call_site()],

-        });

-    }

-    where_clause

-        .predicates

-        .push_value(WherePredicate::Type(new_type_predicate));

-}

-

-/// Add a requirement for [core::fmt::Display] to a `where` predicate for some type.

-fn add_display_constraint_to_type_predicate(

-    predicate_that_needs_a_display_impl: &mut PredicateType,

-) {

-    // Create a `Path` of `::core::fmt::Display`.

-    let display_path = join_paths(&["core", "fmt", "Display"], UseGlobalPrefix::LeadingColon);

-

-    let display_bound = TypeParamBound::Trait(TraitBound {

-        paren_token: None,

-        modifier: TraitBoundModifier::None,

-        lifetimes: None,

-        path: display_path,

-    });

-    if !predicate_that_needs_a_display_impl.bounds.is_empty() {

-        predicate_that_needs_a_display_impl.bounds.push_punct(Plus {

-            spans: [Span::call_site()],

-        });

-    }

-

-    predicate_that_needs_a_display_impl

-        .bounds

-        .push_value(display_bound);

-}

-

-/// Map each declared generic type parameter to the set of all trait boundaries declared on it.

-///

-/// These boundaries may come from the declaration site:

-///     pub enum E<T: MyTrait> { ... }

-/// or a `where` clause after the parameter declarations:

-///     pub enum E<T> where T: MyTrait { ... }

-/// This method will return the boundaries from both of those cases.

-fn extract_trait_constraints_from_source(

-    where_clause: &WhereClause,

-    type_params: &[&TypeParam],

-) -> HashMap<Ident, Vec<TraitBound>> {

-    // Add trait bounds provided at the declaration site of type parameters for the struct/enum.

-    let mut param_constraint_mapping: HashMap<Ident, Vec<TraitBound>> = type_params

-        .iter()

-        .map(|type_param| {

-            let trait_bounds: Vec<TraitBound> = type_param

-                .bounds

-                .iter()

-                .flat_map(|bound| match bound {

-                    TypeParamBound::Trait(trait_bound) => Some(trait_bound),

-                    _ => None,

-                })

-                .cloned()

-                .collect();

-            (type_param.ident.clone(), trait_bounds)

-        })

-        .collect();

-

-    // Add trait bounds from `where` clauses, which may be type parameters or types containing

-    // those parameters.

-    for predicate in where_clause.predicates.iter() {

-        // We only care about type and not lifetime constraints here.

-        if let WherePredicate::Type(ref pred_ty) = predicate {

-            let ident = match &pred_ty.bounded_ty {

-                Type::Path(TypePath { path, qself: None }) => match path.get_ident() {

-                    None => continue,

-                    Some(ident) => ident,

-                },

-                _ => continue,

-            };

-            // We ignore any type constraints that aren't direct references to type

-            // parameters of the current enum of struct definition. No types can be

-            // constrained in a `where` clause unless they are a type parameter or a generic

-            // type instantiated with one of the type parameters, so by only allowing single

-            // identifiers, we can be sure that the constrained type is a type parameter

-            // that is contained in `param_constraint_mapping`.

-            if let Some((_, ref mut known_bounds)) = param_constraint_mapping

-                .iter_mut()

-                .find(|(id, _)| *id == ident)

-            {

-                for bound in pred_ty.bounds.iter() {

-                    // We only care about trait bounds here.

-                    if let TypeParamBound::Trait(ref bound) = bound {

-                        known_bounds.push(bound.clone());

-                    }

-                }

-            }

-        }

-    }

-

-    param_constraint_mapping

-}

-

-/// Hygienically add `where _: Display` to the set of [TypeParamBound]s for `ident`, creating such

-/// a set if necessary.

-fn ensure_display_in_where_clause_for_type(where_clause: &mut WhereClause, ident: Ident) {

-    for pred_ty in where_clause

-        .predicates

-        .iter_mut()

-        // Find the `where` predicate constraining the current type param, if it exists.

-        .flat_map(|predicate| match predicate {

-            WherePredicate::Type(pred_ty) => Some(pred_ty),

-            // We're looking through type constraints, not lifetime constraints.

-            _ => None,

-        })

-    {

-        // Do a complicated destructuring in order to check if the type being constrained in this

-        // `where` clause is the type we're looking for, so we can use the mutable reference to

-        // `pred_ty` if so.

-        let matches_desired_type = matches!(

-            &pred_ty.bounded_ty,

-            Type::Path(TypePath { path, .. }) if Some(&ident) == path.get_ident());

-        if matches_desired_type {

-            add_display_constraint_to_type_predicate(pred_ty);

-            return;

-        }

-    }

-

-    // If there is no `where` predicate for the current type param, we will construct one.

-    let mut new_type_predicate = new_empty_where_type_predicate(ident);

-    add_display_constraint_to_type_predicate(&mut new_type_predicate);

-    append_where_clause_type_predicate(where_clause, new_type_predicate);

-}

-

-/// For all declared type parameters, add a [core::fmt::Display] constraint, unless the type

-/// parameter already has any type constraint.

-fn ensure_where_clause_has_display_for_all_unconstrained_members(

-    where_clause: &mut WhereClause,

-    type_params: &[&TypeParam],

-) {

-    let param_constraint_mapping = extract_trait_constraints_from_source(where_clause, type_params);

-

-    for (ident, known_bounds) in param_constraint_mapping.into_iter() {

-        // If the type parameter has any constraints already, we don't want to touch it, to avoid

-        // breaking use cases where a type parameter only needs to impl `Debug`, for example.

-        if known_bounds.is_empty() {

-            ensure_display_in_where_clause_for_type(where_clause, ident);

-        }

-    }

-}

-

-/// Generate a `where` clause that ensures all generic type parameters `impl`

-/// [core::fmt::Display] unless already constrained.

-///

-/// This approach allows struct/enum definitions deriving [crate::Display] to avoid hardcoding

-/// a [core::fmt::Display] constraint into every type parameter.

-///

-/// If the type parameter isn't already constrained, we add a `where _: Display` clause to our

-/// display implementation to expect to be able to format every enum case or struct member.

-///

-/// In fact, we would preferably only require `where _: Display` or `where _: Debug` where the

-/// format string actually requires it. However, while [`std::fmt` defines a formal syntax for

-/// `format!()`][format syntax], it *doesn't* expose the actual logic to parse the format string,

-/// which appears to live in [`rustc_parse_format`]. While we use the [`syn`] crate to parse rust

-/// syntax, it also doesn't currently provide any method to introspect a `format!()` string. It

-/// would be nice to contribute this upstream in [`syn`].

-///

-/// [format syntax]: std::fmt#syntax

-/// [`rustc_parse_format`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse_format/index.html

-fn generate_where_clause(generics: &Generics, where_clause: Option<&WhereClause>) -> WhereClause {

-    let mut where_clause = where_clause.cloned().unwrap_or_else(new_empty_where_clause);

-    let type_params: Vec<&TypeParam> = generics.type_params().collect();

-    ensure_where_clause_has_display_for_all_unconstrained_members(&mut where_clause, &type_params);

-    where_clause

-}

-

-fn impl_enum(input: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {

-    let ty = &input.ident;

-    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

-    let where_clause = generate_where_clause(&input.generics, where_clause);

-

-    let helper = AttrsHelper::new(&input.attrs);

-

-    let displays = data

-        .variants

-        .iter()

-        .map(|variant| helper.display_with_input(&input.attrs, &variant.attrs))

-        .collect::<Result<Vec<_>>>()?;

-

-    if data.variants.is_empty() {

-        Ok(quote! {

-            impl #impl_generics core::fmt::Display for #ty #ty_generics #where_clause {

-                fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {

-                    unreachable!("empty enums cannot be instantiated and thus cannot be printed")

-                }

-            }

-        })

-    } else if displays.iter().any(Option::is_some) {

-        let arms = data

-            .variants

-            .iter()

-            .zip(displays)

-            .map(|(variant, display)| {

-                let display =

-                    display.ok_or_else(|| Error::new_spanned(variant, "missing doc comment"))?;

-                let ident = &variant.ident;

-                Ok(match &variant.fields {

-                    Fields::Named(fields) => {

-                        let var = fields.named.iter().map(|field| &field.ident);

-                        quote!(Self::#ident { #(#var),* } => { #display })

-                    }

-                    Fields::Unnamed(fields) => {

-                        let var = (0..fields.unnamed.len()).map(|i| format_ident!("_{}", i));

-                        quote!(Self::#ident(#(#var),*) => { #display })

-                    }

-                    Fields::Unit => quote!(Self::#ident => { #display }),

-                })

-            })

-            .collect::<Result<Vec<_>>>()?;

-        Ok(quote! {

-            impl #impl_generics core::fmt::Display for #ty #ty_generics #where_clause {

-                fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {

-                    #[allow(unused_variables)]

-                    match self {

-                        #(#arms,)*

-                    }

-                }

-            }

-        })

-    } else {

-        Err(Error::new_spanned(input, "Missing doc comments"))

-    }

-}

+use super::attr::AttrsHelper;
+use proc_macro2::{Span, TokenStream};
+use quote::{format_ident, quote};
+use syn::{
+    punctuated::Punctuated,
+    token::{Colon, Comma, PathSep, Plus, Where},
+    Data, DataEnum, DataStruct, DeriveInput, Error, Fields, Generics, Ident, Path, PathArguments,
+    PathSegment, PredicateType, Result, TraitBound, TraitBoundModifier, Type, TypeParam,
+    TypeParamBound, TypePath, WhereClause, WherePredicate,
+};
+
+use std::collections::HashMap;
+
+pub(crate) fn derive(input: &DeriveInput) -> Result<TokenStream> {
+    let impls = match &input.data {
+        Data::Struct(data) => impl_struct(input, data),
+        Data::Enum(data) => impl_enum(input, data),
+        Data::Union(_) => Err(Error::new_spanned(input, "Unions are not supported")),
+    }?;
+
+    let helpers = specialization();
+    Ok(quote! {
+        #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
+        const _: () = {
+            #helpers
+            #impls
+        };
+    })
+}
+
+#[cfg(feature = "std")]
+fn specialization() -> TokenStream {
+    quote! {
+        trait DisplayToDisplayDoc {
+            fn __displaydoc_display(&self) -> Self;
+        }
+
+        impl<T: ::core::fmt::Display> DisplayToDisplayDoc for &T {
+            fn __displaydoc_display(&self) -> Self {
+                self
+            }
+        }
+
+        // If the `std` feature gets enabled we want to ensure that any crate
+        // using displaydoc can still reference the std crate, which is already
+        // being compiled in by whoever enabled the `std` feature in
+        // `displaydoc`, even if the crates using displaydoc are no_std.
+        extern crate std;
+
+        trait PathToDisplayDoc {
+            fn __displaydoc_display(&self) -> std::path::Display<'_>;
+        }
+
+        impl PathToDisplayDoc for std::path::Path {
+            fn __displaydoc_display(&self) -> std::path::Display<'_> {
+                self.display()
+            }
+        }
+
+        impl PathToDisplayDoc for std::path::PathBuf {
+            fn __displaydoc_display(&self) -> std::path::Display<'_> {
+                self.display()
+            }
+        }
+    }
+}
+
+#[cfg(not(feature = "std"))]
+fn specialization() -> TokenStream {
+    quote! {}
+}
+
+fn impl_struct(input: &DeriveInput, data: &DataStruct) -> Result<TokenStream> {
+    let ty = &input.ident;
+    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+    let where_clause = generate_where_clause(&input.generics, where_clause);
+
+    let helper = AttrsHelper::new(&input.attrs);
+
+    let display = helper.display(&input.attrs)?.map(|display| {
+        let pat = match &data.fields {
+            Fields::Named(fields) => {
+                let var = fields.named.iter().map(|field| &field.ident);
+                quote!(Self { #(#var),* })
+            }
+            Fields::Unnamed(fields) => {
+                let var = (0..fields.unnamed.len()).map(|i| format_ident!("_{}", i));
+                quote!(Self(#(#var),*))
+            }
+            Fields::Unit => quote!(_),
+        };
+        quote! {
+            impl #impl_generics ::core::fmt::Display for #ty #ty_generics #where_clause {
+                fn fmt(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+                    // NB: This destructures the fields of `self` into named variables (for unnamed
+                    // fields, it uses _0, _1, etc as above). The `#[allow(unused_variables)]`
+                    // section means it doesn't have to parse the individual field references out of
+                    // the docstring.
+                    #[allow(unused_variables)]
+                    let #pat = self;
+                    #display
+                }
+            }
+        }
+    });
+
+    Ok(quote! { #display })
+}
+
+/// Create a `where` predicate for `ident`, without any [bound][TypeParamBound]s yet.
+fn new_empty_where_type_predicate(ident: Ident) -> PredicateType {
+    let mut path_segments = Punctuated::<PathSegment, PathSep>::new();
+    path_segments.push_value(PathSegment {
+        ident,
+        arguments: PathArguments::None,
+    });
+    PredicateType {
+        lifetimes: None,
+        bounded_ty: Type::Path(TypePath {
+            qself: None,
+            path: Path {
+                leading_colon: None,
+                segments: path_segments,
+            },
+        }),
+        colon_token: Colon {
+            spans: [Span::call_site()],
+        },
+        bounds: Punctuated::<TypeParamBound, Plus>::new(),
+    }
+}
+
+/// Create a `where` clause that we can add [WherePredicate]s to.
+fn new_empty_where_clause() -> WhereClause {
+    WhereClause {
+        where_token: Where {
+            span: Span::call_site(),
+        },
+        predicates: Punctuated::<WherePredicate, Comma>::new(),
+    }
+}
+
+enum UseGlobalPrefix {
+    LeadingColon,
+    #[allow(dead_code)]
+    NoLeadingColon,
+}
+
+/// Create a path with segments composed of [Idents] *without* any [PathArguments].
+fn join_paths(name_segments: &[&str], use_global_prefix: UseGlobalPrefix) -> Path {
+    let mut segments = Punctuated::<PathSegment, PathSep>::new();
+    assert!(!name_segments.is_empty());
+    segments.push_value(PathSegment {
+        ident: Ident::new(name_segments[0], Span::call_site()),
+        arguments: PathArguments::None,
+    });
+    for name in name_segments[1..].iter() {
+        segments.push_punct(PathSep {
+            spans: [Span::call_site(), Span::mixed_site()],
+        });
+        segments.push_value(PathSegment {
+            ident: Ident::new(name, Span::call_site()),
+            arguments: PathArguments::None,
+        });
+    }
+    Path {
+        leading_colon: match use_global_prefix {
+            UseGlobalPrefix::LeadingColon => Some(PathSep {
+                spans: [Span::call_site(), Span::mixed_site()],
+            }),
+            UseGlobalPrefix::NoLeadingColon => None,
+        },
+        segments,
+    }
+}
+
+/// Push `new_type_predicate` onto the end of `where_clause`.
+fn append_where_clause_type_predicate(
+    where_clause: &mut WhereClause,
+    new_type_predicate: PredicateType,
+) {
+    // Push a comma at the end if there are already any `where` predicates.
+    if !where_clause.predicates.is_empty() {
+        where_clause.predicates.push_punct(Comma {
+            spans: [Span::call_site()],
+        });
+    }
+    where_clause
+        .predicates
+        .push_value(WherePredicate::Type(new_type_predicate));
+}
+
+/// Add a requirement for [core::fmt::Display] to a `where` predicate for some type.
+fn add_display_constraint_to_type_predicate(
+    predicate_that_needs_a_display_impl: &mut PredicateType,
+) {
+    // Create a `Path` of `::core::fmt::Display`.
+    let display_path = join_paths(&["core", "fmt", "Display"], UseGlobalPrefix::LeadingColon);
+
+    let display_bound = TypeParamBound::Trait(TraitBound {
+        paren_token: None,
+        modifier: TraitBoundModifier::None,
+        lifetimes: None,
+        path: display_path,
+    });
+    if !predicate_that_needs_a_display_impl.bounds.is_empty() {
+        predicate_that_needs_a_display_impl.bounds.push_punct(Plus {
+            spans: [Span::call_site()],
+        });
+    }
+
+    predicate_that_needs_a_display_impl
+        .bounds
+        .push_value(display_bound);
+}
+
+/// Map each declared generic type parameter to the set of all trait boundaries declared on it.
+///
+/// These boundaries may come from the declaration site:
+///     pub enum E<T: MyTrait> { ... }
+/// or a `where` clause after the parameter declarations:
+///     pub enum E<T> where T: MyTrait { ... }
+/// This method will return the boundaries from both of those cases.
+fn extract_trait_constraints_from_source(
+    where_clause: &WhereClause,
+    type_params: &[&TypeParam],
+) -> HashMap<Ident, Vec<TraitBound>> {
+    // Add trait bounds provided at the declaration site of type parameters for the struct/enum.
+    let mut param_constraint_mapping: HashMap<Ident, Vec<TraitBound>> = type_params
+        .iter()
+        .map(|type_param| {
+            let trait_bounds: Vec<TraitBound> = type_param
+                .bounds
+                .iter()
+                .flat_map(|bound| match bound {
+                    TypeParamBound::Trait(trait_bound) => Some(trait_bound),
+                    _ => None,
+                })
+                .cloned()
+                .collect();
+            (type_param.ident.clone(), trait_bounds)
+        })
+        .collect();
+
+    // Add trait bounds from `where` clauses, which may be type parameters or types containing
+    // those parameters.
+    for predicate in where_clause.predicates.iter() {
+        // We only care about type and not lifetime constraints here.
+        if let WherePredicate::Type(ref pred_ty) = predicate {
+            let ident = match &pred_ty.bounded_ty {
+                Type::Path(TypePath { path, qself: None }) => match path.get_ident() {
+                    None => continue,
+                    Some(ident) => ident,
+                },
+                _ => continue,
+            };
+            // We ignore any type constraints that aren't direct references to type
+            // parameters of the current enum of struct definition. No types can be
+            // constrained in a `where` clause unless they are a type parameter or a generic
+            // type instantiated with one of the type parameters, so by only allowing single
+            // identifiers, we can be sure that the constrained type is a type parameter
+            // that is contained in `param_constraint_mapping`.
+            if let Some((_, ref mut known_bounds)) = param_constraint_mapping
+                .iter_mut()
+                .find(|(id, _)| *id == ident)
+            {
+                for bound in pred_ty.bounds.iter() {
+                    // We only care about trait bounds here.
+                    if let TypeParamBound::Trait(ref bound) = bound {
+                        known_bounds.push(bound.clone());
+                    }
+                }
+            }
+        }
+    }
+
+    param_constraint_mapping
+}
+
+/// Hygienically add `where _: Display` to the set of [TypeParamBound]s for `ident`, creating such
+/// a set if necessary.
+fn ensure_display_in_where_clause_for_type(where_clause: &mut WhereClause, ident: Ident) {
+    for pred_ty in where_clause
+        .predicates
+        .iter_mut()
+        // Find the `where` predicate constraining the current type param, if it exists.
+        .flat_map(|predicate| match predicate {
+            WherePredicate::Type(pred_ty) => Some(pred_ty),
+            // We're looking through type constraints, not lifetime constraints.
+            _ => None,
+        })
+    {
+        // Do a complicated destructuring in order to check if the type being constrained in this
+        // `where` clause is the type we're looking for, so we can use the mutable reference to
+        // `pred_ty` if so.
+        let matches_desired_type = matches!(
+            &pred_ty.bounded_ty,
+            Type::Path(TypePath { path, .. }) if Some(&ident) == path.get_ident());
+        if matches_desired_type {
+            add_display_constraint_to_type_predicate(pred_ty);
+            return;
+        }
+    }
+
+    // If there is no `where` predicate for the current type param, we will construct one.
+    let mut new_type_predicate = new_empty_where_type_predicate(ident);
+    add_display_constraint_to_type_predicate(&mut new_type_predicate);
+    append_where_clause_type_predicate(where_clause, new_type_predicate);
+}
+
+/// For all declared type parameters, add a [core::fmt::Display] constraint, unless the type
+/// parameter already has any type constraint.
+fn ensure_where_clause_has_display_for_all_unconstrained_members(
+    where_clause: &mut WhereClause,
+    type_params: &[&TypeParam],
+) {
+    let param_constraint_mapping = extract_trait_constraints_from_source(where_clause, type_params);
+
+    for (ident, known_bounds) in param_constraint_mapping.into_iter() {
+        // If the type parameter has any constraints already, we don't want to touch it, to avoid
+        // breaking use cases where a type parameter only needs to impl `Debug`, for example.
+        if known_bounds.is_empty() {
+            ensure_display_in_where_clause_for_type(where_clause, ident);
+        }
+    }
+}
+
+/// Generate a `where` clause that ensures all generic type parameters `impl`
+/// [core::fmt::Display] unless already constrained.
+///
+/// This approach allows struct/enum definitions deriving [crate::Display] to avoid hardcoding
+/// a [core::fmt::Display] constraint into every type parameter.
+///
+/// If the type parameter isn't already constrained, we add a `where _: Display` clause to our
+/// display implementation to expect to be able to format every enum case or struct member.
+///
+/// In fact, we would preferably only require `where _: Display` or `where _: Debug` where the
+/// format string actually requires it. However, while [`std::fmt` defines a formal syntax for
+/// `format!()`][format syntax], it *doesn't* expose the actual logic to parse the format string,
+/// which appears to live in [`rustc_parse_format`]. While we use the [`syn`] crate to parse rust
+/// syntax, it also doesn't currently provide any method to introspect a `format!()` string. It
+/// would be nice to contribute this upstream in [`syn`].
+///
+/// [format syntax]: std::fmt#syntax
+/// [`rustc_parse_format`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse_format/index.html
+fn generate_where_clause(generics: &Generics, where_clause: Option<&WhereClause>) -> WhereClause {
+    let mut where_clause = where_clause.cloned().unwrap_or_else(new_empty_where_clause);
+    let type_params: Vec<&TypeParam> = generics.type_params().collect();
+    ensure_where_clause_has_display_for_all_unconstrained_members(&mut where_clause, &type_params);
+    where_clause
+}
+
+fn impl_enum(input: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
+    let ty = &input.ident;
+    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+    let where_clause = generate_where_clause(&input.generics, where_clause);
+
+    let helper = AttrsHelper::new(&input.attrs);
+
+    let displays = data
+        .variants
+        .iter()
+        .map(|variant| helper.display_with_input(&input.attrs, &variant.attrs))
+        .collect::<Result<Vec<_>>>()?;
+
+    if data.variants.is_empty() {
+        Ok(quote! {
+            impl #impl_generics ::core::fmt::Display for #ty #ty_generics #where_clause {
+                fn fmt(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+                    unreachable!("empty enums cannot be instantiated and thus cannot be printed")
+                }
+            }
+        })
+    } else if displays.iter().any(Option::is_some) {
+        let arms = data
+            .variants
+            .iter()
+            .zip(displays)
+            .map(|(variant, display)| {
+                let display =
+                    display.ok_or_else(|| Error::new_spanned(variant, "missing doc comment"))?;
+                let ident = &variant.ident;
+                Ok(match &variant.fields {
+                    Fields::Named(fields) => {
+                        let var = fields.named.iter().map(|field| &field.ident);
+                        quote!(Self::#ident { #(#var),* } => { #display })
+                    }
+                    Fields::Unnamed(fields) => {
+                        let var = (0..fields.unnamed.len()).map(|i| format_ident!("_{}", i));
+                        quote!(Self::#ident(#(#var),*) => { #display })
+                    }
+                    Fields::Unit => quote!(Self::#ident => { #display }),
+                })
+            })
+            .collect::<Result<Vec<_>>>()?;
+        Ok(quote! {
+            impl #impl_generics ::core::fmt::Display for #ty #ty_generics #where_clause {
+                fn fmt(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+                    #[allow(unused_variables)]
+                    match self {
+                        #(#arms,)*
+                    }
+                }
+            }
+        })
+    } else {
+        Err(Error::new_spanned(input, "Missing doc comments"))
+    }
+}
diff --git a/crates/displaydoc/src/fmt.rs b/crates/displaydoc/src/fmt.rs
index 3334a82..5848557 100644
--- a/crates/displaydoc/src/fmt.rs
+++ b/crates/displaydoc/src/fmt.rs
@@ -1,159 +1,159 @@
-use crate::attr::Display;

-use proc_macro2::TokenStream;

-use quote::quote_spanned;

-use syn::{Ident, LitStr};

-

-macro_rules! peek_next {

-    ($read:ident) => {

-        match $read.chars().next() {

-            Some(next) => next,

-            None => return,

-        }

-    };

-}

-

-impl Display {

-    // Transform `"error {var}"` to `"error {}", var`.

-    pub(crate) fn expand_shorthand(&mut self) {

-        let span = self.fmt.span();

-        let fmt = self.fmt.value();

-        let mut read = fmt.as_str();

-        let mut out = String::new();

-        let mut args = TokenStream::new();

-

-        while let Some(brace) = read.find('{') {

-            out += &read[..=brace];

-            read = &read[brace + 1..];

-

-            // skip cases where we find a {{

-            if read.starts_with('{') {

-                out.push('{');

-                read = &read[1..];

-                continue;

-            }

-

-            let next = peek_next!(read);

-

-            let var = match next {

-                '0'..='9' => take_int(&mut read),

-                'a'..='z' | 'A'..='Z' | '_' => take_ident(&mut read),

-                _ => return,

-            };

-

-            let ident = Ident::new(&var, span);

-

-            let next = peek_next!(read);

-

-            let arg = if cfg!(feature = "std") && next == '}' {

-                quote_spanned!(span=> , #ident.__displaydoc_display())

-            } else {

-                quote_spanned!(span=> , #ident)

-            };

-

-            args.extend(arg);

-        }

-

-        out += read;

-        self.fmt = LitStr::new(&out, self.fmt.span());

-        self.args = args;

-    }

-}

-

-fn take_int(read: &mut &str) -> String {

-    let mut int = String::new();

-    int.push('_');

-    for (i, ch) in read.char_indices() {

-        match ch {

-            '0'..='9' => int.push(ch),

-            _ => {

-                *read = &read[i..];

-                break;

-            }

-        }

-    }

-    int

-}

-

-fn take_ident(read: &mut &str) -> String {

-    let mut ident = String::new();

-    for (i, ch) in read.char_indices() {

-        match ch {

-            'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),

-            _ => {

-                *read = &read[i..];

-                break;

-            }

-        }

-    }

-    ident

-}

-

-#[cfg(test)]

-mod tests {

-    use super::*;

-    use pretty_assertions::assert_eq;

-    use proc_macro2::Span;

-

-    fn assert(input: &str, fmt: &str, args: &str) {

-        let mut display = Display {

-            fmt: LitStr::new(input, Span::call_site()),

-            args: TokenStream::new(),

-        };

-        display.expand_shorthand();

-        assert_eq!(fmt, display.fmt.value());

-        assert_eq!(args, display.args.to_string());

-    }

-

-    #[test]

-    fn test_expand() {

-        assert("fn main() {{ }}", "fn main() {{ }}", "");

-    }

-

-    #[test]

-    #[cfg_attr(not(feature = "std"), ignore)]

-    fn test_std_expand() {

-        assert(

-            "{v} {v:?} {0} {0:?}",

-            "{} {:?} {} {:?}",

-            ", v . __displaydoc_display () , v , _0 . __displaydoc_display () , _0",

-        );

-        assert("error {var}", "error {}", ", var . __displaydoc_display ()");

-

-        assert(

-            "error {var1}",

-            "error {}",

-            ", var1 . __displaydoc_display ()",

-        );

-

-        assert(

-            "error {var1var}",

-            "error {}",

-            ", var1var . __displaydoc_display ()",

-        );

-

-        assert(

-            "The path {0}",

-            "The path {}",

-            ", _0 . __displaydoc_display ()",

-        );

-        assert("The path {0:?}", "The path {:?}", ", _0");

-    }

-

-    #[test]

-    #[cfg_attr(feature = "std", ignore)]

-    fn test_nostd_expand() {

-        assert(

-            "{v} {v:?} {0} {0:?}",

-            "{} {:?} {} {:?}",

-            ", v , v , _0 , _0",

-        );

-        assert("error {var}", "error {}", ", var");

-

-        assert("The path {0}", "The path {}", ", _0");

-        assert("The path {0:?}", "The path {:?}", ", _0");

-

-        assert("error {var1}", "error {}", ", var1");

-

-        assert("error {var1var}", "error {}", ", var1var");

-    }

-}

+use crate::attr::Display;
+use proc_macro2::TokenStream;
+use quote::quote_spanned;
+use syn::{Ident, LitStr};
+
+macro_rules! peek_next {
+    ($read:ident) => {
+        match $read.chars().next() {
+            Some(next) => next,
+            None => return,
+        }
+    };
+}
+
+impl Display {
+    // Transform `"error {var}"` to `"error {}", var`.
+    pub(crate) fn expand_shorthand(&mut self) {
+        let span = self.fmt.span();
+        let fmt = self.fmt.value();
+        let mut read = fmt.as_str();
+        let mut out = String::new();
+        let mut args = TokenStream::new();
+
+        while let Some(brace) = read.find('{') {
+            out += &read[..=brace];
+            read = &read[brace + 1..];
+
+            // skip cases where we find a {{
+            if read.starts_with('{') {
+                out.push('{');
+                read = &read[1..];
+                continue;
+            }
+
+            let next = peek_next!(read);
+
+            let var = match next {
+                '0'..='9' => take_int(&mut read),
+                'a'..='z' | 'A'..='Z' | '_' => take_ident(&mut read),
+                _ => return,
+            };
+
+            let ident = Ident::new(&var, span);
+
+            let next = peek_next!(read);
+
+            let arg = if cfg!(feature = "std") && next == '}' {
+                quote_spanned!(span=> , #ident.__displaydoc_display())
+            } else {
+                quote_spanned!(span=> , #ident)
+            };
+
+            args.extend(arg);
+        }
+
+        out += read;
+        self.fmt = LitStr::new(&out, self.fmt.span());
+        self.args = args;
+    }
+}
+
+fn take_int(read: &mut &str) -> String {
+    let mut int = String::new();
+    int.push('_');
+    for (i, ch) in read.char_indices() {
+        match ch {
+            '0'..='9' => int.push(ch),
+            _ => {
+                *read = &read[i..];
+                break;
+            }
+        }
+    }
+    int
+}
+
+fn take_ident(read: &mut &str) -> String {
+    let mut ident = String::new();
+    for (i, ch) in read.char_indices() {
+        match ch {
+            'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),
+            _ => {
+                *read = &read[i..];
+                break;
+            }
+        }
+    }
+    ident
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use pretty_assertions::assert_eq;
+    use proc_macro2::Span;
+
+    fn assert(input: &str, fmt: &str, args: &str) {
+        let mut display = Display {
+            fmt: LitStr::new(input, Span::call_site()),
+            args: TokenStream::new(),
+        };
+        display.expand_shorthand();
+        assert_eq!(fmt, display.fmt.value());
+        assert_eq!(args, display.args.to_string());
+    }
+
+    #[test]
+    fn test_expand() {
+        assert("fn main() {{ }}", "fn main() {{ }}", "");
+    }
+
+    #[test]
+    #[cfg_attr(not(feature = "std"), ignore)]
+    fn test_std_expand() {
+        assert(
+            "{v} {v:?} {0} {0:?}",
+            "{} {:?} {} {:?}",
+            ", v . __displaydoc_display () , v , _0 . __displaydoc_display () , _0",
+        );
+        assert("error {var}", "error {}", ", var . __displaydoc_display ()");
+
+        assert(
+            "error {var1}",
+            "error {}",
+            ", var1 . __displaydoc_display ()",
+        );
+
+        assert(
+            "error {var1var}",
+            "error {}",
+            ", var1var . __displaydoc_display ()",
+        );
+
+        assert(
+            "The path {0}",
+            "The path {}",
+            ", _0 . __displaydoc_display ()",
+        );
+        assert("The path {0:?}", "The path {:?}", ", _0");
+    }
+
+    #[test]
+    #[cfg_attr(feature = "std", ignore)]
+    fn test_nostd_expand() {
+        assert(
+            "{v} {v:?} {0} {0:?}",
+            "{} {:?} {} {:?}",
+            ", v , v , _0 , _0",
+        );
+        assert("error {var}", "error {}", ", var");
+
+        assert("The path {0}", "The path {}", ", _0");
+        assert("The path {0:?}", "The path {:?}", ", _0");
+
+        assert("error {var1}", "error {}", ", var1");
+
+        assert("error {var1var}", "error {}", ", var1var");
+    }
+}
diff --git a/crates/displaydoc/src/lib.rs b/crates/displaydoc/src/lib.rs
index e4653d6..8824ff0 100644
--- a/crates/displaydoc/src/lib.rs
+++ b/crates/displaydoc/src/lib.rs
@@ -1,187 +1,186 @@
-//! This library provides a convenient derive macro for the standard library's

-//! [`core::fmt::Display`] trait.

-//!

-//! [`core::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html

-//!

-//! ```toml

-//! [dependencies]

-//! displaydoc = "0.2"

-//! ```

-//!

-//! *Compiler support: requires rustc 1.56+*

-//!

-//! <br>

-//!

-//! ## Example

-//!

-//! *Demonstration alongside the [`Error`][std::error::Error] derive macro from [`thiserror`](https://docs.rs/thiserror/1.0.25/thiserror/index.html),

-//! to propagate source locations from [`io::Error`][std::io::Error] with the `#[source]` attribute:*

-//! ```rust

-//! use std::io;

-//! use displaydoc::Display;

-//! use thiserror::Error;

-//!

-//! #[derive(Display, Error, Debug)]

-//! pub enum DataStoreError {

-//!     /// data store disconnected

-//!     Disconnect(#[source] io::Error),

-//!     /// the data for key `{0}` is not available

-//!     Redaction(String),

-//!     /// invalid header (expected {expected:?}, found {found:?})

-//!     InvalidHeader {

-//!         expected: String,

-//!         found: String,

-//!     },

-//!     /// unknown data store error

-//!     Unknown,

-//! }

-//!

-//! let error = DataStoreError::Redaction("CLASSIFIED CONTENT".to_string());

-//! assert!("the data for key `CLASSIFIED CONTENT` is not available" == &format!("{}", error));

-//! ```

-//! *Note that although [`io::Error`][std::io::Error] implements `Display`, we do not add it to the

-//! generated message for `DataStoreError::Disconnect`, since it is already made available via

-//! `#[source]`. See further context on avoiding duplication in error reports at the rust blog

-//! [here](https://github.com/yaahc/blog.rust-lang.org/blob/master/posts/inside-rust/2021-05-15-What-the-error-handling-project-group-is-working-towards.md#duplicate-information-issue).*

-//!

-//! <br>

-//!

-//! ## Details

-//!

-//! - A `fmt::Display` impl is generated for your enum if you provide

-//!   a docstring comment on each variant as shown above in the example. The

-//!   `Display` derive macro supports a shorthand for interpolating fields from

-//!   the error:

-//!     - `/// {var}` ⟶ `write!("{}", self.var)`

-//!     - `/// {0}` ⟶ `write!("{}", self.0)`

-//!     - `/// {var:?}` ⟶ `write!("{:?}", self.var)`

-//!     - `/// {0:?}` ⟶ `write!("{:?}", self.0)`

-//! - This also works with structs and [generic types][crate::Display#generic-type-parameters]:

-//! ```rust

-//! # use displaydoc::Display;

-//! /// oh no, an error: {0}

-//! #[derive(Display)]

-//! pub struct Error<E>(pub E);

-//!

-//! let error: Error<&str> = Error("muahaha i am an error");

-//! assert!("oh no, an error: muahaha i am an error" == &format!("{}", error));

-//! ```

-//!

-//! - Two optional attributes can be added to your types next to the derive:

-//!

-//!     - `#[ignore_extra_doc_attributes]` makes the macro ignore any doc

-//!       comment attributes (or `///` lines) after the first. Multi-line

-//!       comments using `///` are otherwise treated as an error, so use this

-//!       attribute or consider switching to block doc comments (`/** */`).

-//!

-//!     - `#[prefix_enum_doc_attributes]` combines the doc comment message on

-//!       your enum itself with the messages for each variant, in the format

-//!       “enum: variant”. When added to an enum, the doc comment on the enum

-//!       becomes mandatory. When added to any other type, it has no effect.

-//!

-//! - In case you want to have an independent doc comment, the

-//!   `#[displaydoc("...")` atrribute may be used on the variant or struct to

-//!   override it.

-//!

-//! <br>

-//!

-//! ## FAQ

-//!

-//! 1. **Is this crate `no_std` compatible?**

-//!     * Yes! This crate implements the [`core::fmt::Display`] trait, not the [`std::fmt::Display`] trait, so it should work in `std` and `no_std` environments. Just add `default-features = false`.

-//!

-//! 2. **Does this crate work with `Path` and `PathBuf` via the `Display` trait?**

-//!     * Yuuup. This crate uses @dtolnay's [autoref specialization technique](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md) to add a special trait for types to get the display impl. It then specializes for `Path` and `PathBuf`, and when either of these types are found, it calls `self.display()` to get a `std::path::Display<'_>` type which can be used with the `Display` format specifier!

-#![doc(html_root_url = "https://docs.rs/displaydoc/0.2.3")]

-#![cfg_attr(docsrs, feature(doc_cfg))]

-#![warn(

-    rust_2018_idioms,

-    unreachable_pub,

-    bad_style,

-    dead_code,

-    improper_ctypes,

-    non_shorthand_field_patterns,

-    no_mangle_generic_items,

-    overflowing_literals,

-    path_statements,

-    patterns_in_fns_without_body,

-    private_in_public,

-    unconditional_recursion,

-    unused,

-    unused_allocation,

-    unused_comparisons,

-    unused_parens,

-    while_true

-)]

-#![allow(clippy::try_err)]

-

-#[allow(unused_extern_crates)]

-extern crate proc_macro;

-

-mod attr;

-mod expand;

-mod fmt;

-

-use proc_macro::TokenStream;

-use syn::{parse_macro_input, DeriveInput};

-

-/// [Custom `#[derive(...)]` macro](https://doc.rust-lang.org/edition-guide/rust-2018/macros/custom-derive.html)

-/// for implementing [`fmt::Display`][core::fmt::Display] via doc comment attributes.

-///

-/// ### Generic Type Parameters

-///

-/// Type parameters to an enum or struct using this macro should *not* need to

-/// have an explicit `Display` constraint at the struct or enum definition

-/// site. A `Display` implementation for the `derive`d struct or enum is

-/// generated assuming each type parameter implements `Display`, but that should

-/// be possible without adding the constraint to the struct definition itself:

-/// ```rust

-/// use displaydoc::Display;

-///

-/// /// oh no, an error: {0}

-/// #[derive(Display)]

-/// pub struct Error<E>(pub E);

-///

-/// // No need to require `E: Display`, since `displaydoc::Display` adds that implicitly.

-/// fn generate_error<E>(e: E) -> Error<E> { Error(e) }

-///

-/// assert!("oh no, an error: muahaha" == &format!("{}", generate_error("muahaha")));

-/// ```

-///

-/// ### Using [`Debug`][core::fmt::Debug] Implementations with Type Parameters

-/// However, if a type parameter must instead be constrained with the

-/// [`Debug`][core::fmt::Debug] trait so that some field may be printed with

-/// `{:?}`, that constraint must currently still also be specified redundantly

-/// at the struct or enum definition site. If a struct or enum field is being

-/// formatted with `{:?}` via [`displaydoc`][crate], and a generic type

-/// parameter must implement `Debug` to do that, then that struct or enum

-/// definition will need to propagate the `Debug` constraint to every type

-/// parameter it's instantiated with:

-/// ```rust

-/// use core::fmt::Debug;

-/// use displaydoc::Display;

-///

-/// /// oh no, an error: {0:?}

-/// #[derive(Display)]

-/// pub struct Error<E: Debug>(pub E);

-///

-/// // `E: Debug` now has to propagate to callers.

-/// fn generate_error<E: Debug>(e: E) -> Error<E> { Error(e) }

-///

-/// assert!("oh no, an error: \"cool\"" == &format!("{}", generate_error("cool")));

-///

-/// // Try this with a struct that doesn't impl `Display` at all, unlike `str`.

-/// #[derive(Debug)]

-/// pub struct Oh;

-/// assert!("oh no, an error: Oh" == &format!("{}", generate_error(Oh)));

-/// ```

-#[proc_macro_derive(

-    Display,

-    attributes(ignore_extra_doc_attributes, prefix_enum_doc_attributes, displaydoc)

-)]

-pub fn derive_error(input: TokenStream) -> TokenStream {

-    let input = parse_macro_input!(input as DeriveInput);

-    expand::derive(&input)

-        .unwrap_or_else(|err| err.to_compile_error())

-        .into()

-}

+//! This library provides a convenient derive macro for the standard library's
+//! [`core::fmt::Display`] trait.
+//!
+//! [`core::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
+//!
+//! ```toml
+//! [dependencies]
+//! displaydoc = "0.2"
+//! ```
+//!
+//! *Compiler support: requires rustc 1.56+*
+//!
+//! <br>
+//!
+//! ## Example
+//!
+//! *Demonstration alongside the [`Error`][std::error::Error] derive macro from [`thiserror`](https://docs.rs/thiserror/1.0.25/thiserror/index.html),
+//! to propagate source locations from [`io::Error`][std::io::Error] with the `#[source]` attribute:*
+//! ```rust
+//! use std::io;
+//! use displaydoc::Display;
+//! use thiserror::Error;
+//!
+//! #[derive(Display, Error, Debug)]
+//! pub enum DataStoreError {
+//!     /// data store disconnected
+//!     Disconnect(#[source] io::Error),
+//!     /// the data for key `{0}` is not available
+//!     Redaction(String),
+//!     /// invalid header (expected {expected:?}, found {found:?})
+//!     InvalidHeader {
+//!         expected: String,
+//!         found: String,
+//!     },
+//!     /// unknown data store error
+//!     Unknown,
+//! }
+//!
+//! let error = DataStoreError::Redaction("CLASSIFIED CONTENT".to_string());
+//! assert!("the data for key `CLASSIFIED CONTENT` is not available" == &format!("{}", error));
+//! ```
+//! *Note that although [`io::Error`][std::io::Error] implements `Display`, we do not add it to the
+//! generated message for `DataStoreError::Disconnect`, since it is already made available via
+//! `#[source]`. See further context on avoiding duplication in error reports at the rust blog
+//! [here](https://github.com/yaahc/blog.rust-lang.org/blob/master/posts/inside-rust/2021-05-15-What-the-error-handling-project-group-is-working-towards.md#duplicate-information-issue).*
+//!
+//! <br>
+//!
+//! ## Details
+//!
+//! - A `fmt::Display` impl is generated for your enum if you provide
+//!   a docstring comment on each variant as shown above in the example. The
+//!   `Display` derive macro supports a shorthand for interpolating fields from
+//!   the error:
+//!     - `/// {var}` ⟶ `write!("{}", self.var)`
+//!     - `/// {0}` ⟶ `write!("{}", self.0)`
+//!     - `/// {var:?}` ⟶ `write!("{:?}", self.var)`
+//!     - `/// {0:?}` ⟶ `write!("{:?}", self.0)`
+//! - This also works with structs and [generic types][crate::Display#generic-type-parameters]:
+//! ```rust
+//! # use displaydoc::Display;
+//! /// oh no, an error: {0}
+//! #[derive(Display)]
+//! pub struct Error<E>(pub E);
+//!
+//! let error: Error<&str> = Error("muahaha i am an error");
+//! assert!("oh no, an error: muahaha i am an error" == &format!("{}", error));
+//! ```
+//!
+//! - Two optional attributes can be added to your types next to the derive:
+//!
+//!     - `#[ignore_extra_doc_attributes]` makes the macro ignore any doc
+//!       comment attributes (or `///` lines) after the first. Multi-line
+//!       comments using `///` are otherwise treated as an error, so use this
+//!       attribute or consider switching to block doc comments (`/** */`).
+//!
+//!     - `#[prefix_enum_doc_attributes]` combines the doc comment message on
+//!       your enum itself with the messages for each variant, in the format
+//!       “enum: variant”. When added to an enum, the doc comment on the enum
+//!       becomes mandatory. When added to any other type, it has no effect.
+//!
+//! - In case you want to have an independent doc comment, the
+//!   `#[displaydoc("...")` atrribute may be used on the variant or struct to
+//!   override it.
+//!
+//! <br>
+//!
+//! ## FAQ
+//!
+//! 1. **Is this crate `no_std` compatible?**
+//!     * Yes! This crate implements the [`core::fmt::Display`] trait, not the [`std::fmt::Display`] trait, so it should work in `std` and `no_std` environments. Just add `default-features = false`.
+//!
+//! 2. **Does this crate work with `Path` and `PathBuf` via the `Display` trait?**
+//!     * Yuuup. This crate uses @dtolnay's [autoref specialization technique](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md) to add a special trait for types to get the display impl. It then specializes for `Path` and `PathBuf`, and when either of these types are found, it calls `self.display()` to get a `std::path::Display<'_>` type which can be used with the `Display` format specifier!
+#![doc(html_root_url = "https://docs.rs/displaydoc/0.2.3")]
+#![cfg_attr(docsrs, feature(doc_cfg))]
+#![warn(
+    rust_2018_idioms,
+    unreachable_pub,
+    bad_style,
+    dead_code,
+    improper_ctypes,
+    non_shorthand_field_patterns,
+    no_mangle_generic_items,
+    overflowing_literals,
+    path_statements,
+    patterns_in_fns_without_body,
+    unconditional_recursion,
+    unused,
+    unused_allocation,
+    unused_comparisons,
+    unused_parens,
+    while_true
+)]
+#![allow(clippy::try_err)]
+
+#[allow(unused_extern_crates)]
+extern crate proc_macro;
+
+mod attr;
+mod expand;
+mod fmt;
+
+use proc_macro::TokenStream;
+use syn::{parse_macro_input, DeriveInput};
+
+/// [Custom `#[derive(...)]` macro](https://doc.rust-lang.org/edition-guide/rust-2018/macros/custom-derive.html)
+/// for implementing [`fmt::Display`][core::fmt::Display] via doc comment attributes.
+///
+/// ### Generic Type Parameters
+///
+/// Type parameters to an enum or struct using this macro should *not* need to
+/// have an explicit `Display` constraint at the struct or enum definition
+/// site. A `Display` implementation for the `derive`d struct or enum is
+/// generated assuming each type parameter implements `Display`, but that should
+/// be possible without adding the constraint to the struct definition itself:
+/// ```rust
+/// use displaydoc::Display;
+///
+/// /// oh no, an error: {0}
+/// #[derive(Display)]
+/// pub struct Error<E>(pub E);
+///
+/// // No need to require `E: Display`, since `displaydoc::Display` adds that implicitly.
+/// fn generate_error<E>(e: E) -> Error<E> { Error(e) }
+///
+/// assert!("oh no, an error: muahaha" == &format!("{}", generate_error("muahaha")));
+/// ```
+///
+/// ### Using [`Debug`][core::fmt::Debug] Implementations with Type Parameters
+/// However, if a type parameter must instead be constrained with the
+/// [`Debug`][core::fmt::Debug] trait so that some field may be printed with
+/// `{:?}`, that constraint must currently still also be specified redundantly
+/// at the struct or enum definition site. If a struct or enum field is being
+/// formatted with `{:?}` via [`displaydoc`][crate], and a generic type
+/// parameter must implement `Debug` to do that, then that struct or enum
+/// definition will need to propagate the `Debug` constraint to every type
+/// parameter it's instantiated with:
+/// ```rust
+/// use core::fmt::Debug;
+/// use displaydoc::Display;
+///
+/// /// oh no, an error: {0:?}
+/// #[derive(Display)]
+/// pub struct Error<E: Debug>(pub E);
+///
+/// // `E: Debug` now has to propagate to callers.
+/// fn generate_error<E: Debug>(e: E) -> Error<E> { Error(e) }
+///
+/// assert!("oh no, an error: \"cool\"" == &format!("{}", generate_error("cool")));
+///
+/// // Try this with a struct that doesn't impl `Display` at all, unlike `str`.
+/// #[derive(Debug)]
+/// pub struct Oh;
+/// assert!("oh no, an error: Oh" == &format!("{}", generate_error(Oh)));
+/// ```
+#[proc_macro_derive(
+    Display,
+    attributes(ignore_extra_doc_attributes, prefix_enum_doc_attributes, displaydoc)
+)]
+pub fn derive_error(input: TokenStream) -> TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+    expand::derive(&input)
+        .unwrap_or_else(|err| err.to_compile_error())
+        .into()
+}
diff --git a/crates/displaydoc/tests/compile_tests.rs b/crates/displaydoc/tests/compile_tests.rs
index ac7427a..29c72a8 100644
--- a/crates/displaydoc/tests/compile_tests.rs
+++ b/crates/displaydoc/tests/compile_tests.rs
@@ -1,29 +1,29 @@
-#[allow(unused_attributes)]

-#[rustversion::attr(not(nightly), ignore)]

-#[test]

-fn no_std() {

-    let t = trybuild::TestCases::new();

-    #[cfg(not(feature = "std"))]

-    t.compile_fail("tests/no_std/without.rs");

-    #[cfg(not(feature = "std"))]

-    t.compile_fail("tests/no_std/multi_line.rs");

-    #[cfg(not(feature = "std"))]

-    t.pass("tests/no_std/multi_line_allow.rs");

-    #[cfg(not(feature = "std"))]

-    t.compile_fail("tests/no_std/enum_prefix_missing.rs");

-    #[cfg(not(feature = "std"))]

-    t.pass("tests/no_std/enum_prefix.rs");

-    #[cfg(feature = "std")]

-    t.compile_fail("tests/std/without.rs");

-    #[cfg(feature = "std")]

-    t.compile_fail("tests/std/multi_line.rs");

-    #[cfg(feature = "std")]

-    t.pass("tests/std/multi_line_allow.rs");

-    #[cfg(feature = "std")]

-    t.compile_fail("tests/std/enum_prefix_missing.rs");

-    #[cfg(feature = "std")]

-    t.pass("tests/std/enum_prefix.rs");

-    #[cfg(feature = "std")]

-    t.pass("tests/std/multiple.rs");

-    t.pass("tests/no_std/with.rs");

-}

+#[allow(unused_attributes)]
+#[rustversion::attr(not(nightly), ignore)]
+#[test]
+fn no_std() {
+    let t = trybuild::TestCases::new();
+    #[cfg(not(feature = "std"))]
+    t.compile_fail("tests/no_std/without.rs");
+    #[cfg(not(feature = "std"))]
+    t.compile_fail("tests/no_std/multi_line.rs");
+    #[cfg(not(feature = "std"))]
+    t.pass("tests/no_std/multi_line_allow.rs");
+    #[cfg(not(feature = "std"))]
+    t.compile_fail("tests/no_std/enum_prefix_missing.rs");
+    #[cfg(not(feature = "std"))]
+    t.pass("tests/no_std/enum_prefix.rs");
+    #[cfg(feature = "std")]
+    t.compile_fail("tests/std/without.rs");
+    #[cfg(feature = "std")]
+    t.compile_fail("tests/std/multi_line.rs");
+    #[cfg(feature = "std")]
+    t.pass("tests/std/multi_line_allow.rs");
+    #[cfg(feature = "std")]
+    t.compile_fail("tests/std/enum_prefix_missing.rs");
+    #[cfg(feature = "std")]
+    t.pass("tests/std/enum_prefix.rs");
+    #[cfg(feature = "std")]
+    t.pass("tests/std/multiple.rs");
+    t.pass("tests/no_std/with.rs");
+}
diff --git a/crates/displaydoc/tests/happy.rs b/crates/displaydoc/tests/happy.rs
index f8fde9c..85aa78f 100644
--- a/crates/displaydoc/tests/happy.rs
+++ b/crates/displaydoc/tests/happy.rs
@@ -1,152 +1,152 @@
-use displaydoc::Display;

-

-#[cfg(feature = "std")]

-use std::path::PathBuf;

-

-#[derive(Display)]

-/// Just a basic struct {thing}

-struct HappyStruct {

-    thing: &'static str,

-}

-

-#[derive(Display)]

-#[ignore_extra_doc_attributes]

-/// Just a basic struct {thing}

-/// and this line should get ignored

-struct HappyStruct2 {

-    thing: &'static str,

-}

-

-#[derive(Display)]

-enum Happy {

-    /// I really like Variant1

-    Variant1,

-    /// Variant2 is pretty swell 2

-    Variant2,

-    /// Variant3 is okay {sometimes}

-    Variant3 { sometimes: &'static str },

-    /**

-     * Variant4 wants to have a lot of lines

-     *

-     * Lets see how this works out for it

-     */

-    Variant4,

-    /// Variant5 has a parameter {0} and some regular comments

-    // A regular comment that won't get picked

-    Variant5(u32),

-

-    /// The path {0}

-    #[cfg(feature = "std")]

-    Variant6(PathBuf),

-

-    /// These docs are ignored

-    #[displaydoc("Variant7 has a parameter {0} and uses #[displaydoc]")]

-    /// These docs are also ignored

-    Variant7(u32),

-}

-

-// Used for testing indented doc comments

-mod inner_mod {

-    use super::Display;

-

-    #[derive(Display)]

-    pub enum InnerHappy {

-        /// I really like Variant1

-        Variant1,

-        /// Variant2 is pretty swell 2

-        Variant2,

-        /// Variant3 is okay {sometimes}

-        Variant3 { sometimes: &'static str },

-        /**

-         * Variant4 wants to have a lot of lines

-         *

-         * Lets see how this works out for it

-         */

-        Variant4,

-        /// Variant5 has a parameter {0} and some regular comments

-        // A regular comment that won't get picked

-        Variant5(u32),

-

-        /** what happens if we

-         * put text on the first line?

-         */

-        Variant6,

-

-        /**

-        what happens if we don't use *?

-        */

-        Variant7,

-

-        /**

-         *

-         * what about extra new lines?

-         */

-        Variant8,

-    }

-}

-

-fn assert_display<T: std::fmt::Display>(input: T, expected: &'static str) {

-    let out = format!("{}", input);

-    assert_eq!(expected, out);

-}

-

-#[test]

-fn does_it_print() {

-    assert_display(Happy::Variant1, "I really like Variant1");

-    assert_display(Happy::Variant2, "Variant2 is pretty swell 2");

-    assert_display(Happy::Variant3 { sometimes: "hi" }, "Variant3 is okay hi");

-    assert_display(

-        Happy::Variant4,

-        "Variant4 wants to have a lot of lines\n\nLets see how this works out for it",

-    );

-    assert_display(

-        Happy::Variant5(2),

-        "Variant5 has a parameter 2 and some regular comments",

-    );

-    assert_display(

-        Happy::Variant7(2),

-        "Variant7 has a parameter 2 and uses #[displaydoc]",

-    );

-    assert_display(HappyStruct { thing: "hi" }, "Just a basic struct hi");

-

-    assert_display(HappyStruct2 { thing: "hi2" }, "Just a basic struct hi2");

-

-    assert_display(inner_mod::InnerHappy::Variant1, "I really like Variant1");

-    assert_display(

-        inner_mod::InnerHappy::Variant2,

-        "Variant2 is pretty swell 2",

-    );

-    assert_display(

-        inner_mod::InnerHappy::Variant3 { sometimes: "hi" },

-        "Variant3 is okay hi",

-    );

-    assert_display(

-        inner_mod::InnerHappy::Variant4,

-        "Variant4 wants to have a lot of lines\n\nLets see how this works out for it",

-    );

-    assert_display(

-        inner_mod::InnerHappy::Variant5(2),

-        "Variant5 has a parameter 2 and some regular comments",

-    );

-    assert_display(

-        inner_mod::InnerHappy::Variant6,

-        "what happens if we\nput text on the first line?",

-    );

-    assert_display(

-        inner_mod::InnerHappy::Variant7,

-        "what happens if we don\'t use *?",

-    );

-    assert_display(

-        inner_mod::InnerHappy::Variant8,

-        "what about extra new lines?",

-    );

-}

-

-#[test]

-#[cfg(feature = "std")]

-fn does_it_print_path() {

-    assert_display(

-        Happy::Variant6(PathBuf::from("/var/log/happy")),

-        "The path /var/log/happy",

-    );

-}

+use displaydoc::Display;
+
+#[cfg(feature = "std")]
+use std::path::PathBuf;
+
+#[derive(Display)]
+/// Just a basic struct {thing}
+struct HappyStruct {
+    thing: &'static str,
+}
+
+#[derive(Display)]
+#[ignore_extra_doc_attributes]
+/// Just a basic struct {thing}
+/// and this line should get ignored
+struct HappyStruct2 {
+    thing: &'static str,
+}
+
+#[derive(Display)]
+enum Happy {
+    /// I really like Variant1
+    Variant1,
+    /// Variant2 is pretty swell 2
+    Variant2,
+    /// Variant3 is okay {sometimes}
+    Variant3 { sometimes: &'static str },
+    /**
+     * Variant4 wants to have a lot of lines
+     *
+     * Lets see how this works out for it
+     */
+    Variant4,
+    /// Variant5 has a parameter {0} and some regular comments
+    // A regular comment that won't get picked
+    Variant5(u32),
+
+    /// The path {0}
+    #[cfg(feature = "std")]
+    Variant6(PathBuf),
+
+    /// These docs are ignored
+    #[displaydoc("Variant7 has a parameter {0} and uses #[displaydoc]")]
+    /// These docs are also ignored
+    Variant7(u32),
+}
+
+// Used for testing indented doc comments
+mod inner_mod {
+    use super::Display;
+
+    #[derive(Display)]
+    pub enum InnerHappy {
+        /// I really like Variant1
+        Variant1,
+        /// Variant2 is pretty swell 2
+        Variant2,
+        /// Variant3 is okay {sometimes}
+        Variant3 { sometimes: &'static str },
+        /**
+         * Variant4 wants to have a lot of lines
+         *
+         * Lets see how this works out for it
+         */
+        Variant4,
+        /// Variant5 has a parameter {0} and some regular comments
+        // A regular comment that won't get picked
+        Variant5(u32),
+
+        /** what happens if we
+         * put text on the first line?
+         */
+        Variant6,
+
+        /**
+        what happens if we don't use *?
+        */
+        Variant7,
+
+        /**
+         *
+         * what about extra new lines?
+         */
+        Variant8,
+    }
+}
+
+fn assert_display<T: std::fmt::Display>(input: T, expected: &'static str) {
+    let out = format!("{}", input);
+    assert_eq!(expected, out);
+}
+
+#[test]
+fn does_it_print() {
+    assert_display(Happy::Variant1, "I really like Variant1");
+    assert_display(Happy::Variant2, "Variant2 is pretty swell 2");
+    assert_display(Happy::Variant3 { sometimes: "hi" }, "Variant3 is okay hi");
+    assert_display(
+        Happy::Variant4,
+        "Variant4 wants to have a lot of lines\n\nLets see how this works out for it",
+    );
+    assert_display(
+        Happy::Variant5(2),
+        "Variant5 has a parameter 2 and some regular comments",
+    );
+    assert_display(
+        Happy::Variant7(2),
+        "Variant7 has a parameter 2 and uses #[displaydoc]",
+    );
+    assert_display(HappyStruct { thing: "hi" }, "Just a basic struct hi");
+
+    assert_display(HappyStruct2 { thing: "hi2" }, "Just a basic struct hi2");
+
+    assert_display(inner_mod::InnerHappy::Variant1, "I really like Variant1");
+    assert_display(
+        inner_mod::InnerHappy::Variant2,
+        "Variant2 is pretty swell 2",
+    );
+    assert_display(
+        inner_mod::InnerHappy::Variant3 { sometimes: "hi" },
+        "Variant3 is okay hi",
+    );
+    assert_display(
+        inner_mod::InnerHappy::Variant4,
+        "Variant4 wants to have a lot of lines\n\nLets see how this works out for it",
+    );
+    assert_display(
+        inner_mod::InnerHappy::Variant5(2),
+        "Variant5 has a parameter 2 and some regular comments",
+    );
+    assert_display(
+        inner_mod::InnerHappy::Variant6,
+        "what happens if we\nput text on the first line?",
+    );
+    assert_display(
+        inner_mod::InnerHappy::Variant7,
+        "what happens if we don\'t use *?",
+    );
+    assert_display(
+        inner_mod::InnerHappy::Variant8,
+        "what about extra new lines?",
+    );
+}
+
+#[test]
+#[cfg(feature = "std")]
+fn does_it_print_path() {
+    assert_display(
+        Happy::Variant6(PathBuf::from("/var/log/happy")),
+        "The path /var/log/happy",
+    );
+}
diff --git a/crates/displaydoc/tests/no_std/enum_prefix.rs b/crates/displaydoc/tests/no_std/enum_prefix.rs
index b8482ca..5538e27 100644
--- a/crates/displaydoc/tests/no_std/enum_prefix.rs
+++ b/crates/displaydoc/tests/no_std/enum_prefix.rs
@@ -1,36 +1,36 @@
-#![cfg_attr(not(feature = "std"), feature(lang_items, start))]

-#![cfg_attr(not(feature = "std"), no_std)]

-

-#[cfg_attr(not(feature = "std"), start)]

-fn start(_argc: isize, _argv: *const *const u8) -> isize {

-    0

-}

-#[lang = "eh_personality"]

-#[no_mangle]

-#[cfg(not(feature = "std"))]

-pub extern "C" fn rust_eh_personality() {}

-#[panic_handler]

-#[cfg(not(feature = "std"))]

-fn panic(_info: &core::panic::PanicInfo) -> ! {

-    unsafe {

-        libc::abort();

-    }

-}

-

-use displaydoc::Display;

-

-/// this type is pretty swell

-#[derive(Display)]

-#[prefix_enum_doc_attributes]

-enum TestType {

-    /// this variant is too

-    Variant1,

-

-    /// this variant is two

-    Variant2,

-}

-

-static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-

-#[cfg(feature = "std")]

-fn main() {}

+#![cfg_attr(not(feature = "std"), allow(internal_features), feature(lang_items, start))]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg_attr(not(feature = "std"), start)]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+use displaydoc::Display;
+
+/// this type is pretty swell
+#[derive(Display)]
+#[prefix_enum_doc_attributes]
+enum TestType {
+    /// this variant is too
+    Variant1,
+
+    /// this variant is two
+    Variant2,
+}
+
+static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+
+#[cfg(feature = "std")]
+fn main() {}
diff --git a/crates/displaydoc/tests/no_std/enum_prefix_missing.rs b/crates/displaydoc/tests/no_std/enum_prefix_missing.rs
index 474073e..7171072 100644
--- a/crates/displaydoc/tests/no_std/enum_prefix_missing.rs
+++ b/crates/displaydoc/tests/no_std/enum_prefix_missing.rs
@@ -1,35 +1,35 @@
-#![cfg_attr(not(feature = "std"), feature(lang_items, start))]

-#![cfg_attr(not(feature = "std"), no_std)]

-

-#[cfg_attr(not(feature = "std"), start)]

-fn start(_argc: isize, _argv: *const *const u8) -> isize {

-    0

-}

-#[lang = "eh_personality"]

-#[no_mangle]

-#[cfg(not(feature = "std"))]

-pub extern "C" fn rust_eh_personality() {}

-#[panic_handler]

-#[cfg(not(feature = "std"))]

-fn panic(_info: &core::panic::PanicInfo) -> ! {

-    unsafe {

-        libc::abort();

-    }

-}

-

-use displaydoc::Display;

-

-#[derive(Display)]

-#[prefix_enum_doc_attributes]

-enum TestType {

-    /// this variant is too

-    Variant1,

-

-    /// this variant is two

-    Variant2,

-}

-

-static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-

-#[cfg(feature = "std")]

-fn main() {}

+#![cfg_attr(not(feature = "std"), allow(internal_features), feature(lang_items, start))]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg_attr(not(feature = "std"), start)]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+use displaydoc::Display;
+
+#[derive(Display)]
+#[prefix_enum_doc_attributes]
+enum TestType {
+    /// this variant is too
+    Variant1,
+
+    /// this variant is two
+    Variant2,
+}
+
+static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+
+#[cfg(feature = "std")]
+fn main() {}
diff --git a/crates/displaydoc/tests/no_std/enum_prefix_missing.stderr b/crates/displaydoc/tests/no_std/enum_prefix_missing.stderr
index 8d40232..8cf7993 100644
--- a/crates/displaydoc/tests/no_std/enum_prefix_missing.stderr
+++ b/crates/displaydoc/tests/no_std/enum_prefix_missing.stderr
@@ -1,22 +1,22 @@
-error: proc-macro derive panicked

-  --> $DIR/enum_prefix_missing.rs:22:10

-   |

-22 | #[derive(Display)]

-   |          ^^^^^^^

-   |

-   = help: message: Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself.

-

-error[E0277]: `TestType` doesn't implement `Display`

-  --> $DIR/enum_prefix_missing.rs:32:37

-   |

-32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-   |                                     ^^^^^^^^ `TestType` cannot be formatted with the default formatter

-   |

-   = help: the trait `Display` is not implemented for `TestType`

-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

-note: required by a bound in `assert_impl_all`

-  --> $DIR/enum_prefix_missing.rs:32:1

-   |

-32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`

-   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)

+error: proc-macro derive panicked
+  --> $DIR/enum_prefix_missing.rs:22:10
+   |
+22 | #[derive(Display)]
+   |          ^^^^^^^
+   |
+   = help: message: Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself.
+
+error[E0277]: `TestType` doesn't implement `Display`
+  --> $DIR/enum_prefix_missing.rs:32:37
+   |
+32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+   |                                     ^^^^^^^^ `TestType` cannot be formatted with the default formatter
+   |
+   = help: the trait `Display` is not implemented for `TestType`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `assert_impl_all`
+  --> $DIR/enum_prefix_missing.rs:32:1
+   |
+32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/crates/displaydoc/tests/no_std/multi_line.rs b/crates/displaydoc/tests/no_std/multi_line.rs
index 351f6a4..ca4215c 100644
--- a/crates/displaydoc/tests/no_std/multi_line.rs
+++ b/crates/displaydoc/tests/no_std/multi_line.rs
@@ -1,37 +1,37 @@
-#![cfg_attr(not(feature = "std"), feature(lang_items, start))]

-#![cfg_attr(not(feature = "std"), no_std)]

-

-#[cfg_attr(not(feature = "std"), start)]

-fn start(_argc: isize, _argv: *const *const u8) -> isize {

-    0

-}

-#[lang = "eh_personality"]

-#[no_mangle]

-#[cfg(not(feature = "std"))]

-pub extern "C" fn rust_eh_personality() {}

-#[panic_handler]

-#[cfg(not(feature = "std"))]

-fn panic(_info: &core::panic::PanicInfo) -> ! {

-    unsafe {

-        libc::abort();

-    }

-}

-

-use displaydoc::Display;

-

-/// this type is pretty swell

-#[derive(Display)]

-enum TestType {

-    /// This one is okay

-    Variant1,

-

-    /// Multi

-    /// line

-    /// doc.

-    Variant2,

-}

-

-static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-

-#[cfg(feature = "std")]

-fn main() {}

+#![cfg_attr(not(feature = "std"), allow(internal_features), feature(lang_items, start))]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg_attr(not(feature = "std"), start)]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+use displaydoc::Display;
+
+/// this type is pretty swell
+#[derive(Display)]
+enum TestType {
+    /// This one is okay
+    Variant1,
+
+    /// Multi
+    /// line
+    /// doc.
+    Variant2,
+}
+
+static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+
+#[cfg(feature = "std")]
+fn main() {}
diff --git a/crates/displaydoc/tests/no_std/multi_line.stderr b/crates/displaydoc/tests/no_std/multi_line.stderr
index ae4956e..f3d77b9 100644
--- a/crates/displaydoc/tests/no_std/multi_line.stderr
+++ b/crates/displaydoc/tests/no_std/multi_line.stderr
@@ -1,22 +1,22 @@
-error: proc-macro derive panicked

-  --> $DIR/multi_line.rs:23:10

-   |

-23 | #[derive(Display)]

-   |          ^^^^^^^

-   |

-   = help: message: Multi-line comments are disabled by default by displaydoc. Please consider using block doc comments (/** */) or adding the #[ignore_extra_doc_attributes] attribute to your type next to the derive.

-

-error[E0277]: `TestType` doesn't implement `Display`

-  --> $DIR/multi_line.rs:34:37

-   |

-34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-   |                                     ^^^^^^^^ `TestType` cannot be formatted with the default formatter

-   |

-   = help: the trait `Display` is not implemented for `TestType`

-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

-note: required by a bound in `assert_impl_all`

-  --> $DIR/multi_line.rs:34:1

-   |

-34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`

-   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)

+error: proc-macro derive panicked
+  --> $DIR/multi_line.rs:23:10
+   |
+23 | #[derive(Display)]
+   |          ^^^^^^^
+   |
+   = help: message: Multi-line comments are disabled by default by displaydoc. Please consider using block doc comments (/** */) or adding the #[ignore_extra_doc_attributes] attribute to your type next to the derive.
+
+error[E0277]: `TestType` doesn't implement `Display`
+  --> $DIR/multi_line.rs:34:37
+   |
+34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+   |                                     ^^^^^^^^ `TestType` cannot be formatted with the default formatter
+   |
+   = help: the trait `Display` is not implemented for `TestType`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `assert_impl_all`
+  --> $DIR/multi_line.rs:34:1
+   |
+34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/crates/displaydoc/tests/no_std/multi_line_allow.rs b/crates/displaydoc/tests/no_std/multi_line_allow.rs
index 22511d9..8467681 100644
--- a/crates/displaydoc/tests/no_std/multi_line_allow.rs
+++ b/crates/displaydoc/tests/no_std/multi_line_allow.rs
@@ -1,38 +1,38 @@
-#![cfg_attr(not(feature = "std"), feature(lang_items, start))]

-#![cfg_attr(not(feature = "std"), no_std)]

-

-#[cfg_attr(not(feature = "std"), start)]

-fn start(_argc: isize, _argv: *const *const u8) -> isize {

-    0

-}

-#[lang = "eh_personality"]

-#[no_mangle]

-#[cfg(not(feature = "std"))]

-pub extern "C" fn rust_eh_personality() {}

-#[panic_handler]

-#[cfg(not(feature = "std"))]

-fn panic(_info: &core::panic::PanicInfo) -> ! {

-    unsafe {

-        libc::abort();

-    }

-}

-

-use displaydoc::Display;

-

-/// this type is pretty swell

-#[derive(Display)]

-#[ignore_extra_doc_attributes]

-enum TestType {

-    /// This one is okay

-    Variant1,

-

-    /// Multi

-    /// line

-    /// doc.

-    Variant2,

-}

-

-static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-

-#[cfg(feature = "std")]

-fn main() {}

+#![cfg_attr(not(feature = "std"), allow(internal_features), feature(lang_items, start))]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg_attr(not(feature = "std"), start)]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+use displaydoc::Display;
+
+/// this type is pretty swell
+#[derive(Display)]
+#[ignore_extra_doc_attributes]
+enum TestType {
+    /// This one is okay
+    Variant1,
+
+    /// Multi
+    /// line
+    /// doc.
+    Variant2,
+}
+
+static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+
+#[cfg(feature = "std")]
+fn main() {}
diff --git a/crates/displaydoc/tests/no_std/with.rs b/crates/displaydoc/tests/no_std/with.rs
index eba7460..67aef47 100644
--- a/crates/displaydoc/tests/no_std/with.rs
+++ b/crates/displaydoc/tests/no_std/with.rs
@@ -1,32 +1,32 @@
-#![feature(lang_items, start)]

-#![no_std]

-

-#[start]

-#[cfg(not(feature = "std"))]

-fn start(_argc: isize, _argv: *const *const u8) -> isize {

-    0

-}

-

-#[lang = "eh_personality"]

-#[no_mangle]

-#[cfg(not(feature = "std"))]

-pub extern "C" fn rust_eh_personality() {}

-

-#[panic_handler]

-#[cfg(not(feature = "std"))]

-fn panic(_info: &core::panic::PanicInfo) -> ! {

-    unsafe {

-        libc::abort();

-    }

-}

-

-#[cfg(feature = "std")]

-fn main() {}

-

-use displaydoc::Display;

-

-/// this type is pretty swell

-#[derive(Display)]

-struct FakeType;

-

-static_assertions::assert_impl_all!(FakeType: core::fmt::Display);

+#![feature(lang_items, start)]
+#![no_std]
+
+#[start]
+#[cfg(not(feature = "std"))]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+#[cfg(feature = "std")]
+fn main() {}
+
+use displaydoc::Display;
+
+/// this type is pretty swell
+#[derive(Display)]
+struct FakeType;
+
+static_assertions::assert_impl_all!(FakeType: core::fmt::Display);
diff --git a/crates/displaydoc/tests/no_std/without.rs b/crates/displaydoc/tests/no_std/without.rs
index aab3164..04d4b8f 100644
--- a/crates/displaydoc/tests/no_std/without.rs
+++ b/crates/displaydoc/tests/no_std/without.rs
@@ -1,28 +1,28 @@
-#![cfg_attr(not(feature = "std"), feature(lang_items, start))]

-#![cfg_attr(not(feature = "std"), no_std)]

-

-#[cfg_attr(not(feature = "std"), start)]

-fn start(_argc: isize, _argv: *const *const u8) -> isize {

-    0

-}

-#[lang = "eh_personality"]

-#[no_mangle]

-#[cfg(not(feature = "std"))]

-pub extern "C" fn rust_eh_personality() {}

-#[panic_handler]

-#[cfg(not(feature = "std"))]

-fn panic(_info: &core::panic::PanicInfo) -> ! {

-    unsafe {

-        libc::abort();

-    }

-}

-

-use displaydoc::Display;

-

-/// this type is pretty swell

-struct FakeType;

-

-static_assertions::assert_impl_all!(FakeType: core::fmt::Display);

-

-#[cfg(feature = "std")]

-fn main() {}

+#![cfg_attr(not(feature = "std"), allow(internal_features), feature(lang_items, start))]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg_attr(not(feature = "std"), start)]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+use displaydoc::Display;
+
+/// this type is pretty swell
+struct FakeType;
+
+static_assertions::assert_impl_all!(FakeType: core::fmt::Display);
+
+#[cfg(feature = "std")]
+fn main() {}
diff --git a/crates/displaydoc/tests/no_std/without.stderr b/crates/displaydoc/tests/no_std/without.stderr
index afcea63..a12edc4 100644
--- a/crates/displaydoc/tests/no_std/without.stderr
+++ b/crates/displaydoc/tests/no_std/without.stderr
@@ -1,22 +1,22 @@
-warning: unused import: `displaydoc::Display`

-  --> $DIR/without.rs:20:5

-   |

-20 | use displaydoc::Display;

-   |     ^^^^^^^^^^^^^^^^^^^

-   |

-   = note: `#[warn(unused_imports)]` on by default

-

-error[E0277]: `FakeType` doesn't implement `Display`

-  --> $DIR/without.rs:25:37

-   |

-25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display);

-   |                                     ^^^^^^^^ `FakeType` cannot be formatted with the default formatter

-   |

-   = help: the trait `Display` is not implemented for `FakeType`

-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

-note: required by a bound in `assert_impl_all`

-  --> $DIR/without.rs:25:1

-   |

-25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display);

-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`

-   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)

+warning: unused import: `displaydoc::Display`
+  --> $DIR/without.rs:20:5
+   |
+20 | use displaydoc::Display;
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unused_imports)]` on by default
+
+error[E0277]: `FakeType` doesn't implement `Display`
+  --> $DIR/without.rs:25:37
+   |
+25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display);
+   |                                     ^^^^^^^^ `FakeType` cannot be formatted with the default formatter
+   |
+   = help: the trait `Display` is not implemented for `FakeType`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `assert_impl_all`
+  --> $DIR/without.rs:25:1
+   |
+25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/crates/displaydoc/tests/num_in_field.rs b/crates/displaydoc/tests/num_in_field.rs
index ab90f0d..9510f82 100644
--- a/crates/displaydoc/tests/num_in_field.rs
+++ b/crates/displaydoc/tests/num_in_field.rs
@@ -1,22 +1,22 @@
-/// {foo1} {foo2}

-#[derive(displaydoc::Display)]

-pub struct Test {

-    foo1: String,

-    foo2: String,

-}

-

-fn assert_display<T: std::fmt::Display>(input: T, expected: &'static str) {

-    let out = format!("{}", input);

-    assert_eq!(expected, out);

-}

-

-#[test]

-fn does_it_print() {

-    assert_display(

-        Test {

-            foo1: "hi".into(),

-            foo2: "hello".into(),

-        },

-        "hi hello",

-    );

-}

+/// {foo1} {foo2}
+#[derive(displaydoc::Display)]
+pub struct Test {
+    foo1: String,
+    foo2: String,
+}
+
+fn assert_display<T: std::fmt::Display>(input: T, expected: &'static str) {
+    let out = format!("{}", input);
+    assert_eq!(expected, out);
+}
+
+#[test]
+fn does_it_print() {
+    assert_display(
+        Test {
+            foo1: "hi".into(),
+            foo2: "hello".into(),
+        },
+        "hi hello",
+    );
+}
diff --git a/crates/displaydoc/tests/std/enum_prefix.rs b/crates/displaydoc/tests/std/enum_prefix.rs
index b8482ca..7e6abcc 100644
--- a/crates/displaydoc/tests/std/enum_prefix.rs
+++ b/crates/displaydoc/tests/std/enum_prefix.rs
@@ -1,36 +1,36 @@
-#![cfg_attr(not(feature = "std"), feature(lang_items, start))]

-#![cfg_attr(not(feature = "std"), no_std)]

-

-#[cfg_attr(not(feature = "std"), start)]

-fn start(_argc: isize, _argv: *const *const u8) -> isize {

-    0

-}

-#[lang = "eh_personality"]

-#[no_mangle]

-#[cfg(not(feature = "std"))]

-pub extern "C" fn rust_eh_personality() {}

-#[panic_handler]

-#[cfg(not(feature = "std"))]

-fn panic(_info: &core::panic::PanicInfo) -> ! {

-    unsafe {

-        libc::abort();

-    }

-}

-

-use displaydoc::Display;

-

-/// this type is pretty swell

-#[derive(Display)]

-#[prefix_enum_doc_attributes]

-enum TestType {

-    /// this variant is too

-    Variant1,

-

-    /// this variant is two

-    Variant2,

-}

-

-static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-

-#[cfg(feature = "std")]

-fn main() {}

+#![cfg_attr(not(feature = "std"), feature(lang_items, start))]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg_attr(not(feature = "std"), start)]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+use displaydoc::Display;
+
+/// this type is pretty swell
+#[derive(Display)]
+#[prefix_enum_doc_attributes]
+enum TestType {
+    /// this variant is too
+    Variant1,
+
+    /// this variant is two
+    Variant2,
+}
+
+static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+
+#[cfg(feature = "std")]
+fn main() {}
diff --git a/crates/displaydoc/tests/std/enum_prefix_missing.rs b/crates/displaydoc/tests/std/enum_prefix_missing.rs
index 474073e..45c312b 100644
--- a/crates/displaydoc/tests/std/enum_prefix_missing.rs
+++ b/crates/displaydoc/tests/std/enum_prefix_missing.rs
@@ -1,35 +1,35 @@
-#![cfg_attr(not(feature = "std"), feature(lang_items, start))]

-#![cfg_attr(not(feature = "std"), no_std)]

-

-#[cfg_attr(not(feature = "std"), start)]

-fn start(_argc: isize, _argv: *const *const u8) -> isize {

-    0

-}

-#[lang = "eh_personality"]

-#[no_mangle]

-#[cfg(not(feature = "std"))]

-pub extern "C" fn rust_eh_personality() {}

-#[panic_handler]

-#[cfg(not(feature = "std"))]

-fn panic(_info: &core::panic::PanicInfo) -> ! {

-    unsafe {

-        libc::abort();

-    }

-}

-

-use displaydoc::Display;

-

-#[derive(Display)]

-#[prefix_enum_doc_attributes]

-enum TestType {

-    /// this variant is too

-    Variant1,

-

-    /// this variant is two

-    Variant2,

-}

-

-static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-

-#[cfg(feature = "std")]

-fn main() {}

+#![cfg_attr(not(feature = "std"), feature(lang_items, start))]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg_attr(not(feature = "std"), start)]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+use displaydoc::Display;
+
+#[derive(Display)]
+#[prefix_enum_doc_attributes]
+enum TestType {
+    /// this variant is too
+    Variant1,
+
+    /// this variant is two
+    Variant2,
+}
+
+static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+
+#[cfg(feature = "std")]
+fn main() {}
diff --git a/crates/displaydoc/tests/std/enum_prefix_missing.stderr b/crates/displaydoc/tests/std/enum_prefix_missing.stderr
index fe4b5ef..09e1db6 100644
--- a/crates/displaydoc/tests/std/enum_prefix_missing.stderr
+++ b/crates/displaydoc/tests/std/enum_prefix_missing.stderr
@@ -1,22 +1,22 @@
-error: proc-macro derive panicked

-  --> $DIR/enum_prefix_missing.rs:22:10

-   |

-22 | #[derive(Display)]

-   |          ^^^^^^^

-   |

-   = help: message: Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself.

-

-error[E0277]: `TestType` doesn't implement `std::fmt::Display`

-  --> $DIR/enum_prefix_missing.rs:32:37

-   |

-32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-   |                                     ^^^^^^^^ `TestType` cannot be formatted with the default formatter

-   |

-   = help: the trait `std::fmt::Display` is not implemented for `TestType`

-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

-note: required by a bound in `assert_impl_all`

-  --> $DIR/enum_prefix_missing.rs:32:1

-   |

-32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`

-   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)

+error: proc-macro derive panicked
+  --> $DIR/enum_prefix_missing.rs:22:10
+   |
+22 | #[derive(Display)]
+   |          ^^^^^^^
+   |
+   = help: message: Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself.
+
+error[E0277]: `TestType` doesn't implement `std::fmt::Display`
+  --> $DIR/enum_prefix_missing.rs:32:37
+   |
+32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+   |                                     ^^^^^^^^ `TestType` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `TestType`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `assert_impl_all`
+  --> $DIR/enum_prefix_missing.rs:32:1
+   |
+32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/crates/displaydoc/tests/std/multi_line.rs b/crates/displaydoc/tests/std/multi_line.rs
index 5b0f2cf..ca4215c 100644
--- a/crates/displaydoc/tests/std/multi_line.rs
+++ b/crates/displaydoc/tests/std/multi_line.rs
@@ -1 +1,37 @@
-../no_std/multi_line.rs
\ No newline at end of file
+#![cfg_attr(not(feature = "std"), allow(internal_features), feature(lang_items, start))]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg_attr(not(feature = "std"), start)]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+use displaydoc::Display;
+
+/// this type is pretty swell
+#[derive(Display)]
+enum TestType {
+    /// This one is okay
+    Variant1,
+
+    /// Multi
+    /// line
+    /// doc.
+    Variant2,
+}
+
+static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+
+#[cfg(feature = "std")]
+fn main() {}
diff --git a/crates/displaydoc/tests/std/multi_line.stderr b/crates/displaydoc/tests/std/multi_line.stderr
index a8b6602..c36a75d 100644
--- a/crates/displaydoc/tests/std/multi_line.stderr
+++ b/crates/displaydoc/tests/std/multi_line.stderr
@@ -1,22 +1,22 @@
-error: proc-macro derive panicked

-  --> $DIR/multi_line.rs:23:10

-   |

-23 | #[derive(Display)]

-   |          ^^^^^^^

-   |

-   = help: message: Multi-line comments are disabled by default by displaydoc. Please consider using block doc comments (/** */) or adding the #[ignore_extra_doc_attributes] attribute to your type next to the derive.

-

-error[E0277]: `TestType` doesn't implement `std::fmt::Display`

-  --> $DIR/multi_line.rs:34:37

-   |

-34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-   |                                     ^^^^^^^^ `TestType` cannot be formatted with the default formatter

-   |

-   = help: the trait `std::fmt::Display` is not implemented for `TestType`

-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

-note: required by a bound in `assert_impl_all`

-  --> $DIR/multi_line.rs:34:1

-   |

-34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`

-   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)

+error: proc-macro derive panicked
+  --> $DIR/multi_line.rs:23:10
+   |
+23 | #[derive(Display)]
+   |          ^^^^^^^
+   |
+   = help: message: Multi-line comments are disabled by default by displaydoc. Please consider using block doc comments (/** */) or adding the #[ignore_extra_doc_attributes] attribute to your type next to the derive.
+
+error[E0277]: `TestType` doesn't implement `std::fmt::Display`
+  --> $DIR/multi_line.rs:34:37
+   |
+34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+   |                                     ^^^^^^^^ `TestType` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `TestType`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `assert_impl_all`
+  --> $DIR/multi_line.rs:34:1
+   |
+34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/crates/displaydoc/tests/std/multi_line_allow.rs b/crates/displaydoc/tests/std/multi_line_allow.rs
index 22511d9..e09e8fc 100644
--- a/crates/displaydoc/tests/std/multi_line_allow.rs
+++ b/crates/displaydoc/tests/std/multi_line_allow.rs
@@ -1,38 +1,38 @@
-#![cfg_attr(not(feature = "std"), feature(lang_items, start))]

-#![cfg_attr(not(feature = "std"), no_std)]

-

-#[cfg_attr(not(feature = "std"), start)]

-fn start(_argc: isize, _argv: *const *const u8) -> isize {

-    0

-}

-#[lang = "eh_personality"]

-#[no_mangle]

-#[cfg(not(feature = "std"))]

-pub extern "C" fn rust_eh_personality() {}

-#[panic_handler]

-#[cfg(not(feature = "std"))]

-fn panic(_info: &core::panic::PanicInfo) -> ! {

-    unsafe {

-        libc::abort();

-    }

-}

-

-use displaydoc::Display;

-

-/// this type is pretty swell

-#[derive(Display)]

-#[ignore_extra_doc_attributes]

-enum TestType {

-    /// This one is okay

-    Variant1,

-

-    /// Multi

-    /// line

-    /// doc.

-    Variant2,

-}

-

-static_assertions::assert_impl_all!(TestType: core::fmt::Display);

-

-#[cfg(feature = "std")]

-fn main() {}

+#![cfg_attr(not(feature = "std"), feature(lang_items, start))]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg_attr(not(feature = "std"), start)]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+use displaydoc::Display;
+
+/// this type is pretty swell
+#[derive(Display)]
+#[ignore_extra_doc_attributes]
+enum TestType {
+    /// This one is okay
+    Variant1,
+
+    /// Multi
+    /// line
+    /// doc.
+    Variant2,
+}
+
+static_assertions::assert_impl_all!(TestType: core::fmt::Display);
+
+#[cfg(feature = "std")]
+fn main() {}
diff --git a/crates/displaydoc/tests/std/multiple.rs b/crates/displaydoc/tests/std/multiple.rs
index b0a4de0..66d59b7 100644
--- a/crates/displaydoc/tests/std/multiple.rs
+++ b/crates/displaydoc/tests/std/multiple.rs
@@ -1,38 +1,38 @@
-#![feature(lang_items, start)]

-#![no_std]

-

-#[start]

-#[cfg(not(feature = "std"))]

-fn start(_argc: isize, _argv: *const *const u8) -> isize {

-    0

-}

-

-#[lang = "eh_personality"]

-#[no_mangle]

-#[cfg(not(feature = "std"))]

-pub extern "C" fn rust_eh_personality() {}

-

-#[panic_handler]

-#[cfg(not(feature = "std"))]

-fn panic(_info: &core::panic::PanicInfo) -> ! {

-    unsafe {

-        libc::abort();

-    }

-}

-

-#[cfg(feature = "std")]

-fn main() {}

-

-use displaydoc::Display;

-

-/// this type is pretty swell

-#[derive(Display)]

-struct FakeType;

-

-static_assertions::assert_impl_all!(FakeType: core::fmt::Display);

-

-/// this type is pretty swell2

-#[derive(Display)]

-struct FakeType2;

-

-static_assertions::assert_impl_all!(FakeType2: core::fmt::Display);

+#![feature(lang_items, start)]
+#![no_std]
+
+#[start]
+#[cfg(not(feature = "std"))]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+#[cfg(feature = "std")]
+fn main() {}
+
+use displaydoc::Display;
+
+/// this type is pretty swell
+#[derive(Display)]
+struct FakeType;
+
+static_assertions::assert_impl_all!(FakeType: core::fmt::Display);
+
+/// this type is pretty swell2
+#[derive(Display)]
+struct FakeType2;
+
+static_assertions::assert_impl_all!(FakeType2: core::fmt::Display);
diff --git a/crates/displaydoc/tests/std/without.rs b/crates/displaydoc/tests/std/without.rs
index 6b5b714..04d4b8f 100644
--- a/crates/displaydoc/tests/std/without.rs
+++ b/crates/displaydoc/tests/std/without.rs
@@ -1 +1,28 @@
-../no_std/without.rs
\ No newline at end of file
+#![cfg_attr(not(feature = "std"), allow(internal_features), feature(lang_items, start))]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg_attr(not(feature = "std"), start)]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+#[lang = "eh_personality"]
+#[no_mangle]
+#[cfg(not(feature = "std"))]
+pub extern "C" fn rust_eh_personality() {}
+#[panic_handler]
+#[cfg(not(feature = "std"))]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        libc::abort();
+    }
+}
+
+use displaydoc::Display;
+
+/// this type is pretty swell
+struct FakeType;
+
+static_assertions::assert_impl_all!(FakeType: core::fmt::Display);
+
+#[cfg(feature = "std")]
+fn main() {}
diff --git a/crates/displaydoc/tests/std/without.stderr b/crates/displaydoc/tests/std/without.stderr
index 552ae82..4f0d713 100644
--- a/crates/displaydoc/tests/std/without.stderr
+++ b/crates/displaydoc/tests/std/without.stderr
@@ -1,22 +1,22 @@
-warning: unused import: `displaydoc::Display`

-  --> $DIR/without.rs:20:5

-   |

-20 | use displaydoc::Display;

-   |     ^^^^^^^^^^^^^^^^^^^

-   |

-   = note: `#[warn(unused_imports)]` on by default

-

-error[E0277]: `FakeType` doesn't implement `std::fmt::Display`

-  --> $DIR/without.rs:25:37

-   |

-25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display);

-   |                                     ^^^^^^^^ `FakeType` cannot be formatted with the default formatter

-   |

-   = help: the trait `std::fmt::Display` is not implemented for `FakeType`

-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

-note: required by a bound in `assert_impl_all`

-  --> $DIR/without.rs:25:1

-   |

-25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display);

-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`

-   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)

+warning: unused import: `displaydoc::Display`
+  --> $DIR/without.rs:20:5
+   |
+20 | use displaydoc::Display;
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unused_imports)]` on by default
+
+error[E0277]: `FakeType` doesn't implement `std::fmt::Display`
+  --> $DIR/without.rs:25:37
+   |
+25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display);
+   |                                     ^^^^^^^^ `FakeType` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `FakeType`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `assert_impl_all`
+  --> $DIR/without.rs:25:1
+   |
+25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/crates/displaydoc/tests/variantless.rs b/crates/displaydoc/tests/variantless.rs
index bc23ed4..7511bc7 100644
--- a/crates/displaydoc/tests/variantless.rs
+++ b/crates/displaydoc/tests/variantless.rs
@@ -1,6 +1,6 @@
-use displaydoc::Display;

-

-#[derive(Display)]

-enum EmptyInside {}

-

-static_assertions::assert_impl_all!(EmptyInside: core::fmt::Display);

+use displaydoc::Display;
+
+#[derive(Display)]
+enum EmptyInside {}
+
+static_assertions::assert_impl_all!(EmptyInside: core::fmt::Display);
diff --git a/crates/displaydoc/update-readme.sh b/crates/displaydoc/update-readme.sh
old mode 100644
new mode 100755
index 90db1a8..f67bfd5
--- a/crates/displaydoc/update-readme.sh
+++ b/crates/displaydoc/update-readme.sh
@@ -1,5 +1,5 @@
-#! /usr/bin/env bash

-

-cargo readme > ./README.md

-git add ./README.md

-git commit -m "Update readme" || true

+#! /usr/bin/env bash
+
+cargo readme > ./README.md
+git add ./README.md
+git commit -m "Update readme" || true
diff --git a/crates/document-features/.cargo-checksum.json b/crates/document-features/.cargo-checksum.json
index 0b9d0b4..b288a01 100644
--- a/crates/document-features/.cargo-checksum.json
+++ b/crates/document-features/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"c1ccf4587ca168b3baa54580469c5dcc776decac0d996d3bb31d2341b47efa11","Cargo.toml":"390d32c2b791a6745c075c474e6d57c65d5f77f0e7190ff8a8c5342fbb40722a","LICENSE-APACHE":"074e6e32c86a4c0ef8b3ed25b721ca23aca83df277cd88106ef7177c354615ff","LICENSE-MIT":"aa893340d14b9844625be6a50ac644169a01b52f0211cbf81b09e1874c8cd81d","README.md":"89a83c4acc6891e5651772fc78a1d6362070774eaa6c5b5d4bfbe9e57a957be9","lib.rs":"2f4ede9d0619d85449891d9055605188db681d57b405e40e529831266e014ee5","rustfmt.toml":"f74204a6f92aa7422a16ecb2ffe2d5bae0f123b778d08b5db1a398a3c9ca4306","tests/self-doc.rs":"24bbda93f3b323c0b7c543c1df3bf45522b8026283103211805f070de66abadc"},"package":"ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"4a628703d5fc4ce692f255732a077d6d611aff64d2fddc3b2b4cd6c1bcc35bcf","Cargo.toml":"6e4dc75115db673e743d41149144c638ad8e11da7cfb5435d55e60ea61bd2016","LICENSE-APACHE":"074e6e32c86a4c0ef8b3ed25b721ca23aca83df277cd88106ef7177c354615ff","LICENSE-MIT":"aa893340d14b9844625be6a50ac644169a01b52f0211cbf81b09e1874c8cd81d","README.md":"89a83c4acc6891e5651772fc78a1d6362070774eaa6c5b5d4bfbe9e57a957be9","lib.rs":"f7915d9cd43170ce74f4551b51c39b7a91acbe244ede6ab3ca2fa1c50d505040","rustfmt.toml":"f74204a6f92aa7422a16ecb2ffe2d5bae0f123b778d08b5db1a398a3c9ca4306","tests/self-doc.rs":"24bbda93f3b323c0b7c543c1df3bf45522b8026283103211805f070de66abadc"},"package":"cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0"}
\ No newline at end of file
diff --git a/crates/document-features/Android.bp b/crates/document-features/Android.bp
index d75d388..62d6767 100644
--- a/crates/document-features/Android.bp
+++ b/crates/document-features/Android.bp
@@ -17,7 +17,7 @@
     name: "libdocument_features",
     crate_name: "document_features",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.2.8",
+    cargo_pkg_version: "0.2.10",
     crate_root: "lib.rs",
     edition: "2018",
     features: ["default"],
diff --git a/crates/document-features/CHANGELOG.md b/crates/document-features/CHANGELOG.md
index f94ee19..44ab7b1 100644
--- a/crates/document-features/CHANGELOG.md
+++ b/crates/document-features/CHANGELOG.md
@@ -1,7 +1,17 @@
 # Changelog
 
+## 0.2.1O - 2024-07-12
 
-## 0.2.7 - 2023-12-29
+* Revert parsing of multi-lines string while parsing features
+  (Keep parsing of multi-lines string when detecting if we need to use Cargo.toml.orig)
+
+## 0.2.9 - 2024-07-11
+
+* Fix parsing of multi-lines string (#25)
+* Fix `out_of_scope_macro_calls` compatibility warning
+* Fix documentation having too many `#` (#22)
+
+## 0.2.8 - 2023-12-29
 
 * Remove `\n` between features (#17)
 * Don't throw an error when there is no features in Cargo.toml (#20)
diff --git a/crates/document-features/Cargo.toml b/crates/document-features/Cargo.toml
index bae5ff2..4e8778c 100644
--- a/crates/document-features/Cargo.toml
+++ b/crates/document-features/Cargo.toml
@@ -12,10 +12,10 @@
 [package]
 edition = "2018"
 name = "document-features"
-version = "0.2.8"
-authors = ["Slint Developers <info@slint-ui.com>"]
+version = "0.2.10"
+authors = ["Slint Developers <info@slint.dev>"]
 description = "Extract documentation for the feature flags from comments in Cargo.toml"
-homepage = "https://slint-ui.com"
+homepage = "https://slint.rs"
 readme = "README.md"
 keywords = [
     "documentation",
diff --git a/crates/document-features/METADATA b/crates/document-features/METADATA
index 7c84282..9b261ba 100644
--- a/crates/document-features/METADATA
+++ b/crates/document-features/METADATA
@@ -1,17 +1,17 @@
 name: "document-features"
 description: "Extract documentation for the feature flags from comments in Cargo.toml"
 third_party {
-  version: "0.2.8"
+  version: "0.2.10"
   license_type: NOTICE
   last_upgrade_date {
     year: 2024
-    month: 2
-    day: 8
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/document-features"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/document-features/document-features-0.2.8.crate"
-    version: "0.2.8"
+    value: "https://static.crates.io/crates/document-features/document-features-0.2.10.crate"
+    version: "0.2.10"
   }
 }
diff --git a/crates/document-features/lib.rs b/crates/document-features/lib.rs
index b30ebe7..cd12f1b 100644
--- a/crates/document-features/lib.rs
+++ b/crates/document-features/lib.rs
@@ -41,40 +41,38 @@
 ## Examples:
 
 */
-// Note: because rustdoc escapes the first `#` of a line starting with `#`,
-// these docs comments have one more `#` ,
 #![doc = self_test!(/**
 [package]
 name = "..."
-## ...
+# ...
 
 [features]
 default = ["foo"]
-##! This comments goes on top
+#! This comments goes on top
 
-### The foo feature enables the `foo` functions
+## The foo feature enables the `foo` functions
 foo = []
 
-### The bar feature enables the bar module
+## The bar feature enables the bar module
 bar = []
 
-##! ### Experimental features
-##! The following features are experimental
+#! ### Experimental features
+#! The following features are experimental
 
-### Enable the fusion reactor
-###
-### ⚠️ Can lead to explosions
+## Enable the fusion reactor
+##
+## ⚠️ Can lead to explosions
 fusion = []
 
 [dependencies]
 document-features = "0.2"
 
-##! ### Optional dependencies
+#! ### Optional dependencies
 
-### Enable this feature to implement the trait for the types from the genial crate
+## Enable this feature to implement the trait for the types from the genial crate
 genial = { version = "0.2", optional = true }
 
-### This awesome dependency is specified in its own table
+## This awesome dependency is specified in its own table
 [dependencies.awesome]
 version = "1.3.5"
 optional = true
@@ -256,11 +254,11 @@
     let mut cargo_toml = std::fs::read_to_string(Path::new(&path).join("Cargo.toml"))
         .map_err(|e| error(&format!("Can't open Cargo.toml: {:?}", e)))?;
 
-    if !cargo_toml.contains("\n##") && !cargo_toml.contains("\n#!") {
+    if !has_doc_comments(&cargo_toml) {
         // On crates.io, Cargo.toml is usually "normalized" and stripped of all comments.
         // The original Cargo.toml has been renamed Cargo.toml.orig
         if let Ok(orig) = std::fs::read_to_string(Path::new(&path).join("Cargo.toml.orig")) {
-            if orig.contains("##") || orig.contains("#!") {
+            if has_doc_comments(&orig) {
                 cargo_toml = orig;
             }
         }
@@ -270,6 +268,109 @@
     Ok(std::iter::once(proc_macro::TokenTree::from(proc_macro::Literal::string(&result))).collect())
 }
 
+/// Check if the Cargo.toml has comments that looks like doc comments.
+fn has_doc_comments(cargo_toml: &str) -> bool {
+    let mut lines = cargo_toml.lines().map(str::trim);
+    while let Some(line) = lines.next() {
+        if line.starts_with("## ") || line.starts_with("#! ") {
+            return true;
+        }
+        let before_coment = line.split_once('#').map_or(line, |(before, _)| before);
+        if line.starts_with("#") {
+            continue;
+        }
+        if let Some((_, mut quote)) = before_coment.split_once("\"\"\"") {
+            loop {
+                // skip slashes.
+                if let Some((_, s)) = quote.split_once('\\') {
+                    quote = s.strip_prefix('\\').or_else(|| s.strip_prefix('"')).unwrap_or(s);
+                    continue;
+                }
+                // skip quotes.
+                if let Some((_, out_quote)) = quote.split_once("\"\"\"") {
+                    let out_quote = out_quote.trim_start_matches('"');
+                    let out_quote =
+                        out_quote.split_once('#').map_or(out_quote, |(before, _)| before);
+                    if let Some((_, q)) = out_quote.split_once("\"\"\"") {
+                        quote = q;
+                        continue;
+                    }
+                    break;
+                };
+                match lines.next() {
+                    Some(l) => quote = l,
+                    None => return false,
+                }
+            }
+        }
+    }
+    false
+}
+
+#[test]
+fn test_has_doc_coment() {
+    assert!(has_doc_comments("foo\nbar\n## comment\nddd"));
+    assert!(!has_doc_comments("foo\nbar\n#comment\nddd"));
+    assert!(!has_doc_comments(
+        r#"
+[[package.metadata.release.pre-release-replacements]]
+exactly = 1 # not a doc comment
+file = "CHANGELOG.md"
+replace = """
+<!-- next-header -->
+## [Unreleased] - ReleaseDate
+"""
+search = "<!-- next-header -->"
+array = ["""foo""", """
+bar""", """eee
+## not a comment
+"""]
+    "#
+    ));
+    assert!(has_doc_comments(
+        r#"
+[[package.metadata.release.pre-release-replacements]]
+exactly = 1 # """
+file = "CHANGELOG.md"
+replace = """
+<!-- next-header -->
+## [Unreleased] - ReleaseDate
+"""
+search = "<!-- next-header -->"
+array = ["""foo""", """
+bar""", """eee
+## not a comment
+"""]
+## This is a comment
+feature = "45"
+        "#
+    ));
+
+    assert!(!has_doc_comments(
+        r#"
+[[package.metadata.release.pre-release-replacements]]
+value = """" string \"""
+## within the string
+\""""
+another_string = """"" # """
+## also within"""
+"#
+    ));
+
+    assert!(has_doc_comments(
+        r#"
+[[package.metadata.release.pre-release-replacements]]
+value = """" string \"""
+## within the string
+\""""
+another_string = """"" # """
+## also within"""
+## out of the string
+foo = bar
+        "#
+    ));
+}
+
 fn process_toml(cargo_toml: &str, args: &Args) -> Result<String, String> {
     // Get all lines between the "[features]" and the next block
     let mut lines = cargo_toml
@@ -465,14 +566,20 @@
 #[doc(hidden)]
 /// Helper macro for the tests. Do not use
 pub fn self_test_helper(input: TokenStream) -> TokenStream {
-    process_toml((&input).to_string().trim_matches(|c| c == '"' || c == '#'), &Args::default())
-        .map_or_else(
-            |e| error(&e),
-            |r| {
-                std::iter::once(proc_macro::TokenTree::from(proc_macro::Literal::string(&r)))
-                    .collect()
-            },
-        )
+    let mut code = String::new();
+    for line in (&input).to_string().trim_matches(|c| c == '"' || c == '#').lines() {
+        // Rustdoc removes the lines that starts with `# ` and removes one `#` from lines that starts with # followed by space.
+        // We need to re-add the `#` that was removed by rustdoc to get the original.
+        if line.strip_prefix('#').map_or(false, |x| x.is_empty() || x.starts_with(' ')) {
+            code += "#";
+        }
+        code += line;
+        code += "\n";
+    }
+    process_toml(&code, &Args::default()).map_or_else(
+        |e| error(&e),
+        |r| std::iter::once(proc_macro::TokenTree::from(proc_macro::Literal::string(&r))).collect(),
+    )
 }
 
 #[cfg(feature = "self-test")]
@@ -507,6 +614,8 @@
     };
 }
 
+use self_test;
+
 // The following struct is inserted only during generation of the documentation in order to exploit doc-tests.
 // These doc-tests are used to check that invalid arguments to the `document_features!` macro cause a compile time error.
 // For a more principled way of testing compilation error, maybe investigate <https://docs.rs/trybuild>.
diff --git a/crates/downcast-rs/.cargo-checksum.json b/crates/downcast-rs/.cargo-checksum.json
index cae8189..ad2fb7f 100644
--- a/crates/downcast-rs/.cargo-checksum.json
+++ b/crates/downcast-rs/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"92366db9bf095705cc9f8ca3617a8a4ea01443d23da0c1c0d16c562ce9422b5f","Cargo.toml":"efaf216be3ffacbecf79cb3c27ef38c8e1099a37ea99503f9d838dc8f999ec0c","LICENSE-APACHE":"8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90","LICENSE-MIT":"fb252fecf98d9af8f1d9201c5860319a514f5a8a24700dc84fc6ea287a7a4958","README.md":"1a4fa1020e6a38ff261aa89e095303dbf0e0da2d1e100796c10ac53e66019d15","README.tpl":"fe63f3603c7c1d7c700904cfd69a78474c5eee4da6e9e82d673ef879b23e80a2","src/lib.rs":"127b9cba8f5667390a7e5a5a6cad4c65ab5ada9696b5ff7d09d0e3b1020fd81a","tests/import_via_macro_use.rs":"621d22294eb802e82dc8393d344c706f97b8347da49084135a75aa1331553548","tests/use_via_namespace.rs":"013640597d3b2d8719d3857cfc721942738e4a3eeba61517b25d45ba4165da3c"},"package":"9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"f36a75ad5152a2a065fb8fb2a17be9da2959f43f98e5e99200f69ff318cacc5e","Cargo.toml":"f20629badf8ae359e8b042b1423138a2dbb0fe78c0fb5333a1627e97b56b1e0d","LICENSE-APACHE":"8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90","LICENSE-MIT":"fb252fecf98d9af8f1d9201c5860319a514f5a8a24700dc84fc6ea287a7a4958","README.md":"b2821528972c2e81e8227698d3115996144fd319dcc505e38131d23e2e02456c","README.tpl":"05ff2e25c6b8df663726cf7acef6dc237fe9c3f615d3c95cb127456a4ef36a7d","src/lib.rs":"febe175ec6344e7e1fd5347c3d653600909c5016f481d0f637e203fd5fba5645","tests/import_via_macro_use.rs":"621d22294eb802e82dc8393d344c706f97b8347da49084135a75aa1331553548","tests/use_via_namespace.rs":"013640597d3b2d8719d3857cfc721942738e4a3eeba61517b25d45ba4165da3c"},"package":"75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"}
\ No newline at end of file
diff --git a/crates/downcast-rs/Android.bp b/crates/downcast-rs/Android.bp
index 7346d83..eb6bad1 100644
--- a/crates/downcast-rs/Android.bp
+++ b/crates/downcast-rs/Android.bp
@@ -18,7 +18,7 @@
     host_supported: true,
     crate_name: "downcast_rs",
     cargo_env_compat: true,
-    cargo_pkg_version: "1.2.0",
+    cargo_pkg_version: "1.2.1",
     crate_root: "src/lib.rs",
     test_suites: ["general-tests"],
     auto_gen_config: true,
@@ -37,7 +37,7 @@
     host_supported: true,
     crate_name: "import_via_macro_use",
     cargo_env_compat: true,
-    cargo_pkg_version: "1.2.0",
+    cargo_pkg_version: "1.2.1",
     crate_root: "tests/import_via_macro_use.rs",
     test_suites: ["general-tests"],
     auto_gen_config: true,
@@ -57,7 +57,7 @@
     host_supported: true,
     crate_name: "use_via_namespace",
     cargo_env_compat: true,
-    cargo_pkg_version: "1.2.0",
+    cargo_pkg_version: "1.2.1",
     crate_root: "tests/use_via_namespace.rs",
     test_suites: ["general-tests"],
     auto_gen_config: true,
@@ -77,7 +77,7 @@
     host_supported: true,
     crate_name: "downcast_rs",
     cargo_env_compat: true,
-    cargo_pkg_version: "1.2.0",
+    cargo_pkg_version: "1.2.1",
     crate_root: "src/lib.rs",
     edition: "2015",
     features: [
diff --git a/crates/downcast-rs/CHANGELOG.md b/crates/downcast-rs/CHANGELOG.md
index 149cd4f..ef91ad9 100644
--- a/crates/downcast-rs/CHANGELOG.md
+++ b/crates/downcast-rs/CHANGELOG.md
@@ -4,6 +4,11 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## 1.2.1 - 2024-04-06
+### Change
+- Consolidated bounds on the trait to avoid triggering Clippy's
+  `multiple_bound_locations` lint.
+
 ## 1.2.0 - 2020-06-29
 ### Added
 - `no_std` support.
diff --git a/crates/downcast-rs/Cargo.toml b/crates/downcast-rs/Cargo.toml
index 57a55b7..c65f93f 100644
--- a/crates/downcast-rs/Cargo.toml
+++ b/crates/downcast-rs/Cargo.toml
@@ -3,20 +3,31 @@
 # When uploading crates to the registry Cargo will automatically
 # "normalize" Cargo.toml files for maximal compatibility
 # with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
 #
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
 
 [package]
 name = "downcast-rs"
-version = "1.2.0"
-authors = ["Ashish Myles <marcianx@gmail.com>", "Runji Wang <wangrunji0408@163.com>"]
-description = "Trait object downcasting support using only safe Rust. It supports type\nparameters, associated types, and type constraints.\n"
+version = "1.2.1"
+authors = [
+    "Ashish Myles <marcianx@gmail.com>",
+    "Runji Wang <wangrunji0408@163.com>",
+]
+description = """
+Trait object downcasting support using only safe Rust. It supports type
+parameters, associated types, and type constraints.
+"""
 readme = "README.md"
-keywords = ["downcast", "any", "trait", "associated", "no_std"]
+keywords = [
+    "downcast",
+    "any",
+    "trait",
+    "associated",
+    "no_std",
+]
 license = "MIT/Apache-2.0"
 repository = "https://github.com/marcianx/downcast-rs"
 
diff --git a/crates/downcast-rs/METADATA b/crates/downcast-rs/METADATA
index 9ff0d22..8b32484 100644
--- a/crates/downcast-rs/METADATA
+++ b/crates/downcast-rs/METADATA
@@ -1,17 +1,17 @@
 name: "downcast-rs"
 description: "Trait object downcasting support using only safe Rust. It supports type parameters, associated types, and type constraints."
 third_party {
-  version: "1.2.0"
+  version: "1.2.1"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2020
+    year: 2024
     month: 10
-    day: 27
+    day: 2
   }
   homepage: "https://crates.io/crates/downcast-rs"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/downcast-rs/downcast-rs-1.2.0.crate"
-    version: "1.2.0"
+    value: "https://static.crates.io/crates/downcast-rs/downcast-rs-1.2.1.crate"
+    version: "1.2.1"
   }
 }
diff --git a/crates/downcast-rs/README.md b/crates/downcast-rs/README.md
index 2c462f7..1650955 100644
--- a/crates/downcast-rs/README.md
+++ b/crates/downcast-rs/README.md
@@ -1,6 +1,6 @@
 # downcast-rs
 
-[![Build status](https://img.shields.io/github/workflow/status/marcianx/downcast-rs/CI/master)](https://github.com/marcianx/downcast-rs/actions)
+[![Build status](https://img.shields.io/github/actions/workflow/status/marcianx/downcast-rs/main.yml?branch=master)](https://github.com/marcianx/downcast-rs/actions)
 [![Latest version](https://img.shields.io/crates/v/downcast-rs.svg)](https://crates.io/crates/downcast-rs)
 [![Documentation](https://docs.rs/downcast-rs/badge.svg)](https://docs.rs/downcast-rs)
 
@@ -19,7 +19,7 @@
 
 ```toml
 [dependencies]
-downcast-rs = "1.2.0"
+downcast-rs = "1.2.1"
 ```
 
 This crate is `no_std` compatible. To use it without `std`:
@@ -33,8 +33,7 @@
 `downcast::DowncastSync` and invoke `impl_downcast!` on it as in the examples
 below.
 
-Since 1.1.0, the minimum supported Rust version is 1.33 to support `Rc` and `Arc`
-in the receiver position.
+Since 1.2.0, the minimum supported Rust version is 1.36 due to needing stable access to alloc.
 
 ```rust
 trait Trait: Downcast {}
@@ -152,6 +151,11 @@
 }
 ```
 
+## Why no changes in a while?
+
+This library is a thoroughly-tested boilerplate generator, is code complete, has
+no unsafe, and is vanishingly unlikely to have any security issues to patch.
+
 ## License
 
 Copyright 2020, Ashish Myles (maintainer) and contributors.
diff --git a/crates/downcast-rs/README.tpl b/crates/downcast-rs/README.tpl
index 9ec95d6..b414e32 100644
--- a/crates/downcast-rs/README.tpl
+++ b/crates/downcast-rs/README.tpl
@@ -1,5 +1,10 @@
 {{readme}}
 
+## Why no changes in a while?
+
+This library is a thoroughly-tested boilerplate generator, is code complete, has
+no unsafe, and is vanishingly unlikely to have any security issues to patch.
+
 ## License
 
 Copyright 2020, Ashish Myles (maintainer) and contributors.
diff --git a/crates/downcast-rs/src/lib.rs b/crates/downcast-rs/src/lib.rs
index b211219..0659e18 100644
--- a/crates/downcast-rs/src/lib.rs
+++ b/crates/downcast-rs/src/lib.rs
@@ -1,6 +1,6 @@
-#![deny(unsafe_code)]
+#![deny(unsafe_code,rustdoc::bare_urls)]
 #![cfg_attr(not(feature = "std"), no_std)]
-//! [![Build status](https://img.shields.io/github/workflow/status/marcianx/downcast-rs/CI/master)](https://github.com/marcianx/downcast-rs/actions)
+//! [![Build status](https://img.shields.io/github/actions/workflow/status/marcianx/downcast-rs/main.yml?branch=master)](https://github.com/marcianx/downcast-rs/actions)
 //! [![Latest version](https://img.shields.io/crates/v/downcast-rs.svg)](https://crates.io/crates/downcast-rs)
 //! [![Documentation](https://docs.rs/downcast-rs/badge.svg)](https://docs.rs/downcast-rs)
 //!
@@ -19,7 +19,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! downcast-rs = "1.2.0"
+//! downcast-rs = "1.2.1"
 //! ```
 //!
 //! This crate is `no_std` compatible. To use it without `std`:
@@ -33,8 +33,7 @@
 //! `downcast::DowncastSync` and invoke `impl_downcast!` on it as in the examples
 //! below.
 //!
-//! Since 1.1.0, the minimum supported Rust version is 1.33 to support `Rc` and `Arc`
-//! in the receiver position.
+//! Since 1.2.0, the minimum supported Rust version is 1.36 due to needing stable access to alloc.
 //!
 //! ```
 //! # #[macro_use]
@@ -208,7 +207,7 @@
 /// Adds downcasting support to traits that extend `downcast::Downcast` by defining forwarding
 /// methods to the corresponding implementations on `std::any::Any` in the standard library.
 ///
-/// See https://users.rust-lang.org/t/how-to-create-a-macro-to-impl-a-provided-type-parametrized-trait/5289
+/// See <https://users.rust-lang.org/t/how-to-create-a-macro-to-impl-a-provided-type-parametrized-trait/5289>
 /// for why this is implemented this way to support templatized traits.
 #[macro_export(local_inner_macros)]
 macro_rules! impl_downcast {
@@ -293,10 +292,9 @@
         /// Returns an `Arc`-ed object from an `Arc`-ed trait object if the underlying object is of
         /// type `__T`. Returns the original `Arc`-ed trait if it isn't.
         #[inline]
-        pub fn downcast_arc<__T: $trait_<$($types)*>>(
+        pub fn downcast_arc<__T: $trait_<$($types)*> + $crate::__std::any::Any + $crate::__std::marker::Send + $crate::__std::marker::Sync>(
             self: $crate::__alloc::sync::Arc<Self>,
         ) -> $crate::__std::result::Result<$crate::__alloc::sync::Arc<__T>, $crate::__alloc::sync::Arc<Self>>
-            where __T: $crate::__std::any::Any + $crate::__std::marker::Send + $crate::__std::marker::Sync
         {
             if self.is::<__T>() {
                 Ok($crate::DowncastSync::into_any_arc(self).downcast::<__T>().unwrap())
diff --git a/crates/enumn/.cargo-checksum.json b/crates/enumn/.cargo-checksum.json
index 35f2c54..7b061e1 100644
--- a/crates/enumn/.cargo-checksum.json
+++ b/crates/enumn/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"e9a8be1ba195ad75a43847e565d823c4c932e1e477f982105a389e7f3d4e8ad4","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"fc3e433365f7d8215be37c627159ee7ef1de5f031d2d9f60dfbc99aa88af7973","src/lib.rs":"0279db9b2571809c0eaf9d086cc98804e6262634d15a1faba2d1a0e02f3ca630","tests/test.rs":"ba6aea6b396190113160c5d0ddc41ad700df2488d728186bb647b41b7b79e33a"},"package":"48016319042fb7c87b78d2993084a831793a897a5cd1a2a67cab9d1eeb4b7d76"}
\ No newline at end of file
+{"files":{"Cargo.toml":"71c9d276d315baada29bc6d59c2cf4eff4bcd1e8ac6b674ddf75f7a3aba621ac","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"fc3e433365f7d8215be37c627159ee7ef1de5f031d2d9f60dfbc99aa88af7973","src/lib.rs":"7244d11bd184511b85c6382c00ff1b73e6a48d144d4822067464c601eaa0aa3a","tests/test.rs":"ba6aea6b396190113160c5d0ddc41ad700df2488d728186bb647b41b7b79e33a"},"package":"c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b"}
\ No newline at end of file
diff --git a/crates/enumn/Android.bp b/crates/enumn/Android.bp
index 69b5cdb..34e3059 100644
--- a/crates/enumn/Android.bp
+++ b/crates/enumn/Android.bp
@@ -17,9 +17,9 @@
     name: "libenumn",
     crate_name: "enumn",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.1.8",
+    cargo_pkg_version: "0.1.12",
     crate_root: "src/lib.rs",
-    edition: "2018",
+    edition: "2021",
     rustlibs: [
         "libproc_macro2",
         "libquote",
diff --git a/crates/enumn/Cargo.toml b/crates/enumn/Cargo.toml
index 3c054b5..03e3905 100644
--- a/crates/enumn/Cargo.toml
+++ b/crates/enumn/Cargo.toml
@@ -10,10 +10,10 @@
 # See Cargo.toml.orig for the original contents.
 
 [package]
-edition = "2018"
+edition = "2021"
 rust-version = "1.56"
 name = "enumn"
-version = "0.1.8"
+version = "0.1.12"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 description = "Convert number to enum"
 documentation = "https://docs.rs/enumn"
@@ -25,21 +25,23 @@
 categories = [
     "rust-patterns",
     "no-std",
+    "no-std::no-alloc",
 ]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/dtolnay/enumn"
 
 [package.metadata.docs.rs]
+rustdoc-args = ["--generate-link-to-definition"]
 targets = ["x86_64-unknown-linux-gnu"]
 
 [lib]
 proc-macro = true
 
 [dependencies.proc-macro2]
-version = "1.0"
+version = "1.0.63"
 
 [dependencies.quote]
-version = "1.0"
+version = "1.0.29"
 
 [dependencies.syn]
-version = "2.0"
+version = "2.0.23"
diff --git a/crates/enumn/METADATA b/crates/enumn/METADATA
index 8d04f61..42b56fb 100644
--- a/crates/enumn/METADATA
+++ b/crates/enumn/METADATA
@@ -1,17 +1,17 @@
 name: "enumn"
 description: "Convert number to enum"
 third_party {
-  version: "0.1.8"
+  version: "0.1.12"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2023
-    month: 3
-    day: 23
+    year: 2024
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/enumn"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/enumn/enumn-0.1.8.crate"
-    version: "0.1.8"
+    value: "https://static.crates.io/crates/enumn/enumn-0.1.12.crate"
+    version: "0.1.12"
   }
 }
diff --git a/crates/enumn/rules.mk b/crates/enumn/rules.mk
index db7466d..bd38846 100644
--- a/crates/enumn/rules.mk
+++ b/crates/enumn/rules.mk
@@ -8,7 +8,7 @@
 MODULE_CRATE_NAME := enumn
 MODULE_RUST_CRATE_TYPES := proc-macro
 MODULE_SRCS := $(LOCAL_DIR)/src/lib.rs
-MODULE_RUST_EDITION := 2018
+MODULE_RUST_EDITION := 2021
 MODULE_LIBRARY_DEPS := \
 	$(call FIND_CRATE,proc-macro2) \
 	$(call FIND_CRATE,quote) \
diff --git a/crates/enumn/src/lib.rs b/crates/enumn/src/lib.rs
index 42435da..cb88542 100644
--- a/crates/enumn/src/lib.rs
+++ b/crates/enumn/src/lib.rs
@@ -105,7 +105,7 @@
 //!
 //! Here `Letter::n(65)` would return `Some(Letter::A)`.
 
-#![doc(html_root_url = "https://docs.rs/enumn/0.1.8")]
+#![doc(html_root_url = "https://docs.rs/enumn/0.1.12")]
 #![allow(
     clippy::missing_panics_doc,
     clippy::needless_doctest_main,
@@ -191,6 +191,7 @@
     TokenStream::from(quote! {
         impl #ident {
             pub #signature -> Option<Self> {
+                #[allow(non_camel_case_types)]
                 struct discriminant;
                 #[allow(non_upper_case_globals)]
                 impl discriminant {
diff --git a/crates/strsim/.cargo-checksum.json b/crates/strsim/.cargo-checksum.json
index dc4b8e7..91be29e 100644
--- a/crates/strsim/.cargo-checksum.json
+++ b/crates/strsim/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"37aed92999cbdf75969bd1d8e8c85bfda5ddf95a4eef2a6fb1c1371cf8304c3e","Cargo.toml":"8c41e90e312a6e7e1be6e3c10873ea7eb740a577f3d6d54f66798995b4555ce1","LICENSE":"1e697ce8d21401fbf1bddd9b5c3fd4c4c79ae1e3bdf51f81761c85e11d5a89cd","README.md":"599d424147dfbf88943bb6d78cebca346488fd246611917b586d73502a684c3a","benches/benches.rs":"2f7fae162a517378b42af04b4b077ffd563171f7341cba55b4efca3b4c30426a","src/lib.rs":"2e340450050784ea8e6e19ea36cbedcf9084ecb7829fc206cacdca4f6f069784","tests/lib.rs":"4c8207a5728b82836795e2f87d7d7834db7276082f5ded640f34822feb750cb4"},"package":"5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"fa5e48fab6b5642005fb5fa9f113b116d9da561a829cd773739350042e87e225","Cargo.toml":"e74cc8f9ab1f8680c26aebab519e3fbda7521eebd1e8fdcebdfc2e1bf138a875","LICENSE":"1e697ce8d21401fbf1bddd9b5c3fd4c4c79ae1e3bdf51f81761c85e11d5a89cd","README.md":"599d424147dfbf88943bb6d78cebca346488fd246611917b586d73502a684c3a","SECURITY.md":"db1925a1d93a212ff6b55e9fbbceebb7a8f3a64688d76598475a54f1f242f0bf","benches/benches.rs":"2f7fae162a517378b42af04b4b077ffd563171f7341cba55b4efca3b4c30426a","src/lib.rs":"6f0b31f95526ccc0a88ed788b6be9b929bd8ee32fd0c3f38b0399cb7e63954e3","tests/lib.rs":"4c8207a5728b82836795e2f87d7d7834db7276082f5ded640f34822feb750cb4"},"package":"7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"}
\ No newline at end of file
diff --git a/crates/strsim/Android.bp b/crates/strsim/Android.bp
index 63ba4e6..7fac5f7 100644
--- a/crates/strsim/Android.bp
+++ b/crates/strsim/Android.bp
@@ -18,7 +18,7 @@
     host_supported: true,
     crate_name: "strsim",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.11.0",
+    cargo_pkg_version: "0.11.1",
     crate_root: "src/lib.rs",
     edition: "2015",
     apex_available: [
@@ -34,7 +34,7 @@
     host_supported: true,
     crate_name: "strsim",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.11.0",
+    cargo_pkg_version: "0.11.1",
     crate_root: "src/lib.rs",
     test_suites: ["general-tests"],
     auto_gen_config: true,
@@ -49,7 +49,7 @@
     host_supported: true,
     crate_name: "lib",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.11.0",
+    cargo_pkg_version: "0.11.1",
     crate_root: "tests/lib.rs",
     test_suites: ["general-tests"],
     auto_gen_config: true,
diff --git a/crates/strsim/CHANGELOG.md b/crates/strsim/CHANGELOG.md
index 9c188a6..7bab900 100644
--- a/crates/strsim/CHANGELOG.md
+++ b/crates/strsim/CHANGELOG.md
@@ -4,6 +4,12 @@
 
 ## [Unreleased]
 
+## [0.11.1] - (2024-04-03)
+
+### Fixed
+
+- Drop MSRV down to 1.56 which was mistakenly changed in 0.11.0
+
 ## [0.11.0] - (2024-01-07)
 
 ### Changed
@@ -197,7 +203,8 @@
 
 - Implement Hamming, Jaro, Jaro-Winkler, and Levenshtein
 
-[Unreleased]: https://github.com/rapidfuzz/strsim-rs/compare/0.11.0...HEAD
+[Unreleased]: https://github.com/rapidfuzz/strsim-rs/compare/0.11.1...HEAD
+[0.11.1]: https://github.com/rapidfuzz/strsim-rs/compare/0.11.0...0.11.1
 [0.11.0]: https://github.com/rapidfuzz/strsim-rs/compare/0.10.0...0.11.0
 [0.10.0]: https://github.com/rapidfuzz/strsim-rs/compare/0.9.3...0.10.0
 [0.9.3]: https://github.com/rapidfuzz/strsim-rs/compare/0.9.2...0.9.3
diff --git a/crates/strsim/Cargo.toml b/crates/strsim/Cargo.toml
index ba871a0..88d3016 100644
--- a/crates/strsim/Cargo.toml
+++ b/crates/strsim/Cargo.toml
@@ -10,8 +10,9 @@
 # See Cargo.toml.orig for the original contents.
 
 [package]
+rust-version = "1.56"
 name = "strsim"
-version = "0.11.0"
+version = "0.11.1"
 authors = [
     "Danny Guo <danny@dannyguo.com>",
     "maxbachmann <oss@maxbachmann.de>",
diff --git a/crates/strsim/METADATA b/crates/strsim/METADATA
index 21501d6..116eec9 100644
--- a/crates/strsim/METADATA
+++ b/crates/strsim/METADATA
@@ -1,17 +1,17 @@
 name: "strsim"
 description: "()"
 third_party {
-  version: "0.11.0"
+  version: "0.11.1"
   license_type: NOTICE
   last_upgrade_date {
     year: 2024
-    month: 2
-    day: 22
+    month: 10
+    day: 2
   }
   homepage: "https://crates.io/crates/strsim"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/strsim/strsim-0.11.0.crate"
-    version: "0.11.0"
+    value: "https://static.crates.io/crates/strsim/strsim-0.11.1.crate"
+    version: "0.11.1"
   }
 }
diff --git a/crates/strsim/SECURITY.md b/crates/strsim/SECURITY.md
new file mode 100644
index 0000000..5ad4a63
--- /dev/null
+++ b/crates/strsim/SECURITY.md
@@ -0,0 +1,19 @@
+## Reporting Security Issues
+
+If you believe you have found a security vulnerability in the project, please report it to us through coordinated disclosure.
+
+**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
+
+Instead, please send an email to oss@maxbachmann.de.
+
+Please include as much of the information listed below as you can to help us better understand and resolve the issue:
+
+  * The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
+  * Full paths of source file(s) related to the manifestation of the issue
+  * The location of the affected source code (tag/branch/commit or direct URL)
+  * Any special configuration required to reproduce the issue
+  * Step-by-step instructions to reproduce the issue
+  * Proof-of-concept or exploit code (if possible)
+  * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
diff --git a/crates/strsim/src/lib.rs b/crates/strsim/src/lib.rs
index 8118277..6a3b098 100644
--- a/crates/strsim/src/lib.rs
+++ b/crates/strsim/src/lib.rs
@@ -40,7 +40,7 @@
             StrSimError::DifferentLengthArgs => "Differing length arguments provided",
         };
 
-        write!(fmt, "{text}")
+        write!(fmt, "{}", text)
     }
 }
 
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index 3d344ec..bafa60a 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -255,7 +255,7 @@
  "socket2",
  "spin",
  "spki",
- "strsim 0.11.0",
+ "strsim",
  "strum",
  "strum_macros",
  "syn-mid",
@@ -440,9 +440,9 @@
 
 [[package]]
 name = "async-trait"
-version = "0.1.74"
+version = "0.1.76"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
+checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -704,9 +704,9 @@
 
 [[package]]
 name = "camino"
-version = "1.1.6"
+version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
+checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
 
 [[package]]
 name = "cast"
@@ -878,9 +878,9 @@
 
 [[package]]
 name = "combine"
-version = "4.6.6"
+version = "4.6.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
 dependencies = [
  "bytes",
  "memchr",
@@ -980,9 +980,9 @@
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.11"
+version = "0.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
+checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
 dependencies = [
  "crossbeam-utils",
 ]
@@ -1039,9 +1039,9 @@
 
 [[package]]
 name = "darling"
-version = "0.20.8"
+version = "0.20.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391"
+checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -1049,23 +1049,23 @@
 
 [[package]]
 name = "darling_core"
-version = "0.20.8"
+version = "0.20.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"
+checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
 dependencies = [
  "fnv",
  "ident_case",
  "proc-macro2",
  "quote",
- "strsim 0.10.0",
+ "strsim",
  "syn 2.0.43",
 ]
 
 [[package]]
 name = "darling_macro"
-version = "0.20.8"
+version = "0.20.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
+checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
 dependencies = [
  "darling_core",
  "quote",
@@ -1106,9 +1106,9 @@
 
 [[package]]
 name = "der_derive"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049"
+checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1145,9 +1145,9 @@
 
 [[package]]
 name = "displaydoc"
-version = "0.2.4"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1165,9 +1165,9 @@
 
 [[package]]
 name = "document-features"
-version = "0.2.8"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95"
+checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0"
 dependencies = [
  "litrs 0.4.1",
 ]
@@ -1180,9 +1180,9 @@
 
 [[package]]
 name = "downcast-rs"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
+checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
 
 [[package]]
 name = "drm"
@@ -1231,9 +1231,9 @@
 
 [[package]]
 name = "enumn"
-version = "0.1.8"
+version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48016319042fb7c87b78d2993084a831793a897a5cd1a2a67cab9d1eeb4b7d76"
+checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3244,15 +3244,9 @@
 
 [[package]]
 name = "strsim"
-version = "0.10.0"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
-[[package]]
-name = "strsim"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "strum"
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index e67811e..b5aaf42 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -20,7 +20,7 @@
 async-stream = "=0.3.5"
 async-stream-impl = "=0.3.5"
 async-task = "=4.5.0"
-async-trait = "=0.1.74"
+async-trait = "=0.1.76"
 atomic = "=0.6.0"
 atty = "=0.2.14"
 axum = "=0.6.20"
@@ -33,7 +33,7 @@
 bytemuck_derive = "=1.5.0"
 byteorder = "=1.4.3"
 bytes = "=1.5.0"
-camino = "=1.1.6"
+camino = "=1.1.9"
 cast = "=0.3.0"
 cesu8 = "=1.1.0"
 cexpr = "=0.6.0"
@@ -44,31 +44,31 @@
 clap_complete = "=4.4.9"
 clap_derive = "=4.2.0"
 clap_lex = "=0.3.2"
-combine = "=4.6.6"
+combine = "=4.6.7"
 command-fds = "=0.3.0"
 const-oid = "=0.9.6"
 coset = "=0.3.7"
 crc32fast = "=1.3.2"
 criterion = "=0.4.0"
 criterion-plot = "=0.5.0"
-crossbeam-channel = "=0.5.11"
+crossbeam-channel = "=0.5.13"
 crossbeam-deque = "=0.8.5"
 crossbeam-epoch = "=0.9.18"
 crossbeam-queue = "=0.3.11"
 crossbeam-utils = "=0.8.19"
-darling_core = "=0.20.8"
-darling_macro = "=0.20.8"
+darling_core = "=0.20.10"
+darling_macro = "=0.20.10"
 dashmap = "=5.5.3"
 data-encoding = "=2.5.0"
 der = "=0.7.8"
-der_derive = "=0.7.2"
+der_derive = "=0.7.3"
 derive_arbitrary = "=1.3.2"
-displaydoc = "=0.2.4"
-document-features = "=0.2.8"
-downcast-rs = "=1.2.0"
+displaydoc = "=0.2.5"
+document-features = "=0.2.10"
+downcast-rs = "=1.2.1"
 drm = "=0.11.1"
 either = "=1.9.0"
-enumn = "=0.1.8"
+enumn = "=0.1.12"
 env_logger = "=0.10.0"
 epoll = "=4.3.3"
 errno = "=0.3.8"
@@ -190,7 +190,7 @@
 socket2 = "=0.5.5"
 spin = "=0.9.8"
 spki = "=0.7.3"
-strsim = "=0.11.0"
+strsim = "=0.11.1"
 strum = "=0.25.0"
 strum_macros = "=0.25.3"
 syn-mid = "=0.6.0"