flams_utils/
sourcerefs.rs

1use 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}