diff options
author | Aleksey Kladov <[email protected]> | 2018-08-28 12:06:30 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-28 12:06:30 +0100 |
commit | 7e74af32268f9b0783ca94107b0b10d52e4ebe5e (patch) | |
tree | 179d818c695a27ceee3f8193e219234854190f9a /crates/libsyntax2/src/yellow/syntax_text.rs | |
parent | 363f466627db373fab23d1df94b7382223b8675a (diff) |
Avoid materializing strings
Diffstat (limited to 'crates/libsyntax2/src/yellow/syntax_text.rs')
-rw-r--r-- | crates/libsyntax2/src/yellow/syntax_text.rs | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/crates/libsyntax2/src/yellow/syntax_text.rs b/crates/libsyntax2/src/yellow/syntax_text.rs new file mode 100644 index 000000000..268547470 --- /dev/null +++ b/crates/libsyntax2/src/yellow/syntax_text.rs | |||
@@ -0,0 +1,101 @@ | |||
1 | use std::{ | ||
2 | fmt, ops, | ||
3 | }; | ||
4 | |||
5 | use { | ||
6 | SyntaxNodeRef, TextRange, TextUnit, | ||
7 | algo::walk::preorder, | ||
8 | text_utils::{intersect, contains_offset_nonstrict}, | ||
9 | }; | ||
10 | |||
11 | #[derive(Clone)] | ||
12 | pub struct SyntaxText<'a> { | ||
13 | node: SyntaxNodeRef<'a>, | ||
14 | range: TextRange, | ||
15 | } | ||
16 | |||
17 | impl<'a> SyntaxText<'a> { | ||
18 | pub(crate) fn new(node: SyntaxNodeRef<'a>) -> SyntaxText<'a> { | ||
19 | SyntaxText { | ||
20 | node, | ||
21 | range: node.range() | ||
22 | } | ||
23 | } | ||
24 | pub fn chunks(&self) -> impl Iterator<Item=&'a str> { | ||
25 | let range = self.range; | ||
26 | preorder(self.node) | ||
27 | .filter_map(move |node| { | ||
28 | let text = node.leaf_text_ref()?; | ||
29 | let range = intersect(range, node.range())?; | ||
30 | let range = range - node.range().start(); | ||
31 | Some(&text[range]) | ||
32 | }) | ||
33 | } | ||
34 | pub fn to_string(&self) -> String { | ||
35 | self.chunks().collect() | ||
36 | } | ||
37 | pub fn contains(&self, c: char) -> bool { | ||
38 | self.chunks().any(|it| it.contains(c)) | ||
39 | } | ||
40 | pub fn find(&self, c: char) -> Option<TextUnit> { | ||
41 | let mut acc: TextUnit = 0.into(); | ||
42 | for chunk in self.chunks() { | ||
43 | if let Some(pos) = chunk.find(c) { | ||
44 | let pos: TextUnit = (pos as u32).into(); | ||
45 | return Some(acc + pos); | ||
46 | } | ||
47 | acc += TextUnit::of_str(chunk); | ||
48 | } | ||
49 | None | ||
50 | } | ||
51 | pub fn len(&self) -> TextUnit { | ||
52 | self.range.len() | ||
53 | } | ||
54 | pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> { | ||
55 | let range = range.restrict(self.range) | ||
56 | .unwrap_or_else(|| { | ||
57 | panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range) | ||
58 | }); | ||
59 | SyntaxText { node: self.node, range } | ||
60 | } | ||
61 | } | ||
62 | |||
63 | impl<'a> fmt::Debug for SyntaxText<'a> { | ||
64 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
65 | fmt::Debug::fmt(&self.to_string(), f) | ||
66 | } | ||
67 | } | ||
68 | |||
69 | impl<'a> fmt::Display for SyntaxText<'a> { | ||
70 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
71 | fmt::Display::fmt(&self.to_string(), f) | ||
72 | } | ||
73 | } | ||
74 | |||
75 | pub trait SyntaxTextSlice: fmt::Debug { | ||
76 | fn restrict(&self, range: TextRange) -> Option<TextRange>; | ||
77 | } | ||
78 | |||
79 | impl SyntaxTextSlice for TextRange { | ||
80 | fn restrict(&self, range: TextRange) -> Option<TextRange> { | ||
81 | intersect(*self, range) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | impl SyntaxTextSlice for ops::RangeTo<TextUnit> { | ||
86 | fn restrict(&self, range: TextRange) -> Option<TextRange> { | ||
87 | if !contains_offset_nonstrict(range, self.end) { | ||
88 | return None; | ||
89 | } | ||
90 | Some(TextRange::from_to(range.start(), self.end)) | ||
91 | } | ||
92 | } | ||
93 | |||
94 | impl SyntaxTextSlice for ops::RangeFrom<TextUnit> { | ||
95 | fn restrict(&self, range: TextRange) -> Option<TextRange> { | ||
96 | if !contains_offset_nonstrict(range, self.start) { | ||
97 | return None; | ||
98 | } | ||
99 | Some(TextRange::from_to(self.start, range.end())) | ||
100 | } | ||
101 | } | ||