| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- // 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);
- }
- }
- }
|