flams_utils/
sourcerefs.rs1use std::fmt::{Debug, Display};
2use crate::CondSerialize;
3
4pub trait SourcePos: Clone + Copy + Default + Debug + PartialOrd + Ord + 'static + CondSerialize {
5 fn update(&mut self, c: char);
6 fn update_newline(&mut self, rn: bool);
7 fn update_str_no_newline(&mut self, s: &str);
8 fn update_str_maybe_newline(&mut self, s: &str);
9}
10impl SourcePos for () {
11 #[inline]
12 fn update(&mut self, _: char) {}
13 #[inline]
14 fn update_newline(&mut self, _: bool) {}
15 #[inline]
16 fn update_str_no_newline(&mut self, _: &str) {}
17 #[inline]
18 fn update_str_maybe_newline(&mut self, _: &str) {}
19}
20
21#[derive(Clone, Copy, PartialEq, Eq, Default,PartialOrd,Ord)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct ByteOffset {
24 pub offset: usize,
25}
26impl Display for ByteOffset {
27 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
28 write!(f, "{}", self.offset)
29 }
30}
31impl Debug for ByteOffset {
32 #[inline]
33 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
34 <Self as Display>::fmt(self, f)
35 }
36}
37impl SourcePos for ByteOffset {
38 #[inline]
39 fn update(&mut self, c: char) {
40 self.offset += c.len_utf8();
41 }
42 #[inline]
43 fn update_newline(&mut self, rn: bool) {
44 self.offset += if rn { 2 } else { 1 };
45 }
46 #[inline]
47 fn update_str_no_newline(&mut self, s: &str) {
48 self.offset += s.len();
49 }
50 #[inline]
51 fn update_str_maybe_newline(&mut self, s: &str) {
52 self.update_str_no_newline(s);
53 }
54}
55
56#[derive(Clone, Copy, PartialEq, Eq,Default)]
57#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
58pub struct LSPLineCol {
59 pub line: u32,
60 pub col: u32,
61}
62impl Ord for LSPLineCol {
63 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
64 self.line.cmp(&other.line).then(self.col.cmp(&other.col))
65 }
66}
67impl PartialOrd for LSPLineCol {
68 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
69 Some(self.cmp(other))
70 }
71}
72
73impl Display for LSPLineCol {
74 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
75 write!(f, "l. {} c. {}", self.line, self.col)
76 }
77}
78impl Debug for LSPLineCol {
79 #[inline]
80 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
81 <Self as Display>::fmt(self, f)
82 }
83}
84
85impl SourcePos for LSPLineCol {
86 #[inline]
87 #[allow(clippy::cast_possible_truncation)]
88 fn update(&mut self, c: char) {
89 self.col += c.len_utf16() as u32;
90 }
91 #[inline]
92 fn update_newline(&mut self, _: bool) {
93 self.line += 1;
94 self.col = 0;
95 }
96
97 #[inline]
98 #[allow(clippy::cast_possible_truncation)]
99 fn update_str_no_newline(&mut self, s: &str) {
100 self.col += s.chars().map(|c| char::len_utf16(c) as u32).sum::<u32>();
101 }
102
103 #[allow(clippy::cast_possible_truncation)]
104 fn update_str_maybe_newline(&mut self, s: &str) {
105 let s = s.split("\r\n").flat_map(|s| s.split(['\n', '\r']));
106 let mut last = "";
107 let mut first = true;
108 for l in s {
109 if first {
110 first = false;
111 } else {
112 self.line += 1;
113 self.col = 0;
114 }
115 last = l;
116 }
117 self.col += last.chars().map(|c| char::len_utf16(c) as u32).sum::<u32>();
118 }
119}
120
121impl<A: SourcePos, B: SourcePos> SourcePos for (A, B) {
122 #[inline]
123 fn update(&mut self, c: char) {
124 self.0.update(c);
125 self.1.update(c);
126 }
127 #[inline]
128 fn update_newline(&mut self, rn: bool) {
129 self.0.update_newline(rn);
130 self.1.update_newline(rn);
131 }
132 #[inline]
133 fn update_str_no_newline(&mut self, s: &str) {
134 self.0.update_str_no_newline(s);
135 self.1.update_str_no_newline(s);
136 }
137 #[inline]
138 fn update_str_maybe_newline(&mut self, s: &str) {
139 self.0.update_str_maybe_newline(s);
140 self.1.update_str_maybe_newline(s);
141 }
142}
143
144#[derive(Clone, Copy, PartialEq, Eq, Default)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146pub struct SourceRange<P: SourcePos> {
147 pub start: P,
148 pub end: P,
149}
150impl<P: SourcePos> Display for SourceRange<P> {
151 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
152 write!(f, "{:#?}-{:#?}", self.start, self.end)
153 }
154}
155impl<P: SourcePos> Debug for SourceRange<P> {
156 #[inline]
157 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
158 <Self as Display>::fmt(self, f)
159 }
160}
161impl<P:SourcePos> SourceRange<P> {
162 pub fn contains(&self, pos: P) -> bool {
163 self.start <= pos && pos <= self.end
164 }
165}
166
167#[test]
168fn test() {
169 let str = "\n\n";
170 let len = str.split("\r\n").flat_map(|s| s.split(['\r', '\n'])).count();
171 assert_eq!(len, 3);
172}