2
2
crate :: TextSize ,
3
3
std:: {
4
4
cmp,
5
- convert:: { TryFrom , TryInto } ,
5
+ convert:: TryInto ,
6
6
fmt,
7
- ops:: { Bound , Index , IndexMut , Range , RangeBounds } ,
7
+ ops:: { Bound , Index , IndexMut , RangeBounds } ,
8
8
} ,
9
9
} ;
10
10
@@ -30,15 +30,11 @@ use {
30
30
/// † See the note on [`TextRange::len`] for differing behavior for incorrect reverse ranges.
31
31
#[ derive( Copy , Clone , Eq , PartialEq , Hash ) ]
32
32
pub struct TextRange {
33
+ // Invariant: start <= end
33
34
start : TextSize ,
34
35
end : TextSize ,
35
36
}
36
37
37
- #[ allow( non_snake_case) ]
38
- pub ( crate ) const fn TextRange ( start : TextSize , end : TextSize ) -> TextRange {
39
- TextRange { start, end }
40
- }
41
-
42
38
impl fmt:: Debug for TextRange {
43
39
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
44
40
write ! ( f, "[{}..{})" , self . start( ) , self . end( ) )
@@ -47,6 +43,16 @@ impl fmt::Debug for TextRange {
47
43
48
44
/// Identity methods.
49
45
impl TextRange {
46
+ /// Creates a new `TextRange` with given `start` and `end.
47
+ ///
48
+ /// # Panics
49
+ ///
50
+ /// Panics if `end < start`.
51
+ pub fn new ( start : TextSize , end : TextSize ) -> TextRange {
52
+ assert ! ( start <= end) ;
53
+ TextRange { start, end }
54
+ }
55
+
50
56
/// The start point of this range.
51
57
pub const fn start ( self ) -> TextSize {
52
58
self . start
@@ -58,11 +64,6 @@ impl TextRange {
58
64
}
59
65
60
66
/// The size of this range.
61
- ///
62
- /// # Panics
63
- ///
64
- /// When `end() < start()`, triggers a subtraction overflow.
65
- /// This will panic with debug assertions, and overflow without.
66
67
pub const fn len ( self ) -> TextSize {
67
68
// HACK for const fn: math on primitives only
68
69
TextSize ( self . end ( ) . raw - self . start ( ) . raw )
@@ -71,11 +72,10 @@ impl TextRange {
71
72
/// Check if this range empty or reversed.
72
73
///
73
74
/// When `end() < start()`, this returns false.
74
- /// Code should prefer `is_empty()` to `len() == 0`,
75
- /// as this safeguards against incorrect reverse ranges.
75
+ /// Code should prefer `is_empty()` to `len() == 0`.
76
76
pub const fn is_empty ( self ) -> bool {
77
77
// HACK for const fn: math on primitives only
78
- self . start ( ) . raw > = self . end ( ) . raw
78
+ self . start ( ) . raw = = self . end ( ) . raw
79
79
}
80
80
}
81
81
@@ -91,14 +91,17 @@ impl TextRange {
91
91
pub fn intersection ( lhs : TextRange , rhs : TextRange ) -> Option < TextRange > {
92
92
let start = cmp:: max ( lhs. start ( ) , rhs. start ( ) ) ;
93
93
let end = cmp:: min ( lhs. end ( ) , rhs. end ( ) ) ;
94
- Some ( TextRange ( start, end) ) . filter ( |_| start <= end)
94
+ if end < start {
95
+ return None ;
96
+ }
97
+ Some ( TextRange :: new ( start, end) )
95
98
}
96
99
97
100
/// The smallest range that completely contains both ranges.
98
101
pub fn covering ( lhs : TextRange , rhs : TextRange ) -> TextRange {
99
102
let start = cmp:: min ( lhs. start ( ) , rhs. start ( ) ) ;
100
103
let end = cmp:: max ( lhs. end ( ) , rhs. end ( ) ) ;
101
- TextRange ( start, end)
104
+ TextRange :: new ( start, end)
102
105
}
103
106
104
107
/// Check if this range contains a point.
@@ -145,54 +148,3 @@ impl RangeBounds<TextSize> for TextRange {
145
148
Bound :: Excluded ( & self . end )
146
149
}
147
150
}
148
-
149
- macro_rules! conversions {
150
- ( From <$lte: ident> for TextRange ) => {
151
- impl From <Range <$lte>> for TextRange {
152
- fn from( value: Range <$lte>) -> TextRange {
153
- TextRange ( value. start. into( ) , value. end. into( ) )
154
- }
155
- }
156
- // Just support `start..end` for now, not `..end`, `start..=end`, `..=end`.
157
- } ;
158
- ( TryFrom <$gt: ident> for TextRange ) => {
159
- impl TryFrom <Range <$gt>> for TextRange {
160
- type Error = <$gt as TryInto <u32 >>:: Error ;
161
- fn try_from( value: Range <$gt>) -> Result <TextRange , Self :: Error > {
162
- Ok ( TextRange ( value. start. try_into( ) ?, value. end. try_into( ) ?) )
163
- }
164
- }
165
- // Just support `start..end` for now, not `..end`, `start..=end`, `..=end`.
166
- } ;
167
- {
168
- lt TextSize [ $( $lt: ident) * ]
169
- eq TextSize [ $( $eq: ident) * ]
170
- gt TextSize [ $( $gt: ident) * ]
171
- varries [ $( $var: ident) * ]
172
- } => {
173
- $(
174
- conversions!( From <$lt> for TextRange ) ;
175
- // unlike TextSize, we do not provide conversions in the "out" direction.
176
- ) *
177
-
178
- $(
179
- conversions!( From <$eq> for TextRange ) ;
180
- ) *
181
-
182
- $(
183
- conversions!( TryFrom <$gt> for TextRange ) ;
184
- ) *
185
-
186
- $(
187
- conversions!( TryFrom <$var> for TextRange ) ;
188
- ) *
189
- } ;
190
- }
191
-
192
- // FIXME: when `default impl` is usable, change to blanket impls for [Try]Into<TextSize> instead
193
- conversions ! {
194
- lt TextSize [ u8 u16 ]
195
- eq TextSize [ u32 TextSize ]
196
- gt TextSize [ u64 ]
197
- varries [ usize ]
198
- }
0 commit comments