dprint_core/formatting/tokens/
token_finder.rs

1/// Trait for a collection of tokens.
2pub trait TokenCollection<'a> {
3  /// The position type the token uses.
4  type TPos: PartialOrd + Copy;
5  /// The token type.
6  type TToken: 'a;
7
8  /// Gets the start position at the specified collection index.
9  fn get_start_at_index(&self, index: usize) -> Self::TPos;
10  /// Gets the end position at the specified collection index.
11  fn get_end_at_index(&self, index: usize) -> Self::TPos;
12  /// Gets the token at the specified collection index.
13  fn get_token_at_index(&self, index: usize) -> &'a Self::TToken;
14  /// Gets the length of the collection.
15  fn len(&self) -> usize;
16  /// Gets if the collection is empty.
17  fn is_empty(&self) -> bool;
18}
19
20/// Searches a token collection for
21pub struct TokenFinder<TTokenCollection> {
22  tokens: TTokenCollection,
23  token_index: usize,
24}
25
26impl<'a, TTokenCollection> TokenFinder<TTokenCollection>
27where
28  TTokenCollection: TokenCollection<'a>,
29{
30  pub fn new(tokens: TTokenCollection) -> TokenFinder<TTokenCollection> {
31    TokenFinder { tokens, token_index: 0 }
32  }
33
34  #[inline]
35  pub fn get_next_token_if(
36    &mut self,
37    end: TTokenCollection::TPos,
38    is_match: impl FnOnce(&'a TTokenCollection::TToken) -> bool,
39  ) -> Option<&'a TTokenCollection::TToken> {
40    let next_token = self.get_next_token(end)?;
41    if is_match(next_token) {
42      Some(next_token)
43    } else {
44      None
45    }
46  }
47
48  #[inline]
49  pub fn get_next_token(&mut self, end: TTokenCollection::TPos) -> Option<&'a TTokenCollection::TToken> {
50    self.get_first_token_after(end, |_| true)
51  }
52
53  #[inline]
54  pub fn get_previous_token_if(
55    &mut self,
56    start: TTokenCollection::TPos,
57    is_match: impl FnOnce(&'a TTokenCollection::TToken) -> bool,
58  ) -> Option<&'a TTokenCollection::TToken> {
59    let previous_token = self.get_previous_token(start)?;
60    if is_match(previous_token) {
61      Some(previous_token)
62    } else {
63      None
64    }
65  }
66
67  #[inline]
68  pub fn get_previous_token(&mut self, start: TTokenCollection::TPos) -> Option<&'a TTokenCollection::TToken> {
69    self.get_first_token_before(start, |_| true)
70  }
71
72  pub fn get_first_token_within(
73    &mut self,
74    start: TTokenCollection::TPos,
75    end: TTokenCollection::TPos,
76    is_match: impl Fn(&'a TTokenCollection::TToken) -> bool,
77  ) -> Option<&'a TTokenCollection::TToken> {
78    if self.tokens.is_empty() {
79      return None;
80    }
81    self.move_to_node_start(start);
82
83    loop {
84      let token_start = self.tokens.get_start_at_index(self.token_index);
85      if token_start >= end {
86        break;
87      } else {
88        let current_token = self.tokens.get_token_at_index(self.token_index);
89        if is_match(current_token) {
90          return Some(current_token);
91        }
92      }
93
94      if !self.try_increment_index() {
95        break;
96      }
97    }
98
99    None
100  }
101
102  pub fn get_last_token_within(
103    &mut self,
104    start: TTokenCollection::TPos,
105    end: TTokenCollection::TPos,
106    is_match: impl Fn(&'a TTokenCollection::TToken) -> bool,
107  ) -> Option<&'a TTokenCollection::TToken> {
108    if self.tokens.is_empty() {
109      return None;
110    }
111
112    self.move_to_node_end(end);
113
114    loop {
115      let token_start = self.tokens.get_start_at_index(self.token_index);
116      if token_start >= end || token_start < start {
117        break;
118      } else {
119        let current_token = self.tokens.get_token_at_index(self.token_index);
120        if is_match(current_token) {
121          return Some(current_token);
122        }
123      }
124
125      if !self.try_decrement_index() {
126        break;
127      }
128    }
129
130    None
131  }
132
133  pub fn get_first_token_before(
134    &mut self,
135    start: TTokenCollection::TPos,
136    is_match: impl Fn(&'a TTokenCollection::TToken) -> bool,
137  ) -> Option<&'a TTokenCollection::TToken> {
138    if self.tokens.is_empty() {
139      return None;
140    }
141    self.move_to_node_start(start);
142
143    if self.tokens.get_start_at_index(self.token_index) < start {
144      let current_token = self.tokens.get_token_at_index(self.token_index);
145      if is_match(current_token) {
146        return Some(current_token);
147      }
148    }
149
150    while self.try_decrement_index() {
151      let current_token = self.tokens.get_token_at_index(self.token_index);
152      if is_match(current_token) {
153        return Some(current_token);
154      }
155    }
156
157    None
158  }
159
160  pub fn get_first_token_after(
161    &mut self,
162    end: TTokenCollection::TPos,
163    is_match: impl Fn(&'a TTokenCollection::TToken) -> bool,
164  ) -> Option<&'a TTokenCollection::TToken> {
165    if self.tokens.is_empty() {
166      return None;
167    }
168    self.move_to_node_end(end);
169
170    while self.try_increment_index() {
171      let current_token = self.tokens.get_token_at_index(self.token_index);
172      if is_match(current_token) {
173        return Some(current_token);
174      }
175    }
176
177    None
178  }
179
180  fn move_to_node_start(&mut self, start: TTokenCollection::TPos) {
181    while self.tokens.get_start_at_index(self.token_index) < start {
182      if !self.try_increment_index() {
183        break;
184      }
185    }
186
187    while self.tokens.get_start_at_index(self.token_index) > start {
188      if !self.try_decrement_index() {
189        break;
190      }
191    }
192  }
193
194  fn move_to_node_end(&mut self, end: TTokenCollection::TPos) {
195    while self.tokens.get_end_at_index(self.token_index) < end {
196      if !self.try_increment_index() {
197        break;
198      }
199    }
200
201    while self.tokens.get_end_at_index(self.token_index) > end {
202      if !self.try_decrement_index() {
203        break;
204      }
205    }
206  }
207
208  fn try_increment_index(&mut self) -> bool {
209    if self.token_index == self.tokens.len() - 1 {
210      false
211    } else {
212      self.token_index += 1;
213      true
214    }
215  }
216
217  fn try_decrement_index(&mut self) -> bool {
218    if self.token_index == 0 {
219      false
220    } else {
221      self.token_index -= 1;
222      true
223    }
224  }
225}