| 1 | use crate::find::find; | 
| 2 | use std::fmt::Debug; | 
|---|
| 3 | use std::ops::{self, RangeFrom, RangeFull, RangeTo}; | 
|---|
| 4 |  | 
|---|
| 5 | #[ derive(Copy, Clone)] | 
|---|
| 6 | pub struct Range<'a> { | 
|---|
| 7 | pub doc: &'a [char], | 
|---|
| 8 | pub offset: usize, | 
|---|
| 9 | pub len: usize, | 
|---|
| 10 | } | 
|---|
| 11 |  | 
|---|
| 12 | impl<'a> Range<'a> { | 
|---|
| 13 | pub fn empty() -> Self { | 
|---|
| 14 | Range { | 
|---|
| 15 | doc: &[], | 
|---|
| 16 | offset: 0, | 
|---|
| 17 | len: 0, | 
|---|
| 18 | } | 
|---|
| 19 | } | 
|---|
| 20 |  | 
|---|
| 21 | pub fn new(doc: &'a [char], bounds: impl RangeBounds) -> Self { | 
|---|
| 22 | let (offset, len) = bounds.index(doc.len()); | 
|---|
| 23 | Range { doc, offset, len } | 
|---|
| 24 | } | 
|---|
| 25 |  | 
|---|
| 26 | pub fn is_empty(&self) -> bool { | 
|---|
| 27 | self.len == 0 | 
|---|
| 28 | } | 
|---|
| 29 |  | 
|---|
| 30 | pub fn len_bytes(&self) -> usize { | 
|---|
| 31 | self.chars().map(char::len_utf8).sum() | 
|---|
| 32 | } | 
|---|
| 33 |  | 
|---|
| 34 | pub fn substring(&self, bounds: impl RangeBounds) -> Self { | 
|---|
| 35 | let (offset, len) = bounds.index(self.len); | 
|---|
| 36 | Range { | 
|---|
| 37 | doc: self.doc, | 
|---|
| 38 | offset: self.offset + offset, | 
|---|
| 39 | len, | 
|---|
| 40 | } | 
|---|
| 41 | } | 
|---|
| 42 |  | 
|---|
| 43 | pub fn get(&self, bounds: impl RangeBounds) -> Option<Self> { | 
|---|
| 44 | let (offset, len) = bounds.try_index(self.len)?; | 
|---|
| 45 | Some(Range { | 
|---|
| 46 | doc: self.doc, | 
|---|
| 47 | offset: self.offset + offset, | 
|---|
| 48 | len, | 
|---|
| 49 | }) | 
|---|
| 50 | } | 
|---|
| 51 |  | 
|---|
| 52 | pub fn split_at(&self, mid: usize) -> (Self, Self) { | 
|---|
| 53 | (self.substring(..mid), self.substring(mid..)) | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | pub fn chars( | 
|---|
| 57 | &self, | 
|---|
| 58 | ) -> impl Iterator<Item = char> + DoubleEndedIterator + ExactSizeIterator + 'a { | 
|---|
| 59 | slice(*self).iter().copied() | 
|---|
| 60 | } | 
|---|
| 61 |  | 
|---|
| 62 | pub fn starts_with(&self, prefix: impl AsRef<[char]>) -> bool { | 
|---|
| 63 | slice(*self).starts_with(prefix.as_ref()) | 
|---|
| 64 | } | 
|---|
| 65 |  | 
|---|
| 66 | pub fn ends_with(&self, suffix: impl AsRef<[char]>) -> bool { | 
|---|
| 67 | slice(*self).ends_with(suffix.as_ref()) | 
|---|
| 68 | } | 
|---|
| 69 |  | 
|---|
| 70 | pub fn find(&self, needle: impl AsRef<[char]>) -> Option<usize> { | 
|---|
| 71 | find(slice(*self), needle.as_ref()) | 
|---|
| 72 | } | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 | pub fn slice(range: Range) -> &[char] { | 
|---|
| 76 | &range.doc[range.offset..range.offset + range.len] | 
|---|
| 77 | } | 
|---|
| 78 |  | 
|---|
| 79 | impl AsRef<[char]> for Range<'_> { | 
|---|
| 80 | fn as_ref(&self) -> &[char] { | 
|---|
| 81 | slice(*self) | 
|---|
| 82 | } | 
|---|
| 83 | } | 
|---|
| 84 |  | 
|---|
| 85 | pub trait RangeBounds: Sized + Clone + Debug { | 
|---|
| 86 | // Returns (offset, len). | 
|---|
| 87 | fn try_index(self, len: usize) -> Option<(usize, usize)>; | 
|---|
| 88 | fn index(self, len: usize) -> (usize, usize) { | 
|---|
| 89 | match self.clone().try_index(len) { | 
|---|
| 90 | Some(range: (usize, usize)) => range, | 
|---|
| 91 | None => panic!( "index out of range, index={:?} , len={} ", self, len), | 
|---|
| 92 | } | 
|---|
| 93 | } | 
|---|
| 94 | } | 
|---|
| 95 |  | 
|---|
| 96 | impl RangeBounds for ops::Range<usize> { | 
|---|
| 97 | fn try_index(self, len: usize) -> Option<(usize, usize)> { | 
|---|
| 98 | if self.start <= self.end && self.end <= len { | 
|---|
| 99 | Some((self.start, self.end - self.start)) | 
|---|
| 100 | } else { | 
|---|
| 101 | None | 
|---|
| 102 | } | 
|---|
| 103 | } | 
|---|
| 104 | } | 
|---|
| 105 |  | 
|---|
| 106 | impl RangeBounds for RangeFrom<usize> { | 
|---|
| 107 | fn try_index(self, len: usize) -> Option<(usize, usize)> { | 
|---|
| 108 | if self.start <= len { | 
|---|
| 109 | Some((self.start, len - self.start)) | 
|---|
| 110 | } else { | 
|---|
| 111 | None | 
|---|
| 112 | } | 
|---|
| 113 | } | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | impl RangeBounds for RangeTo<usize> { | 
|---|
| 117 | fn try_index(self, len: usize) -> Option<(usize, usize)> { | 
|---|
| 118 | if self.end <= len { | 
|---|
| 119 | Some((0, self.end)) | 
|---|
| 120 | } else { | 
|---|
| 121 | None | 
|---|
| 122 | } | 
|---|
| 123 | } | 
|---|
| 124 | } | 
|---|
| 125 |  | 
|---|
| 126 | impl RangeBounds for RangeFull { | 
|---|
| 127 | fn try_index(self, len: usize) -> Option<(usize, usize)> { | 
|---|
| 128 | Some((0, len)) | 
|---|
| 129 | } | 
|---|
| 130 | } | 
|---|
| 131 |  | 
|---|