1use std::cmp::Ordering;
11use std::fmt;
12use std::hash::{Hash, Hasher};
13use std::ops::Range;
14use std::str;
15use std::sync::Arc;
16
17use span;
18
19#[derive(Clone)]
21pub struct Position {
22 input: Arc<str>,
23 pos: usize,
27}
28
29impl Position {
30 pub(crate) unsafe fn new_unchecked(input: Arc<str>, pos: usize) -> Position {
36 debug_assert!(input.get(pos..).is_some());
37 Position { input, pos }
38 }
39
40 #[allow(clippy::new_ret_no_self)]
54 pub fn new(input: Arc<str>, pos: usize) -> Option<Position> {
55 match input.get(pos..) {
56 Some(..) => Some(Position { input, pos }),
57 None => None,
58 }
59 }
60
61 #[inline]
72 pub fn from_start(input: Arc<str>) -> Position {
73 Position { input, pos: 0 }
75 }
76
77 #[inline]
90 pub fn pos(&self) -> usize {
91 self.pos
92 }
93
94 #[inline]
113 pub fn span(&self, other: &Position) -> span::Span {
114 if Arc::ptr_eq(&self.input, &other.input)
115 {
117 unsafe { span::Span::new_unchecked(self.input.clone(), self.pos, other.pos) }
119 } else {
120 panic!("span created from positions from different inputs")
122 }
123 }
124
125 #[inline]
143 pub fn line_col(&self) -> (usize, usize) {
144 if self.pos > self.input.len() {
145 panic!("position out of bounds");
146 }
147
148 let mut pos = self.pos;
149 let slice = &self.input[..pos];
151 let mut chars = slice.chars().peekable();
152
153 let mut line_col = (1, 1);
154
155 while pos != 0 {
156 match chars.next() {
157 Some('\r') => {
158 if let Some(&'\n') = chars.peek() {
159 chars.next();
160
161 if pos == 1 {
162 pos -= 1;
163 } else {
164 pos -= 2;
165 }
166
167 line_col = (line_col.0 + 1, 1);
168 } else {
169 pos -= 1;
170 line_col = (line_col.0, line_col.1 + 1);
171 }
172 }
173 Some('\n') => {
174 pos -= 1;
175 line_col = (line_col.0 + 1, 1);
176 }
177 Some(c) => {
178 pos -= c.len_utf8();
179 line_col = (line_col.0, line_col.1 + 1);
180 }
181 None => unreachable!(),
182 }
183 }
184
185 line_col
186 }
187
188 #[inline]
206 pub fn line_of(&self) -> &str {
207 if self.pos > self.input.len() {
208 panic!("position out of bounds");
209 };
210 &self.input[self.find_line_start()..self.find_line_end()]
212 }
213
214 pub(crate) fn find_line_start(&self) -> usize {
215 if self.input.is_empty() {
216 return 0;
217 };
218 let start = self
220 .input
221 .char_indices()
222 .rev()
223 .skip_while(|&(i, _)| i >= self.pos)
224 .find(|&(_, c)| c == '\n');
225 match start {
226 Some((i, _)) => i + 1,
227 None => 0,
228 }
229 }
230
231 pub(crate) fn find_line_end(&self) -> usize {
232 if self.input.is_empty() {
233 0
234 } else if self.pos == self.input.len() - 1 {
235 self.input.len()
236 } else {
237 let end = self
239 .input
240 .char_indices()
241 .skip_while(|&(i, _)| i < self.pos)
242 .find(|&(_, c)| c == '\n');
243 match end {
244 Some((i, _)) => i + 1,
245 None => self.input.len(),
246 }
247 }
248 }
249
250 #[inline]
252 pub(crate) fn at_start(&self) -> bool {
253 self.pos == 0
254 }
255
256 #[inline]
258 pub(crate) fn at_end(&self) -> bool {
259 self.pos == self.input.len()
260 }
261
262 #[inline]
265 pub(crate) fn skip(&mut self, n: usize) -> bool {
266 let skipped = {
267 let mut len = 0;
268 let mut chars = (&self.input[self.pos..]).chars();
270 for _ in 0..n {
271 if let Some(c) = chars.next() {
272 len += c.len_utf8();
273 } else {
274 return false;
275 }
276 }
277 len
278 };
279
280 self.pos += skipped;
281 true
282 }
283
284 #[inline]
287 pub(crate) fn skip_back(&mut self, n: usize) -> bool {
288 let skipped = {
289 let mut len = 0;
290 let mut chars = (&self.input[..self.pos]).chars().rev();
292 for _ in 0..n {
293 if let Some(c) = chars.next() {
294 len += c.len_utf8();
295 } else {
296 return false;
297 }
298 }
299 len
300 };
301
302 self.pos -= skipped;
303 true
304 }
305
306 #[inline]
309 pub(crate) fn skip_until(&mut self, strings: &[&str]) -> bool {
310 for from in self.pos..self.input.len() {
311 let bytes = if let Some(string) = self.input.get(from..) {
312 string.as_bytes()
313 } else {
314 continue;
315 };
316
317 for slice in strings.iter() {
318 let to = slice.len();
319 if Some(slice.as_bytes()) == bytes.get(0..to) {
320 self.pos = from;
321 return true;
322 }
323 }
324 }
325
326 self.pos = self.input.len();
327 false
328 }
329
330 #[inline]
333 pub(crate) fn match_char_by<F>(&mut self, f: F) -> bool
334 where
335 F: FnOnce(char) -> bool,
336 {
337 if let Some(c) = (&self.input[self.pos..]).chars().next() {
338 if f(c) {
339 self.pos += c.len_utf8();
340 true
341 } else {
342 false
343 }
344 } else {
345 false
346 }
347 }
348
349 #[inline]
352 pub(crate) fn match_string(&mut self, string: &str) -> bool {
353 let to = self.pos + string.len();
354
355 if Some(string.as_bytes()) == self.input.as_bytes().get(self.pos..to) {
356 self.pos = to;
357 true
358 } else {
359 false
360 }
361 }
362
363 #[inline]
366 pub(crate) fn match_insensitive(&mut self, string: &str) -> bool {
367 let matched = {
368 let slice = &self.input[self.pos..];
369 if let Some(slice) = slice.get(0..string.len()) {
370 slice.eq_ignore_ascii_case(string)
371 } else {
372 false
373 }
374 };
375
376 if matched {
377 self.pos += string.len();
378 true
379 } else {
380 false
381 }
382 }
383
384 #[inline]
387 pub(crate) fn match_range(&mut self, range: Range<char>) -> bool {
388 if let Some(c) = (&self.input[self.pos..]).chars().next() {
389 if range.start <= c && c <= range.end {
390 self.pos += c.len_utf8();
391 return true;
392 }
393 }
394
395 false
396 }
397}
398
399impl fmt::Debug for Position {
400 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
401 f.debug_struct("Position").field("pos", &self.pos).finish()
402 }
403}
404
405impl PartialEq for Position {
406 fn eq(&self, other: &Position) -> bool {
407 Arc::ptr_eq(&self.input, &other.input) && self.pos == other.pos
408 }
409}
410
411impl Eq for Position {}
412
413impl PartialOrd for Position {
414 fn partial_cmp(&self, other: &Position) -> Option<Ordering> {
415 if Arc::ptr_eq(&self.input, &other.input) {
416 self.pos.partial_cmp(&other.pos)
417 } else {
418 None
419 }
420 }
421}
422
423impl Ord for Position {
424 fn cmp(&self, other: &Position) -> Ordering {
425 self.partial_cmp(other)
426 .expect("cannot compare positions from different strs")
427 }
428}
429
430impl Hash for Position {
431 fn hash<H: Hasher>(&self, state: &mut H) {
432 Arc::as_ptr(&self.input).hash(state);
433 self.pos.hash(state);
434 }
435}
436
437#[cfg(test)]
438mod tests {
439 use super::*;
440
441 #[test]
442 fn empty() {
443 let input: Arc<str> = Arc::from("");
444 assert_eq!(
445 Position::new(input.clone(), 0).unwrap().match_string(""),
446 true
447 );
448 assert_eq!(
449 !Position::new(input.clone(), 0).unwrap().match_string("a"),
450 true
451 );
452 }
453
454 #[test]
455 fn parts() {
456 let input: Arc<str> = Arc::from("asdasdf");
457
458 assert_eq!(
459 Position::new(input.clone(), 0).unwrap().match_string("asd"),
460 true
461 );
462 assert_eq!(
463 Position::new(input.clone(), 3)
464 .unwrap()
465 .match_string("asdf"),
466 true
467 );
468 }
469
470 #[test]
471 fn line_col() {
472 let input: Arc<str> = Arc::from("a\rb\nc\r\nd嗨");
473
474 assert_eq!(Position::new(input.clone(), 0).unwrap().line_col(), (1, 1));
475 assert_eq!(Position::new(input.clone(), 1).unwrap().line_col(), (1, 2));
476 assert_eq!(Position::new(input.clone(), 2).unwrap().line_col(), (1, 3));
477 assert_eq!(Position::new(input.clone(), 3).unwrap().line_col(), (1, 4));
478 assert_eq!(Position::new(input.clone(), 4).unwrap().line_col(), (2, 1));
479 assert_eq!(Position::new(input.clone(), 5).unwrap().line_col(), (2, 2));
480 assert_eq!(Position::new(input.clone(), 6).unwrap().line_col(), (2, 3));
481 assert_eq!(Position::new(input.clone(), 7).unwrap().line_col(), (3, 1));
482 assert_eq!(Position::new(input.clone(), 8).unwrap().line_col(), (3, 2));
483 assert_eq!(Position::new(input.clone(), 11).unwrap().line_col(), (3, 3));
484 }
485
486 #[test]
487 fn line_of() {
488 let input: Arc<str> = Arc::from("a\rb\nc\r\nd嗨");
489
490 assert_eq!(Position::new(input.clone(), 0).unwrap().line_of(), "a\rb\n");
491 assert_eq!(Position::new(input.clone(), 1).unwrap().line_of(), "a\rb\n");
492 assert_eq!(Position::new(input.clone(), 2).unwrap().line_of(), "a\rb\n");
493 assert_eq!(Position::new(input.clone(), 3).unwrap().line_of(), "a\rb\n");
494 assert_eq!(Position::new(input.clone(), 4).unwrap().line_of(), "c\r\n");
495 assert_eq!(Position::new(input.clone(), 5).unwrap().line_of(), "c\r\n");
496 assert_eq!(Position::new(input.clone(), 6).unwrap().line_of(), "c\r\n");
497 assert_eq!(Position::new(input.clone(), 7).unwrap().line_of(), "d嗨");
498 assert_eq!(Position::new(input.clone(), 8).unwrap().line_of(), "d嗨");
499 assert_eq!(Position::new(input.clone(), 11).unwrap().line_of(), "d嗨");
500 }
501
502 #[test]
503 fn line_of_empty() {
504 let input: Arc<str> = Arc::from("");
505
506 assert_eq!(Position::new(input, 0).unwrap().line_of(), "");
507 }
508
509 #[test]
510 fn line_of_new_line() {
511 let input: Arc<str> = Arc::from("\n");
512
513 assert_eq!(Position::new(input, 0).unwrap().line_of(), "\n");
514 }
515
516 #[test]
517 fn line_of_between_new_line() {
518 let input: Arc<str> = Arc::from("\n\n");
519
520 assert_eq!(Position::new(input, 1).unwrap().line_of(), "\n");
521 }
522
523 fn measure_skip(input: &Arc<str>, pos: usize, n: usize) -> Option<usize> {
524 let mut p = Position::new(input.clone(), pos).unwrap();
525 if p.skip(n) {
526 Some(p.pos - pos)
527 } else {
528 None
529 }
530 }
531
532 #[test]
533 fn skip_empty() {
534 let input: Arc<str> = Arc::from("");
535
536 assert_eq!(measure_skip(&input, 0, 0), Some(0));
537 assert_eq!(measure_skip(&input, 0, 1), None);
538 }
539
540 #[test]
541 fn skip() {
542 let input: Arc<str> = Arc::from("d嗨");
543
544 assert_eq!(measure_skip(&input, 0, 0), Some(0));
545 assert_eq!(measure_skip(&input, 0, 1), Some(1));
546 assert_eq!(measure_skip(&input, 1, 1), Some(3));
547 }
548
549 #[test]
550 fn skip_until() {
551 let input: Arc<str> = Arc::from("ab ac");
552 let pos = Position::from_start(input);
553
554 let mut test_pos = pos.clone();
555 test_pos.skip_until(&["a", "b"]);
556 assert_eq!(test_pos.pos(), 0);
557
558 test_pos = pos.clone();
559 test_pos.skip_until(&["b"]);
560 assert_eq!(test_pos.pos(), 1);
561
562 test_pos = pos.clone();
563 test_pos.skip_until(&["ab"]);
564 assert_eq!(test_pos.pos(), 0);
565
566 test_pos = pos.clone();
567 test_pos.skip_until(&["ac", "z"]);
568 assert_eq!(test_pos.pos(), 3);
569
570 test_pos = pos.clone();
571 assert!(!test_pos.skip_until(&["z"]));
572 assert_eq!(test_pos.pos(), 5);
573 }
574
575 #[test]
576 fn match_range() {
577 let input: Arc<str> = Arc::from("b");
578
579 assert_eq!(
580 Position::new(input.clone(), 0)
581 .unwrap()
582 .match_range('a'..'c'),
583 true
584 );
585 assert_eq!(
586 Position::new(input.clone(), 0)
587 .unwrap()
588 .match_range('b'..'b'),
589 true
590 );
591 assert_eq!(
592 !Position::new(input.clone(), 0)
593 .unwrap()
594 .match_range('a'..'a'),
595 true
596 );
597 assert_eq!(
598 !Position::new(input.clone(), 0)
599 .unwrap()
600 .match_range('c'..'c'),
601 true
602 );
603 assert_eq!(
604 Position::new(input.clone(), 0)
605 .unwrap()
606 .match_range('a'..'嗨'),
607 true
608 );
609 }
610
611 #[test]
612 fn match_insensitive() {
613 let input: Arc<str> = Arc::from("AsdASdF");
614
615 assert_eq!(
616 Position::new(input.clone(), 0)
617 .unwrap()
618 .match_insensitive("asd"),
619 true
620 );
621 assert_eq!(
622 Position::new(input.clone(), 3)
623 .unwrap()
624 .match_insensitive("asdf"),
625 true
626 );
627 }
628
629 #[test]
630 fn cmp() {
631 let input: Arc<str> = Arc::from("a");
632 let start = Position::from_start(input);
633 let mut end = start.clone();
634
635 assert!(end.skip(1));
636 let result = start.cmp(&end);
637
638 assert_eq!(result, Ordering::Less);
639 }
640
641 #[test]
642 #[should_panic]
643 fn cmp_panic() {
644 let input1 = Arc::from("a");
645 let input2 = Arc::from("b");
646 let pos1 = Position::from_start(input1);
647 let pos2 = Position::from_start(input2);
648
649 let _ = pos1.cmp(&pos2);
650 }
651
652 #[test]
653 #[cfg(feature = "std")]
654 fn hash() {
655 use std::collections::HashSet;
656
657 let input: Arc<str> = Arc::from("a");
658 let start = Position::from_start(input);
659 let mut positions = HashSet::new();
660
661 positions.insert(start);
662 }
663}