daml_syntax/
coordinate.rs1use std::fmt;
8use text_size::TextSize;
9
10macro_rules! define_coordinate {
11 ($(#[$meta:meta])* $name:ident) => {
12 $(#[$meta])*
13 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
14 pub struct $name(usize);
15
16 impl $name {
17 #[must_use]
18 pub const fn new(value: usize) -> Self {
19 Self(value)
20 }
21 }
22
23 impl Coordinate for $name {
24 fn get(self) -> usize {
25 self.0
26 }
27 }
28
29 impl fmt::Debug for $name {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 write!(f, "{}({})", stringify!($name), self.0)
32 }
33 }
34
35 impl fmt::Display for $name {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 self.0.fmt(f)
38 }
39 }
40 };
41}
42
43pub trait Coordinate {
45 fn get(self) -> usize;
46}
47
48define_coordinate!(LineNumber);
50define_coordinate!(ByteColumn);
52define_coordinate!(CharColumn);
54define_coordinate!(ByteOffset);
59define_coordinate!(Utf16Offset);
61
62impl From<TextSize> for ByteOffset {
63 fn from(offset: TextSize) -> Self {
64 Self::new(usize::from(offset))
65 }
66}
67
68impl TryFrom<ByteOffset> for TextSize {
69 type Error = std::num::TryFromIntError;
70
71 fn try_from(offset: ByteOffset) -> Result<Self, Self::Error> {
72 Self::try_from(offset.get())
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct ByteLineCol {
79 pub line: LineNumber,
80 pub column: ByteColumn,
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub struct CharLineCol {
87 pub line: LineNumber,
88 pub column: CharColumn,
89}
90
91#[cfg(test)]
92#[allow(clippy::unwrap_used)]
93mod tests {
94 use super::*;
95
96 fn assert_distinct_coordinate_types() {
97 let line = LineNumber::new(1);
98 let byte_col = ByteColumn::new(4);
99 let char_col = CharColumn::new(4);
100 let byte = ByteOffset::new(10);
101 let utf16 = Utf16Offset::new(10);
102
103 assert_eq!(line.get(), 1);
104 assert_eq!(byte_col.get(), char_col.get());
105 assert_ne!(byte.get(), line.get());
106
107 let _: ByteColumn = byte_col;
108 let _: CharColumn = char_col;
109 let _: ByteOffset = byte;
110 let _: Utf16Offset = utf16;
111 }
113
114 #[test]
115 fn coordinate_newtypes_are_not_interchangeable() {
116 assert_distinct_coordinate_types();
117 }
118
119 #[test]
120 fn byte_offset_converts_to_text_size() {
121 let offset = ByteOffset::new(5);
122 assert_eq!(TextSize::try_from(offset).unwrap(), TextSize::from(5));
123 assert_eq!(ByteOffset::from(TextSize::from(5)), ByteOffset::new(5));
124 }
125}