// SPDX-License-Identifier: Apache-2.0 OR MIT #[cfg(feature = "parsing")]use crate::lookahead;use proc_macro2::{Ident, Span};use std::cmp::Ordering;use std::fmt::{self, Display};use std::hash::{Hash, Hasher}; /// 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.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), } } pub fn span(&self) -> Span { self.apostrophe .join(self.ident.span()) .unwrap_or(self.apostrophe) } pub fn set_span(&mut self, span: Span) { self.apostrophe = span; self.ident.set_span(span); }} impl Display for Lifetime { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { "'".fmt(formatter)?; self.ident.fmt(formatter) }} impl Clone for Lifetime { fn clone(&self) -> Self { Lifetime { apostrophe: self.apostrophe, ident: self.ident.clone(), } }} 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<Ordering> { 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<H: Hasher>(&self, h: &mut H) { self.ident.hash(h); }} #[cfg(feature = "parsing")]pub_if_not_doc! { #[doc(hidden)] #[allow(non_snake_case)] pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime { match marker {} }} #[cfg(feature = "parsing")]pub(crate) mod parsing { use crate::error::Result; use crate::lifetime::Lifetime; use crate::parse::{Parse, ParseStream}; #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for Lifetime { fn parse(input: ParseStream) -> Result<Self> { input.step(|cursor| { cursor .lifetime() .ok_or_else(|| cursor.error("expected lifetime")) }) } }} #[cfg(feature = "printing")]mod printing { use crate::lifetime::Lifetime; use proc_macro2::{Punct, Spacing, TokenStream}; use quote::{ToTokens, TokenStreamExt}; #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 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); } }}
// SPDX-License-Identifier: Apache-2.0 OR MIT
#[cfg(feature = "parsing")]
use crate::lookahead;
use proc_macro2::{Ident, Span};
use std::cmp::Ordering;
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};
/// 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.
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),
}
}
pub fn span(&self) -> Span {
self.apostrophe
.join(self.ident.span())
.unwrap_or(self.apostrophe)
}
pub fn set_span(&mut self, span: Span) {
self.apostrophe = span;
self.ident.set_span(span);
}
}
impl Display for Lifetime {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
"'".fmt(formatter)?;
self.ident.fmt(formatter)
}
}
impl Clone for Lifetime {
fn clone(&self) -> Self {
Lifetime {
apostrophe: self.apostrophe,
ident: self.ident.clone(),
}
}
}
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<Ordering> {
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<H: Hasher>(&self, h: &mut H) {
self.ident.hash(h);
}
}
#[cfg(feature = "parsing")]
pub_if_not_doc! {
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
match marker {}
}
}
#[cfg(feature = "parsing")]
pub(crate) mod parsing {
use crate::error::Result;
use crate::lifetime::Lifetime;
use crate::parse::{Parse, ParseStream};
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
impl Parse for Lifetime {
fn parse(input: ParseStream) -> Result<Self> {
input.step(|cursor| {
cursor
.lifetime()
.ok_or_else(|| cursor.error("expected lifetime"))
})
}
}
}
#[cfg(feature = "printing")]
mod printing {
use crate::lifetime::Lifetime;
use proc_macro2::{Punct, Spacing, TokenStream};
use quote::{ToTokens, TokenStreamExt};
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
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);
}
}
}