diff --git a/Cargo.lock b/Cargo.lock index 7535e65..0bffee7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,6 +134,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "trait-transformer" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "tokio", +] + [[package]] name = "trait-variant" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index 61df904..dc525bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "trait-variant", + "trait-transformer", ] resolver = "2" diff --git a/README.md b/README.md index f95a4eb..a56c042 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ Utilities for working with impl traits in Rust. -## `make_variant` +## `trait_variant` -`make_variant` generates a specialized version of a base trait that uses `async fn` and/or `-> impl Trait`. For example, if you want a `Send`able version of your trait, you'd write: +`trait_variant` generates a specialized version of a base trait that uses `async fn` and/or `-> impl Trait`. For example, if you want a `Send`able version of your trait, you'd write: ```rust -#[trait_variant::make_variant(SendIntFactory: Send)] +#[trait_variant::make(SendIntFactory: Send)] trait IntFactory { async fn make(&self) -> i32; // ..or.. @@ -20,10 +20,6 @@ Which creates a new `SendIntFactory: IntFactory + Send` trait and additionally b Implementers of the trait can choose to implement the variant instead of the original trait. The macro creates a blanket impl which ensures that any type which implements the variant also implements the original trait. -## `trait_transformer` - -`trait_transformer` does the same thing as `make_variant`, but using experimental nightly-only syntax that depends on the `return_type_notation` feature. It may be used to experiment with new kinds of trait transformations in the future. - #### License and usage notes Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or diff --git a/trait-transformer/Cargo.toml b/trait-transformer/Cargo.toml new file mode 100644 index 0000000..c2e77f8 --- /dev/null +++ b/trait-transformer/Cargo.toml @@ -0,0 +1,30 @@ +# Copyright (c) 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +[package] +name = "trait-transformer" +version = "0.0.0" +description = "Utilities for working with impl traits in Rust" +categories = ["asynchronous", "no-std", "rust-patterns"] +keywords = ["async", "trait", "impl"] +license.workspace = true +repository.workspace = true +edition = "2021" + +[lib] +proc-macro = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +proc-macro2 = "1.0" +quote = "1.0" +syn = { version = "2.0", features = ["full"] } + +[dev-dependencies] +tokio = { version = "1", features = ["rt"] } diff --git a/trait-transformer/README.md b/trait-transformer/README.md new file mode 100644 index 0000000..3e3b755 --- /dev/null +++ b/trait-transformer/README.md @@ -0,0 +1,3 @@ +## `trait_transformer` + +`trait_transformer` does the same thing as `trait_variant`, but using experimental nightly-only syntax that depends on the `return_type_notation` feature. It may be used to experiment with new kinds of trait transformations in the future. diff --git a/trait-variant/examples/trait_transformer.rs b/trait-transformer/examples/trait_transformer.rs similarity index 96% rename from trait-variant/examples/trait_transformer.rs rename to trait-transformer/examples/trait_transformer.rs index 619514e..80129a0 100644 --- a/trait-variant/examples/trait_transformer.rs +++ b/trait-transformer/examples/trait_transformer.rs @@ -11,7 +11,7 @@ use std::iter; -use trait_variant::trait_transformer; +use trait_transformer::trait_transformer; #[trait_transformer(SendIntFactory: Send)] trait IntFactory { diff --git a/trait-transformer/src/lib.rs b/trait-transformer/src/lib.rs new file mode 100644 index 0000000..89d6b65 --- /dev/null +++ b/trait-transformer/src/lib.rs @@ -0,0 +1,17 @@ +// Copyright (c) 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod transformer; + +#[proc_macro_attribute] +pub fn trait_transformer( + attr: proc_macro::TokenStream, + item: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + transformer::trait_transformer(attr, item) +} diff --git a/trait-variant/src/transformer.rs b/trait-transformer/src/transformer.rs similarity index 100% rename from trait-variant/src/transformer.rs rename to trait-transformer/src/transformer.rs diff --git a/trait-variant/examples/variant.rs b/trait-variant/examples/variant.rs index 93c2ebe..9c15409 100644 --- a/trait-variant/examples/variant.rs +++ b/trait-variant/examples/variant.rs @@ -8,10 +8,8 @@ use std::future::Future; -use trait_variant::make_variant; - -#[make_variant(SendIntFactory: Send)] -trait IntFactory { +#[trait_variant::make(IntFactory: Send)] +pub trait LocalIntFactory { const NAME: &'static str; type MyFut<'a>: Future @@ -24,4 +22,11 @@ trait IntFactory { fn another_async(&self, input: Result<(), &str>) -> Self::MyFut<'_>; } +#[allow(dead_code)] +fn spawn_task(factory: impl IntFactory + 'static) { + tokio::spawn(async move { + let _int = factory.make(1, "foo").await; + }); +} + fn main() {} diff --git a/trait-variant/src/lib.rs b/trait-variant/src/lib.rs index 2694318..7c03519 100644 --- a/trait-variant/src/lib.rs +++ b/trait-variant/src/lib.rs @@ -8,21 +8,12 @@ #![doc = include_str!("../README.md")] -mod transformer; mod variant; #[proc_macro_attribute] -pub fn trait_transformer( +pub fn make( attr: proc_macro::TokenStream, item: proc_macro::TokenStream, ) -> proc_macro::TokenStream { - transformer::trait_transformer(attr, item) -} - -#[proc_macro_attribute] -pub fn make_variant( - attr: proc_macro::TokenStream, - item: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - variant::make_variant(attr, item) + variant::make(attr, item) } diff --git a/trait-variant/src/variant.rs b/trait-variant/src/variant.rs index 1a5bd1f..74efcc1 100644 --- a/trait-variant/src/variant.rs +++ b/trait-variant/src/variant.rs @@ -49,22 +49,36 @@ impl Parse for MakeVariant { } } -pub fn make_variant( +pub fn make( attr: proc_macro::TokenStream, item: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let attrs = parse_macro_input!(attr as Attrs); let item = parse_macro_input!(item as ItemTrait); + let maybe_allow_async_lint = if attrs + .variant + .bounds + .iter() + .any(|b| b.path.segments.last().unwrap().ident.to_string() == "Send") + { + quote! { #[allow(async_fn_in_trait)] } + } else { + quote! {} + }; + let variant = mk_variant(&attrs, &item); let blanket_impl = mk_blanket_impl(&attrs, &item); - let output = quote! { + + quote! { + #maybe_allow_async_lint #item + #variant - #blanket_impl - }; - output.into() + #blanket_impl + } + .into() } fn mk_variant(attrs: &Attrs, tr: &ItemTrait) -> TokenStream {