xref: /linux/rust/syn/ext.rs (revision 784faa8eca8270671e0ed6d9d21f04bbb80fc5f7)
1 // SPDX-License-Identifier: Apache-2.0 OR MIT
2 
3 //! Extension traits to provide parsing methods on foreign types.
4 
5 use crate::buffer::Cursor;
6 use crate::error::Result;
7 use crate::parse::ParseStream;
8 use crate::parse::Peek;
9 use crate::sealed::lookahead;
10 use crate::token::CustomToken;
11 use proc_macro2::Ident;
12 
13 /// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro.
14 ///
15 /// This trait is sealed and cannot be implemented for types outside of Syn. It
16 /// is implemented only for `proc_macro2::Ident`.
17 pub trait IdentExt: Sized + private::Sealed {
18     /// Parses any identifier including keywords.
19     ///
20     /// This is useful when parsing macro input which allows Rust keywords as
21     /// identifiers.
22     ///
23     /// # Example
24     ///
25     /// ```
26     /// use syn::{Error, Ident, Result, Token};
27     /// use syn::ext::IdentExt;
28     /// use syn::parse::ParseStream;
29     ///
30     /// mod kw {
31     ///     syn::custom_keyword!(name);
32     /// }
33     ///
34     /// // Parses input that looks like `name = NAME` where `NAME` can be
35     /// // any identifier.
36     /// //
37     /// // Examples:
38     /// //
39     /// //     name = anything
40     /// //     name = impl
41     /// fn parse_dsl(input: ParseStream) -> Result<Ident> {
42     ///     input.parse::<kw::name>()?;
43     ///     input.parse::<Token![=]>()?;
44     ///     let name = input.call(Ident::parse_any)?;
45     ///     Ok(name)
46     /// }
47     /// ```
parse_any(input: ParseStream) -> Result<Self>48     fn parse_any(input: ParseStream) -> Result<Self>;
49 
50     /// Peeks any identifier including keywords. Usage:
51     /// `input.peek(Ident::peek_any)`
52     ///
53     /// This is different from `input.peek(Ident)` which only returns true in
54     /// the case of an ident which is not a Rust keyword.
55     #[allow(non_upper_case_globals)]
56     const peek_any: private::PeekFn = private::PeekFn;
57 
58     /// Strips the raw marker `r#`, if any, from the beginning of an ident.
59     ///
60     ///   - unraw(`x`) = `x`
61     ///   - unraw(`move`) = `move`
62     ///   - unraw(`r#move`) = `move`
63     ///
64     /// # Example
65     ///
66     /// In the case of interop with other languages like Python that have a
67     /// different set of keywords than Rust, we might come across macro input
68     /// that involves raw identifiers to refer to ordinary variables in the
69     /// other language with a name that happens to be a Rust keyword.
70     ///
71     /// The function below appends an identifier from the caller's input onto a
72     /// fixed prefix. Without using `unraw()`, this would tend to produce
73     /// invalid identifiers like `__pyo3_get_r#move`.
74     ///
75     /// ```
76     /// use proc_macro2::Span;
77     /// use syn::Ident;
78     /// use syn::ext::IdentExt;
79     ///
80     /// fn ident_for_getter(variable: &Ident) -> Ident {
81     ///     let getter = format!("__pyo3_get_{}", variable.unraw());
82     ///     Ident::new(&getter, Span::call_site())
83     /// }
84     /// ```
unraw(&self) -> Ident85     fn unraw(&self) -> Ident;
86 }
87 
88 impl IdentExt for Ident {
parse_any(input: ParseStream) -> Result<Self>89     fn parse_any(input: ParseStream) -> Result<Self> {
90         input.step(|cursor| match cursor.ident() {
91             Some((ident, rest)) => Ok((ident, rest)),
92             None => Err(cursor.error("expected ident")),
93         })
94     }
95 
unraw(&self) -> Ident96     fn unraw(&self) -> Ident {
97         let string = self.to_string();
98         if let Some(string) = string.strip_prefix("r#") {
99             Ident::new(string, self.span())
100         } else {
101             self.clone()
102         }
103     }
104 }
105 
106 impl Peek for private::PeekFn {
107     type Token = private::IdentAny;
108 }
109 
110 impl CustomToken for private::IdentAny {
peek(cursor: Cursor) -> bool111     fn peek(cursor: Cursor) -> bool {
112         cursor.ident().is_some()
113     }
114 
display() -> &'static str115     fn display() -> &'static str {
116         "identifier"
117     }
118 }
119 
120 impl lookahead::Sealed for private::PeekFn {}
121 
122 mod private {
123     use proc_macro2::Ident;
124 
125     pub trait Sealed {}
126 
127     impl Sealed for Ident {}
128 
129     pub struct PeekFn;
130     pub struct IdentAny;
131 
132     impl Copy for PeekFn {}
133     impl Clone for PeekFn {
clone(&self) -> Self134         fn clone(&self) -> Self {
135             *self
136         }
137     }
138 }
139