svelte_syntax/
primitives.rs1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(
7 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Default,
8)]
9#[repr(transparent)]
10pub struct BytePos(u32);
11
12impl BytePos {
13 pub const ZERO: Self = Self(0);
15
16 pub const fn new(raw: u32) -> Self {
18 Self(raw)
19 }
20
21 pub const fn as_u32(self) -> u32 {
23 self.0
24 }
25
26 pub const fn as_usize(self) -> usize {
28 self.0 as usize
29 }
30}
31
32impl TryFrom<usize> for BytePos {
33 type Error = &'static str;
34
35 fn try_from(value: usize) -> Result<Self, Self::Error> {
36 u32::try_from(value)
37 .map(Self)
38 .map_err(|_| "byte position exceeds u32 range")
39 }
40}
41
42impl From<u32> for BytePos {
43 fn from(value: u32) -> Self {
44 Self(value)
45 }
46}
47
48impl fmt::Display for BytePos {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(f, "{}", self.0)
51 }
52}
53
54#[derive(
56 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Default,
57)]
58pub struct Span {
59 pub start: BytePos,
61 pub end: BytePos,
63}
64
65impl Span {
66 pub const EMPTY: Self = Self {
68 start: BytePos::ZERO,
69 end: BytePos::ZERO,
70 };
71
72 pub const fn new(start: BytePos, end: BytePos) -> Self {
74 Self { start, end }
75 }
76
77 pub fn from_offsets(start: usize, end: usize) -> Option<Self> {
80 Some(Self {
81 start: BytePos::try_from(start).ok()?,
82 end: BytePos::try_from(end).ok()?,
83 })
84 }
85
86 pub const fn len(self) -> u32 {
88 self.end.as_u32().saturating_sub(self.start.as_u32())
89 }
90
91 pub const fn is_empty(self) -> bool {
93 self.start.as_u32() >= self.end.as_u32()
94 }
95
96 pub fn contains(self, pos: BytePos) -> bool {
98 pos >= self.start && pos <= self.end
99 }
100
101 pub fn join(self, other: Span) -> Span {
103 Span {
104 start: if self.start <= other.start {
105 self.start
106 } else {
107 other.start
108 },
109 end: if self.end >= other.end {
110 self.end
111 } else {
112 other.end
113 },
114 }
115 }
116}
117
118impl fmt::Display for Span {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 write!(f, "{}..{}", self.start, self.end)
121 }
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
127#[repr(transparent)]
128pub struct SourceId(u32);
129
130impl SourceId {
131 pub const fn new(raw: u32) -> Self {
133 Self(raw)
134 }
135
136 pub const fn as_u32(self) -> u32 {
138 self.0
139 }
140}
141
142impl fmt::Display for SourceId {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 write!(f, "{}", self.0)
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::{BytePos, Span};
151
152 #[test]
153 fn span_join_and_len() {
154 let a = Span::new(BytePos::new(2), BytePos::new(5));
155 let b = Span::new(BytePos::new(4), BytePos::new(10));
156 let joined = a.join(b);
157
158 assert_eq!(joined.start.as_u32(), 2);
159 assert_eq!(joined.end.as_u32(), 10);
160 assert_eq!(joined.len(), 8);
161 }
162}