1use std::fmt::{self, Debug, Formatter};
2use std::num::{NonZeroU16, NonZeroU32, NonZeroU64};
3use std::ops::Range;
4
5use ecow::{EcoString, eco_format};
6
7use crate::FileId;
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
63pub struct Span(NonZeroU64);
64
65#[derive(Debug, Copy, Clone, Eq, PartialEq)]
72pub struct SpanNumber(pub(crate) u64);
73
74#[derive(Debug)]
76pub enum SpanKind {
77 Detached,
79 Number { id: FileId, num: SpanNumber },
81 Range { id: FileId, range: Range<usize> },
83}
84
85impl Span {
86 pub(crate) const FULL: Range<u64> = 2..(1 << 47);
88
89 const DETACHED: Self = Self(NonZeroU64::new(1).unwrap());
91
92 const NUMBER_BITS: usize = 48;
103 const RANGE_BITS: usize = 46;
104 const FILE_ID_SHIFT: usize = Self::NUMBER_BITS;
105 const NUMBER_MASK: u64 = (1 << Self::NUMBER_BITS) - 1;
106 const EXTERNAL_BASE: u64 = Self::FULL.end;
107 const EXTERNAL_VALUE_MAX: u64 = (1 << Self::RANGE_BITS) - 1;
108 const RANGE_BASE: u64 = Self::EXTERNAL_BASE + (1 << Self::RANGE_BITS);
109 const RANGE_VALUE_BITS: usize = 23;
110 const RANGE_VALUE_MAX: u64 = (1 << Self::RANGE_VALUE_BITS) - 1;
111
112 pub const fn detached() -> Self {
114 Self::DETACHED
115 }
116
117 pub(crate) const fn from_number(id: FileId, SpanNumber(number): SpanNumber) -> Self {
119 debug_assert!(Self::FULL.start <= number);
120 debug_assert!(number < Self::FULL.end);
121 Self::pack(id, number)
122 }
123
124 pub(crate) const fn from_range(id: FileId, range: Range<usize>) -> Self {
129 let start = saturate(range.start, Self::RANGE_VALUE_MAX);
130 let end = saturate(range.end, Self::RANGE_VALUE_MAX);
131 let number = (start << Self::RANGE_VALUE_BITS) | end;
132 Self::pack(id, Self::RANGE_BASE + number)
133 }
134
135 pub const fn from_raw(v: NonZeroU64) -> Self {
141 Self(v)
142 }
143
144 const fn pack(id: FileId, low: u64) -> Self {
146 let bits = ((id.into_raw().get() as u64) << Self::FILE_ID_SHIFT) | low;
147
148 Self(NonZeroU64::new(bits).unwrap())
150 }
151
152 pub const fn is_detached(self) -> bool {
154 self.0.get() == Self::DETACHED.0.get()
155 }
156
157 pub const fn id(self) -> Option<FileId> {
161 match NonZeroU16::new((self.0.get() >> Self::FILE_ID_SHIFT) as u16) {
164 Some(v) => Some(FileId::from_raw(v)),
165 None => None,
166 }
167 }
168
169 pub(crate) const fn number(self) -> u64 {
171 self.0.get() & Self::NUMBER_MASK
172 }
173
174 pub const fn get(self) -> SpanKind {
178 let Some(id) = self.id() else { return SpanKind::Detached };
179 let num = self.number();
180 if let Some(packed_range) = num.checked_sub(Self::RANGE_BASE) {
181 let start = (packed_range >> Self::RANGE_VALUE_BITS) as usize;
182 let end = (packed_range & Self::RANGE_VALUE_MAX) as usize;
183 SpanKind::Range { id, range: start..end }
184 } else {
185 SpanKind::Number { id, num: SpanNumber(num) }
186 }
187 }
188
189 pub const fn into_raw(self) -> NonZeroU64 {
191 self.0
192 }
193
194 pub fn or(self, other: Self) -> Self {
196 if self.is_detached() { other } else { self }
197 }
198
199 pub fn find(iter: impl IntoIterator<Item = Self>) -> Self {
201 iter.into_iter()
202 .find(|span| !span.is_detached())
203 .unwrap_or(Span::detached())
204 }
205}
206
207#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
219pub struct DiagSpan {
220 span: Span,
221 extra: u64,
222}
223
224#[derive(Debug)]
226pub enum DiagSpanKind {
227 Detached,
229 Number { id: FileId, num: SpanNumber, sub_range: Option<SubRange> },
231 Range { id: FileId, range: Range<usize> },
233}
234
235impl DiagSpan {
236 pub const fn detached() -> Self {
238 Self { span: Span::DETACHED, extra: 0 }
239 }
240
241 pub fn from_range(id: FileId, range: Range<usize>) -> Self {
247 let start = saturate(range.start, Span::EXTERNAL_VALUE_MAX);
248 let end = saturate(range.end, Span::EXTERNAL_VALUE_MAX);
249 Self {
250 span: Span::pack(id, Span::EXTERNAL_BASE + start),
251 extra: end,
252 }
253 }
254
255 pub fn from_span(span: Span, sub_range: Option<SubRange>) -> Self {
260 let extra = sub_range.map_or(0, |SubRange { start, end }| {
261 ((start as u64) << 32) | (end.get() as u64)
262 });
263 Self { span, extra }
264 }
265
266 pub const fn is_detached(self) -> bool {
268 self.span.0.get() == Span::DETACHED.0.get()
269 }
270
271 pub fn id(self) -> Option<FileId> {
275 self.span.id()
276 }
277
278 pub fn or(self, other: Self) -> Self {
280 if self.is_detached() { other } else { self }
281 }
282
283 pub fn get(self) -> DiagSpanKind {
288 let DiagSpan { span, extra } = self;
289 match span.get() {
290 SpanKind::Detached => DiagSpanKind::Detached,
291 SpanKind::Number { id, num } => {
292 if let Some(start) = num.0.checked_sub(Span::EXTERNAL_BASE) {
293 let start = start as usize;
296 let end = extra as usize;
297 DiagSpanKind::Range { id, range: start..end }
298 } else {
299 let sub_range = {
300 let start = (extra >> 32) as u32;
301 let end = NonZeroU32::new(extra as u32); end.map(|end| SubRange { start, end })
303 };
304 DiagSpanKind::Number { id, num, sub_range }
305 }
306 }
307 SpanKind::Range { id, range } => {
308 if let Some(end) = NonZeroU32::new(extra as u32) {
309 let start = (extra >> 32) as u32;
310 let sub_range = SubRange { start, end };
311 let range = sub_range.to_absolute(range.start);
312 DiagSpanKind::Range { id, range }
313 } else {
314 DiagSpanKind::Range { id, range }
315 }
316 }
317 }
318 }
319}
320
321impl From<Span> for DiagSpan {
322 fn from(span: Span) -> Self {
323 Self::from_span(span, None)
324 }
325}
326
327const fn saturate(value: usize, max: u64) -> u64 {
330 if value as u64 > max { max } else { value as u64 }
331}
332
333#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
335pub struct SubRange {
336 start: u32,
337 end: NonZeroU32,
338}
339
340impl SubRange {
341 pub fn new(start: usize, end: usize) -> Option<Self> {
346 if start < end {
347 Some(Self {
348 start: to_u32_saturated(start),
349 end: NonZeroU32::new(to_u32_saturated(end)).unwrap(),
351 })
352 } else {
353 None
354 }
355 }
356
357 pub fn to_relative(self) -> Range<usize> {
359 Range {
360 start: self.start as usize,
361 end: self.end.get() as usize,
362 }
363 }
364
365 pub fn to_absolute(self, offset: usize) -> Range<usize> {
367 Range {
368 start: self.start as usize + offset,
369 end: self.end.get() as usize + offset,
370 }
371 }
372}
373
374fn to_u32_saturated(value: usize) -> u32 {
376 value.try_into().unwrap_or(u32::MAX)
377}
378
379#[derive(Copy, Clone, Eq, PartialEq, Hash)]
381#[expect(private_bounds)]
382pub struct Spanned<T, S: Copy + SpanDetached = Span> {
383 pub v: T,
385 pub span: S,
387}
388
389#[expect(private_bounds)]
390impl<T, S: Copy + SpanDetached> Spanned<T, S> {
391 pub const fn new(v: T, span: S) -> Self {
393 Self { v, span }
394 }
395
396 pub const fn detached(v: T) -> Self {
398 Self { v, span: S::SPAN_DETACHED }
399 }
400
401 pub const fn as_ref(&self) -> Spanned<&T, S> {
403 Spanned { v: &self.v, span: self.span }
404 }
405
406 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Spanned<U, S> {
408 Spanned { v: f(self.v), span: self.span }
409 }
410}
411
412impl<T: Debug, S: Copy + SpanDetached> Debug for Spanned<T, S> {
413 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
414 self.v.fmt(f)
415 }
416}
417
418trait SpanDetached {
421 const SPAN_DETACHED: Self;
422}
423
424impl SpanDetached for Span {
425 const SPAN_DETACHED: Self = Self::detached();
426}
427
428impl SpanDetached for DiagSpan {
429 const SPAN_DETACHED: Self = Self::detached();
430}
431
432#[derive(Hash)]
440pub struct RangeMapper {
441 vec: Vec<Mapping>,
442 total: usize,
443}
444
445#[derive(Hash, Clone, Copy)]
447struct Mapping {
448 old: usize,
449 new: usize,
450}
451
452impl RangeMapper {
453 pub fn new(
464 segments: impl IntoIterator<Item = Range<usize>>,
465 ) -> Result<Self, EcoString> {
466 let mut map = Mapping { old: 0, new: 0 };
467 let vec = segments
468 .into_iter()
469 .map(|Range { start, end }| {
470 if start > end || map.new > start {
471 return Err(eco_format!("invalid mapper segment: ({start}, {end})"));
472 }
473 map.new = start;
474 let segment_map = map;
475 map.old += end - start;
476 Ok(segment_map)
477 })
478 .collect::<Result<Vec<Mapping>, EcoString>>()?;
479
480 if vec.is_empty() {
481 Ok(Self { vec: vec![map], total: 0 })
482 } else {
483 Ok(Self { vec, total: map.old })
484 }
485 }
486
487 pub(crate) fn total_len(&self) -> usize {
489 self.total
490 }
491
492 pub(crate) fn map(&self, range: Range<usize>) -> Range<usize> {
499 debug_assert!(range.start <= range.end);
500 if range.end == 0 {
501 let offset = self.vec[0].new;
503 offset..offset
504 } else if range.start == range.end {
505 let offset = self.map_end(range.start);
508 offset..offset
509 } else {
510 let start = self.map_start(range.start);
513 let end = self.map_end(range.end);
514 start..end
515 }
516 }
517
518 pub(crate) fn map_sub_range(&self, offset: usize, sub_range: SubRange) -> SubRange {
522 let range = sub_range.to_absolute(offset);
523 let new_offset = self.map_start(offset);
524 let start = self.map_start(range.start);
525 let end = self.map_end(range.end); SubRange::new(start - new_offset, end - new_offset).unwrap()
527 }
528
529 fn map_start(&self, offset: usize) -> usize {
531 let idx = self.vec.partition_point(|&Mapping { old, new: _ }| old <= offset);
532 let Mapping { old, new } = &self.vec[idx - 1];
537 new + (offset - old)
538 }
539
540 fn map_end(&self, offset: usize) -> usize {
544 debug_assert_ne!(offset, 0);
545 let idx = self.vec.partition_point(|&Mapping { old, new: _ }| old < offset);
546 let Mapping { old, new } = &self.vec[idx - 1];
549 new + (offset - old)
550 }
551}
552
553#[cfg(test)]
554mod tests {
555 use super::*;
556
557 #[test]
558 fn test_span_detached() {
559 let span = Span::detached();
560 assert!(span.is_detached());
561 assert_eq!(span.id(), None);
562 }
563
564 #[test]
565 fn test_span_number_encoding() {
566 let id = FileId::from_raw(NonZeroU16::new(5).unwrap());
567 let span = Span::from_number(id, SpanNumber(10));
568 assert_eq!(span.id(), Some(id));
569 assert_eq!(span.number(), 10);
570 }
571
572 #[test]
573 fn test_span_range_encoding() {
574 let file_id = FileId::from_raw(NonZeroU16::new(u16::MAX).unwrap());
575 let roundtrip = |range: Range<usize>| {
576 let span = Span::from_range(file_id, range.clone());
577 let SpanKind::Range { id, range: actual } = span.get() else {
578 panic!("bad span kind")
579 };
580 assert_eq!(id, file_id);
581 assert_eq!(actual, range);
582 };
583
584 roundtrip(0..0);
585 roundtrip(177..233);
586 roundtrip(0..8388607);
587 roundtrip(8388606..8388607); }
589
590 #[test]
591 fn test_diag_span_range() {
592 let file_id = FileId::from_raw(NonZeroU16::new(u16::MAX).unwrap());
593 let roundtrip = |range: Range<usize>| {
594 let span = DiagSpan::from_range(file_id, range.clone());
595 let DiagSpanKind::Range { id, range: actual } = span.get() else {
596 panic!("bad diagspan kind")
597 };
598 assert_eq!(id, file_id);
599 assert_eq!(actual, range);
600 };
601
602 roundtrip(0..0);
603 roundtrip(177..233);
604 roundtrip(0..8388607);
605 roundtrip(8388606..8388607); roundtrip(8388608..8388609); #[cfg(target_pointer_width = "64")]
608 roundtrip(70368744177662..70368744177663); }
610
611 #[test]
612 fn test_sub_range_constructor() {
613 let max = u32::MAX as usize;
614 assert!(SubRange::new(0, 1).is_some());
616 assert!(SubRange::new(4, 5).is_some());
617 assert!(SubRange::new(0, max).is_some());
618 assert!(SubRange::new(0, max - 1).is_some());
619 assert!(SubRange::new(max - 1, max).is_some());
620 assert!(SubRange::new(0, 0).is_none());
622 assert!(SubRange::new(5, 5).is_none());
623 assert!(SubRange::new(5, 4).is_none());
624 assert!(SubRange::new(max - 1, max - 1).is_none());
625 assert!(SubRange::new(max, max).is_none());
626 }
627
628 #[cfg(target_pointer_width = "64")]
629 #[test]
630 fn test_sub_range_saturating() {
631 let max = u32::MAX as usize;
633 let maxxed = SubRange::new(max, max + 1).unwrap();
634 assert_eq!(maxxed.start, maxxed.end.get());
635 assert_eq!(SubRange::new(1 << 47, 1 << 63), Some(maxxed));
636 }
637
638 #[test]
639 fn test_range_mapper() {
640 let base = "-- Hello\n-- world\n";
641 let ranges = [(3..9), (12..18)];
642 let mapped = ranges.iter().map(|r| &base[r.clone()]).collect::<String>();
643 let m = RangeMapper::new(ranges).unwrap();
644
645 assert_eq!(mapped, "Hello\nworld\n");
646 assert_eq!(m.map(2..3), 5..6); assert_eq!(m.map(4..6), (7..9)); assert_eq!(m.map(6..8), (12..14)); assert_eq!(m.map(8..11), (14..17)); assert_eq!(m.map(2..12), (5..18)); assert_eq!(m.map(0..0), (3..3));
654 assert_eq!(m.map(6..6), (9..9)); assert_eq!(m.map(12..12), (18..18));
656 }
657
658 #[test]
660 fn test_range_mapper_exhaustive() {
661 let empty = RangeMapper::new([]).unwrap();
662 assert_eq!(empty.map(0..0), 0..0);
663
664 let exact = RangeMapper::new(Some(0..1)).unwrap();
665 assert_eq!(exact.map(0..0), 0..0);
666 assert_eq!(exact.map(0..1), 0..1);
667 assert_eq!(exact.map(1..1), 1..1);
668
669 let plus = RangeMapper::new(Some(10..11)).unwrap();
670 assert_eq!(plus.map(0..0), 10..10);
671 assert_eq!(plus.map(0..1), 10..11);
672 assert_eq!(plus.map(1..1), 11..11);
673
674 let disjoint = RangeMapper::new([(10..11), (21..22)]).unwrap();
675 assert_eq!(disjoint.map(0..0), 10..10);
676 assert_eq!(disjoint.map(0..1), 10..11);
677 assert_eq!(disjoint.map(0..2), 10..22);
678 assert_eq!(disjoint.map(1..1), 11..11);
679 assert_eq!(disjoint.map(1..2), 21..22);
680 assert_eq!(disjoint.map(2..2), 22..22);
681
682 let with_empty = RangeMapper::new([
684 (10..10),
685 (10..11),
686 (11..11),
687 (16..16),
688 (21..21),
689 (21..22),
690 (22..22),
691 ])
692 .unwrap();
693 assert_eq!(with_empty.map(0..0), 10..10);
694 assert_eq!(with_empty.map(0..1), 10..11);
695 assert_eq!(with_empty.map(0..2), 10..22);
696 assert_eq!(with_empty.map(1..1), 11..11);
697 assert_eq!(with_empty.map(1..2), 21..22);
698 assert_eq!(with_empty.map(2..2), 22..22);
699 }
700
701 #[test]
702 fn test_sub_range_mapping() {
703 let base = "01_23__45";
704 let ranges = [(0..2), (3..5), (7..9)];
705 let mapped = ranges.iter().map(|r| &base[r.clone()]).collect::<String>();
706 assert_eq!(mapped, "012345");
707 let m = RangeMapper::new(ranges).unwrap();
708
709 let map_at = |at: usize, sr: Option<SubRange>| {
710 let sub_range = sr.unwrap();
711 m.map_sub_range(at, sub_range).to_relative()
712 };
713
714 assert_eq!(map_at(0, SubRange::new(0, 1)), 0..1); assert_eq!(map_at(0, SubRange::new(2, 3)), 3..4); assert_eq!(map_at(0, SubRange::new(2, 4)), 3..5); assert_eq!(map_at(0, SubRange::new(4, 5)), 7..8); assert_eq!(map_at(1, SubRange::new(0, 1)), 0..1); assert_eq!(map_at(3, SubRange::new(0, 1)), 0..1); assert_eq!(map_at(4, SubRange::new(0, 2)), 0..2); assert_eq!(map_at(1, SubRange::new(0, 2)), 0..3); assert_eq!(map_at(0, SubRange::new(1, 3)), 1..4); assert_eq!(map_at(3, SubRange::new(0, 2)), 0..4); assert_eq!(map_at(0, SubRange::new(3, 5)), 4..8); assert_eq!(map_at(1, SubRange::new(0, 4)), 0..7); assert_eq!(map_at(0, SubRange::new(1, 5)), 1..8); assert_eq!(map_at(0, SubRange::new(0, 6)), 0..9); }
731}