1use std::{
2 borrow::Cow,
3 cmp, fmt,
4 hash::{Hash, Hasher},
5 ops::{Add, Sub},
6 path::PathBuf,
7 sync::{atomic::AtomicU32, Mutex},
8};
9
10use bytes_str::BytesStr;
11use serde::{Deserialize, Serialize};
12use url::Url;
13
14use self::hygiene::MarkData;
15pub use self::hygiene::{Mark, SyntaxContext};
16use crate::{cache::CacheCell, rustc_data_structures::stable_hasher::StableHasher, sync::Lrc};
17
18mod analyze_source_file;
19pub mod hygiene;
20
21#[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize)]
32#[cfg_attr(
33 any(feature = "rkyv-impl"),
34 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
35)]
36#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
37#[cfg_attr(feature = "rkyv-impl", repr(C))]
38#[cfg_attr(
39 feature = "encoding-impl",
40 derive(::ast_node::Encode, ::ast_node::Decode)
41)]
42#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
43pub struct Span {
44 #[serde(rename = "start")]
45 #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
46 pub lo: BytePos,
47 #[serde(rename = "end")]
48 #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
49 pub hi: BytePos,
50}
51
52impl std::fmt::Debug for Span {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 write!(f, "{}..{}", self.lo.0, self.hi.0,)
55 }
56}
57
58impl From<(BytePos, BytePos)> for Span {
59 #[inline]
60 fn from(sp: (BytePos, BytePos)) -> Self {
61 Span::new(sp.0, sp.1)
62 }
63}
64
65impl From<Span> for (BytePos, BytePos) {
66 #[inline]
67 fn from(sp: Span) -> Self {
68 (sp.lo, sp.hi)
69 }
70}
71
72#[cfg(feature = "arbitrary")]
73#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
74impl<'a> arbitrary::Arbitrary<'a> for Span {
75 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
76 let lo = u.arbitrary::<BytePos>()?;
77 let hi = u.arbitrary::<BytePos>()?;
78
79 Ok(Self::new(lo, hi))
80 }
81}
82
83pub const DUMMY_SP: Span = Span {
86 lo: BytePos::DUMMY,
87 hi: BytePos::DUMMY,
88};
89
90pub const PURE_SP: Span = Span {
92 lo: BytePos::PURE,
93 hi: BytePos::PURE,
94};
95
96pub const PLACEHOLDER_SP: Span = Span {
98 lo: BytePos::PLACEHOLDER,
99 hi: BytePos::PLACEHOLDER,
100};
101
102pub struct Globals {
103 hygiene_data: Mutex<hygiene::HygieneData>,
104 #[allow(unused)]
105 dummy_cnt: AtomicU32,
106 #[allow(unused)]
107 marks: Mutex<Vec<MarkData>>,
108}
109
110const DUMMY_RESERVE: u32 = u32::MAX - 2_u32.pow(16);
111
112impl Default for Globals {
113 fn default() -> Self {
114 Self::new()
115 }
116}
117
118impl Globals {
119 pub fn new() -> Globals {
120 Globals {
121 hygiene_data: Mutex::new(hygiene::HygieneData::new()),
122 marks: Mutex::new(vec![MarkData {
123 parent: Mark::root(),
124 }]),
125 dummy_cnt: AtomicU32::new(DUMMY_RESERVE),
126 }
127 }
128
129 pub fn clone_data(&self) -> Self {
133 Globals {
134 hygiene_data: Mutex::new(self.hygiene_data.lock().unwrap().clone()),
135 marks: Mutex::new(self.marks.lock().unwrap().clone()),
136 dummy_cnt: AtomicU32::new(self.dummy_cnt.load(std::sync::atomic::Ordering::SeqCst)),
137 }
138 }
139}
140
141better_scoped_tls::scoped_tls!(
142
143 pub static GLOBALS: Globals
168);
169
170#[cfg_attr(
171 any(feature = "rkyv-impl"),
172 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
173)]
174#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
175#[cfg_attr(feature = "rkyv-impl", repr(u32))]
176#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
177pub enum FileName {
178 Real(
179 #[cfg_attr(
180 any(feature = "rkyv-impl"),
181 rkyv(with = crate::source_map::EncodePathBuf)
182 )]
183 PathBuf,
184 ),
185 Macros(String),
188 QuoteExpansion,
190 Anon,
192 MacroExpansion,
194 ProcMacroSourceCode,
195 Url(#[cfg_attr(any(feature = "rkyv-impl"), rkyv(with = crate::source_map::EncodeUrl))] Url),
196 Internal(String),
197 Custom(String),
199}
200
201#[cfg(feature = "rkyv-impl")]
211#[derive(Debug, Clone, Copy)]
212#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
213#[cfg_attr(feature = "rkyv-impl", repr(C))]
214pub struct EncodePathBuf;
215
216#[cfg(feature = "rkyv-impl")]
217impl rkyv::with::ArchiveWith<PathBuf> for EncodePathBuf {
218 type Archived = rkyv::string::ArchivedString;
219 type Resolver = rkyv::string::StringResolver;
220
221 #[inline]
222 fn resolve_with(field: &PathBuf, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
223 rkyv::string::ArchivedString::resolve_from_str(field.to_str().unwrap(), resolver, out);
226 }
227}
228
229#[cfg(feature = "rkyv-impl")]
230impl<S> rkyv::with::SerializeWith<PathBuf, S> for EncodePathBuf
231where
232 S: ?Sized + rancor::Fallible + rkyv::ser::Writer,
233 S::Error: rancor::Source,
234{
235 #[inline]
236 fn serialize_with(field: &PathBuf, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
237 let s = field.to_str().unwrap_or_default();
238 rkyv::string::ArchivedString::serialize_from_str(s, serializer)
239 }
240}
241
242#[cfg(feature = "rkyv-impl")]
243impl<D> rkyv::with::DeserializeWith<rkyv::string::ArchivedString, PathBuf, D> for EncodePathBuf
244where
245 D: ?Sized + rancor::Fallible,
246{
247 #[inline]
248 fn deserialize_with(
249 field: &rkyv::string::ArchivedString,
250 _: &mut D,
251 ) -> Result<PathBuf, D::Error> {
252 Ok(<PathBuf as std::str::FromStr>::from_str(field.as_str()).unwrap())
253 }
254}
255
256#[cfg(feature = "rkyv-impl")]
258#[derive(Debug, Clone, Copy)]
259#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
260#[cfg_attr(feature = "rkyv-impl", repr(C))]
261pub struct EncodeUrl;
262
263#[cfg(feature = "rkyv-impl")]
264impl rkyv::with::ArchiveWith<Url> for EncodeUrl {
265 type Archived = rkyv::string::ArchivedString;
266 type Resolver = rkyv::string::StringResolver;
267
268 #[inline]
269 fn resolve_with(field: &Url, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
270 rkyv::string::ArchivedString::resolve_from_str(field.as_str(), resolver, out);
271 }
272}
273
274#[cfg(feature = "rkyv-impl")]
275impl<S> rkyv::with::SerializeWith<Url, S> for EncodeUrl
276where
277 S: ?Sized + rancor::Fallible + rkyv::ser::Writer,
278 S::Error: rancor::Source,
279{
280 #[inline]
281 fn serialize_with(field: &Url, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
282 let field = field.as_str();
283 rkyv::string::ArchivedString::serialize_from_str(field, serializer)
284 }
285}
286
287#[cfg(feature = "rkyv-impl")]
288impl<D> rkyv::with::DeserializeWith<rkyv::Archived<String>, Url, D> for EncodeUrl
289where
290 D: ?Sized + rancor::Fallible,
291{
292 #[inline]
293 fn deserialize_with(field: &rkyv::string::ArchivedString, _: &mut D) -> Result<Url, D::Error> {
294 Ok(Url::parse(field.as_str()).unwrap())
295 }
296}
297
298impl std::fmt::Display for FileName {
299 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300 match *self {
301 FileName::Real(ref path) => write!(fmt, "{}", path.display()),
302 FileName::Macros(ref name) => write!(fmt, "<{name} macros>"),
303 FileName::QuoteExpansion => write!(fmt, "<quote expansion>"),
304 FileName::MacroExpansion => write!(fmt, "<macro expansion>"),
305 FileName::Anon => write!(fmt, "<anon>"),
306 FileName::ProcMacroSourceCode => write!(fmt, "<proc-macro source code>"),
307 FileName::Url(ref u) => write!(fmt, "{u}"),
308 FileName::Custom(ref s) => {
309 write!(fmt, "{s}")
310 }
311 FileName::Internal(ref s) => write!(fmt, "<{s}>"),
312 }
313 }
314}
315
316impl From<PathBuf> for FileName {
317 fn from(p: PathBuf) -> Self {
318 assert!(!p.to_string_lossy().ends_with('>'));
319 FileName::Real(p)
320 }
321}
322
323impl From<Url> for FileName {
324 fn from(url: Url) -> Self {
325 FileName::Url(url)
326 }
327}
328
329impl FileName {
330 pub fn is_real(&self) -> bool {
331 match *self {
332 FileName::Real(_) => true,
333 FileName::Macros(_)
334 | FileName::Anon
335 | FileName::MacroExpansion
336 | FileName::ProcMacroSourceCode
337 | FileName::Custom(_)
338 | FileName::QuoteExpansion
339 | FileName::Internal(_)
340 | FileName::Url(_) => false,
341 }
342 }
343
344 pub fn is_macros(&self) -> bool {
345 match *self {
346 FileName::Real(_)
347 | FileName::Anon
348 | FileName::MacroExpansion
349 | FileName::ProcMacroSourceCode
350 | FileName::Custom(_)
351 | FileName::QuoteExpansion
352 | FileName::Internal(_)
353 | FileName::Url(_) => false,
354 FileName::Macros(_) => true,
355 }
356 }
357}
358
359#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
360#[cfg_attr(
361 feature = "diagnostic-serde",
362 derive(serde::Serialize, serde::Deserialize)
363)]
364#[cfg_attr(
365 any(feature = "rkyv-impl"),
366 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
367)]
368#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
369#[cfg_attr(feature = "rkyv-impl", repr(C))]
370pub struct PrimarySpanLabel(pub Span, pub String);
371
372#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
379#[cfg_attr(
380 feature = "diagnostic-serde",
381 derive(serde::Serialize, serde::Deserialize)
382)]
383#[cfg_attr(
384 any(feature = "rkyv-impl"),
385 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
386)]
387#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
388#[cfg_attr(feature = "rkyv-impl", repr(C))]
389pub struct MultiSpan {
390 primary_spans: Vec<Span>,
391 span_labels: Vec<PrimarySpanLabel>,
392}
393
394extern "C" {
395 fn __span_dummy_with_cmt_proxy() -> u32;
396}
397
398impl Span {
399 #[inline]
400 pub fn lo(self) -> BytePos {
401 self.lo
402 }
403
404 #[inline]
405 pub fn new(mut lo: BytePos, mut hi: BytePos) -> Self {
406 if lo > hi {
407 std::mem::swap(&mut lo, &mut hi);
408 }
409
410 Span { lo, hi }
411 }
412
413 #[inline]
414 #[track_caller]
415 pub fn new_with_checked(lo: BytePos, hi: BytePos) -> Self {
416 debug_assert!(lo <= hi, "lo: {lo:#?}, hi: {hi:#?}");
417 Span { lo, hi }
418 }
419
420 #[inline]
421 pub fn with_lo(&self, lo: BytePos) -> Span {
422 Span::new(lo, self.hi)
423 }
424
425 #[inline(always)]
426 pub fn hi(self) -> BytePos {
427 self.hi
428 }
429
430 #[inline]
431 pub fn with_hi(&self, hi: BytePos) -> Span {
432 Span::new(self.lo, hi)
433 }
434
435 #[inline]
437 pub fn is_dummy(self) -> bool {
438 self.lo.0 == 0 && self.hi.0 == 0 || self.lo.0 >= DUMMY_RESERVE
439 }
440
441 #[inline]
442 pub fn is_pure(self) -> bool {
443 self.lo.is_pure()
444 }
445
446 #[inline]
447 pub fn is_placeholder(self) -> bool {
448 self.lo.is_placeholder()
449 }
450
451 #[inline]
453 pub fn is_dummy_ignoring_cmt(self) -> bool {
454 self.lo.0 == 0 && self.hi.0 == 0
455 }
456
457 #[inline]
460 pub fn shrink_to_lo(self) -> Span {
461 self.with_hi(self.lo)
462 }
463
464 #[inline]
466 pub fn shrink_to_hi(self) -> Span {
467 self.with_lo(self.hi)
468 }
469
470 pub fn substitute_dummy(self, other: Span) -> Span {
472 if self.is_dummy() {
473 other
474 } else {
475 self
476 }
477 }
478
479 pub fn contains(self, other: Span) -> bool {
481 self.lo <= other.lo && other.hi <= self.hi
482 }
483
484 pub fn source_equal(self, other: Span) -> bool {
489 self.lo == other.lo && self.hi == other.hi
490 }
491
492 pub fn trim_start(self, other: Span) -> Option<Span> {
494 if self.hi > other.hi {
495 Some(self.with_lo(cmp::max(self.lo, other.hi)))
496 } else {
497 None
498 }
499 }
500
501 pub fn to(self, end: Span) -> Span {
503 let span_data = self;
504 let end_data = end;
505 Span::new(
511 cmp::min(span_data.lo, end_data.lo),
512 cmp::max(span_data.hi, end_data.hi),
513 )
514 }
515
516 pub fn between(self, end: Span) -> Span {
518 let span = self;
519 Span::new(span.hi, end.lo)
520 }
521
522 pub fn until(self, end: Span) -> Span {
525 let span = self;
526 Span::new(span.lo, end.lo)
527 }
528
529 pub fn from_inner_byte_pos(self, start: usize, end: usize) -> Span {
530 let span = self;
531 Span::new(
532 span.lo + BytePos::from_usize(start),
533 span.lo + BytePos::from_usize(end),
534 )
535 }
536
537 pub fn dummy_with_cmt() -> Self {
540 #[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
541 {
542 let lo = BytePos(unsafe { __span_dummy_with_cmt_proxy() });
543
544 return Span { lo, hi: lo };
545 }
546
547 #[cfg(not(all(any(feature = "__plugin_mode"), target_arch = "wasm32")))]
548 return GLOBALS.with(|globals| {
549 let lo = BytePos(
550 globals
551 .dummy_cnt
552 .fetch_add(1, std::sync::atomic::Ordering::SeqCst),
553 );
554 Span { lo, hi: lo }
555 });
556 }
557}
558
559#[derive(Clone, Debug)]
560pub struct SpanLabel {
561 pub span: Span,
563
564 pub is_primary: bool,
567
568 pub label: Option<String>,
570}
571
572impl Default for Span {
573 fn default() -> Self {
574 DUMMY_SP
575 }
576}
577
578impl MultiSpan {
579 #[inline]
580 pub fn new() -> MultiSpan {
581 Self::default()
582 }
583
584 pub fn from_span(primary_span: Span) -> MultiSpan {
585 MultiSpan {
586 primary_spans: vec![primary_span],
587 span_labels: Vec::new(),
588 }
589 }
590
591 pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
592 MultiSpan {
593 primary_spans: vec,
594 span_labels: Vec::new(),
595 }
596 }
597
598 pub fn push_span_label(&mut self, span: Span, label: String) {
599 self.span_labels.push(PrimarySpanLabel(span, label));
600 }
601
602 pub fn primary_span(&self) -> Option<Span> {
604 self.primary_spans.first().cloned()
605 }
606
607 pub fn primary_spans(&self) -> &[Span] {
609 &self.primary_spans
610 }
611
612 pub fn is_dummy(&self) -> bool {
615 let mut is_dummy = true;
616 for span in &self.primary_spans {
617 if !span.is_dummy() {
618 is_dummy = false;
619 }
620 }
621 is_dummy
622 }
623
624 pub fn replace(&mut self, before: Span, after: Span) -> bool {
628 let mut replacements_occurred = false;
629 for primary_span in &mut self.primary_spans {
630 if *primary_span == before {
631 *primary_span = after;
632 replacements_occurred = true;
633 }
634 }
635 for span_label in &mut self.span_labels {
636 if span_label.0 == before {
637 span_label.0 = after;
638 replacements_occurred = true;
639 }
640 }
641 replacements_occurred
642 }
643
644 pub fn span_labels(&self) -> Vec<SpanLabel> {
650 let is_primary = |span| self.primary_spans.contains(&span);
651
652 let mut span_labels = self
653 .span_labels
654 .iter()
655 .map(|&PrimarySpanLabel(span, ref label)| SpanLabel {
656 span,
657 is_primary: is_primary(span),
658 label: Some(label.clone()),
659 })
660 .collect::<Vec<_>>();
661
662 for &span in &self.primary_spans {
663 if !span_labels.iter().any(|sl| sl.span == span) {
664 span_labels.push(SpanLabel {
665 span,
666 is_primary: true,
667 label: None,
668 });
669 }
670 }
671
672 span_labels
673 }
674}
675
676impl From<Span> for MultiSpan {
677 fn from(span: Span) -> MultiSpan {
678 MultiSpan::from_span(span)
679 }
680}
681
682impl From<Vec<Span>> for MultiSpan {
683 fn from(spans: Vec<Span>) -> MultiSpan {
684 MultiSpan::from_spans(spans)
685 }
686}
687
688pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
689
690#[cfg_attr(
692 any(feature = "rkyv-impl"),
693 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
694)]
695#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
696#[cfg_attr(feature = "rkyv-impl", repr(C))]
697#[derive(Copy, Clone, Eq, PartialEq, Debug)]
698pub struct MultiByteChar {
699 pub pos: BytePos,
701 pub bytes: u8,
703}
704
705impl MultiByteChar {
706 pub fn byte_to_char_diff(&self) -> u8 {
712 if self.bytes == 4 {
713 2
714 } else {
715 self.bytes - 1
716 }
717 }
718}
719
720#[cfg_attr(
722 any(feature = "rkyv-impl"),
723 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
724)]
725#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
726#[cfg_attr(feature = "rkyv-impl", repr(u32))]
727#[derive(Copy, Clone, Eq, PartialEq, Debug)]
728pub enum NonNarrowChar {
729 ZeroWidth(BytePos),
731 Wide(BytePos, usize),
733 Tab(BytePos),
736}
737
738impl NonNarrowChar {
739 fn new(pos: BytePos, width: usize) -> Self {
740 match width {
741 0 => NonNarrowChar::ZeroWidth(pos),
742 4 => NonNarrowChar::Tab(pos),
743 w => NonNarrowChar::Wide(pos, w),
744 }
745 }
746
747 pub fn pos(self) -> BytePos {
749 match self {
750 NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p, _) | NonNarrowChar::Tab(p) => p,
751 }
752 }
753
754 pub fn width(self) -> usize {
756 match self {
757 NonNarrowChar::ZeroWidth(_) => 0,
758 NonNarrowChar::Wide(_, width) => width,
759 NonNarrowChar::Tab(_) => 4,
760 }
761 }
762}
763
764impl Add<BytePos> for NonNarrowChar {
765 type Output = Self;
766
767 fn add(self, rhs: BytePos) -> Self {
768 match self {
769 NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
770 NonNarrowChar::Wide(pos, width) => NonNarrowChar::Wide(pos + rhs, width),
771 NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs),
772 }
773 }
774}
775
776impl Sub<BytePos> for NonNarrowChar {
777 type Output = Self;
778
779 fn sub(self, rhs: BytePos) -> Self {
780 match self {
781 NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
782 NonNarrowChar::Wide(pos, width) => NonNarrowChar::Wide(pos - rhs, width),
783 NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs),
784 }
785 }
786}
787
788#[cfg_attr(
790 any(feature = "rkyv-impl"),
791 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
792)]
793#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
794#[cfg_attr(feature = "rkyv-impl", repr(C))]
795#[derive(Clone)]
796pub struct SourceFile {
797 pub name: Lrc<FileName>,
801 pub name_was_remapped: bool,
804 pub unmapped_path: Option<Lrc<FileName>>,
807 pub crate_of_origin: u32,
809 pub src: BytesStr,
811 pub src_hash: u128,
813 pub start_pos: BytePos,
815 pub end_pos: BytePos,
817 pub name_hash: u128,
819
820 lazy: CacheCell<SourceFileAnalysis>,
821}
822
823#[cfg_attr(
824 any(feature = "rkyv-impl"),
825 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
826)]
827#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
828#[cfg_attr(feature = "rkyv-impl", repr(C))]
829#[derive(Clone)]
830pub struct SourceFileAnalysis {
831 pub lines: Vec<BytePos>,
833 pub multibyte_chars: Vec<MultiByteChar>,
835 pub non_narrow_chars: Vec<NonNarrowChar>,
837}
838
839impl fmt::Debug for SourceFile {
840 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
841 write!(fmt, "SourceFile({})", self.name)
842 }
843}
844
845impl SourceFile {
846 pub fn new(
848 name: Lrc<FileName>,
849 name_was_remapped: bool,
850 unmapped_path: Lrc<FileName>,
851 src: BytesStr,
852 start_pos: BytePos,
853 ) -> SourceFile {
854 debug_assert_ne!(
855 start_pos,
856 BytePos::DUMMY,
857 "BytePos::DUMMY is reserved and `SourceFile` should not use it"
858 );
859
860 let src_hash = {
861 let mut hasher: StableHasher = StableHasher::new();
862 hasher.write(src.as_bytes());
863 hasher.finish()
864 };
865 let name_hash = {
866 let mut hasher: StableHasher = StableHasher::new();
867 name.hash(&mut hasher);
868 hasher.finish()
869 };
870 let end_pos = start_pos.to_usize() + src.len();
871
872 SourceFile {
873 name,
874 name_was_remapped,
875 unmapped_path: Some(unmapped_path),
876 crate_of_origin: 0,
877 src,
878 src_hash,
879 start_pos,
880 end_pos: SmallPos::from_usize(end_pos),
881 name_hash,
882 lazy: CacheCell::new(),
883 }
884 }
885
886 pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
888 let line_index = self.lookup_line(pos).unwrap();
889 let analysis = self.analyze();
890 analysis.lines[line_index]
891 }
892
893 pub fn get_line(&self, line_number: usize) -> Option<Cow<'_, str>> {
896 fn get_until_newline(src: &str, begin: usize) -> &str {
897 let slice = &src[begin..];
901 match slice.find('\n') {
902 Some(e) => &slice[..e],
903 None => slice,
904 }
905 }
906
907 let begin = {
908 let analysis = self.analyze();
909 let line = analysis.lines.get(line_number)?;
910 let begin: BytePos = *line - self.start_pos;
911 begin.to_usize()
912 };
913
914 Some(Cow::from(get_until_newline(&self.src, begin)))
915 }
916
917 pub fn is_real_file(&self) -> bool {
918 self.name.is_real()
919 }
920
921 pub fn byte_length(&self) -> u32 {
922 self.end_pos.0 - self.start_pos.0
923 }
924
925 pub fn count_lines(&self) -> usize {
926 let analysis = self.analyze();
927 analysis.lines.len()
928 }
929
930 pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
935 let analysis = self.analyze();
936 if analysis.lines.is_empty() {
937 return None;
938 }
939
940 let line_index = lookup_line(&analysis.lines, pos);
941 assert!(line_index < analysis.lines.len() as isize);
942 if line_index >= 0 {
943 Some(line_index as usize)
944 } else {
945 None
946 }
947 }
948
949 pub fn line_bounds(&self, line_index: usize) -> (BytePos, BytePos) {
950 if self.start_pos == self.end_pos {
951 return (self.start_pos, self.end_pos);
952 }
953
954 let analysis = self.analyze();
955
956 assert!(line_index < analysis.lines.len());
957 if line_index == (analysis.lines.len() - 1) {
958 (analysis.lines[line_index], self.end_pos)
959 } else {
960 (analysis.lines[line_index], analysis.lines[line_index + 1])
961 }
962 }
963
964 #[inline]
965 pub fn contains(&self, byte_pos: BytePos) -> bool {
966 byte_pos >= self.start_pos && byte_pos <= self.end_pos
967 }
968
969 pub fn analyze(&self) -> &SourceFileAnalysis {
970 self.lazy.get_or_init(|| {
971 let (lines, multibyte_chars, non_narrow_chars) =
972 analyze_source_file::analyze_source_file(&self.src[..], self.start_pos);
973 SourceFileAnalysis {
974 lines,
975 multibyte_chars,
976 non_narrow_chars,
977 }
978 })
979 }
980}
981
982pub trait SmallPos {
987 fn from_usize(n: usize) -> Self;
988 fn to_usize(&self) -> usize;
989 fn from_u32(n: u32) -> Self;
990 fn to_u32(&self) -> u32;
991}
992
993#[derive(
1006 Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize, Default,
1007)]
1008#[serde(transparent)]
1009#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1010#[cfg_attr(
1011 any(feature = "rkyv-impl"),
1012 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1013)]
1014#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1015#[cfg_attr(feature = "rkyv-impl", repr(C))]
1016#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
1017pub struct BytePos(#[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub u32);
1018
1019#[cfg(feature = "encoding-impl")]
1020impl cbor4ii::core::enc::Encode for BytePos {
1021 #[inline]
1022 fn encode<W: cbor4ii::core::enc::Write>(
1023 &self,
1024 writer: &mut W,
1025 ) -> Result<(), cbor4ii::core::enc::Error<W::Error>> {
1026 self.0.encode(writer)
1027 }
1028}
1029
1030#[cfg(feature = "encoding-impl")]
1031impl<'de> cbor4ii::core::dec::Decode<'de> for BytePos {
1032 #[inline]
1033 fn decode<R: cbor4ii::core::dec::Read<'de>>(
1034 reader: &mut R,
1035 ) -> Result<Self, cbor4ii::core::dec::Error<R::Error>> {
1036 u32::decode(reader).map(BytePos)
1037 }
1038}
1039
1040impl BytePos {
1041 pub const DUMMY: Self = BytePos(0);
1043 const MIN_RESERVED: Self = BytePos(DUMMY_RESERVE);
1044 pub const PLACEHOLDER: Self = BytePos(u32::MAX - 2);
1047 pub const PURE: Self = BytePos(u32::MAX - 1);
1049 pub const SYNTHESIZED: Self = BytePos(u32::MAX);
1051
1052 pub const fn is_reserved_for_comments(self) -> bool {
1053 self.0 >= Self::MIN_RESERVED.0 && self.0 != u32::MAX
1054 }
1055
1056 pub const fn is_dummy(self) -> bool {
1059 self.0 == 0
1060 }
1061
1062 pub const fn is_pure(self) -> bool {
1063 self.0 == Self::PURE.0
1064 }
1065
1066 pub const fn is_placeholder(self) -> bool {
1067 self.0 == Self::PLACEHOLDER.0
1068 }
1069
1070 pub const fn can_have_comment(self) -> bool {
1073 self.0 != 0
1074 }
1075}
1076
1077#[cfg_attr(
1081 any(feature = "rkyv-impl"),
1082 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1083)]
1084#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1085#[cfg_attr(feature = "rkyv-impl", repr(C))]
1086#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1087pub struct CharPos(pub usize);
1088
1089impl SmallPos for BytePos {
1093 #[inline(always)]
1094 fn from_usize(n: usize) -> BytePos {
1095 BytePos(n as u32)
1096 }
1097
1098 #[inline(always)]
1099 fn to_usize(&self) -> usize {
1100 self.0 as usize
1101 }
1102
1103 #[inline(always)]
1104 fn from_u32(n: u32) -> BytePos {
1105 BytePos(n)
1106 }
1107
1108 #[inline(always)]
1109 fn to_u32(&self) -> u32 {
1110 self.0
1111 }
1112}
1113
1114impl Add for BytePos {
1115 type Output = BytePos;
1116
1117 #[inline(always)]
1118 fn add(self, rhs: BytePos) -> BytePos {
1119 BytePos((self.to_usize() + rhs.to_usize()) as u32)
1120 }
1121}
1122
1123impl Sub for BytePos {
1124 type Output = BytePos;
1125
1126 #[inline(always)]
1127 fn sub(self, rhs: BytePos) -> BytePos {
1128 BytePos((self.to_usize() - rhs.to_usize()) as u32)
1129 }
1130}
1131
1132impl SmallPos for CharPos {
1133 #[inline(always)]
1134 fn from_usize(n: usize) -> CharPos {
1135 CharPos(n)
1136 }
1137
1138 #[inline(always)]
1139 fn to_usize(&self) -> usize {
1140 self.0
1141 }
1142
1143 #[inline(always)]
1144 fn from_u32(n: u32) -> CharPos {
1145 CharPos(n as usize)
1146 }
1147
1148 #[inline(always)]
1149 fn to_u32(&self) -> u32 {
1150 self.0 as u32
1151 }
1152}
1153
1154impl Add for CharPos {
1155 type Output = CharPos;
1156
1157 #[inline(always)]
1158 fn add(self, rhs: CharPos) -> CharPos {
1159 CharPos(self.to_usize() + rhs.to_usize())
1160 }
1161}
1162
1163impl Sub for CharPos {
1164 type Output = CharPos;
1165
1166 #[inline(always)]
1167 fn sub(self, rhs: CharPos) -> CharPos {
1168 CharPos(self.to_usize() - rhs.to_usize())
1169 }
1170}
1171
1172#[derive(Debug, Clone)]
1183pub struct Loc {
1184 pub file: Lrc<SourceFile>,
1186 pub line: usize,
1188 pub col: CharPos,
1190 pub col_display: usize,
1192}
1193
1194#[cfg_attr(
1197 any(feature = "rkyv-impl"),
1198 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Debug, Clone)
1199)]
1200#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1201#[cfg_attr(feature = "rkyv-impl", repr(C))]
1202pub struct PartialLoc {
1203 pub source_file: Option<Lrc<SourceFile>>,
1204 pub line: usize,
1205 pub col: usize,
1206 pub col_display: usize,
1207}
1208
1209#[derive(Debug)]
1213pub struct LocWithOpt {
1214 pub filename: Lrc<FileName>,
1215 pub line: usize,
1216 pub col: CharPos,
1217 pub file: Option<Lrc<SourceFile>>,
1218}
1219
1220#[derive(Debug)]
1222pub struct SourceFileAndLine {
1223 pub sf: Lrc<SourceFile>,
1224 pub line: usize,
1225}
1226
1227#[cfg_attr(
1228 any(feature = "rkyv-impl"),
1229 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1230)]
1231#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1232#[cfg_attr(feature = "rkyv-impl", repr(C))]
1233#[derive(Debug)]
1234pub struct SourceFileAndBytePos {
1235 pub sf: Lrc<SourceFile>,
1236 pub pos: BytePos,
1237}
1238
1239#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1240#[cfg_attr(
1241 any(feature = "rkyv-impl"),
1242 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1243)]
1244#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1245#[cfg_attr(feature = "rkyv-impl", repr(C))]
1246pub struct LineInfo {
1247 pub line_index: usize,
1249
1250 pub start_col: CharPos,
1252
1253 pub end_col: CharPos,
1255}
1256
1257#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1259pub struct LineCol {
1260 pub line: u32,
1262
1263 pub col: u32,
1265}
1266
1267pub struct FileLines {
1274 pub file: Lrc<SourceFile>,
1275 pub lines: Vec<LineInfo>,
1276}
1277
1278#[cfg_attr(
1281 any(feature = "rkyv-impl"),
1282 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Debug, Clone)
1283)]
1284#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1285#[cfg_attr(feature = "rkyv-impl", repr(C))]
1286pub struct PartialFileLines {
1287 pub file: Option<Lrc<SourceFile>>,
1288 pub lines: Vec<LineInfo>,
1289}
1290
1291pub type FileLinesResult = Result<FileLines, Box<SpanLinesError>>;
1297#[cfg(feature = "__plugin")]
1298pub type PartialFileLinesResult = Result<PartialFileLines, Box<SpanLinesError>>;
1299
1300#[derive(Clone, PartialEq, Eq, Debug)]
1301#[cfg_attr(
1302 any(feature = "rkyv-impl"),
1303 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1304)]
1305#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1306#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1307pub enum SpanLinesError {
1308 IllFormedSpan(Span),
1309 DistinctSources(DistinctSources),
1310}
1311
1312#[derive(Clone, PartialEq, Eq, Debug)]
1313#[cfg_attr(
1314 any(feature = "rkyv-impl"),
1315 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1316)]
1317#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1318#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1319pub enum SpanSnippetError {
1320 DummyBytePos,
1321 IllFormedSpan(Span),
1322 DistinctSources(DistinctSources),
1323 MalformedForSourcemap(MalformedSourceMapPositions),
1324 SourceNotAvailable { filename: FileName },
1325 LookupFailed(SourceMapLookupError),
1326}
1327
1328#[derive(Clone, PartialEq, Eq, Debug)]
1333#[cfg_attr(
1334 any(feature = "rkyv-impl"),
1335 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1336)]
1337#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1338#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1339pub enum SourceMapLookupError {
1340 NoFileFor(BytePos),
1341}
1342
1343#[derive(Clone, PartialEq, Eq, Debug)]
1344#[cfg_attr(
1345 any(feature = "rkyv-impl"),
1346 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1347)]
1348#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1349#[cfg_attr(feature = "rkyv-impl", repr(C))]
1350pub struct FilePos(pub Lrc<FileName>, pub BytePos);
1351
1352#[derive(Clone, PartialEq, Eq, Debug)]
1353#[cfg_attr(
1354 any(feature = "rkyv-impl"),
1355 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1356)]
1357#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1358#[cfg_attr(feature = "rkyv-impl", repr(C))]
1359pub struct DistinctSources {
1360 pub begin: FilePos,
1361 pub end: FilePos,
1362}
1363
1364#[derive(Clone, PartialEq, Eq, Debug)]
1365#[cfg_attr(
1366 any(feature = "rkyv-impl"),
1367 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1368)]
1369#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1370#[cfg_attr(feature = "rkyv-impl", repr(C))]
1371pub struct MalformedSourceMapPositions {
1372 pub name: Lrc<FileName>,
1373 pub source_len: usize,
1374 pub begin_pos: BytePos,
1375 pub end_pos: BytePos,
1376}
1377
1378fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize {
1382 match lines.binary_search(&pos) {
1383 Ok(line) => line as isize,
1384 Err(line) => line as isize - 1,
1385 }
1386}
1387
1388impl From<SourceMapLookupError> for Box<SpanSnippetError> {
1389 #[cold]
1390 fn from(err: SourceMapLookupError) -> Self {
1391 Box::new(SpanSnippetError::LookupFailed(err))
1392 }
1393}
1394
1395#[cfg(test)]
1396mod tests {
1397 use super::{lookup_line, BytePos, Span};
1398
1399 #[test]
1400 fn test_lookup_line() {
1401 let lines = &[BytePos(3), BytePos(17), BytePos(28)];
1402
1403 assert_eq!(lookup_line(lines, BytePos(0)), -1);
1404 assert_eq!(lookup_line(lines, BytePos(3)), 0);
1405 assert_eq!(lookup_line(lines, BytePos(4)), 0);
1406
1407 assert_eq!(lookup_line(lines, BytePos(16)), 0);
1408 assert_eq!(lookup_line(lines, BytePos(17)), 1);
1409 assert_eq!(lookup_line(lines, BytePos(18)), 1);
1410
1411 assert_eq!(lookup_line(lines, BytePos(28)), 2);
1412 assert_eq!(lookup_line(lines, BytePos(29)), 2);
1413 }
1414
1415 #[test]
1416 fn size_of_span() {
1417 assert_eq!(std::mem::size_of::<Span>(), 8);
1418 }
1419}