use std::cmp::Ordering; use std::fmt::{self, Display}; use std::hash::{Hash, Hasher}; use proc_macro2::{Ident, Span}; #[cfg(feature = "parsing")] use crate::lookahead; /// A Rust lifetime: `'a`. /// /// Lifetime names must conform to the following rules: /// /// - Must start with an apostrophe. /// - Must not consist of just an apostrophe: `'`. /// - Character after the apostrophe must be `_` or a Unicode code point with /// the XID_Start property. /// - All following characters must be Unicode code points with the XID_Continue /// property. /// /// *This type is available if Syn is built with the `"derive"` or `"full"` /// feature.* #[cfg_attr(feature = "extra-traits", derive(Debug))] #[derive(Clone)] pub struct Lifetime { pub apostrophe: Span, pub ident: Ident, } impl Lifetime { /// # Panics /// /// Panics if the lifetime does not conform to the bulleted rules above. /// /// # Invocation /// /// ``` /// # use proc_macro2::Span; /// # use syn::Lifetime; /// # /// # fn f() -> Lifetime { /// Lifetime::new("'a", Span::call_site()) /// # } /// ``` pub fn new(symbol: &str, span: Span) -> Self { if !symbol.starts_with('\'') { panic!( "lifetime name must start with apostrophe as in \"'a\", got {:?}", symbol ); } if symbol == "'" { panic!("lifetime name must not be empty"); } if !crate::ident::xid_ok(&symbol[1..]) { panic!("{:?} is not a valid lifetime name", symbol); } Lifetime { apostrophe: span, ident: Ident::new(&symbol[1..], span), } } } impl Display for Lifetime { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { "'".fmt(formatter)?; self.ident.fmt(formatter) } } impl PartialEq for Lifetime { fn eq(&self, other: &Lifetime) -> bool { self.ident.eq(&other.ident) } } impl Eq for Lifetime {} impl PartialOrd for Lifetime { fn partial_cmp(&self, other: &Lifetime) -> Option { Some(self.cmp(other)) } } impl Ord for Lifetime { fn cmp(&self, other: &Lifetime) -> Ordering { self.ident.cmp(&other.ident) } } impl Hash for Lifetime { fn hash(&self, h: &mut H) { self.ident.hash(h) } } #[cfg(feature = "parsing")] #[doc(hidden)] #[allow(non_snake_case)] pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime { match marker {} } #[cfg(feature = "parsing")] pub mod parsing { use super::*; use crate::parse::{Parse, ParseStream, Result}; impl Parse for Lifetime { fn parse(input: ParseStream) -> Result { input.step(|cursor| { cursor .lifetime() .ok_or_else(|| cursor.error("expected lifetime")) }) } } } #[cfg(feature = "printing")] mod printing { use super::*; use proc_macro2::{Punct, Spacing, TokenStream}; use quote::{ToTokens, TokenStreamExt}; impl ToTokens for Lifetime { fn to_tokens(&self, tokens: &mut TokenStream) { let mut apostrophe = Punct::new('\'', Spacing::Joint); apostrophe.set_span(self.apostrophe); tokens.append(apostrophe); self.ident.to_tokens(tokens); } } }