/rust/registry/src/index.crates.io-1949cf8c6b5b557f/proc-macro2-1.0.101/src/extra.rs
Line | Count | Source |
1 | | //! Items which do not have a correspondence to any API in the proc_macro crate, |
2 | | //! but are necessary to include in proc-macro2. |
3 | | |
4 | | use crate::fallback; |
5 | | use crate::imp; |
6 | | use crate::marker::{ProcMacroAutoTraits, MARKER}; |
7 | | use crate::Span; |
8 | | use core::fmt::{self, Debug}; |
9 | | |
10 | | /// Invalidate any `proc_macro2::Span` that exist on the current thread. |
11 | | /// |
12 | | /// The implementation of `Span` uses thread-local data structures and this |
13 | | /// function clears them. Calling any method on a `Span` on the current thread |
14 | | /// created prior to the invalidation will return incorrect values or crash. |
15 | | /// |
16 | | /// This function is useful for programs that process more than 2<sup>32</sup> |
17 | | /// bytes of Rust source code on the same thread. Just like rustc, proc-macro2 |
18 | | /// uses 32-bit source locations, and these wrap around when the total source |
19 | | /// code processed by the same thread exceeds 2<sup>32</sup> bytes (4 |
20 | | /// gigabytes). After a wraparound, `Span` methods such as `source_text()` can |
21 | | /// return wrong data. |
22 | | /// |
23 | | /// # Example |
24 | | /// |
25 | | /// As of late 2023, there is 200 GB of Rust code published on crates.io. |
26 | | /// Looking at just the newest version of every crate, it is 16 GB of code. So a |
27 | | /// workload that involves parsing it all would overflow a 32-bit source |
28 | | /// location unless spans are being invalidated. |
29 | | /// |
30 | | /// ``` |
31 | | /// use flate2::read::GzDecoder; |
32 | | /// use std::ffi::OsStr; |
33 | | /// use std::io::{BufReader, Read}; |
34 | | /// use std::str::FromStr; |
35 | | /// use tar::Archive; |
36 | | /// |
37 | | /// rayon::scope(|s| { |
38 | | /// for krate in every_version_of_every_crate() { |
39 | | /// s.spawn(move |_| { |
40 | | /// proc_macro2::extra::invalidate_current_thread_spans(); |
41 | | /// |
42 | | /// let reader = BufReader::new(krate); |
43 | | /// let tar = GzDecoder::new(reader); |
44 | | /// let mut archive = Archive::new(tar); |
45 | | /// for entry in archive.entries().unwrap() { |
46 | | /// let mut entry = entry.unwrap(); |
47 | | /// let path = entry.path().unwrap(); |
48 | | /// if path.extension() != Some(OsStr::new("rs")) { |
49 | | /// continue; |
50 | | /// } |
51 | | /// let mut content = String::new(); |
52 | | /// entry.read_to_string(&mut content).unwrap(); |
53 | | /// match proc_macro2::TokenStream::from_str(&content) { |
54 | | /// Ok(tokens) => {/* ... */}, |
55 | | /// Err(_) => continue, |
56 | | /// } |
57 | | /// } |
58 | | /// }); |
59 | | /// } |
60 | | /// }); |
61 | | /// # |
62 | | /// # fn every_version_of_every_crate() -> Vec<std::fs::File> { |
63 | | /// # Vec::new() |
64 | | /// # } |
65 | | /// ``` |
66 | | /// |
67 | | /// # Panics |
68 | | /// |
69 | | /// This function is not applicable to and will panic if called from a |
70 | | /// procedural macro. |
71 | | #[cfg(span_locations)] |
72 | | #[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))] |
73 | | pub fn invalidate_current_thread_spans() { |
74 | | crate::imp::invalidate_current_thread_spans(); |
75 | | } |
76 | | |
77 | | /// An object that holds a [`Group`]'s `span_open()` and `span_close()` together |
78 | | /// in a more compact representation than holding those 2 spans individually. |
79 | | /// |
80 | | /// [`Group`]: crate::Group |
81 | | #[derive(Copy, Clone)] |
82 | | pub struct DelimSpan { |
83 | | inner: DelimSpanEnum, |
84 | | _marker: ProcMacroAutoTraits, |
85 | | } |
86 | | |
87 | | #[derive(Copy, Clone)] |
88 | | enum DelimSpanEnum { |
89 | | #[cfg(wrap_proc_macro)] |
90 | | Compiler { |
91 | | join: proc_macro::Span, |
92 | | open: proc_macro::Span, |
93 | | close: proc_macro::Span, |
94 | | }, |
95 | | Fallback(fallback::Span), |
96 | | } |
97 | | |
98 | | impl DelimSpan { |
99 | 0 | pub(crate) fn new(group: &imp::Group) -> Self { |
100 | | #[cfg(wrap_proc_macro)] |
101 | 0 | let inner = match group { |
102 | 0 | imp::Group::Compiler(group) => DelimSpanEnum::Compiler { |
103 | 0 | join: group.span(), |
104 | 0 | open: group.span_open(), |
105 | 0 | close: group.span_close(), |
106 | 0 | }, |
107 | 0 | imp::Group::Fallback(group) => DelimSpanEnum::Fallback(group.span()), |
108 | | }; |
109 | | |
110 | | #[cfg(not(wrap_proc_macro))] |
111 | | let inner = DelimSpanEnum::Fallback(group.span()); |
112 | | |
113 | 0 | DelimSpan { |
114 | 0 | inner, |
115 | 0 | _marker: MARKER, |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | | /// Returns a span covering the entire delimited group. |
120 | 0 | pub fn join(&self) -> Span { |
121 | 0 | match &self.inner { |
122 | | #[cfg(wrap_proc_macro)] |
123 | 0 | DelimSpanEnum::Compiler { join, .. } => Span::_new(imp::Span::Compiler(*join)), |
124 | 0 | DelimSpanEnum::Fallback(span) => Span::_new_fallback(*span), |
125 | | } |
126 | 0 | } |
127 | | |
128 | | /// Returns a span for the opening punctuation of the group only. |
129 | 0 | pub fn open(&self) -> Span { |
130 | 0 | match &self.inner { |
131 | | #[cfg(wrap_proc_macro)] |
132 | 0 | DelimSpanEnum::Compiler { open, .. } => Span::_new(imp::Span::Compiler(*open)), |
133 | 0 | DelimSpanEnum::Fallback(span) => Span::_new_fallback(span.first_byte()), |
134 | | } |
135 | 0 | } |
136 | | |
137 | | /// Returns a span for the closing punctuation of the group only. |
138 | 0 | pub fn close(&self) -> Span { |
139 | 0 | match &self.inner { |
140 | | #[cfg(wrap_proc_macro)] |
141 | 0 | DelimSpanEnum::Compiler { close, .. } => Span::_new(imp::Span::Compiler(*close)), |
142 | 0 | DelimSpanEnum::Fallback(span) => Span::_new_fallback(span.last_byte()), |
143 | | } |
144 | 0 | } |
145 | | } |
146 | | |
147 | | impl Debug for DelimSpan { |
148 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
149 | 0 | Debug::fmt(&self.join(), f) |
150 | 0 | } |
151 | | } |