1use std::{
2 cmp::Ordering,
3 fmt::{self, Debug},
4 num::NonZeroU32,
5};
6
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct Position {
16 line_number: NonZeroU32,
18 column_number: NonZeroU32,
20}
21
22impl Default for Position {
23 #[inline]
25 fn default() -> Self {
26 Self::new(1, 1)
27 }
28}
29
30impl Position {
31 #[inline]
37 #[track_caller]
38 #[must_use]
39 pub const fn new(line_number: u32, column_number: u32) -> Self {
40 Self {
41 line_number: NonZeroU32::new(line_number).expect("line number cannot be 0"),
42 column_number: NonZeroU32::new(column_number).expect("column number cannot be 0"),
43 }
44 }
45
46 #[inline]
48 #[must_use]
49 pub const fn line_number(self) -> u32 {
50 self.line_number.get()
51 }
52
53 #[inline]
55 #[must_use]
56 pub const fn column_number(self) -> u32 {
57 self.column_number.get()
58 }
59}
60
61impl fmt::Display for Position {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 write!(f, "{}:{}", self.line_number, self.column_number)
64 }
65}
66
67impl From<PositionGroup> for Position {
68 #[inline]
69 fn from(value: PositionGroup) -> Self {
70 value.pos
71 }
72}
73
74impl From<(NonZeroU32, NonZeroU32)> for Position {
75 #[inline]
76 fn from(value: (NonZeroU32, NonZeroU32)) -> Self {
77 Position {
78 line_number: value.0,
79 column_number: value.1,
80 }
81 }
82}
83
84impl From<(u32, u32)> for Position {
85 #[inline]
86 #[track_caller]
87 fn from(value: (u32, u32)) -> Self {
88 Position::new(value.0, value.1)
89 }
90}
91
92#[cfg(feature = "arbitrary")]
93impl<'a> arbitrary::Arbitrary<'a> for Span {
94 fn arbitrary(_u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
95 Ok(Span::new(Position::new(1, 1), Position::new(1, 1)))
96 }
97}
98
99#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
104#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
105pub struct LinearPosition {
106 pos: usize,
107}
108
109impl LinearPosition {
110 #[inline]
112 #[must_use]
113 pub const fn new(pos: usize) -> Self {
114 Self { pos }
115 }
116 #[inline]
118 #[must_use]
119 pub const fn pos(self) -> usize {
120 self.pos
121 }
122}
123impl fmt::Display for LinearPosition {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 write!(f, "{}", self.pos())
126 }
127}
128
129#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
136#[derive(Clone, Copy, PartialEq, Eq, Hash)]
137pub struct Span {
138 start: Position,
139 end: Position,
140}
141
142impl Debug for Span {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 write!(
145 f,
146 "Span(({}, {}), ({}, {}))",
147 self.start.line_number,
148 self.start.column_number,
149 self.end.line_number,
150 self.end.column_number,
151 )
152 }
153}
154
155impl Span {
156 #[inline]
162 #[track_caller]
163 #[must_use]
164 pub fn new<T, U>(start: T, end: U) -> Self
165 where
166 T: Into<Position>,
167 U: Into<Position>,
168 {
169 let start = start.into();
170 let end = end.into();
171
172 assert!(start <= end, "a span cannot start after its end");
173
174 Self { start, end }
175 }
176
177 #[inline]
179 #[must_use]
180 pub const fn start(self) -> Position {
181 self.start
182 }
183
184 #[inline]
186 #[must_use]
187 pub const fn end(self) -> Position {
188 self.end
189 }
190
191 pub fn contains<S>(self, other: S) -> bool
193 where
194 S: Into<Self>,
195 {
196 let other = other.into();
197 self.start <= other.start && self.end >= other.end
198 }
199}
200
201impl From<Position> for Span {
202 fn from(pos: Position) -> Self {
203 Self {
204 start: pos,
205 end: pos,
206 }
207 }
208}
209
210impl Spanned for Span {
211 #[inline]
212 fn span(&self) -> Span {
213 *self
214 }
215}
216
217impl<T: Spanned> Spanned for &T {
218 #[inline]
219 fn span(&self) -> Span {
220 T::span(*self)
221 }
222}
223
224impl PartialOrd for Span {
225 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
226 if self == other {
227 Some(Ordering::Equal)
228 } else if self.end < other.start {
229 Some(Ordering::Less)
230 } else if self.start > other.end {
231 Some(Ordering::Greater)
232 } else {
233 None
234 }
235 }
236}
237
238impl fmt::Display for Span {
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 write!(f, "[{}..{}]", self.start, self.end)
241 }
242}
243
244pub trait Spanned {
246 #[must_use]
248 fn span(&self) -> Span;
249}
250
251#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
258#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
259pub struct LinearSpan {
260 start: LinearPosition,
261 end: LinearPosition,
262}
263impl LinearSpan {
264 #[inline]
270 #[track_caller]
271 #[must_use]
272 pub const fn new(start: LinearPosition, end: LinearPosition) -> Self {
273 assert!(
274 start.pos <= end.pos,
275 "a linear span cannot start after its end"
276 );
277
278 Self { start, end }
279 }
280
281 #[inline]
283 #[must_use]
284 pub fn is_empty(self) -> bool {
285 self.start == self.end
286 }
287
288 #[inline]
290 #[must_use]
291 pub const fn start(self) -> LinearPosition {
292 self.start
293 }
294
295 #[inline]
297 #[must_use]
298 pub const fn end(self) -> LinearPosition {
299 self.end
300 }
301
302 pub fn contains<S>(self, other: S) -> bool
304 where
305 S: Into<Self>,
306 {
307 let other = other.into();
308 self.start <= other.start && self.end >= other.end
309 }
310
311 #[inline]
313 #[must_use]
314 pub fn union(self, other: impl Into<Self>) -> Self {
315 let other: Self = other.into();
316 Self {
317 start: LinearPosition::new(self.start.pos.min(other.start.pos)),
318 end: LinearPosition::new(self.end.pos.max(other.end.pos)),
319 }
320 }
321}
322#[cfg(feature = "arbitrary")]
323impl<'a> arbitrary::Arbitrary<'a> for LinearSpan {
324 fn arbitrary(_: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
325 let zero_pos = LinearPosition::new(0);
326 Ok(Self::new(zero_pos, zero_pos))
327 }
328}
329
330impl From<LinearPosition> for LinearSpan {
331 fn from(pos: LinearPosition) -> Self {
332 Self {
333 start: pos,
334 end: pos,
335 }
336 }
337}
338
339impl PartialOrd for LinearSpan {
340 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
341 if self == other {
342 Some(Ordering::Equal)
343 } else if self.end < other.start {
344 Some(Ordering::Less)
345 } else if self.start > other.end {
346 Some(Ordering::Greater)
347 } else {
348 None
349 }
350 }
351}
352
353#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
355#[derive(Debug, Clone, Copy)]
356pub struct LinearSpanIgnoreEq(pub LinearSpan);
357impl PartialEq for LinearSpanIgnoreEq {
358 fn eq(&self, _: &Self) -> bool {
359 true
360 }
361}
362impl From<LinearSpan> for LinearSpanIgnoreEq {
363 fn from(value: LinearSpan) -> Self {
364 Self(value)
365 }
366}
367#[cfg(feature = "arbitrary")]
368impl<'a> arbitrary::Arbitrary<'a> for LinearSpanIgnoreEq {
369 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
370 Ok(Self(LinearSpan::arbitrary(u)?))
371 }
372}
373
374#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
375#[derive(Debug, Clone, Copy, PartialEq, Eq)]
376pub struct PositionGroup {
378 pos: Position,
379 linear_pos: LinearPosition,
380}
381impl PositionGroup {
382 #[inline]
384 #[must_use]
385 pub const fn new(pos: Position, linear_pos: LinearPosition) -> Self {
386 Self { pos, linear_pos }
387 }
388 #[inline]
390 #[must_use]
391 pub fn position(&self) -> Position {
392 self.pos
393 }
394 #[inline]
396 #[must_use]
397 pub fn linear_position(&self) -> LinearPosition {
398 self.linear_pos
399 }
400
401 #[inline]
403 #[must_use]
404 pub const fn line_number(&self) -> u32 {
405 self.pos.line_number()
406 }
407
408 #[inline]
410 #[must_use]
411 pub const fn column_number(&self) -> u32 {
412 self.pos.column_number()
413 }
414}
415
416#[cfg(test)]
417mod tests {
418 #![allow(clippy::similar_names)]
419 #![allow(unused_must_use)]
420 use super::{LinearPosition, LinearSpan, Position, Span};
421
422 #[test]
424 #[should_panic(expected = "column number cannot be 0")]
425 fn invalid_position_column() {
426 Position::new(10, 0);
427 }
428
429 #[test]
431 #[should_panic(expected = "line number cannot be 0")]
432 fn invalid_position_line() {
433 Position::new(0, 10);
434 }
435
436 #[test]
438 fn position_equality() {
439 assert_eq!(Position::new(10, 50), Position::new(10, 50));
440 assert_ne!(Position::new(10, 50), Position::new(10, 51));
441 assert_ne!(Position::new(10, 50), Position::new(11, 50));
442 assert_ne!(Position::new(10, 50), Position::new(11, 51));
443 }
444
445 #[test]
447 fn linear_position_equality() {
448 assert_eq!(LinearPosition::new(1050), LinearPosition::new(1050));
449 assert_ne!(LinearPosition::new(1050), LinearPosition::new(1051));
450 }
451
452 #[test]
454 fn position_order() {
455 assert!(Position::new(10, 50) < Position::new(10, 51));
456 assert!(Position::new(9, 50) < Position::new(10, 50));
457 assert!(Position::new(10, 50) < Position::new(11, 51));
458 assert!(Position::new(10, 50) < Position::new(11, 49));
459
460 assert!(Position::new(10, 51) > Position::new(10, 50));
461 assert!(Position::new(10, 50) > Position::new(9, 50));
462 assert!(Position::new(11, 51) > Position::new(10, 50));
463 assert!(Position::new(11, 49) > Position::new(10, 50));
464 }
465
466 #[test]
468 fn linear_position_order() {
469 assert!(LinearPosition::new(1050) < LinearPosition::new(1051));
470 assert!(LinearPosition::new(1149) > LinearPosition::new(1050));
471 }
472
473 #[test]
475 fn position_getters() {
476 let pos = Position::new(10, 50);
477 assert_eq!(pos.line_number(), 10);
478 assert_eq!(pos.column_number(), 50);
479 }
480
481 #[test]
483 fn position_to_string() {
484 let pos = Position::new(10, 50);
485
486 assert_eq!("10:50", pos.to_string());
487 assert_eq!("10:50", pos.to_string());
488 }
489
490 #[test]
492 #[should_panic(expected = "a span cannot start after its end")]
493 fn invalid_span() {
494 let a = Position::new(10, 30);
495 let b = Position::new(10, 50);
496 Span::new(b, a);
497 }
498
499 #[test]
501 #[should_panic(expected = "a linear span cannot start after its end")]
502 fn invalid_linear_span() {
503 let a = LinearPosition::new(1030);
504 let b = LinearPosition::new(1050);
505 LinearSpan::new(b, a);
506 }
507
508 #[test]
510 fn span_creation() {
511 let a = Position::new(10, 30);
512 let b = Position::new(10, 50);
513
514 Span::new(a, b);
515 Span::new(a, a);
516 Span::from(a);
517 }
518
519 #[test]
521 fn linear_span_creation() {
522 let a = LinearPosition::new(1030);
523 let b = LinearPosition::new(1050);
524
525 LinearSpan::new(a, b);
526 let span_aa = LinearSpan::new(a, a);
527 assert_eq!(LinearSpan::from(a), span_aa);
528 }
529
530 #[test]
532 fn span_equality() {
533 let a = Position::new(10, 50);
534 let b = Position::new(10, 52);
535 let c = Position::new(11, 20);
536
537 let span_ab = Span::new(a, b);
538 let span_ab_2 = Span::new(a, b);
539 let span_ac = Span::new(a, c);
540 let span_bc = Span::new(b, c);
541
542 assert_eq!(span_ab, span_ab_2);
543 assert_ne!(span_ab, span_ac);
544 assert_ne!(span_ab, span_bc);
545 assert_ne!(span_bc, span_ac);
546
547 let span_a = Span::from(a);
548 let span_aa = Span::new(a, a);
549
550 assert_eq!(span_a, span_aa);
551 }
552
553 #[test]
555 fn linear_span_equality() {
556 let a = LinearPosition::new(1030);
557 let b = LinearPosition::new(1050);
558 let c = LinearPosition::new(1150);
559
560 let span_ab = LinearSpan::new(a, b);
561 let span_ab_2 = LinearSpan::new(a, b);
562 let span_ac = LinearSpan::new(a, c);
563 let span_bc = LinearSpan::new(b, c);
564
565 assert_eq!(span_ab, span_ab_2);
566 assert_ne!(span_ab, span_ac);
567 assert_ne!(span_ab, span_bc);
568 assert_ne!(span_bc, span_ac);
569 }
570
571 #[test]
573 fn span_getters() {
574 let a = Position::new(10, 50);
575 let b = Position::new(10, 52);
576
577 let span = Span::new(a, b);
578
579 assert_eq!(span.start(), a);
580 assert_eq!(span.end(), b);
581 }
582
583 #[test]
585 fn span_contains() {
586 let a = Position::new(10, 50);
587 let b = Position::new(10, 52);
588 let c = Position::new(11, 20);
589 let d = Position::new(12, 5);
590
591 let span_ac = Span::new(a, c);
592 assert!(span_ac.contains(b));
593
594 let span_ab = Span::new(a, b);
595 let span_cd = Span::new(c, d);
596
597 assert!(!span_ab.contains(span_cd));
598 assert!(span_ab.contains(b));
599
600 let span_ad = Span::new(a, d);
601 let span_bc = Span::new(b, c);
602
603 assert!(span_ad.contains(span_bc));
604 assert!(!span_bc.contains(span_ad));
605
606 let span_ac = Span::new(a, c);
607 let span_bd = Span::new(b, d);
608
609 assert!(!span_ac.contains(span_bd));
610 assert!(!span_bd.contains(span_ac));
611 }
612
613 #[test]
615 fn linear_span_contains() {
616 let a = LinearPosition::new(1050);
617 let b = LinearPosition::new(1080);
618 let c = LinearPosition::new(1120);
619 let d = LinearPosition::new(1125);
620
621 let span_ac = LinearSpan::new(a, c);
622 assert!(span_ac.contains(b));
623
624 let span_ab = LinearSpan::new(a, b);
625 let span_cd = LinearSpan::new(c, d);
626
627 assert!(!span_ab.contains(span_cd));
628 assert!(span_ab.contains(b));
629
630 let span_ad = LinearSpan::new(a, d);
631 let span_bc = LinearSpan::new(b, c);
632
633 assert!(span_ad.contains(span_bc));
634 assert!(!span_bc.contains(span_ad));
635
636 let span_ac = LinearSpan::new(a, c);
637 let span_bd = LinearSpan::new(b, d);
638
639 assert!(!span_ac.contains(span_bd));
640 assert!(!span_bd.contains(span_ac));
641 }
642
643 #[test]
645 fn span_to_string() {
646 let a = Position::new(10, 50);
647 let b = Position::new(11, 20);
648 let span = Span::new(a, b);
649
650 assert_eq!("[10:50..11:20]", span.to_string());
651 assert_eq!("[10:50..11:20]", span.to_string());
652 }
653
654 #[test]
656 fn span_ordering() {
657 let a = Position::new(10, 50);
658 let b = Position::new(10, 52);
659 let c = Position::new(11, 20);
660 let d = Position::new(12, 5);
661
662 let span_ab = Span::new(a, b);
663 let span_cd = Span::new(c, d);
664
665 assert!(span_ab < span_cd);
666 assert!(span_cd > span_ab);
667 }
668
669 #[test]
671 fn linear_span_ordering() {
672 let a = LinearPosition::new(1050);
673 let b = LinearPosition::new(1052);
674 let c = LinearPosition::new(1120);
675 let d = LinearPosition::new(1125);
676
677 let span_ab = LinearSpan::new(a, b);
678 let span_cd = LinearSpan::new(c, d);
679
680 let span_ac = LinearSpan::new(a, c);
681 let span_bd = LinearSpan::new(b, d);
682
683 assert!(span_ab < span_cd);
684 assert!(span_cd > span_ab);
685 assert_eq!(span_bd.partial_cmp(&span_ac), None);
686 assert_eq!(span_ac.partial_cmp(&span_bd), None);
687 }
688
689 #[test]
691 fn linear_union() {
692 let a = LinearPosition::new(1050);
693 let b = LinearPosition::new(1052);
694 let c = LinearPosition::new(1120);
695 let d = LinearPosition::new(1125);
696
697 let span_ab = LinearSpan::new(a, b);
698 let span_ad = LinearSpan::new(a, d);
699 let span_bc = LinearSpan::new(b, c);
700 let span_cd = LinearSpan::new(c, d);
701 let span_ac = LinearSpan::new(a, c);
702 let span_bd = LinearSpan::new(b, d);
703
704 assert_eq!(span_bd.union(a), span_ad);
705 assert_eq!(span_ab.union(a), span_ab);
706 assert_eq!(span_bd.union(span_ac), span_ad);
707 assert_eq!(span_ac.union(span_bd), span_ad);
708 assert_eq!(span_ac.union(span_bd), span_ad);
709 assert_eq!(span_ac.union(b), span_ac);
710 assert_eq!(span_bc.union(span_ab), span_ac);
711 assert_eq!(span_ab.union(span_bc), span_ac);
712 assert_eq!(span_ac.union(span_ab), span_ac);
713 assert_eq!(span_cd.union(a), span_ad);
714 assert_eq!(span_cd.union(span_bc), span_bd);
715 }
716}
717
718