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(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
39pub struct Span {
40    #[serde(rename = "start")]
41    #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
42    pub lo: BytePos,
43    #[serde(rename = "end")]
44    #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
45    pub hi: BytePos,
46}
47
48impl std::fmt::Debug for Span {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        write!(f, "{}..{}", self.lo.0, self.hi.0,)
51    }
52}
53
54impl From<(BytePos, BytePos)> for Span {
55    #[inline]
56    fn from(sp: (BytePos, BytePos)) -> Self {
57        Span::new(sp.0, sp.1)
58    }
59}
60
61impl From<Span> for (BytePos, BytePos) {
62    #[inline]
63    fn from(sp: Span) -> Self {
64        (sp.lo, sp.hi)
65    }
66}
67
68#[cfg(feature = "arbitrary")]
69#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
70impl<'a> arbitrary::Arbitrary<'a> for Span {
71    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
72        let lo = u.arbitrary::<BytePos>()?;
73        let hi = u.arbitrary::<BytePos>()?;
74
75        Ok(Self::new(lo, hi))
76    }
77}
78
79pub const DUMMY_SP: Span = Span {
82    lo: BytePos::DUMMY,
83    hi: BytePos::DUMMY,
84};
85
86pub const PURE_SP: Span = Span {
88    lo: BytePos::PURE,
89    hi: BytePos::PURE,
90};
91
92pub const PLACEHOLDER_SP: Span = Span {
94    lo: BytePos::PLACEHOLDER,
95    hi: BytePos::PLACEHOLDER,
96};
97
98pub struct Globals {
99    hygiene_data: Mutex<hygiene::HygieneData>,
100    #[allow(unused)]
101    dummy_cnt: AtomicU32,
102    #[allow(unused)]
103    marks: Mutex<Vec<MarkData>>,
104}
105
106const DUMMY_RESERVE: u32 = u32::MAX - 2_u32.pow(16);
107
108impl Default for Globals {
109    fn default() -> Self {
110        Self::new()
111    }
112}
113
114impl Globals {
115    pub fn new() -> Globals {
116        Globals {
117            hygiene_data: Mutex::new(hygiene::HygieneData::new()),
118            marks: Mutex::new(vec![MarkData {
119                parent: Mark::root(),
120            }]),
121            dummy_cnt: AtomicU32::new(DUMMY_RESERVE),
122        }
123    }
124
125    pub fn clone_data(&self) -> Self {
129        Globals {
130            hygiene_data: Mutex::new(self.hygiene_data.lock().unwrap().clone()),
131            marks: Mutex::new(self.marks.lock().unwrap().clone()),
132            dummy_cnt: AtomicU32::new(self.dummy_cnt.load(std::sync::atomic::Ordering::SeqCst)),
133        }
134    }
135}
136
137better_scoped_tls::scoped_tls!(
138
139    pub static GLOBALS: Globals
164);
165
166#[cfg_attr(
167    any(feature = "rkyv-impl"),
168    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
169)]
170#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
171#[cfg_attr(feature = "rkyv-impl", repr(u32))]
172#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
173pub enum FileName {
174    Real(
175        #[cfg_attr(
176            any(feature = "rkyv-impl"),
177            rkyv(with = crate::source_map::EncodePathBuf)
178        )]
179        PathBuf,
180    ),
181    Macros(String),
184    QuoteExpansion,
186    Anon,
188    MacroExpansion,
190    ProcMacroSourceCode,
191    Url(#[cfg_attr(any(feature = "rkyv-impl"), rkyv(with = crate::source_map::EncodeUrl))] Url),
192    Internal(String),
193    Custom(String),
195}
196
197#[cfg(feature = "rkyv-impl")]
207#[derive(Debug, Clone, Copy)]
208#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
209#[cfg_attr(feature = "rkyv-impl", repr(C))]
210pub struct EncodePathBuf;
211
212#[cfg(feature = "rkyv-impl")]
213impl rkyv::with::ArchiveWith<PathBuf> for EncodePathBuf {
214    type Archived = rkyv::string::ArchivedString;
215    type Resolver = rkyv::string::StringResolver;
216
217    #[inline]
218    fn resolve_with(field: &PathBuf, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
219        rkyv::string::ArchivedString::resolve_from_str(field.to_str().unwrap(), resolver, out);
222    }
223}
224
225#[cfg(feature = "rkyv-impl")]
226impl<S> rkyv::with::SerializeWith<PathBuf, S> for EncodePathBuf
227where
228    S: ?Sized + rancor::Fallible + rkyv::ser::Writer,
229    S::Error: rancor::Source,
230{
231    #[inline]
232    fn serialize_with(field: &PathBuf, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
233        let s = field.to_str().unwrap_or_default();
234        rkyv::string::ArchivedString::serialize_from_str(s, serializer)
235    }
236}
237
238#[cfg(feature = "rkyv-impl")]
239impl<D> rkyv::with::DeserializeWith<rkyv::string::ArchivedString, PathBuf, D> for EncodePathBuf
240where
241    D: ?Sized + rancor::Fallible,
242{
243    #[inline]
244    fn deserialize_with(
245        field: &rkyv::string::ArchivedString,
246        _: &mut D,
247    ) -> Result<PathBuf, D::Error> {
248        Ok(<PathBuf as std::str::FromStr>::from_str(field.as_str()).unwrap())
249    }
250}
251
252#[cfg(feature = "rkyv-impl")]
254#[derive(Debug, Clone, Copy)]
255#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
256#[cfg_attr(feature = "rkyv-impl", repr(C))]
257pub struct EncodeUrl;
258
259#[cfg(feature = "rkyv-impl")]
260impl rkyv::with::ArchiveWith<Url> for EncodeUrl {
261    type Archived = rkyv::string::ArchivedString;
262    type Resolver = rkyv::string::StringResolver;
263
264    #[inline]
265    fn resolve_with(field: &Url, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
266        rkyv::string::ArchivedString::resolve_from_str(field.as_str(), resolver, out);
267    }
268}
269
270#[cfg(feature = "rkyv-impl")]
271impl<S> rkyv::with::SerializeWith<Url, S> for EncodeUrl
272where
273    S: ?Sized + rancor::Fallible + rkyv::ser::Writer,
274    S::Error: rancor::Source,
275{
276    #[inline]
277    fn serialize_with(field: &Url, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
278        let field = field.as_str();
279        rkyv::string::ArchivedString::serialize_from_str(field, serializer)
280    }
281}
282
283#[cfg(feature = "rkyv-impl")]
284impl<D> rkyv::with::DeserializeWith<rkyv::Archived<String>, Url, D> for EncodeUrl
285where
286    D: ?Sized + rancor::Fallible,
287{
288    #[inline]
289    fn deserialize_with(field: &rkyv::string::ArchivedString, _: &mut D) -> Result<Url, D::Error> {
290        Ok(Url::parse(field.as_str()).unwrap())
291    }
292}
293
294impl std::fmt::Display for FileName {
295    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296        match *self {
297            FileName::Real(ref path) => write!(fmt, "{}", path.display()),
298            FileName::Macros(ref name) => write!(fmt, "<{name} macros>"),
299            FileName::QuoteExpansion => write!(fmt, "<quote expansion>"),
300            FileName::MacroExpansion => write!(fmt, "<macro expansion>"),
301            FileName::Anon => write!(fmt, "<anon>"),
302            FileName::ProcMacroSourceCode => write!(fmt, "<proc-macro source code>"),
303            FileName::Url(ref u) => write!(fmt, "{u}"),
304            FileName::Custom(ref s) => {
305                write!(fmt, "{s}")
306            }
307            FileName::Internal(ref s) => write!(fmt, "<{s}>"),
308        }
309    }
310}
311
312impl From<PathBuf> for FileName {
313    fn from(p: PathBuf) -> Self {
314        assert!(!p.to_string_lossy().ends_with('>'));
315        FileName::Real(p)
316    }
317}
318
319impl From<Url> for FileName {
320    fn from(url: Url) -> Self {
321        FileName::Url(url)
322    }
323}
324
325impl FileName {
326    pub fn is_real(&self) -> bool {
327        match *self {
328            FileName::Real(_) => true,
329            FileName::Macros(_)
330            | FileName::Anon
331            | FileName::MacroExpansion
332            | FileName::ProcMacroSourceCode
333            | FileName::Custom(_)
334            | FileName::QuoteExpansion
335            | FileName::Internal(_)
336            | FileName::Url(_) => false,
337        }
338    }
339
340    pub fn is_macros(&self) -> bool {
341        match *self {
342            FileName::Real(_)
343            | FileName::Anon
344            | FileName::MacroExpansion
345            | FileName::ProcMacroSourceCode
346            | FileName::Custom(_)
347            | FileName::QuoteExpansion
348            | FileName::Internal(_)
349            | FileName::Url(_) => false,
350            FileName::Macros(_) => true,
351        }
352    }
353}
354
355#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
356#[cfg_attr(
357    feature = "diagnostic-serde",
358    derive(serde::Serialize, serde::Deserialize)
359)]
360#[cfg_attr(
361    any(feature = "rkyv-impl"),
362    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
363)]
364#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
365#[cfg_attr(feature = "rkyv-impl", repr(C))]
366pub struct PrimarySpanLabel(pub Span, pub String);
367
368#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
375#[cfg_attr(
376    feature = "diagnostic-serde",
377    derive(serde::Serialize, serde::Deserialize)
378)]
379#[cfg_attr(
380    any(feature = "rkyv-impl"),
381    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
382)]
383#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
384#[cfg_attr(feature = "rkyv-impl", repr(C))]
385pub struct MultiSpan {
386    primary_spans: Vec<Span>,
387    span_labels: Vec<PrimarySpanLabel>,
388}
389
390extern "C" {
391    fn __span_dummy_with_cmt_proxy() -> u32;
392}
393
394impl Span {
395    #[inline]
396    pub fn lo(self) -> BytePos {
397        self.lo
398    }
399
400    #[inline]
401    pub fn new(mut lo: BytePos, mut hi: BytePos) -> Self {
402        if lo > hi {
403            std::mem::swap(&mut lo, &mut hi);
404        }
405
406        Span { lo, hi }
407    }
408
409    #[inline]
410    #[track_caller]
411    pub fn new_with_checked(lo: BytePos, hi: BytePos) -> Self {
412        debug_assert!(lo <= hi, "lo: {lo:#?}, hi: {hi:#?}");
413        Span { lo, hi }
414    }
415
416    #[inline]
417    pub fn with_lo(&self, lo: BytePos) -> Span {
418        Span::new(lo, self.hi)
419    }
420
421    #[inline(always)]
422    pub fn hi(self) -> BytePos {
423        self.hi
424    }
425
426    #[inline]
427    pub fn with_hi(&self, hi: BytePos) -> Span {
428        Span::new(self.lo, hi)
429    }
430
431    #[inline]
433    pub fn is_dummy(self) -> bool {
434        self.lo.0 == 0 && self.hi.0 == 0 || self.lo.0 >= DUMMY_RESERVE
435    }
436
437    #[inline]
438    pub fn is_pure(self) -> bool {
439        self.lo.is_pure()
440    }
441
442    #[inline]
443    pub fn is_placeholder(self) -> bool {
444        self.lo.is_placeholder()
445    }
446
447    #[inline]
449    pub fn is_dummy_ignoring_cmt(self) -> bool {
450        self.lo.0 == 0 && self.hi.0 == 0
451    }
452
453    #[inline]
456    pub fn shrink_to_lo(self) -> Span {
457        self.with_hi(self.lo)
458    }
459
460    #[inline]
462    pub fn shrink_to_hi(self) -> Span {
463        self.with_lo(self.hi)
464    }
465
466    pub fn substitute_dummy(self, other: Span) -> Span {
468        if self.is_dummy() {
469            other
470        } else {
471            self
472        }
473    }
474
475    pub fn contains(self, other: Span) -> bool {
477        self.lo <= other.lo && other.hi <= self.hi
478    }
479
480    pub fn source_equal(self, other: Span) -> bool {
485        self.lo == other.lo && self.hi == other.hi
486    }
487
488    pub fn trim_start(self, other: Span) -> Option<Span> {
490        if self.hi > other.hi {
491            Some(self.with_lo(cmp::max(self.lo, other.hi)))
492        } else {
493            None
494        }
495    }
496
497    pub fn to(self, end: Span) -> Span {
499        let span_data = self;
500        let end_data = end;
501        Span::new(
507            cmp::min(span_data.lo, end_data.lo),
508            cmp::max(span_data.hi, end_data.hi),
509        )
510    }
511
512    pub fn between(self, end: Span) -> Span {
514        let span = self;
515        Span::new(span.hi, end.lo)
516    }
517
518    pub fn until(self, end: Span) -> Span {
521        let span = self;
522        Span::new(span.lo, end.lo)
523    }
524
525    pub fn from_inner_byte_pos(self, start: usize, end: usize) -> Span {
526        let span = self;
527        Span::new(
528            span.lo + BytePos::from_usize(start),
529            span.lo + BytePos::from_usize(end),
530        )
531    }
532
533    pub fn dummy_with_cmt() -> Self {
536        #[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
537        {
538            let lo = BytePos(unsafe { __span_dummy_with_cmt_proxy() });
539
540            return Span { lo, hi: lo };
541        }
542
543        #[cfg(not(all(any(feature = "__plugin_mode"), target_arch = "wasm32")))]
544        return GLOBALS.with(|globals| {
545            let lo = BytePos(
546                globals
547                    .dummy_cnt
548                    .fetch_add(1, std::sync::atomic::Ordering::SeqCst),
549            );
550            Span { lo, hi: lo }
551        });
552    }
553}
554
555#[derive(Clone, Debug)]
556pub struct SpanLabel {
557    pub span: Span,
559
560    pub is_primary: bool,
563
564    pub label: Option<String>,
566}
567
568impl Default for Span {
569    fn default() -> Self {
570        DUMMY_SP
571    }
572}
573
574impl MultiSpan {
575    #[inline]
576    pub fn new() -> MultiSpan {
577        Self::default()
578    }
579
580    pub fn from_span(primary_span: Span) -> MultiSpan {
581        MultiSpan {
582            primary_spans: vec![primary_span],
583            span_labels: Vec::new(),
584        }
585    }
586
587    pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
588        MultiSpan {
589            primary_spans: vec,
590            span_labels: Vec::new(),
591        }
592    }
593
594    pub fn push_span_label(&mut self, span: Span, label: String) {
595        self.span_labels.push(PrimarySpanLabel(span, label));
596    }
597
598    pub fn primary_span(&self) -> Option<Span> {
600        self.primary_spans.first().cloned()
601    }
602
603    pub fn primary_spans(&self) -> &[Span] {
605        &self.primary_spans
606    }
607
608    pub fn is_dummy(&self) -> bool {
611        let mut is_dummy = true;
612        for span in &self.primary_spans {
613            if !span.is_dummy() {
614                is_dummy = false;
615            }
616        }
617        is_dummy
618    }
619
620    pub fn replace(&mut self, before: Span, after: Span) -> bool {
624        let mut replacements_occurred = false;
625        for primary_span in &mut self.primary_spans {
626            if *primary_span == before {
627                *primary_span = after;
628                replacements_occurred = true;
629            }
630        }
631        for span_label in &mut self.span_labels {
632            if span_label.0 == before {
633                span_label.0 = after;
634                replacements_occurred = true;
635            }
636        }
637        replacements_occurred
638    }
639
640    pub fn span_labels(&self) -> Vec<SpanLabel> {
646        let is_primary = |span| self.primary_spans.contains(&span);
647
648        let mut span_labels = self
649            .span_labels
650            .iter()
651            .map(|&PrimarySpanLabel(span, ref label)| SpanLabel {
652                span,
653                is_primary: is_primary(span),
654                label: Some(label.clone()),
655            })
656            .collect::<Vec<_>>();
657
658        for &span in &self.primary_spans {
659            if !span_labels.iter().any(|sl| sl.span == span) {
660                span_labels.push(SpanLabel {
661                    span,
662                    is_primary: true,
663                    label: None,
664                });
665            }
666        }
667
668        span_labels
669    }
670}
671
672impl From<Span> for MultiSpan {
673    fn from(span: Span) -> MultiSpan {
674        MultiSpan::from_span(span)
675    }
676}
677
678impl From<Vec<Span>> for MultiSpan {
679    fn from(spans: Vec<Span>) -> MultiSpan {
680        MultiSpan::from_spans(spans)
681    }
682}
683
684pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
685
686#[cfg_attr(
688    any(feature = "rkyv-impl"),
689    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
690)]
691#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
692#[cfg_attr(feature = "rkyv-impl", repr(C))]
693#[derive(Copy, Clone, Eq, PartialEq, Debug)]
694pub struct MultiByteChar {
695    pub pos: BytePos,
697    pub bytes: u8,
699}
700
701impl MultiByteChar {
702    pub fn byte_to_char_diff(&self) -> u8 {
708        if self.bytes == 4 {
709            2
710        } else {
711            self.bytes - 1
712        }
713    }
714}
715
716#[cfg_attr(
718    any(feature = "rkyv-impl"),
719    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
720)]
721#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
722#[cfg_attr(feature = "rkyv-impl", repr(u32))]
723#[derive(Copy, Clone, Eq, PartialEq, Debug)]
724pub enum NonNarrowChar {
725    ZeroWidth(BytePos),
727    Wide(BytePos, usize),
729    Tab(BytePos),
732}
733
734impl NonNarrowChar {
735    fn new(pos: BytePos, width: usize) -> Self {
736        match width {
737            0 => NonNarrowChar::ZeroWidth(pos),
738            4 => NonNarrowChar::Tab(pos),
739            w => NonNarrowChar::Wide(pos, w),
740        }
741    }
742
743    pub fn pos(self) -> BytePos {
745        match self {
746            NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p, _) | NonNarrowChar::Tab(p) => p,
747        }
748    }
749
750    pub fn width(self) -> usize {
752        match self {
753            NonNarrowChar::ZeroWidth(_) => 0,
754            NonNarrowChar::Wide(_, width) => width,
755            NonNarrowChar::Tab(_) => 4,
756        }
757    }
758}
759
760impl Add<BytePos> for NonNarrowChar {
761    type Output = Self;
762
763    fn add(self, rhs: BytePos) -> Self {
764        match self {
765            NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
766            NonNarrowChar::Wide(pos, width) => NonNarrowChar::Wide(pos + rhs, width),
767            NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs),
768        }
769    }
770}
771
772impl Sub<BytePos> for NonNarrowChar {
773    type Output = Self;
774
775    fn sub(self, rhs: BytePos) -> Self {
776        match self {
777            NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
778            NonNarrowChar::Wide(pos, width) => NonNarrowChar::Wide(pos - rhs, width),
779            NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs),
780        }
781    }
782}
783
784#[cfg_attr(
786    any(feature = "rkyv-impl"),
787    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
788)]
789#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
790#[cfg_attr(feature = "rkyv-impl", repr(C))]
791#[derive(Clone)]
792pub struct SourceFile {
793    pub name: Lrc<FileName>,
797    pub name_was_remapped: bool,
800    pub unmapped_path: Option<Lrc<FileName>>,
803    pub crate_of_origin: u32,
805    pub src: BytesStr,
807    pub src_hash: u128,
809    pub start_pos: BytePos,
811    pub end_pos: BytePos,
813    pub name_hash: u128,
815
816    lazy: CacheCell<SourceFileAnalysis>,
817}
818
819#[cfg_attr(
820    any(feature = "rkyv-impl"),
821    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
822)]
823#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
824#[cfg_attr(feature = "rkyv-impl", repr(C))]
825#[derive(Clone)]
826pub struct SourceFileAnalysis {
827    pub lines: Vec<BytePos>,
829    pub multibyte_chars: Vec<MultiByteChar>,
831    pub non_narrow_chars: Vec<NonNarrowChar>,
833}
834
835impl fmt::Debug for SourceFile {
836    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
837        write!(fmt, "SourceFile({})", self.name)
838    }
839}
840
841impl SourceFile {
842    pub fn new(
844        name: Lrc<FileName>,
845        name_was_remapped: bool,
846        unmapped_path: Lrc<FileName>,
847        src: BytesStr,
848        start_pos: BytePos,
849    ) -> SourceFile {
850        debug_assert_ne!(
851            start_pos,
852            BytePos::DUMMY,
853            "BytePos::DUMMY is reserved and `SourceFile` should not use it"
854        );
855
856        let src_hash = {
857            let mut hasher: StableHasher = StableHasher::new();
858            hasher.write(src.as_bytes());
859            hasher.finish()
860        };
861        let name_hash = {
862            let mut hasher: StableHasher = StableHasher::new();
863            name.hash(&mut hasher);
864            hasher.finish()
865        };
866        let end_pos = start_pos.to_usize() + src.len();
867
868        SourceFile {
869            name,
870            name_was_remapped,
871            unmapped_path: Some(unmapped_path),
872            crate_of_origin: 0,
873            src,
874            src_hash,
875            start_pos,
876            end_pos: SmallPos::from_usize(end_pos),
877            name_hash,
878            lazy: CacheCell::new(),
879        }
880    }
881
882    pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
884        let line_index = self.lookup_line(pos).unwrap();
885        let analysis = self.analyze();
886        analysis.lines[line_index]
887    }
888
889    pub fn get_line(&self, line_number: usize) -> Option<Cow<'_, str>> {
892        fn get_until_newline(src: &str, begin: usize) -> &str {
893            let slice = &src[begin..];
897            match slice.find('\n') {
898                Some(e) => &slice[..e],
899                None => slice,
900            }
901        }
902
903        let begin = {
904            let analysis = self.analyze();
905            let line = analysis.lines.get(line_number)?;
906            let begin: BytePos = *line - self.start_pos;
907            begin.to_usize()
908        };
909
910        Some(Cow::from(get_until_newline(&self.src, begin)))
911    }
912
913    pub fn is_real_file(&self) -> bool {
914        self.name.is_real()
915    }
916
917    pub fn byte_length(&self) -> u32 {
918        self.end_pos.0 - self.start_pos.0
919    }
920
921    pub fn count_lines(&self) -> usize {
922        let analysis = self.analyze();
923        analysis.lines.len()
924    }
925
926    pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
931        let analysis = self.analyze();
932        if analysis.lines.is_empty() {
933            return None;
934        }
935
936        let line_index = lookup_line(&analysis.lines, pos);
937        assert!(line_index < analysis.lines.len() as isize);
938        if line_index >= 0 {
939            Some(line_index as usize)
940        } else {
941            None
942        }
943    }
944
945    pub fn line_bounds(&self, line_index: usize) -> (BytePos, BytePos) {
946        if self.start_pos == self.end_pos {
947            return (self.start_pos, self.end_pos);
948        }
949
950        let analysis = self.analyze();
951
952        assert!(line_index < analysis.lines.len());
953        if line_index == (analysis.lines.len() - 1) {
954            (analysis.lines[line_index], self.end_pos)
955        } else {
956            (analysis.lines[line_index], analysis.lines[line_index + 1])
957        }
958    }
959
960    #[inline]
961    pub fn contains(&self, byte_pos: BytePos) -> bool {
962        byte_pos >= self.start_pos && byte_pos <= self.end_pos
963    }
964
965    pub fn analyze(&self) -> &SourceFileAnalysis {
966        self.lazy.get_or_init(|| {
967            let (lines, multibyte_chars, non_narrow_chars) =
968                analyze_source_file::analyze_source_file(&self.src[..], self.start_pos);
969            SourceFileAnalysis {
970                lines,
971                multibyte_chars,
972                non_narrow_chars,
973            }
974        })
975    }
976}
977
978pub trait SmallPos {
983    fn from_usize(n: usize) -> Self;
984    fn to_usize(&self) -> usize;
985    fn from_u32(n: u32) -> Self;
986    fn to_u32(&self) -> u32;
987}
988
989#[derive(
1002    Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize, Default,
1003)]
1004#[serde(transparent)]
1005#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1006#[cfg_attr(
1007    any(feature = "rkyv-impl"),
1008    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1009)]
1010#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1011#[cfg_attr(feature = "rkyv-impl", repr(C))]
1012#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
1013pub struct BytePos(#[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub u32);
1014
1015impl BytePos {
1016    pub const DUMMY: Self = BytePos(0);
1018    const MIN_RESERVED: Self = BytePos(DUMMY_RESERVE);
1019    pub const PLACEHOLDER: Self = BytePos(u32::MAX - 2);
1022    pub const PURE: Self = BytePos(u32::MAX - 1);
1024    pub const SYNTHESIZED: Self = BytePos(u32::MAX);
1026
1027    pub const fn is_reserved_for_comments(self) -> bool {
1028        self.0 >= Self::MIN_RESERVED.0 && self.0 != u32::MAX
1029    }
1030
1031    pub const fn is_dummy(self) -> bool {
1034        self.0 == 0
1035    }
1036
1037    pub const fn is_pure(self) -> bool {
1038        self.0 == Self::PURE.0
1039    }
1040
1041    pub const fn is_placeholder(self) -> bool {
1042        self.0 == Self::PLACEHOLDER.0
1043    }
1044
1045    pub const fn can_have_comment(self) -> bool {
1048        self.0 != 0
1049    }
1050}
1051
1052#[cfg_attr(
1056    any(feature = "rkyv-impl"),
1057    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1058)]
1059#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1060#[cfg_attr(feature = "rkyv-impl", repr(C))]
1061#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1062pub struct CharPos(pub usize);
1063
1064impl SmallPos for BytePos {
1068    #[inline(always)]
1069    fn from_usize(n: usize) -> BytePos {
1070        BytePos(n as u32)
1071    }
1072
1073    #[inline(always)]
1074    fn to_usize(&self) -> usize {
1075        self.0 as usize
1076    }
1077
1078    #[inline(always)]
1079    fn from_u32(n: u32) -> BytePos {
1080        BytePos(n)
1081    }
1082
1083    #[inline(always)]
1084    fn to_u32(&self) -> u32 {
1085        self.0
1086    }
1087}
1088
1089impl Add for BytePos {
1090    type Output = BytePos;
1091
1092    #[inline(always)]
1093    fn add(self, rhs: BytePos) -> BytePos {
1094        BytePos((self.to_usize() + rhs.to_usize()) as u32)
1095    }
1096}
1097
1098impl Sub for BytePos {
1099    type Output = BytePos;
1100
1101    #[inline(always)]
1102    fn sub(self, rhs: BytePos) -> BytePos {
1103        BytePos((self.to_usize() - rhs.to_usize()) as u32)
1104    }
1105}
1106
1107impl SmallPos for CharPos {
1108    #[inline(always)]
1109    fn from_usize(n: usize) -> CharPos {
1110        CharPos(n)
1111    }
1112
1113    #[inline(always)]
1114    fn to_usize(&self) -> usize {
1115        self.0
1116    }
1117
1118    #[inline(always)]
1119    fn from_u32(n: u32) -> CharPos {
1120        CharPos(n as usize)
1121    }
1122
1123    #[inline(always)]
1124    fn to_u32(&self) -> u32 {
1125        self.0 as u32
1126    }
1127}
1128
1129impl Add for CharPos {
1130    type Output = CharPos;
1131
1132    #[inline(always)]
1133    fn add(self, rhs: CharPos) -> CharPos {
1134        CharPos(self.to_usize() + rhs.to_usize())
1135    }
1136}
1137
1138impl Sub for CharPos {
1139    type Output = CharPos;
1140
1141    #[inline(always)]
1142    fn sub(self, rhs: CharPos) -> CharPos {
1143        CharPos(self.to_usize() - rhs.to_usize())
1144    }
1145}
1146
1147#[derive(Debug, Clone)]
1158pub struct Loc {
1159    pub file: Lrc<SourceFile>,
1161    pub line: usize,
1163    pub col: CharPos,
1165    pub col_display: usize,
1167}
1168
1169#[cfg_attr(
1172    any(feature = "rkyv-impl"),
1173    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Debug, Clone)
1174)]
1175#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1176#[cfg_attr(feature = "rkyv-impl", repr(C))]
1177pub struct PartialLoc {
1178    pub source_file: Option<Lrc<SourceFile>>,
1179    pub line: usize,
1180    pub col: usize,
1181    pub col_display: usize,
1182}
1183
1184#[derive(Debug)]
1188pub struct LocWithOpt {
1189    pub filename: Lrc<FileName>,
1190    pub line: usize,
1191    pub col: CharPos,
1192    pub file: Option<Lrc<SourceFile>>,
1193}
1194
1195#[derive(Debug)]
1197pub struct SourceFileAndLine {
1198    pub sf: Lrc<SourceFile>,
1199    pub line: usize,
1200}
1201
1202#[cfg_attr(
1203    any(feature = "rkyv-impl"),
1204    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1205)]
1206#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1207#[cfg_attr(feature = "rkyv-impl", repr(C))]
1208#[derive(Debug)]
1209pub struct SourceFileAndBytePos {
1210    pub sf: Lrc<SourceFile>,
1211    pub pos: BytePos,
1212}
1213
1214#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1215#[cfg_attr(
1216    any(feature = "rkyv-impl"),
1217    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1218)]
1219#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1220#[cfg_attr(feature = "rkyv-impl", repr(C))]
1221pub struct LineInfo {
1222    pub line_index: usize,
1224
1225    pub start_col: CharPos,
1227
1228    pub end_col: CharPos,
1230}
1231
1232#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1234pub struct LineCol {
1235    pub line: u32,
1237
1238    pub col: u32,
1240}
1241
1242pub struct FileLines {
1249    pub file: Lrc<SourceFile>,
1250    pub lines: Vec<LineInfo>,
1251}
1252
1253#[cfg_attr(
1256    any(feature = "rkyv-impl"),
1257    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Debug, Clone)
1258)]
1259#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1260#[cfg_attr(feature = "rkyv-impl", repr(C))]
1261pub struct PartialFileLines {
1262    pub file: Option<Lrc<SourceFile>>,
1263    pub lines: Vec<LineInfo>,
1264}
1265
1266pub type FileLinesResult = Result<FileLines, Box<SpanLinesError>>;
1272#[cfg(feature = "__plugin")]
1273pub type PartialFileLinesResult = Result<PartialFileLines, Box<SpanLinesError>>;
1274
1275#[derive(Clone, PartialEq, Eq, Debug)]
1276#[cfg_attr(
1277    any(feature = "rkyv-impl"),
1278    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1279)]
1280#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1281#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1282pub enum SpanLinesError {
1283    IllFormedSpan(Span),
1284    DistinctSources(DistinctSources),
1285}
1286
1287#[derive(Clone, PartialEq, Eq, Debug)]
1288#[cfg_attr(
1289    any(feature = "rkyv-impl"),
1290    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1291)]
1292#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1293#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1294pub enum SpanSnippetError {
1295    DummyBytePos,
1296    IllFormedSpan(Span),
1297    DistinctSources(DistinctSources),
1298    MalformedForSourcemap(MalformedSourceMapPositions),
1299    SourceNotAvailable { filename: FileName },
1300    LookupFailed(SourceMapLookupError),
1301}
1302
1303#[derive(Clone, PartialEq, Eq, Debug)]
1308#[cfg_attr(
1309    any(feature = "rkyv-impl"),
1310    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1311)]
1312#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1313#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1314pub enum SourceMapLookupError {
1315    NoFileFor(BytePos),
1316}
1317
1318#[derive(Clone, PartialEq, Eq, Debug)]
1319#[cfg_attr(
1320    any(feature = "rkyv-impl"),
1321    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1322)]
1323#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1324#[cfg_attr(feature = "rkyv-impl", repr(C))]
1325pub struct FilePos(pub Lrc<FileName>, pub BytePos);
1326
1327#[derive(Clone, PartialEq, Eq, Debug)]
1328#[cfg_attr(
1329    any(feature = "rkyv-impl"),
1330    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1331)]
1332#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1333#[cfg_attr(feature = "rkyv-impl", repr(C))]
1334pub struct DistinctSources {
1335    pub begin: FilePos,
1336    pub end: FilePos,
1337}
1338
1339#[derive(Clone, PartialEq, Eq, Debug)]
1340#[cfg_attr(
1341    any(feature = "rkyv-impl"),
1342    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1343)]
1344#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1345#[cfg_attr(feature = "rkyv-impl", repr(C))]
1346pub struct MalformedSourceMapPositions {
1347    pub name: Lrc<FileName>,
1348    pub source_len: usize,
1349    pub begin_pos: BytePos,
1350    pub end_pos: BytePos,
1351}
1352
1353fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize {
1357    match lines.binary_search(&pos) {
1358        Ok(line) => line as isize,
1359        Err(line) => line as isize - 1,
1360    }
1361}
1362
1363impl From<SourceMapLookupError> for Box<SpanSnippetError> {
1364    #[cold]
1365    fn from(err: SourceMapLookupError) -> Self {
1366        Box::new(SpanSnippetError::LookupFailed(err))
1367    }
1368}
1369
1370#[cfg(test)]
1371mod tests {
1372    use super::{lookup_line, BytePos, Span};
1373
1374    #[test]
1375    fn test_lookup_line() {
1376        let lines = &[BytePos(3), BytePos(17), BytePos(28)];
1377
1378        assert_eq!(lookup_line(lines, BytePos(0)), -1);
1379        assert_eq!(lookup_line(lines, BytePos(3)), 0);
1380        assert_eq!(lookup_line(lines, BytePos(4)), 0);
1381
1382        assert_eq!(lookup_line(lines, BytePos(16)), 0);
1383        assert_eq!(lookup_line(lines, BytePos(17)), 1);
1384        assert_eq!(lookup_line(lines, BytePos(18)), 1);
1385
1386        assert_eq!(lookup_line(lines, BytePos(28)), 2);
1387        assert_eq!(lookup_line(lines, BytePos(29)), 2);
1388    }
1389
1390    #[test]
1391    fn size_of_span() {
1392        assert_eq!(std::mem::size_of::<Span>(), 8);
1393    }
1394}