1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
//! Source code spans.
//!
//! The [`DefaultEmitter`](crate::DefaultEmitter) is generic over a [`Span`].
//! This library comes with two Span implementations:
//!
//! * one for `()` which acts as the no-op implementation for when you don't want to track spans
//! * one for [`Range<usize>`] for when you do want to track spans
//!
//! To use the latter your reader however has to implement [`Position<usize>`].
//! You can easily use any existing reader by wrapping it in the [`PosTrackingReader`] struct
//! which implements the [`Position<usize>`] trait and takes care of tracking the current position.
use std::ops::{Add, Range};
use crate::reader::{IntoReader, Reader};
pub struct NoopOffset;
/// A trait to be implemented by readers that track their own position.
pub trait Position<T> {
/// Returns the byte index of the current position.
fn position(&self) -> T;
}
impl<R: Reader> Position<NoopOffset> for R {
fn position(&self) -> NoopOffset {
NoopOffset
}
}
/// Wraps a [`Reader`] so that it implements [`Position<usize>`].
pub struct PosTrackingReader<R> {
/// The wrapped reader.
reader: R,
/// The current position.
position: usize,
}
impl<R> PosTrackingReader<R> {
/// Wraps the given [`Reader`] so that it implements [`Position<usize>`] with the position starting from 0.
pub fn new<'a>(into_reader: impl IntoReader<'a, Reader = R>) -> Self {
Self {
reader: into_reader.into_reader(),
position: 0,
}
}
}
impl<R> Position<usize> for PosTrackingReader<R> {
fn position(&self) -> usize {
self.position
}
}
/// A byte range in the source code.
pub trait Span: Default + Clone {
type Offset: Add<usize, Output = Self::Offset>;
/// Constructs a new span from the given byte offsets.
fn new(start: Self::Offset, end: Self::Offset) -> Self;
/// Extends the span by the length of the given string.
fn push_str(&mut self, str: &str);
}
impl Span for () {
type Offset = NoopOffset;
fn new(_start: Self::Offset, _end: Self::Offset) -> Self {
()
}
fn push_str(&mut self, _str: &str) {}
}
impl Add<usize> for NoopOffset {
type Output = Self;
fn add(self, _rhs: usize) -> NoopOffset {
self
}
}
impl Span for Range<usize> {
type Offset = usize;
fn new(start: Self::Offset, end: Self::Offset) -> Self {
start - 1..end - 1
}
fn push_str(&mut self, str: &str) {
self.end += str.len();
}
}
impl<R: Reader> Reader for PosTrackingReader<R> {
type Error = R::Error;
fn read_char(&mut self) -> Result<Option<char>, Self::Error> {
match self.reader.read_char()? {
Some(char) => {
self.position += char.len_utf8();
Ok(Some(char))
}
None => Ok(None),
}
}
fn try_read_string(&mut self, s: &str, case_sensitive: bool) -> Result<bool, Self::Error> {
match self.reader.try_read_string(s, case_sensitive)? {
true => {
self.position += s.len();
Ok(true)
}
false => Ok(false),
}
}
}
|