From 1891b388c67cb05027b40d422f6ddc97cd996b26 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 13 Jan 2024 23:10:08 +0900 Subject: [PATCH] Add support for http-body v1 --- CHANGELOG.md | 2 + Cargo.toml | 3 + README.md | 5 +- src/derive/external/http_body1.rs | 48 ++++++++++++++ src/derive/external/mod.rs | 3 + src/enum_derive.rs | 3 + src/lib.rs | 5 ++ tests/compiletest.rs | 1 + .../external/http_body/body.expanded.rs | 62 +++++++++++++++++++ tests/expand/external/http_body/body.rs | 13 ++++ tests/run-pass/http_body1.rs | 13 ++++ 11 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/derive/external/http_body1.rs create mode 100644 tests/expand/external/http_body/body.expanded.rs create mode 100644 tests/expand/external/http_body/body.rs create mode 100644 tests/run-pass/http_body1.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b816067..d5fde1fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com ## [Unreleased] +- Add support for `http_body1::Body`. + ## [0.8.3] - 2023-10-21 - Update to [new coroutine API since nightly-2023-10-21](https://github.com/rust-lang/rust/pull/116958). This renames unstable `generator_trait` feature to `coroutine_trait`. The old cargo feature name is kept as a deprecated alias and will be removed in the next breaking release. ([daf9165](https://github.com/taiki-e/auto_enums/commit/daf91653b925d53cde57b598f0d884fe35a53c60)) diff --git a/Cargo.toml b/Cargo.toml index a1915771..b454aaf3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,8 @@ tokio03 = [] tokio02 = [] # https://docs.rs/tokio/0.1 tokio01 = [] +# https://docs.rs/http-body/1 +http_body1 = [] # ============================================================================== # Unstable features @@ -98,6 +100,7 @@ tokio02_crate = { package = "tokio", version = "0.2", default-features = false } tokio01_crate = { package = "tokio", version = "0.1", default-features = false, features = ["io"] } rayon_crate = { package = "rayon", version = "1" } serde_crate = { package = "serde", version = "1" } +http_body1_crate = { package = "http-body", version = "1", default-features = false } [lints] workspace = true diff --git a/README.md b/README.md index dd9838fb..ffd8e452 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ traits to `#[derive]`. `#[enum_derive]` supports many of the standard library traits and some popular third-party libraries traits such as [rayon], [futures][futures03], -[tokio][tokio1]. **See [documentation](https://docs.rs/auto_enums/latest/auto_enums/#supported-traits) for a complete list of supported traits.** +[tokio][tokio1], [http_body][http_body1]. **See [documentation](https://docs.rs/auto_enums/latest/auto_enums/#supported-traits) for a complete list of supported traits.** If you want to use traits that are not supported by `#[enum_derive]`, you can use another crate that provides [derives macros][proc-macro-derive], or @@ -165,6 +165,8 @@ enum Foo { - **`trusted_len`** - Enable to use `[std|core]::iter::TrustedLen` trait. - Note that this feature is unstable and may cause incompatible changes between patch versions. +- **`http_body1`** + - Enable to use [http_body v1][http_body1] traits. ### `type_analysis` feature @@ -218,6 +220,7 @@ Please be careful if you return another traits with the same name. [tokio02]: https://docs.rs/tokio/0.2 [tokio03]: https://docs.rs/tokio/0.3 [tokio1]: https://docs.rs/tokio/1 +[http_body1]: https://docs.rs/http_body/1 ## License diff --git a/src/derive/external/http_body1.rs b/src/derive/external/http_body1.rs new file mode 100644 index 00000000..1f2e89c0 --- /dev/null +++ b/src/derive/external/http_body1.rs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +pub(crate) mod body { + use quote::ToTokens; + + use crate::derive::*; + + pub(crate) const NAME: &[&str] = &["http_body1::Body"]; + + pub(crate) fn derive(cx: &Context, data: &Data) -> Result { + cx.needs_pin_projection(); + + let ident = &data.ident; + let pin = quote!(::core::pin::Pin); + let trait_: syn::Path = parse_quote!(::http_body::Body); + let mut impl_ = EnumImpl::from_trait(data, trait_.clone(), None, parse_quote! { + trait Body { + type Data; + type Error; + #[inline] + fn is_end_stream(&self) -> bool; + #[inline] + fn size_hint(&self) -> ::http_body::SizeHint; + } + }) + .build_impl(); + + let poll_frame = data + .variant_idents() + .map(|v| quote!(#ident::#v(x) => #trait_::poll_frame(#pin::new_unchecked(x), cx))); + impl_.items.push(parse_quote! { + fn poll_frame( + self: #pin<&mut Self>, + cx: &mut ::core::task::Context<'_>, + ) -> ::core::task::Poll< + ::core::option::Option< + ::core::result::Result<::http_body::Frame, Self::Error>, + >, + > { + unsafe { + match self.get_unchecked_mut() { #(#poll_frame,)* } + } + } + }); + + Ok(impl_.into_token_stream()) + } +} diff --git a/src/derive/external/mod.rs b/src/derive/external/mod.rs index 2cb3bdf4..2c2472c9 100644 --- a/src/derive/external/mod.rs +++ b/src/derive/external/mod.rs @@ -24,3 +24,6 @@ pub(crate) mod tokio03; // https://docs.rs/tokio/1 #[cfg(feature = "tokio1")] pub(crate) mod tokio1; +// https://docs.rs/http-body/1 +#[cfg(feature = "http_body1")] +pub(crate) mod http_body1; diff --git a/src/enum_derive.rs b/src/enum_derive.rs index 258ace95..ff400a47 100644 --- a/src/enum_derive.rs +++ b/src/enum_derive.rs @@ -164,6 +164,9 @@ fn get_derive(s: &str) -> Option { external::tokio01::async_read, #[cfg(feature = "tokio01")] external::tokio01::async_write, + // http_body1 + #[cfg(feature = "http_body1")] + external::http_body1::body, } None diff --git a/src/lib.rs b/src/lib.rs index b61b6a6a..22d58cf6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -735,6 +735,10 @@ fn func(x: i32) -> impl ParallelIterator { - [`tokio01::AsyncRead`](https://docs.rs/tokio/0.1/tokio/io/trait.AsyncRead.html) - [`tokio01::AsyncWrite`](https://docs.rs/tokio/0.1/tokio/io/trait.AsyncWrite.html) +### [http_body v1][http_body1] *(requires `"http_body1"` crate feature)* + +- [`http_body1::Body`](https://docs.rs/http-body/1/http_body/trait.Body.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/http_body/body.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/http_body/body.expanded.rs) + ## Inherent methods These don't derive traits, but derive inherent methods instead. @@ -859,6 +863,7 @@ Please be careful if you return another traits with the same name. [tokio02]: https://docs.rs/tokio/0.2 [tokio03]: https://docs.rs/tokio/0.3 [tokio1]: https://docs.rs/tokio/1 +[http_body1]: https://docs.rs/http-body/1 */ #![doc(test( diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 1cc06bc9..09a4171a 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -14,6 +14,7 @@ feature = "tokio02", feature = "tokio03", feature = "tokio1", + feature = "http_body1", ))] #[rustversion::attr(not(nightly), ignore)] diff --git a/tests/expand/external/http_body/body.expanded.rs b/tests/expand/external/http_body/body.expanded.rs new file mode 100644 index 00000000..21e70895 --- /dev/null +++ b/tests/expand/external/http_body/body.expanded.rs @@ -0,0 +1,62 @@ +extern crate http_body1_crate as http_body; +use auto_enums::enum_derive; +enum Enum { + A(A), + B(B), +} +impl ::http_body::Body for Enum +where + A: ::http_body::Body, + B: ::http_body::Body< + Data = ::Data, + Error = ::Error, + >, +{ + type Data = ::Data; + type Error = ::Error; + #[inline] + fn is_end_stream(&self) -> bool { + match self { + Enum::A(x) => ::http_body::Body::is_end_stream(x), + Enum::B(x) => ::http_body::Body::is_end_stream(x), + } + } + #[inline] + fn size_hint(&self) -> ::http_body::SizeHint { + match self { + Enum::A(x) => ::http_body::Body::size_hint(x), + Enum::B(x) => ::http_body::Body::size_hint(x), + } + } + fn poll_frame( + self: ::core::pin::Pin<&mut Self>, + cx: &mut ::core::task::Context<'_>, + ) -> ::core::task::Poll< + ::core::option::Option< + ::core::result::Result<::http_body::Frame, Self::Error>, + >, + > { + unsafe { + match self.get_unchecked_mut() { + Enum::A(x) => { + ::http_body::Body::poll_frame(::core::pin::Pin::new_unchecked(x), cx) + } + Enum::B(x) => { + ::http_body::Body::poll_frame(::core::pin::Pin::new_unchecked(x), cx) + } + } + } + } +} +impl ::core::marker::Unpin for Enum +where + A: ::core::marker::Unpin, + B: ::core::marker::Unpin, +{} +const _: () = { + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Enum {} +}; +fn main() {} diff --git a/tests/expand/external/http_body/body.rs b/tests/expand/external/http_body/body.rs new file mode 100644 index 00000000..42268aa0 --- /dev/null +++ b/tests/expand/external/http_body/body.rs @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +extern crate http_body1_crate as http_body; + +use auto_enums::enum_derive; + +#[enum_derive(http_body1::Body)] +enum Enum { + A(A), + B(B), +} + +fn main() {} diff --git a/tests/run-pass/http_body1.rs b/tests/run-pass/http_body1.rs new file mode 100644 index 00000000..092ff3fb --- /dev/null +++ b/tests/run-pass/http_body1.rs @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +extern crate http_body1_crate as http_body; + +use auto_enums::enum_derive; + +#[enum_derive(http_body1::Body)] +enum HttpBody1 { + A(A), + B(B), +} + +fn main() {}