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 = "encoding-impl")]
202impl cbor4ii::core::enc::Encode for FileName {
203 #[inline]
204 fn encode<W: cbor4ii::core::enc::Write>(
205 &self,
206 writer: &mut W,
207 ) -> Result<(), cbor4ii::core::enc::Error<W::Error>> {
208 use cbor4ii::core::types::{Array, Nothing, Tag};
209
210 match self {
211 FileName::Real(name) => {
212 let name = name.to_str().unwrap();
213 Tag(1, name).encode(writer)?;
214 }
215 FileName::Macros(name) => Tag(2, name).encode(writer)?,
216 FileName::QuoteExpansion => {
217 Tag(3, Nothing).encode(writer)?;
218 Array::bounded(0, writer)?;
219 }
220 FileName::Anon => {
221 Tag(4, Nothing).encode(writer)?;
222 Array::bounded(0, writer)?;
223 }
224 FileName::MacroExpansion => {
225 Tag(5, Nothing).encode(writer)?;
226 Array::bounded(0, writer)?;
227 }
228 FileName::ProcMacroSourceCode => {
229 Tag(6, Nothing).encode(writer)?;
230 Array::bounded(0, writer)?;
231 }
232 FileName::Url(name) => Tag(7, name.as_str()).encode(writer)?,
233 FileName::Internal(name) => Tag(8, name).encode(writer)?,
234 FileName::Custom(name) => Tag(9, name).encode(writer)?,
235 }
236
237 Ok(())
238 }
239}
240
241#[cfg(feature = "encoding-impl")]
242impl<'de> cbor4ii::core::dec::Decode<'de> for FileName {
243 #[inline]
244 fn decode<R: cbor4ii::core::dec::Read<'de>>(
245 reader: &mut R,
246 ) -> Result<Self, cbor4ii::core::dec::Error<R::Error>> {
247 use cbor4ii::core::types::{Array, Tag};
248
249 let tag = Tag::tag(reader)?;
250 match tag {
251 1 => {
252 let name = String::decode(reader)?;
253 Ok(FileName::Real(PathBuf::from(name)))
254 }
255 2 => {
256 let name = String::decode(reader)?;
257 Ok(FileName::Macros(name))
258 }
259 3 => {
260 let n = Array::len(reader)?;
261 debug_assert_eq!(n, Some(0));
262 Ok(FileName::QuoteExpansion)
263 }
264 4 => {
265 let n = Array::len(reader)?;
266 debug_assert_eq!(n, Some(0));
267 Ok(FileName::Anon)
268 }
269 5 => {
270 let n = Array::len(reader)?;
271 debug_assert_eq!(n, Some(0));
272 Ok(FileName::MacroExpansion)
273 }
274 6 => {
275 let n = Array::len(reader)?;
276 debug_assert_eq!(n, Some(0));
277 Ok(FileName::ProcMacroSourceCode)
278 }
279 7 => {
280 let name = <&str>::decode(reader)?;
281 Ok(FileName::Url(Url::parse(name).unwrap()))
282 }
283 8 => {
284 let name = String::decode(reader)?;
285 Ok(FileName::Internal(name))
286 }
287 9 => {
288 let name = String::decode(reader)?;
289 Ok(FileName::Custom(name))
290 }
291 tag => Err(cbor4ii::core::error::DecodeError::Custom {
292 name: &"FileName",
293 num: tag as u32,
294 }),
295 }
296 }
297}
298
299#[cfg(feature = "rkyv-impl")]
309#[derive(Debug, Clone, Copy)]
310#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
311#[cfg_attr(feature = "rkyv-impl", repr(C))]
312pub struct EncodePathBuf;
313
314#[cfg(feature = "rkyv-impl")]
315impl rkyv::with::ArchiveWith<PathBuf> for EncodePathBuf {
316 type Archived = rkyv::string::ArchivedString;
317 type Resolver = rkyv::string::StringResolver;
318
319 #[inline]
320 fn resolve_with(field: &PathBuf, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
321 rkyv::string::ArchivedString::resolve_from_str(field.to_str().unwrap(), resolver, out);
324 }
325}
326
327#[cfg(feature = "rkyv-impl")]
328impl<S> rkyv::with::SerializeWith<PathBuf, S> for EncodePathBuf
329where
330 S: ?Sized + rancor::Fallible + rkyv::ser::Writer,
331 S::Error: rancor::Source,
332{
333 #[inline]
334 fn serialize_with(field: &PathBuf, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
335 let s = field.to_str().unwrap_or_default();
336 rkyv::string::ArchivedString::serialize_from_str(s, serializer)
337 }
338}
339
340#[cfg(feature = "rkyv-impl")]
341impl<D> rkyv::with::DeserializeWith<rkyv::string::ArchivedString, PathBuf, D> for EncodePathBuf
342where
343 D: ?Sized + rancor::Fallible,
344{
345 #[inline]
346 fn deserialize_with(
347 field: &rkyv::string::ArchivedString,
348 _: &mut D,
349 ) -> Result<PathBuf, D::Error> {
350 Ok(<PathBuf as std::str::FromStr>::from_str(field.as_str()).unwrap())
351 }
352}
353
354#[cfg(feature = "rkyv-impl")]
356#[derive(Debug, Clone, Copy)]
357#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
358#[cfg_attr(feature = "rkyv-impl", repr(C))]
359pub struct EncodeUrl;
360
361#[cfg(feature = "rkyv-impl")]
362impl rkyv::with::ArchiveWith<Url> for EncodeUrl {
363 type Archived = rkyv::string::ArchivedString;
364 type Resolver = rkyv::string::StringResolver;
365
366 #[inline]
367 fn resolve_with(field: &Url, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
368 rkyv::string::ArchivedString::resolve_from_str(field.as_str(), resolver, out);
369 }
370}
371
372#[cfg(feature = "rkyv-impl")]
373impl<S> rkyv::with::SerializeWith<Url, S> for EncodeUrl
374where
375 S: ?Sized + rancor::Fallible + rkyv::ser::Writer,
376 S::Error: rancor::Source,
377{
378 #[inline]
379 fn serialize_with(field: &Url, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
380 let field = field.as_str();
381 rkyv::string::ArchivedString::serialize_from_str(field, serializer)
382 }
383}
384
385#[cfg(feature = "rkyv-impl")]
386impl<D> rkyv::with::DeserializeWith<rkyv::Archived<String>, Url, D> for EncodeUrl
387where
388 D: ?Sized + rancor::Fallible,
389{
390 #[inline]
391 fn deserialize_with(field: &rkyv::string::ArchivedString, _: &mut D) -> Result<Url, D::Error> {
392 Ok(Url::parse(field.as_str()).unwrap())
393 }
394}
395
396impl std::fmt::Display for FileName {
397 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
398 match *self {
399 FileName::Real(ref path) => write!(fmt, "{}", path.display()),
400 FileName::Macros(ref name) => write!(fmt, "<{name} macros>"),
401 FileName::QuoteExpansion => write!(fmt, "<quote expansion>"),
402 FileName::MacroExpansion => write!(fmt, "<macro expansion>"),
403 FileName::Anon => write!(fmt, "<anon>"),
404 FileName::ProcMacroSourceCode => write!(fmt, "<proc-macro source code>"),
405 FileName::Url(ref u) => write!(fmt, "{u}"),
406 FileName::Custom(ref s) => {
407 write!(fmt, "{s}")
408 }
409 FileName::Internal(ref s) => write!(fmt, "<{s}>"),
410 }
411 }
412}
413
414impl From<PathBuf> for FileName {
415 fn from(p: PathBuf) -> Self {
416 assert!(!p.to_string_lossy().ends_with('>'));
417 FileName::Real(p)
418 }
419}
420
421impl From<Url> for FileName {
422 fn from(url: Url) -> Self {
423 FileName::Url(url)
424 }
425}
426
427impl FileName {
428 pub fn is_real(&self) -> bool {
429 match *self {
430 FileName::Real(_) => true,
431 FileName::Macros(_)
432 | FileName::Anon
433 | FileName::MacroExpansion
434 | FileName::ProcMacroSourceCode
435 | FileName::Custom(_)
436 | FileName::QuoteExpansion
437 | FileName::Internal(_)
438 | FileName::Url(_) => false,
439 }
440 }
441
442 pub fn is_macros(&self) -> bool {
443 match *self {
444 FileName::Real(_)
445 | FileName::Anon
446 | FileName::MacroExpansion
447 | FileName::ProcMacroSourceCode
448 | FileName::Custom(_)
449 | FileName::QuoteExpansion
450 | FileName::Internal(_)
451 | FileName::Url(_) => false,
452 FileName::Macros(_) => true,
453 }
454 }
455}
456
457#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
458#[cfg_attr(
459 feature = "diagnostic-serde",
460 derive(serde::Serialize, serde::Deserialize)
461)]
462#[cfg_attr(
463 any(feature = "rkyv-impl"),
464 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
465)]
466#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
467#[cfg_attr(feature = "rkyv-impl", repr(C))]
468#[cfg_attr(
469 feature = "encoding-impl",
470 derive(::ast_node::Encode, ::ast_node::Decode)
471)]
472pub struct PrimarySpanLabel(pub Span, pub String);
473
474#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
481#[cfg_attr(
482 feature = "diagnostic-serde",
483 derive(serde::Serialize, serde::Deserialize)
484)]
485#[cfg_attr(
486 any(feature = "rkyv-impl"),
487 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
488)]
489#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
490#[cfg_attr(feature = "rkyv-impl", repr(C))]
491#[cfg_attr(
492 feature = "encoding-impl",
493 derive(::ast_node::Encode, ::ast_node::Decode)
494)]
495pub struct MultiSpan {
496 primary_spans: Vec<Span>,
497 span_labels: Vec<PrimarySpanLabel>,
498}
499
500extern "C" {
501 fn __span_dummy_with_cmt_proxy() -> u32;
502}
503
504impl Span {
505 #[inline]
506 pub fn lo(self) -> BytePos {
507 self.lo
508 }
509
510 #[inline]
511 pub fn new(mut lo: BytePos, mut hi: BytePos) -> Self {
512 if lo > hi {
513 std::mem::swap(&mut lo, &mut hi);
514 }
515
516 Span { lo, hi }
517 }
518
519 #[inline]
520 #[track_caller]
521 pub fn new_with_checked(lo: BytePos, hi: BytePos) -> Self {
522 debug_assert!(lo <= hi, "lo: {lo:#?}, hi: {hi:#?}");
523 Span { lo, hi }
524 }
525
526 #[inline]
527 pub fn with_lo(&self, lo: BytePos) -> Span {
528 Span::new(lo, self.hi)
529 }
530
531 #[inline(always)]
532 pub fn hi(self) -> BytePos {
533 self.hi
534 }
535
536 #[inline]
537 pub fn with_hi(&self, hi: BytePos) -> Span {
538 Span::new(self.lo, hi)
539 }
540
541 #[inline]
543 pub fn is_dummy(self) -> bool {
544 self.lo.0 == 0 && self.hi.0 == 0 || self.lo.0 >= DUMMY_RESERVE
545 }
546
547 #[inline]
548 pub fn is_pure(self) -> bool {
549 self.lo.is_pure()
550 }
551
552 #[inline]
553 pub fn is_placeholder(self) -> bool {
554 self.lo.is_placeholder()
555 }
556
557 #[inline]
559 pub fn is_dummy_ignoring_cmt(self) -> bool {
560 self.lo.0 == 0 && self.hi.0 == 0
561 }
562
563 #[inline]
566 pub fn shrink_to_lo(self) -> Span {
567 self.with_hi(self.lo)
568 }
569
570 #[inline]
572 pub fn shrink_to_hi(self) -> Span {
573 self.with_lo(self.hi)
574 }
575
576 pub fn substitute_dummy(self, other: Span) -> Span {
578 if self.is_dummy() {
579 other
580 } else {
581 self
582 }
583 }
584
585 pub fn contains(self, other: Span) -> bool {
587 self.lo <= other.lo && other.hi <= self.hi
588 }
589
590 pub fn source_equal(self, other: Span) -> bool {
595 self.lo == other.lo && self.hi == other.hi
596 }
597
598 pub fn trim_start(self, other: Span) -> Option<Span> {
600 if self.hi > other.hi {
601 Some(self.with_lo(cmp::max(self.lo, other.hi)))
602 } else {
603 None
604 }
605 }
606
607 pub fn to(self, end: Span) -> Span {
609 let span_data = self;
610 let end_data = end;
611 Span::new(
617 cmp::min(span_data.lo, end_data.lo),
618 cmp::max(span_data.hi, end_data.hi),
619 )
620 }
621
622 pub fn between(self, end: Span) -> Span {
624 let span = self;
625 Span::new(span.hi, end.lo)
626 }
627
628 pub fn until(self, end: Span) -> Span {
631 let span = self;
632 Span::new(span.lo, end.lo)
633 }
634
635 pub fn from_inner_byte_pos(self, start: usize, end: usize) -> Span {
636 let span = self;
637 Span::new(
638 span.lo + BytePos::from_usize(start),
639 span.lo + BytePos::from_usize(end),
640 )
641 }
642
643 pub fn dummy_with_cmt() -> Self {
646 #[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
647 {
648 let lo = BytePos(unsafe { __span_dummy_with_cmt_proxy() });
649
650 return Span { lo, hi: lo };
651 }
652
653 #[cfg(not(all(any(feature = "__plugin_mode"), target_arch = "wasm32")))]
654 return GLOBALS.with(|globals| {
655 let lo = BytePos(
656 globals
657 .dummy_cnt
658 .fetch_add(1, std::sync::atomic::Ordering::SeqCst),
659 );
660 Span { lo, hi: lo }
661 });
662 }
663}
664
665#[derive(Clone, Debug)]
666pub struct SpanLabel {
667 pub span: Span,
669
670 pub is_primary: bool,
673
674 pub label: Option<String>,
676}
677
678impl Default for Span {
679 fn default() -> Self {
680 DUMMY_SP
681 }
682}
683
684impl MultiSpan {
685 #[inline]
686 pub fn new() -> MultiSpan {
687 Self::default()
688 }
689
690 pub fn from_span(primary_span: Span) -> MultiSpan {
691 MultiSpan {
692 primary_spans: vec![primary_span],
693 span_labels: Vec::new(),
694 }
695 }
696
697 pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
698 MultiSpan {
699 primary_spans: vec,
700 span_labels: Vec::new(),
701 }
702 }
703
704 pub fn push_span_label(&mut self, span: Span, label: String) {
705 self.span_labels.push(PrimarySpanLabel(span, label));
706 }
707
708 pub fn primary_span(&self) -> Option<Span> {
710 self.primary_spans.first().cloned()
711 }
712
713 pub fn primary_spans(&self) -> &[Span] {
715 &self.primary_spans
716 }
717
718 pub fn is_dummy(&self) -> bool {
721 let mut is_dummy = true;
722 for span in &self.primary_spans {
723 if !span.is_dummy() {
724 is_dummy = false;
725 }
726 }
727 is_dummy
728 }
729
730 pub fn replace(&mut self, before: Span, after: Span) -> bool {
734 let mut replacements_occurred = false;
735 for primary_span in &mut self.primary_spans {
736 if *primary_span == before {
737 *primary_span = after;
738 replacements_occurred = true;
739 }
740 }
741 for span_label in &mut self.span_labels {
742 if span_label.0 == before {
743 span_label.0 = after;
744 replacements_occurred = true;
745 }
746 }
747 replacements_occurred
748 }
749
750 pub fn span_labels(&self) -> Vec<SpanLabel> {
756 let is_primary = |span| self.primary_spans.contains(&span);
757
758 let mut span_labels = self
759 .span_labels
760 .iter()
761 .map(|&PrimarySpanLabel(span, ref label)| SpanLabel {
762 span,
763 is_primary: is_primary(span),
764 label: Some(label.clone()),
765 })
766 .collect::<Vec<_>>();
767
768 for &span in &self.primary_spans {
769 if !span_labels.iter().any(|sl| sl.span == span) {
770 span_labels.push(SpanLabel {
771 span,
772 is_primary: true,
773 label: None,
774 });
775 }
776 }
777
778 span_labels
779 }
780}
781
782impl From<Span> for MultiSpan {
783 fn from(span: Span) -> MultiSpan {
784 MultiSpan::from_span(span)
785 }
786}
787
788impl From<Vec<Span>> for MultiSpan {
789 fn from(spans: Vec<Span>) -> MultiSpan {
790 MultiSpan::from_spans(spans)
791 }
792}
793
794pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
795
796#[cfg_attr(
798 any(feature = "rkyv-impl"),
799 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
800)]
801#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
802#[cfg_attr(feature = "rkyv-impl", repr(C))]
803#[derive(Copy, Clone, Eq, PartialEq, Debug)]
804pub struct MultiByteChar {
805 pub pos: BytePos,
807 pub bytes: u8,
809}
810
811impl MultiByteChar {
812 pub fn byte_to_char_diff(&self) -> u8 {
818 if self.bytes == 4 {
819 2
820 } else {
821 self.bytes - 1
822 }
823 }
824}
825
826#[cfg_attr(
828 any(feature = "rkyv-impl"),
829 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
830)]
831#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
832#[cfg_attr(feature = "rkyv-impl", repr(u32))]
833#[derive(Copy, Clone, Eq, PartialEq, Debug)]
834pub enum NonNarrowChar {
835 ZeroWidth(BytePos),
837 Wide(BytePos, usize),
839 Tab(BytePos),
842}
843
844impl NonNarrowChar {
845 fn new(pos: BytePos, width: usize) -> Self {
846 match width {
847 0 => NonNarrowChar::ZeroWidth(pos),
848 4 => NonNarrowChar::Tab(pos),
849 w => NonNarrowChar::Wide(pos, w),
850 }
851 }
852
853 pub fn pos(self) -> BytePos {
855 match self {
856 NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p, _) | NonNarrowChar::Tab(p) => p,
857 }
858 }
859
860 pub fn width(self) -> usize {
862 match self {
863 NonNarrowChar::ZeroWidth(_) => 0,
864 NonNarrowChar::Wide(_, width) => width,
865 NonNarrowChar::Tab(_) => 4,
866 }
867 }
868}
869
870impl Add<BytePos> for NonNarrowChar {
871 type Output = Self;
872
873 fn add(self, rhs: BytePos) -> Self {
874 match self {
875 NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
876 NonNarrowChar::Wide(pos, width) => NonNarrowChar::Wide(pos + rhs, width),
877 NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs),
878 }
879 }
880}
881
882impl Sub<BytePos> for NonNarrowChar {
883 type Output = Self;
884
885 fn sub(self, rhs: BytePos) -> Self {
886 match self {
887 NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
888 NonNarrowChar::Wide(pos, width) => NonNarrowChar::Wide(pos - rhs, width),
889 NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs),
890 }
891 }
892}
893
894#[cfg_attr(
896 any(feature = "rkyv-impl"),
897 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
898)]
899#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
900#[cfg_attr(feature = "rkyv-impl", repr(C))]
901#[cfg_attr(feature = "encoding-impl", derive(crate::Encode, crate::Decode))]
902#[derive(Clone)]
903pub struct SourceFile {
904 #[cfg_attr(
908 feature = "encoding-impl",
909 encoding(with = "encoding_helper::LrcHelper")
910 )]
911 pub name: Lrc<FileName>,
912 pub name_was_remapped: bool,
915 #[cfg_attr(
918 feature = "encoding-impl",
919 encoding(with = "encoding_helper::LrcHelper")
920 )]
921 pub unmapped_path: Option<Lrc<FileName>>,
922 pub crate_of_origin: u32,
924 #[cfg_attr(feature = "encoding-impl", encoding(with = "encoding_helper::Str"))]
926 pub src: BytesStr,
927 pub src_hash: u128,
929 pub start_pos: BytePos,
931 pub end_pos: BytePos,
933 pub name_hash: u128,
935
936 #[cfg_attr(feature = "encoding-impl", encoding(ignore))]
937 lazy: CacheCell<SourceFileAnalysis>,
938}
939
940#[cfg_attr(
941 any(feature = "rkyv-impl"),
942 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
943)]
944#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
945#[cfg_attr(feature = "rkyv-impl", repr(C))]
946#[derive(Clone)]
947pub struct SourceFileAnalysis {
948 pub lines: Vec<BytePos>,
950 pub multibyte_chars: Vec<MultiByteChar>,
952 pub non_narrow_chars: Vec<NonNarrowChar>,
954}
955
956impl fmt::Debug for SourceFile {
957 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
958 write!(fmt, "SourceFile({})", self.name)
959 }
960}
961
962impl SourceFile {
963 pub fn new(
965 name: Lrc<FileName>,
966 name_was_remapped: bool,
967 unmapped_path: Lrc<FileName>,
968 src: BytesStr,
969 start_pos: BytePos,
970 ) -> SourceFile {
971 debug_assert_ne!(
972 start_pos,
973 BytePos::DUMMY,
974 "BytePos::DUMMY is reserved and `SourceFile` should not use it"
975 );
976
977 let src_hash = {
978 let mut hasher: StableHasher = StableHasher::new();
979 hasher.write(src.as_bytes());
980 hasher.finish()
981 };
982 let name_hash = {
983 let mut hasher: StableHasher = StableHasher::new();
984 name.hash(&mut hasher);
985 hasher.finish()
986 };
987 let end_pos = start_pos.to_usize() + src.len();
988
989 SourceFile {
990 name,
991 name_was_remapped,
992 unmapped_path: Some(unmapped_path),
993 crate_of_origin: 0,
994 src,
995 src_hash,
996 start_pos,
997 end_pos: SmallPos::from_usize(end_pos),
998 name_hash,
999 lazy: CacheCell::new(),
1000 }
1001 }
1002
1003 pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
1005 let line_index = self.lookup_line(pos).unwrap();
1006 let analysis = self.analyze();
1007 analysis.lines[line_index]
1008 }
1009
1010 pub fn get_line(&self, line_number: usize) -> Option<Cow<'_, str>> {
1013 fn get_until_newline(src: &str, begin: usize) -> &str {
1014 let slice = &src[begin..];
1018 match slice.find('\n') {
1019 Some(e) => &slice[..e],
1020 None => slice,
1021 }
1022 }
1023
1024 let begin = {
1025 let analysis = self.analyze();
1026 let line = analysis.lines.get(line_number)?;
1027 let begin: BytePos = *line - self.start_pos;
1028 begin.to_usize()
1029 };
1030
1031 Some(Cow::from(get_until_newline(&self.src, begin)))
1032 }
1033
1034 pub fn is_real_file(&self) -> bool {
1035 self.name.is_real()
1036 }
1037
1038 pub fn byte_length(&self) -> u32 {
1039 self.end_pos.0 - self.start_pos.0
1040 }
1041
1042 pub fn count_lines(&self) -> usize {
1043 let analysis = self.analyze();
1044 analysis.lines.len()
1045 }
1046
1047 pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
1052 let analysis = self.analyze();
1053 if analysis.lines.is_empty() {
1054 return None;
1055 }
1056
1057 let line_index = lookup_line(&analysis.lines, pos);
1058 assert!(line_index < analysis.lines.len() as isize);
1059 if line_index >= 0 {
1060 Some(line_index as usize)
1061 } else {
1062 None
1063 }
1064 }
1065
1066 pub fn line_bounds(&self, line_index: usize) -> (BytePos, BytePos) {
1067 if self.start_pos == self.end_pos {
1068 return (self.start_pos, self.end_pos);
1069 }
1070
1071 let analysis = self.analyze();
1072
1073 assert!(line_index < analysis.lines.len());
1074 if line_index == (analysis.lines.len() - 1) {
1075 (analysis.lines[line_index], self.end_pos)
1076 } else {
1077 (analysis.lines[line_index], analysis.lines[line_index + 1])
1078 }
1079 }
1080
1081 #[inline]
1082 pub fn contains(&self, byte_pos: BytePos) -> bool {
1083 byte_pos >= self.start_pos && byte_pos <= self.end_pos
1084 }
1085
1086 pub fn analyze(&self) -> &SourceFileAnalysis {
1087 self.lazy.get_or_init(|| {
1088 let (lines, multibyte_chars, non_narrow_chars) =
1089 analyze_source_file::analyze_source_file(&self.src[..], self.start_pos);
1090 SourceFileAnalysis {
1091 lines,
1092 multibyte_chars,
1093 non_narrow_chars,
1094 }
1095 })
1096 }
1097}
1098
1099pub trait SmallPos {
1104 fn from_usize(n: usize) -> Self;
1105 fn to_usize(&self) -> usize;
1106 fn from_u32(n: u32) -> Self;
1107 fn to_u32(&self) -> u32;
1108}
1109
1110#[derive(
1123 Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize, Default,
1124)]
1125#[serde(transparent)]
1126#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1127#[cfg_attr(
1128 any(feature = "rkyv-impl"),
1129 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1130)]
1131#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1132#[cfg_attr(feature = "rkyv-impl", repr(C))]
1133#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
1134pub struct BytePos(#[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub u32);
1135
1136#[cfg(feature = "encoding-impl")]
1137impl cbor4ii::core::enc::Encode for BytePos {
1138 #[inline]
1139 fn encode<W: cbor4ii::core::enc::Write>(
1140 &self,
1141 writer: &mut W,
1142 ) -> Result<(), cbor4ii::core::enc::Error<W::Error>> {
1143 self.0.encode(writer)
1144 }
1145}
1146
1147#[cfg(feature = "encoding-impl")]
1148impl<'de> cbor4ii::core::dec::Decode<'de> for BytePos {
1149 #[inline]
1150 fn decode<R: cbor4ii::core::dec::Read<'de>>(
1151 reader: &mut R,
1152 ) -> Result<Self, cbor4ii::core::dec::Error<R::Error>> {
1153 u32::decode(reader).map(BytePos)
1154 }
1155}
1156
1157impl BytePos {
1158 pub const DUMMY: Self = BytePos(0);
1160 const MIN_RESERVED: Self = BytePos(DUMMY_RESERVE);
1161 pub const PLACEHOLDER: Self = BytePos(u32::MAX - 2);
1164 pub const PURE: Self = BytePos(u32::MAX - 1);
1166 pub const SYNTHESIZED: Self = BytePos(u32::MAX);
1168
1169 pub const fn is_reserved_for_comments(self) -> bool {
1170 self.0 >= Self::MIN_RESERVED.0 && self.0 != u32::MAX
1171 }
1172
1173 pub const fn is_dummy(self) -> bool {
1176 self.0 == 0
1177 }
1178
1179 pub const fn is_pure(self) -> bool {
1180 self.0 == Self::PURE.0
1181 }
1182
1183 pub const fn is_placeholder(self) -> bool {
1184 self.0 == Self::PLACEHOLDER.0
1185 }
1186
1187 pub const fn can_have_comment(self) -> bool {
1190 self.0 != 0
1191 }
1192}
1193
1194#[cfg_attr(
1198 any(feature = "rkyv-impl"),
1199 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1200)]
1201#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1202#[cfg_attr(feature = "rkyv-impl", repr(C))]
1203#[cfg_attr(feature = "encoding-impl", derive(crate::Encode, crate::Decode))]
1204#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1205pub struct CharPos(
1206 #[cfg_attr(feature = "encoding-impl", encoding(with = "encoding_helper::Usize"))] pub usize,
1207);
1208
1209impl SmallPos for BytePos {
1213 #[inline(always)]
1214 fn from_usize(n: usize) -> BytePos {
1215 BytePos(n as u32)
1216 }
1217
1218 #[inline(always)]
1219 fn to_usize(&self) -> usize {
1220 self.0 as usize
1221 }
1222
1223 #[inline(always)]
1224 fn from_u32(n: u32) -> BytePos {
1225 BytePos(n)
1226 }
1227
1228 #[inline(always)]
1229 fn to_u32(&self) -> u32 {
1230 self.0
1231 }
1232}
1233
1234impl Add for BytePos {
1235 type Output = BytePos;
1236
1237 #[inline(always)]
1238 fn add(self, rhs: BytePos) -> BytePos {
1239 BytePos((self.to_usize() + rhs.to_usize()) as u32)
1240 }
1241}
1242
1243impl Sub for BytePos {
1244 type Output = BytePos;
1245
1246 #[inline(always)]
1247 fn sub(self, rhs: BytePos) -> BytePos {
1248 BytePos((self.to_usize() - rhs.to_usize()) as u32)
1249 }
1250}
1251
1252impl SmallPos for CharPos {
1253 #[inline(always)]
1254 fn from_usize(n: usize) -> CharPos {
1255 CharPos(n)
1256 }
1257
1258 #[inline(always)]
1259 fn to_usize(&self) -> usize {
1260 self.0
1261 }
1262
1263 #[inline(always)]
1264 fn from_u32(n: u32) -> CharPos {
1265 CharPos(n as usize)
1266 }
1267
1268 #[inline(always)]
1269 fn to_u32(&self) -> u32 {
1270 self.0 as u32
1271 }
1272}
1273
1274impl Add for CharPos {
1275 type Output = CharPos;
1276
1277 #[inline(always)]
1278 fn add(self, rhs: CharPos) -> CharPos {
1279 CharPos(self.to_usize() + rhs.to_usize())
1280 }
1281}
1282
1283impl Sub for CharPos {
1284 type Output = CharPos;
1285
1286 #[inline(always)]
1287 fn sub(self, rhs: CharPos) -> CharPos {
1288 CharPos(self.to_usize() - rhs.to_usize())
1289 }
1290}
1291
1292#[derive(Debug, Clone)]
1303pub struct Loc {
1304 pub file: Lrc<SourceFile>,
1306 pub line: usize,
1308 pub col: CharPos,
1310 pub col_display: usize,
1312}
1313
1314#[cfg_attr(
1317 any(feature = "rkyv-impl"),
1318 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Debug, Clone)
1319)]
1320#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1321#[cfg_attr(feature = "rkyv-impl", repr(C))]
1322#[cfg_attr(feature = "encoding-impl", derive(crate::Encode, crate::Decode))]
1323pub struct PartialLoc {
1324 #[cfg_attr(
1325 feature = "encoding-impl",
1326 encoding(with = "encoding_helper::LrcHelper")
1327 )]
1328 pub source_file: Option<Lrc<SourceFile>>,
1329 #[cfg_attr(feature = "encoding-impl", encoding(with = "encoding_helper::Usize"))]
1330 pub line: usize,
1331 #[cfg_attr(feature = "encoding-impl", encoding(with = "encoding_helper::Usize"))]
1332 pub col: usize,
1333 #[cfg_attr(feature = "encoding-impl", encoding(with = "encoding_helper::Usize"))]
1334 pub col_display: usize,
1335}
1336
1337#[derive(Debug)]
1341pub struct LocWithOpt {
1342 pub filename: Lrc<FileName>,
1343 pub line: usize,
1344 pub col: CharPos,
1345 pub file: Option<Lrc<SourceFile>>,
1346}
1347
1348#[derive(Debug)]
1350pub struct SourceFileAndLine {
1351 pub sf: Lrc<SourceFile>,
1352 pub line: usize,
1353}
1354
1355#[cfg_attr(
1356 any(feature = "rkyv-impl"),
1357 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1358)]
1359#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1360#[cfg_attr(feature = "rkyv-impl", repr(C))]
1361#[cfg_attr(
1362 feature = "encoding-impl",
1363 derive(::ast_node::Encode, ::ast_node::Decode)
1364)]
1365#[derive(Debug)]
1366pub struct SourceFileAndBytePos {
1367 #[cfg_attr(
1368 feature = "encoding-impl",
1369 encoding(with = "encoding_helper::LrcHelper")
1370 )]
1371 pub sf: Lrc<SourceFile>,
1372 pub pos: BytePos,
1373}
1374
1375#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1376#[cfg_attr(
1377 any(feature = "rkyv-impl"),
1378 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1379)]
1380#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1381#[cfg_attr(feature = "rkyv-impl", repr(C))]
1382#[cfg_attr(feature = "encoding-impl", derive(crate::Encode, crate::Decode))]
1383pub struct LineInfo {
1384 #[cfg_attr(feature = "encoding-impl", encoding(with = "encoding_helper::Usize"))]
1386 pub line_index: usize,
1387
1388 pub start_col: CharPos,
1390
1391 pub end_col: CharPos,
1393}
1394
1395#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1397pub struct LineCol {
1398 pub line: u32,
1400
1401 pub col: u32,
1403}
1404
1405pub struct FileLines {
1412 pub file: Lrc<SourceFile>,
1413 pub lines: Vec<LineInfo>,
1414}
1415
1416#[cfg_attr(
1419 any(feature = "rkyv-impl"),
1420 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Debug, Clone)
1421)]
1422#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1423#[cfg_attr(feature = "rkyv-impl", repr(C))]
1424#[cfg_attr(
1425 feature = "encoding-impl",
1426 derive(::ast_node::Encode, ::ast_node::Decode)
1427)]
1428pub struct PartialFileLines {
1429 #[cfg_attr(
1430 feature = "encoding-impl",
1431 encoding(with = "encoding_helper::LrcHelper")
1432 )]
1433 pub file: Option<Lrc<SourceFile>>,
1434 pub lines: Vec<LineInfo>,
1435}
1436
1437pub type FileLinesResult = Result<FileLines, Box<SpanLinesError>>;
1443#[cfg(feature = "__plugin")]
1444pub type PartialFileLinesResult = Result<PartialFileLines, Box<SpanLinesError>>;
1445
1446#[derive(Clone, PartialEq, Eq, Debug)]
1447#[cfg_attr(
1448 any(feature = "rkyv-impl"),
1449 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1450)]
1451#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1452#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1453#[cfg_attr(
1454 feature = "encoding-impl",
1455 derive(::ast_node::Encode, ::ast_node::Decode)
1456)]
1457pub enum SpanLinesError {
1458 IllFormedSpan(Span),
1459 DistinctSources(DistinctSources),
1460}
1461
1462#[derive(Clone, PartialEq, Eq, Debug)]
1463#[cfg_attr(
1464 any(feature = "rkyv-impl"),
1465 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1466)]
1467#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1468#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1469pub enum SpanSnippetError {
1470 DummyBytePos,
1471 IllFormedSpan(Span),
1472 DistinctSources(DistinctSources),
1473 MalformedForSourcemap(MalformedSourceMapPositions),
1474 SourceNotAvailable { filename: FileName },
1475 LookupFailed(SourceMapLookupError),
1476}
1477
1478#[cfg(feature = "encoding-impl")]
1479impl cbor4ii::core::enc::Encode for SpanSnippetError {
1480 #[inline]
1481 fn encode<W: cbor4ii::core::enc::Write>(
1482 &self,
1483 writer: &mut W,
1484 ) -> Result<(), cbor4ii::core::enc::Error<W::Error>> {
1485 use cbor4ii::core::types::{Array, Nothing, Tag};
1486
1487 match self {
1488 SpanSnippetError::DummyBytePos => {
1489 Tag(1, Nothing).encode(writer)?;
1490 Array::bounded(0, writer)
1491 }
1492 SpanSnippetError::IllFormedSpan(span) => Tag(2, span).encode(writer),
1493 SpanSnippetError::DistinctSources(src) => Tag(3, src).encode(writer),
1494 SpanSnippetError::MalformedForSourcemap(pos) => Tag(4, pos).encode(writer),
1495 SpanSnippetError::SourceNotAvailable { filename } => Tag(5, filename).encode(writer),
1496 SpanSnippetError::LookupFailed(err) => Tag(6, err).encode(writer),
1497 }
1498 }
1499}
1500
1501#[cfg(feature = "encoding-impl")]
1502impl<'de> cbor4ii::core::dec::Decode<'de> for SpanSnippetError {
1503 #[inline]
1504 fn decode<R: cbor4ii::core::dec::Read<'de>>(
1505 reader: &mut R,
1506 ) -> Result<Self, cbor4ii::core::dec::Error<R::Error>> {
1507 use cbor4ii::core::types::{Array, Tag};
1508
1509 let tag = Tag::tag(reader)?;
1510 match tag {
1511 1 => {
1512 let n = Array::len(reader)?;
1513 debug_assert_eq!(n, Some(0));
1514 Ok(SpanSnippetError::DummyBytePos)
1515 }
1516 2 => Span::decode(reader).map(SpanSnippetError::IllFormedSpan),
1517 3 => DistinctSources::decode(reader).map(SpanSnippetError::DistinctSources),
1518 4 => MalformedSourceMapPositions::decode(reader)
1519 .map(SpanSnippetError::MalformedForSourcemap),
1520 5 => FileName::decode(reader)
1521 .map(|filename| SpanSnippetError::SourceNotAvailable { filename }),
1522 6 => SourceMapLookupError::decode(reader).map(SpanSnippetError::LookupFailed),
1523 tag => Err(cbor4ii::core::error::DecodeError::Custom {
1524 name: &"SpanSnippetError",
1525 num: tag as u32,
1526 }),
1527 }
1528 }
1529}
1530
1531#[derive(Clone, PartialEq, Eq, Debug)]
1536#[cfg_attr(
1537 any(feature = "rkyv-impl"),
1538 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1539)]
1540#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1541#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1542#[cfg_attr(
1543 feature = "encoding-impl",
1544 derive(::ast_node::Encode, ::ast_node::Decode)
1545)]
1546pub enum SourceMapLookupError {
1547 NoFileFor(BytePos),
1548}
1549
1550#[derive(Clone, PartialEq, Eq, Debug)]
1551#[cfg_attr(
1552 any(feature = "rkyv-impl"),
1553 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1554)]
1555#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1556#[cfg_attr(feature = "rkyv-impl", repr(C))]
1557#[cfg_attr(
1558 feature = "encoding-impl",
1559 derive(::ast_node::Encode, ::ast_node::Decode)
1560)]
1561pub struct FilePos(
1562 #[cfg_attr(
1563 feature = "encoding-impl",
1564 encoding(with = "encoding_helper::LrcHelper")
1565 )]
1566 pub Lrc<FileName>,
1567 pub BytePos,
1568);
1569
1570#[derive(Clone, PartialEq, Eq, Debug)]
1571#[cfg_attr(
1572 any(feature = "rkyv-impl"),
1573 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1574)]
1575#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1576#[cfg_attr(feature = "rkyv-impl", repr(C))]
1577#[cfg_attr(
1578 feature = "encoding-impl",
1579 derive(::ast_node::Encode, ::ast_node::Decode)
1580)]
1581pub struct DistinctSources {
1582 pub begin: FilePos,
1583 pub end: FilePos,
1584}
1585
1586#[derive(Clone, PartialEq, Eq, Debug)]
1587#[cfg_attr(
1588 any(feature = "rkyv-impl"),
1589 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1590)]
1591#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1592#[cfg_attr(feature = "rkyv-impl", repr(C))]
1593#[cfg_attr(
1594 feature = "encoding-impl",
1595 derive(::ast_node::Encode, ::ast_node::Decode)
1596)]
1597pub struct MalformedSourceMapPositions {
1598 #[cfg_attr(
1599 feature = "encoding-impl",
1600 encoding(with = "encoding_helper::LrcHelper")
1601 )]
1602 pub name: Lrc<FileName>,
1603 #[cfg_attr(feature = "encoding-impl", encoding(with = "encoding_helper::Usize"))]
1604 pub source_len: usize,
1605 pub begin_pos: BytePos,
1606 pub end_pos: BytePos,
1607}
1608
1609fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize {
1613 match lines.binary_search(&pos) {
1614 Ok(line) => line as isize,
1615 Err(line) => line as isize - 1,
1616 }
1617}
1618
1619impl From<SourceMapLookupError> for Box<SpanSnippetError> {
1620 #[cold]
1621 fn from(err: SourceMapLookupError) -> Self {
1622 Box::new(SpanSnippetError::LookupFailed(err))
1623 }
1624}
1625
1626#[cfg(feature = "encoding-impl")]
1627mod encoding_helper {
1628 use super::Lrc;
1629
1630 pub struct LrcHelper<T>(pub T);
1631
1632 impl<T: cbor4ii::core::enc::Encode> cbor4ii::core::enc::Encode for LrcHelper<&'_ Lrc<T>> {
1633 fn encode<W: cbor4ii::core::enc::Write>(
1634 &self,
1635 writer: &mut W,
1636 ) -> Result<(), cbor4ii::core::enc::Error<W::Error>> {
1637 self.0.encode(writer)
1638 }
1639 }
1640
1641 impl<'de, T: cbor4ii::core::dec::Decode<'de>> cbor4ii::core::dec::Decode<'de>
1642 for LrcHelper<Lrc<T>>
1643 {
1644 fn decode<R: cbor4ii::core::dec::Read<'de>>(
1645 reader: &mut R,
1646 ) -> Result<Self, cbor4ii::core::dec::Error<R::Error>> {
1647 T::decode(reader).map(Lrc::new).map(LrcHelper)
1648 }
1649 }
1650
1651 impl<T: cbor4ii::core::enc::Encode> cbor4ii::core::enc::Encode for LrcHelper<&'_ Option<Lrc<T>>> {
1652 fn encode<W: cbor4ii::core::enc::Write>(
1653 &self,
1654 writer: &mut W,
1655 ) -> Result<(), cbor4ii::core::enc::Error<W::Error>> {
1656 let v = self.0.as_deref();
1658 cbor4ii::core::types::Array::bounded(v.is_some() as usize, writer)?;
1659 if let Some(v) = v {
1660 v.encode(writer)?;
1661 }
1662 Ok(())
1663 }
1664 }
1665
1666 impl<'de, T: cbor4ii::core::dec::Decode<'de>> cbor4ii::core::dec::Decode<'de>
1667 for LrcHelper<Option<Lrc<T>>>
1668 {
1669 fn decode<R: cbor4ii::core::dec::Read<'de>>(
1670 reader: &mut R,
1671 ) -> Result<Self, cbor4ii::core::dec::Error<R::Error>> {
1672 <cbor4ii::core::types::Maybe<Option<T>>>::decode(reader)
1673 .map(|maybe| maybe.0.map(Lrc::new))
1674 .map(LrcHelper)
1675 }
1676 }
1677
1678 pub struct Usize<T>(pub T);
1679
1680 impl cbor4ii::core::enc::Encode for Usize<&'_ usize> {
1681 fn encode<W: cbor4ii::core::enc::Write>(
1682 &self,
1683 writer: &mut W,
1684 ) -> Result<(), cbor4ii::core::enc::Error<W::Error>> {
1685 (*self.0 as u64).encode(writer)
1686 }
1687 }
1688
1689 impl<'de> cbor4ii::core::dec::Decode<'de> for Usize<usize> {
1690 fn decode<R: cbor4ii::core::dec::Read<'de>>(
1691 reader: &mut R,
1692 ) -> Result<Self, cbor4ii::core::dec::Error<R::Error>> {
1693 <u64>::decode(reader)
1694 .map(|n| n.try_into().unwrap())
1695 .map(Usize)
1696 }
1697 }
1698
1699 pub struct Str<T>(pub T);
1700
1701 impl cbor4ii::core::enc::Encode for Str<&'_ bytes_str::BytesStr> {
1702 fn encode<W: cbor4ii::core::enc::Write>(
1703 &self,
1704 writer: &mut W,
1705 ) -> Result<(), cbor4ii::core::enc::Error<W::Error>> {
1706 cbor4ii::core::enc::Encode::encode(&self.0.as_str(), writer)
1707 }
1708 }
1709
1710 impl<'de> cbor4ii::core::dec::Decode<'de> for Str<bytes_str::BytesStr> {
1711 fn decode<R: cbor4ii::core::dec::Read<'de>>(
1712 reader: &mut R,
1713 ) -> Result<Self, cbor4ii::core::dec::Error<R::Error>> {
1714 String::decode(reader)
1715 .map(bytes_str::BytesStr::from)
1716 .map(Str)
1717 }
1718 }
1719}
1720
1721#[cfg(test)]
1722mod tests {
1723 use super::{lookup_line, BytePos, Span};
1724
1725 #[test]
1726 fn test_lookup_line() {
1727 let lines = &[BytePos(3), BytePos(17), BytePos(28)];
1728
1729 assert_eq!(lookup_line(lines, BytePos(0)), -1);
1730 assert_eq!(lookup_line(lines, BytePos(3)), 0);
1731 assert_eq!(lookup_line(lines, BytePos(4)), 0);
1732
1733 assert_eq!(lookup_line(lines, BytePos(16)), 0);
1734 assert_eq!(lookup_line(lines, BytePos(17)), 1);
1735 assert_eq!(lookup_line(lines, BytePos(18)), 1);
1736
1737 assert_eq!(lookup_line(lines, BytePos(28)), 2);
1738 assert_eq!(lookup_line(lines, BytePos(29)), 2);
1739 }
1740
1741 #[test]
1742 fn size_of_span() {
1743 assert_eq!(std::mem::size_of::<Span>(), 8);
1744 }
1745}