lifetime.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // SPDX-License-Identifier: Apache-2.0 OR MIT
  2. #[cfg(feature = "parsing")]
  3. use crate::lookahead;
  4. use proc_macro2::{Ident, Span};
  5. use std::cmp::Ordering;
  6. use std::fmt::{self, Display};
  7. use std::hash::{Hash, Hasher};
  8. /// A Rust lifetime: `'a`.
  9. ///
  10. /// Lifetime names must conform to the following rules:
  11. ///
  12. /// - Must start with an apostrophe.
  13. /// - Must not consist of just an apostrophe: `'`.
  14. /// - Character after the apostrophe must be `_` or a Unicode code point with
  15. /// the XID_Start property.
  16. /// - All following characters must be Unicode code points with the XID_Continue
  17. /// property.
  18. pub struct Lifetime {
  19. pub apostrophe: Span,
  20. pub ident: Ident,
  21. }
  22. impl Lifetime {
  23. /// # Panics
  24. ///
  25. /// Panics if the lifetime does not conform to the bulleted rules above.
  26. ///
  27. /// # Invocation
  28. ///
  29. /// ```
  30. /// # use proc_macro2::Span;
  31. /// # use syn::Lifetime;
  32. /// #
  33. /// # fn f() -> Lifetime {
  34. /// Lifetime::new("'a", Span::call_site())
  35. /// # }
  36. /// ```
  37. pub fn new(symbol: &str, span: Span) -> Self {
  38. if !symbol.starts_with('\'') {
  39. panic!(
  40. "lifetime name must start with apostrophe as in \"'a\", got {:?}",
  41. symbol
  42. );
  43. }
  44. if symbol == "'" {
  45. panic!("lifetime name must not be empty");
  46. }
  47. if !crate::ident::xid_ok(&symbol[1..]) {
  48. panic!("{:?} is not a valid lifetime name", symbol);
  49. }
  50. Lifetime {
  51. apostrophe: span,
  52. ident: Ident::new(&symbol[1..], span),
  53. }
  54. }
  55. pub fn span(&self) -> Span {
  56. self.apostrophe
  57. .join(self.ident.span())
  58. .unwrap_or(self.apostrophe)
  59. }
  60. pub fn set_span(&mut self, span: Span) {
  61. self.apostrophe = span;
  62. self.ident.set_span(span);
  63. }
  64. }
  65. impl Display for Lifetime {
  66. fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
  67. "'".fmt(formatter)?;
  68. self.ident.fmt(formatter)
  69. }
  70. }
  71. impl Clone for Lifetime {
  72. fn clone(&self) -> Self {
  73. Lifetime {
  74. apostrophe: self.apostrophe,
  75. ident: self.ident.clone(),
  76. }
  77. }
  78. }
  79. impl PartialEq for Lifetime {
  80. fn eq(&self, other: &Lifetime) -> bool {
  81. self.ident.eq(&other.ident)
  82. }
  83. }
  84. impl Eq for Lifetime {}
  85. impl PartialOrd for Lifetime {
  86. fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> {
  87. Some(self.cmp(other))
  88. }
  89. }
  90. impl Ord for Lifetime {
  91. fn cmp(&self, other: &Lifetime) -> Ordering {
  92. self.ident.cmp(&other.ident)
  93. }
  94. }
  95. impl Hash for Lifetime {
  96. fn hash<H: Hasher>(&self, h: &mut H) {
  97. self.ident.hash(h);
  98. }
  99. }
  100. #[cfg(feature = "parsing")]
  101. pub_if_not_doc! {
  102. #[doc(hidden)]
  103. #[allow(non_snake_case)]
  104. pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
  105. match marker {}
  106. }
  107. }
  108. #[cfg(feature = "parsing")]
  109. pub(crate) mod parsing {
  110. use crate::error::Result;
  111. use crate::lifetime::Lifetime;
  112. use crate::parse::{Parse, ParseStream};
  113. #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
  114. impl Parse for Lifetime {
  115. fn parse(input: ParseStream) -> Result<Self> {
  116. input.step(|cursor| {
  117. cursor
  118. .lifetime()
  119. .ok_or_else(|| cursor.error("expected lifetime"))
  120. })
  121. }
  122. }
  123. }
  124. #[cfg(feature = "printing")]
  125. mod printing {
  126. use crate::lifetime::Lifetime;
  127. use proc_macro2::{Punct, Spacing, TokenStream};
  128. use quote::{ToTokens, TokenStreamExt};
  129. #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
  130. impl ToTokens for Lifetime {
  131. fn to_tokens(&self, tokens: &mut TokenStream) {
  132. let mut apostrophe = Punct::new('\'', Spacing::Joint);
  133. apostrophe.set_span(self.apostrophe);
  134. tokens.append(apostrophe);
  135. self.ident.to_tokens(tokens);
  136. }
  137. }
  138. }