1use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8pub struct Span {
9 pub start: usize,
11 pub end: usize,
13}
14
15impl Span {
16 pub fn new(start: usize, end: usize) -> Self {
18 Span { start, end }
19 }
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Error)]
24#[error("parse error at bytes {}..{}: {message}", .span.start, .span.end)]
25pub struct ParseError {
26 pub message: String,
28 pub span: Span,
30}
31
32impl ParseError {
33 pub fn new(message: impl Into<String>, span: Span) -> Self {
35 ParseError {
36 message: message.into(),
37 span,
38 }
39 }
40}
41
42pub type Result<T> = std::result::Result<T, ParseError>;
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn span_records_offsets() {
51 let span = Span::new(3, 7);
52 assert_eq!(span.start, 3);
53 assert_eq!(span.end, 7);
54 }
55
56 #[test]
57 fn parse_error_displays_with_span() {
58 let err = ParseError::new("unexpected token", Span::new(5, 6));
59 let msg = format!("{err}");
60 assert!(msg.contains("unexpected token"), "got: {msg}");
61 assert!(msg.contains('5'), "span start should appear: {msg}");
62 }
63}