asciidoc_parser/parser/
source_map.rs1use std::fmt;
2
3#[derive(Clone, Default, Eq, PartialEq)]
10pub struct SourceMap(pub Vec<(usize, SourceLine)>);
11
12#[derive(Clone, Debug, Default, Eq, PartialEq)]
22pub struct SourceLine(pub Option<String>, pub usize);
23
24impl SourceMap {
25 pub(crate) fn append(&mut self, preprocessed_line: usize, source_line: SourceLine) {
26 self.0.push((preprocessed_line, source_line));
29 }
30
31 pub fn original_file_and_line(&self, key: usize) -> Option<SourceLine> {
35 match self.0.binary_search_by_key(&key, |(k, _)| *k) {
36 Ok(i) => self.0.get(i).map(|(_k, v)| v.clone()),
37 Err(0) => Some(SourceLine(None, key)),
38 Err(i) => self
39 .0
40 .get(i - 1)
41 .map(|(k, v)| SourceLine(v.0.clone(), v.1 + key - k)),
42 }
43 }
44}
45
46impl fmt::Debug for SourceMap {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 f.write_str("SourceMap(&")?;
49 f.debug_list()
50 .entries(self.0.iter().map(|(k, v)| (k, v)))
51 .finish()?;
52 f.write_str(")")
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 #![allow(clippy::unwrap_used)]
59
60 use crate::parser::{SourceLine, SourceMap};
61
62 #[test]
63 fn empty() {
64 let sm = SourceMap::default();
65 assert_eq!(sm.original_file_and_line(1), Some(SourceLine(None, 1)));
66 }
67
68 #[test]
69 fn one_entry() {
70 let mut sm = SourceMap::default();
71 sm.append(1, SourceLine(None, 1));
72
73 assert_eq!(sm.original_file_and_line(0), Some(SourceLine(None, 0)));
74 assert_eq!(sm.original_file_and_line(1), Some(SourceLine(None, 1)));
75 assert_eq!(sm.original_file_and_line(4), Some(SourceLine(None, 4)));
76
77 assert_eq!(
78 sm.original_file_and_line(4000),
79 Some(SourceLine(None, 4000))
80 );
81 }
82
83 #[test]
84 fn multiple_entries() {
85 let mut sm = SourceMap::default();
86 sm.append(1, SourceLine(None, 1));
87 sm.append(10, SourceLine(Some("foo.adoc".to_owned()), 1));
88 sm.append(20, SourceLine(Some("bar.adoc".to_owned()), 18));
89 sm.append(30, SourceLine(None, 11));
90
91 assert_eq!(sm.original_file_and_line(1), Some(SourceLine(None, 1)));
92 assert_eq!(sm.original_file_and_line(4), Some(SourceLine(None, 4)));
93
94 assert_eq!(
95 sm.original_file_and_line(10),
96 Some(SourceLine(Some("foo.adoc".to_owned()), 1))
97 );
98 assert_eq!(
99 sm.original_file_and_line(19),
100 Some(SourceLine(Some("foo.adoc".to_owned()), 10))
101 );
102
103 assert_eq!(
104 sm.original_file_and_line(20),
105 Some(SourceLine(Some("bar.adoc".to_owned()), 18))
106 );
107 assert_eq!(
108 sm.original_file_and_line(21),
109 Some(SourceLine(Some("bar.adoc".to_owned()), 19))
110 );
111 assert_eq!(
112 sm.original_file_and_line(29),
113 Some(SourceLine(Some("bar.adoc".to_owned()), 27))
114 );
115
116 assert_eq!(sm.original_file_and_line(30), Some(SourceLine(None, 11)));
117 assert_eq!(sm.original_file_and_line(40), Some(SourceLine(None, 21)));
118 }
119
120 #[test]
121 fn impl_debug() {
122 let mut sm = SourceMap::default();
123 sm.append(1, SourceLine(None, 1));
124
125 assert_eq!(
126 format!("{sm:#?}"),
127 "SourceMap(&[\n (\n 1,\n SourceLine(\n None,\n 1,\n ),\n ),\n])"
128 );
129 }
130}