Skip to main content

provenant/models/
line_number.rs

1use std::num::NonZeroUsize;
2use std::ops::{Add, AddAssign, Sub};
3
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
7#[serde(transparent)]
8pub struct LineNumber(NonZeroUsize);
9
10impl LineNumber {
11    pub const ONE: Self = match NonZeroUsize::new(1) {
12        Some(n) => Self(n),
13        None => unreachable!(),
14    };
15
16    pub fn new(n: usize) -> Option<Self> {
17        NonZeroUsize::new(n).map(Self)
18    }
19
20    pub fn from_0_indexed(i: usize) -> Self {
21        Self(NonZeroUsize::new(i + 1).expect("0-indexed line overflow"))
22    }
23
24    pub fn get(self) -> usize {
25        self.0.get()
26    }
27
28    pub fn saturating_add(self, n: usize) -> Self {
29        Self(NonZeroUsize::new(self.0.get().saturating_add(n)).expect("LineNumber overflow"))
30    }
31
32    pub fn saturating_sub(self, n: usize) -> usize {
33        self.0.get().saturating_sub(n)
34    }
35
36    pub fn abs_diff(self, other: Self) -> usize {
37        self.0.get().abs_diff(other.0.get())
38    }
39}
40
41impl Add<usize> for LineNumber {
42    type Output = Self;
43    fn add(self, rhs: usize) -> Self::Output {
44        Self(NonZeroUsize::new(self.0.get() + rhs).expect("LineNumber overflow"))
45    }
46}
47
48impl AddAssign<usize> for LineNumber {
49    fn add_assign(&mut self, rhs: usize) {
50        *self = *self + rhs;
51    }
52}
53
54impl Sub<usize> for LineNumber {
55    type Output = usize;
56    fn sub(self, rhs: usize) -> Self::Output {
57        self.0.get() - rhs
58    }
59}
60
61impl Sub for LineNumber {
62    type Output = usize;
63    fn sub(self, rhs: Self) -> Self::Output {
64        self.0.get() - rhs.0.get()
65    }
66}
67
68impl std::fmt::Display for LineNumber {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        self.0.fmt(f)
71    }
72}