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