1use std::fmt::{self, Debug, Display};
2use std::ops::Range;
3#[cfg(feature = "filename")]
4use std::path::PathBuf;
5#[cfg(feature = "filename")]
6use std::sync::Arc;
7
8use crate::libyaml::error::Mark;
9
10#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
12pub struct Span {
13 pub start: Marker,
15
16 pub end: Marker,
18
19 #[cfg(feature = "filename")]
20 pub filename: Option<Arc<PathBuf>>,
22}
23
24impl Span {
25 pub fn new(start: Marker, end: Marker) -> Self {
27 Span {
28 start,
29 end,
30 #[cfg(feature = "filename")]
31 filename: None,
32 }
33 }
34
35 pub fn is_valid(&self) -> bool {
37 self.start.index <= self.end.index
38 && self.start.line > 0
39 && self.start.column > 0
40 && self.end.line > 0
41 && self.end.column > 0
42 }
43
44 pub const fn zero() -> Self {
46 Span {
47 start: Marker::zero(),
48 end: Marker::zero(),
49 #[cfg(feature = "filename")]
50 filename: None,
51 }
52 }
53}
54
55#[cfg(feature = "filename")]
56impl Span {
57 pub fn new_with_filename(
59 start: impl Into<Marker>,
60 end: impl Into<Marker>,
61 filename: impl Into<Arc<PathBuf>>,
62 ) -> Self {
63 Span {
64 start: start.into(),
65 end: end.into(),
66 filename: Some(filename.into()),
67 }
68 }
69
70 pub fn with_filename(self, filename: impl Into<Arc<PathBuf>>) -> Self {
72 Span {
73 filename: Some(filename.into()),
74 ..self
75 }
76 }
77
78 pub fn get_filename(&self) -> Option<&std::path::Path> {
80 self.filename.as_deref().map(|f| f.as_ref())
81 }
82
83 pub(crate) fn maybe_capture_filename(self) -> Self {
84 if let Some(filename) = crate::spanned::get_filename() {
85 Self {
86 filename: Some(filename),
87 ..self
88 }
89 } else {
90 self
91 }
92 }
93}
94
95impl Default for Span {
96 fn default() -> Self {
97 Span::zero()
98 }
99}
100
101impl Debug for Span {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 write!(f, "{:?}..{:?}", self.start, self.end)
104 }
105}
106
107impl Display for Span {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 write!(f, "{}..{}", self.start, self.end)
110 }
111}
112
113impl From<(Marker, Marker)> for Span {
114 fn from((start, end): (Marker, Marker)) -> Self {
115 Span::new(start, end)
116 }
117}
118
119impl From<Range<Option<Marker>>> for Span {
120 fn from(range: Range<Option<Marker>>) -> Self {
121 let start = range.start.unwrap_or_default();
122 let end = range.end.unwrap_or_default();
123 Span::new(start, end)
124 }
125}
126
127impl From<Marker> for Span {
128 fn from(marker: Marker) -> Self {
129 Span::new(marker, marker)
130 }
131}
132
133#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
135pub struct Marker {
136 pub index: usize,
138
139 pub line: usize,
141
142 pub column: usize,
144}
145
146impl Marker {
147 pub fn new(index: usize, line: usize, column: usize) -> Self {
149 Marker {
150 index,
151 line,
152 column,
153 }
154 }
155
156 pub const fn start() -> Self {
158 Marker {
159 index: 0,
160 line: 1,
161 column: 1,
162 }
163 }
164
165 pub const fn zero() -> Self {
167 Marker {
168 index: 0,
169 line: 0,
170 column: 0,
171 }
172 }
173
174 pub fn line(&self) -> usize {
176 self.line
177 }
178
179 pub fn column(&self) -> usize {
181 self.column
182 }
183
184 pub fn index(&self) -> usize {
186 self.index
187 }
188}
189
190impl Default for Marker {
191 fn default() -> Self {
192 Marker::zero()
193 }
194}
195
196impl From<Mark> for Marker {
197 fn from(mark: Mark) -> Self {
198 Marker {
199 index: mark.index() as usize,
200 line: mark.line() as usize + 1,
202 column: mark.column() as usize + 1,
203 }
204 }
205}
206
207impl Debug for Marker {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 write!(f, "{}:{}[{}]", self.line, self.column, self.index)
210 }
211}
212
213impl Display for Marker {
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 write!(f, "line {} column {}", self.line, self.column)
216 }
217}