[2/3] rust: macros: concat_idents: Allow :: paths in the first argument

Message ID 20230224-rust-macros-v1-2-b39fae46e102@asahilina.net
State New
Headers
Series rust: Miscellaneous macro improvements |

Commit Message

Asahi Lina Feb. 24, 2023, 7:25 a.m. UTC
  This makes things like concat_idents!(bindings::foo, bar) work.
Otherwise, there is no way to concatenate two idents and then use the
result as part of a type path.

Signed-off-by: Asahi Lina <lina@asahilina.net>
---
 rust/macros/concat_idents.rs | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)
  

Comments

Gary Guo Feb. 25, 2023, 12:31 a.m. UTC | #1
On Fri, 24 Feb 2023 16:25:56 +0900
Asahi Lina <lina@asahilina.net> wrote:

> This makes things like concat_idents!(bindings::foo, bar) work.
> Otherwise, there is no way to concatenate two idents and then use the
> result as part of a type path.

It seems weird to me that this is called `concat_idents` despite
working for more things than just idents.

How about just implement a simple version of the `paste` macro instead?

Best,
Gary

> 
> Signed-off-by: Asahi Lina <lina@asahilina.net>
> ---
>  rust/macros/concat_idents.rs | 24 +++++++++++++++++++++---
>  1 file changed, 21 insertions(+), 3 deletions(-)
> 
> diff --git a/rust/macros/concat_idents.rs b/rust/macros/concat_idents.rs
> index 6d955d65016e..d6614b900aa2 100644
> --- a/rust/macros/concat_idents.rs
> +++ b/rust/macros/concat_idents.rs
> @@ -14,10 +14,28 @@ fn expect_ident(it: &mut token_stream::IntoIter) -> Ident {
>  
>  pub(crate) fn concat_idents(ts: TokenStream) -> TokenStream {
>      let mut it = ts.into_iter();
> -    let a = expect_ident(&mut it);
> -    assert_eq!(expect_punct(&mut it).as_char(), ',');
> +    let mut out = TokenStream::new();
> +    let a = loop {
> +        let ident = expect_ident(&mut it);
> +        let punct = expect_punct(&mut it);
> +        match punct.as_char() {
> +            ',' => break ident,
> +            ':' => {
> +                let punct2 = expect_punct(&mut it);
> +                assert_eq!(punct2.as_char(), ':');
> +                out.extend([
> +                    TokenTree::Ident(ident),
> +                    TokenTree::Punct(punct),
> +                    TokenTree::Punct(punct2),
> +                ]);
> +            }
> +            _ => panic!("Expected , or ::"),
> +        }
> +    };
> +
>      let b = expect_ident(&mut it);
>      assert!(it.next().is_none(), "only two idents can be concatenated");
>      let res = Ident::new(&format!("{a}{b}"), b.span());
> -    TokenStream::from_iter([TokenTree::Ident(res)])
> +    out.extend([TokenTree::Ident(res)]);
> +    out
>  }
>
  
Vincenzo Palazzo March 1, 2023, 5:18 p.m. UTC | #2
> This makes things like concat_idents!(bindings::foo, bar) work.
> Otherwise, there is no way to concatenate two idents and then use the
> result as part of a type path.
>
> Signed-off-by: Asahi Lina <lina@asahilina.net>
> ---

Reviewed-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
  
Miguel Ojeda March 7, 2023, 8:22 p.m. UTC | #3
On Sat, Feb 25, 2023 at 1:32 AM Gary Guo <gary@garyguo.net> wrote:
>
> It seems weird to me that this is called `concat_idents` despite
> working for more things than just idents.
>
> How about just implement a simple version of the `paste` macro instead?

Opened https://github.com/Rust-for-Linux/linux/issues/983 in case we
end up applying the patch.

Cheers,
Miguel
  
Miguel Ojeda March 8, 2023, 8:57 p.m. UTC | #4
On Sat, Feb 25, 2023 at 1:32 AM Gary Guo <gary@garyguo.net> wrote:
>
> It seems weird to me that this is called `concat_idents` despite
> working for more things than just idents.
>
> How about just implement a simple version of the `paste` macro instead?

We discussed this in our latest meeting: what about a change of name
to `concat_paths`? That addresses the concern plus it avoids sharing
the name with the unstable `concat_idents` which could be even more
confusing after this patch.

Cheers,
Miguel
  

Patch

diff --git a/rust/macros/concat_idents.rs b/rust/macros/concat_idents.rs
index 6d955d65016e..d6614b900aa2 100644
--- a/rust/macros/concat_idents.rs
+++ b/rust/macros/concat_idents.rs
@@ -14,10 +14,28 @@  fn expect_ident(it: &mut token_stream::IntoIter) -> Ident {
 
 pub(crate) fn concat_idents(ts: TokenStream) -> TokenStream {
     let mut it = ts.into_iter();
-    let a = expect_ident(&mut it);
-    assert_eq!(expect_punct(&mut it).as_char(), ',');
+    let mut out = TokenStream::new();
+    let a = loop {
+        let ident = expect_ident(&mut it);
+        let punct = expect_punct(&mut it);
+        match punct.as_char() {
+            ',' => break ident,
+            ':' => {
+                let punct2 = expect_punct(&mut it);
+                assert_eq!(punct2.as_char(), ':');
+                out.extend([
+                    TokenTree::Ident(ident),
+                    TokenTree::Punct(punct),
+                    TokenTree::Punct(punct2),
+                ]);
+            }
+            _ => panic!("Expected , or ::"),
+        }
+    };
+
     let b = expect_ident(&mut it);
     assert!(it.next().is_none(), "only two idents can be concatenated");
     let res = Ident::new(&format!("{a}{b}"), b.span());
-    TokenStream::from_iter([TokenTree::Ident(res)])
+    out.extend([TokenTree::Ident(res)]);
+    out
 }