1use std::cell::RefCell;
2
3use super::Source;
4use crate::span::fallback::Span;
5
6thread_local! {
7 static GLOBAL: RefCell<SourceMap> = RefCell::new(SourceMap::new());
8}
9
10#[derive(Debug, Default)]
11pub struct SourceMap(Vec<Source>);
12
13impl SourceMap {
14 pub fn new() -> Self {
15 Self(vec![])
16 }
17
18 pub fn with<R>(f: impl FnOnce(&Self) -> R) -> R {
19 GLOBAL.with(|sm| f(&sm.borrow()))
20 }
21
22 pub fn with_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R {
23 GLOBAL.with(|sm| f(&mut sm.borrow_mut()))
24 }
25
26 pub fn as_slice(&self) -> &[Source] {
27 &self.0
28 }
29
30 pub fn len(&self) -> usize {
31 self.0.len()
32 }
33
34 pub fn is_empty(&self) -> bool {
35 self.0.is_empty()
36 }
37
38 pub fn find(&self, span: Span) -> Option<&Source> {
39 match self.find_index(span) {
40 None => None,
41 Some(i) => Some(&self.0[i]),
42 }
43 }
44
45 pub fn find_mut(&mut self, span: Span) -> Option<&mut Source> {
46 match self.find_index(span) {
47 None => None,
48 Some(i) => Some(&mut self.0[i]),
49 }
50 }
51
52 pub fn find_path(&self, span: Span) -> Option<String> {
53 if let Some(i) = self.find_index(span) {
54 return if i == 0 {
55 Some("<unspecified>".to_owned())
56 } else {
57 Some(format!("<parsed string {}>", i))
58 };
59 }
60
61 None
62 }
63
64 pub fn find_index(&self, span: Span) -> Option<usize> {
65 let sr = span.byte_range();
66 self.0
67 .binary_search_by(|src| {
68 let fr = src.span().byte_range();
69
70 if fr.end < sr.start {
71 std::cmp::Ordering::Less
72 } else if fr.start > sr.end {
73 std::cmp::Ordering::Greater
74 } else {
75 std::cmp::Ordering::Equal
76 }
77 })
78 .ok()
79 }
80
81 pub fn push(&mut self, src: impl Into<String>) -> Span {
82 let start = self.0.last().map(|src| src.span().byte_range().end).unwrap_or(0);
83 let src = Source::new(start, src);
84 let span = src.span();
85 self.0.push(src);
86 span
87 }
88}