1use core::ops::Range;
8
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
14#[cfg_attr(
15 feature = "serde",
16 derive(serde::Deserialize, serde::Serialize),
17 serde(transparent)
18)]
19pub struct ByteIndex(pub usize);
20
21#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
26#[cfg_attr(
27 feature = "serde",
28 derive(serde::Deserialize, serde::Serialize),
29 serde(transparent)
30)]
31pub struct CharIndex(pub usize);
32
33macro_rules! impl_text_index {
34 ($Type:ident) => {
35 impl $Type {
36 pub const ZERO: Self = Self(0);
38
39 #[inline]
41 pub fn saturating_add(self, rhs: usize) -> Self {
42 Self(self.0.saturating_add(rhs))
43 }
44
45 #[inline]
47 pub fn saturating_sub(self, rhs: usize) -> Self {
48 Self(self.0.saturating_sub(rhs))
49 }
50 }
51
52 impl From<usize> for $Type {
53 #[inline]
54 fn from(index: usize) -> Self {
55 Self(index)
56 }
57 }
58
59 impl From<$Type> for usize {
60 #[inline]
61 fn from(index: $Type) -> Self {
62 index.0
63 }
64 }
65
66 impl core::ops::Add<usize> for $Type {
67 type Output = Self;
68
69 #[inline]
70 fn add(self, rhs: usize) -> Self {
71 Self(self.0 + rhs)
72 }
73 }
74
75 impl core::ops::Add<$Type> for $Type {
77 type Output = Self;
78
79 #[inline]
80 fn add(self, rhs: Self) -> Self {
81 Self(self.0 + rhs.0)
82 }
83 }
84
85 impl core::ops::Sub<usize> for $Type {
86 type Output = Self;
87
88 #[inline]
89 fn sub(self, rhs: usize) -> Self {
90 Self(self.0 - rhs)
91 }
92 }
93
94 impl core::ops::Sub<$Type> for $Type {
95 type Output = Self;
96
97 #[inline]
98 fn sub(self, rhs: Self) -> Self {
99 Self(self.0 - rhs.0)
100 }
101 }
102
103 impl core::ops::AddAssign<usize> for $Type {
104 #[inline]
105 fn add_assign(&mut self, rhs: usize) {
106 self.0 += rhs;
107 }
108 }
109
110 impl core::ops::AddAssign<$Type> for $Type {
111 #[inline]
112 fn add_assign(&mut self, rhs: Self) {
113 self.0 += rhs.0;
114 }
115 }
116
117 impl core::ops::SubAssign<usize> for $Type {
118 #[inline]
119 fn sub_assign(&mut self, rhs: usize) {
120 self.0 -= rhs;
121 }
122 }
123
124 impl core::fmt::Display for $Type {
125 #[inline]
126 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
127 self.0.fmt(f)
128 }
129 }
130 };
131}
132
133impl_text_index!(ByteIndex);
134impl_text_index!(CharIndex);
135
136pub type ByteRange = Range<ByteIndex>;
138
139pub type CharRange = Range<CharIndex>;
141
142pub trait ByteRangeExt {
144 fn full(text: &str) -> Self;
146
147 fn as_usize(&self) -> Range<usize>;
149
150 fn slice<'s>(&self, text: &'s str) -> &'s str;
152}
153
154impl ByteRangeExt for ByteRange {
155 #[inline]
156 fn full(text: &str) -> Self {
157 ByteIndex::ZERO..ByteIndex(text.len())
158 }
159
160 #[inline]
161 fn as_usize(&self) -> Range<usize> {
162 self.start.0..self.end.0
163 }
164
165 #[inline]
166 fn slice<'s>(&self, text: &'s str) -> &'s str {
167 &text[self.as_usize()]
168 }
169}
170
171pub trait CharRangeExt {
173 fn full(text: &str) -> Self;
175}
176
177impl CharRangeExt for CharRange {
178 #[inline]
179 fn full(text: &str) -> Self {
180 CharIndex::ZERO..CharIndex(text.chars().count())
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::CharIndex;
187
188 #[test]
189 fn arithmetic() {
190 assert_eq!(CharIndex(2) + CharIndex(3), CharIndex(5));
192 assert_eq!(CharIndex(2) + 3, CharIndex(5));
193
194 let mut idx = CharIndex(2);
195 idx += CharIndex(3);
196 assert_eq!(idx, CharIndex(5));
197
198 assert_eq!(CharIndex(5) - CharIndex(2), CharIndex(3));
200 assert_eq!(CharIndex(5) - 2, CharIndex(3));
201 }
202}