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