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
use std::fmt::{Display, Error};
/// Position represents the location within an Ion stream where an error has been
/// identified. For all formats `byte_offset` will contain the number of bytes into the stream
/// that have been processed prior to encountering the error. When working with the text format,
/// `line_column` will be updated to contain the line and column as well.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Position {
pub(crate) byte_offset: usize,
pub(crate) byte_length: Option<usize>,
pub(crate) line_column: Option<(usize, usize)>,
}
impl Position {
/// Creates a new Position with the provided offset in bytes.
/// Line and Column offsets can be added using [`Self::with_line_and_column()`].
pub fn with_offset(offset: usize) -> Self {
Position {
byte_offset: offset,
byte_length: None,
line_column: None,
}
}
pub fn with_length(mut self, length: usize) -> Self {
self.byte_length = Some(length);
self
}
/// Add line and column information to the current Position.
pub fn with_line_and_column(mut self, line: usize, column: usize) -> Self {
self.line_column = Some((line, column));
self
}
/// Returns the offset from the start of the Ion stream in bytes.
pub fn byte_offset(&self) -> usize {
self.byte_offset
}
/// If available, returns the length of the input slice in question.
pub fn byte_length(&self) -> Option<usize> {
self.byte_length
}
/// If available, returns the text position as line and column offsets.
pub fn line_and_column(&self) -> Option<(usize, usize)> {
self.line_column
}
/// If available, returns the line component of the text position.
pub fn line(&self) -> Option<usize> {
self.line_column.map(|(line, _column)| line)
}
/// If available, returns the column component of the text position.
pub fn column(&self) -> Option<usize> {
self.line_column.map(|(_line, column)| column)
}
/// Returns true if the current Position contains line and column offsets.
pub fn has_line_and_column(&self) -> bool {
self.line_column.is_some()
}
}
impl Display for Position {
// Formats the position based on whether we have a LineAndColumn or not.
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), Error> {
match &self.line_column {
None => write!(f, "{}", self.byte_offset),
Some((line, column)) => {
write!(f, "{} ({}:{})", self.byte_offset, line, column)
}
}
}
}
impl From<usize> for Position {
fn from(offset: usize) -> Self {
Position::with_offset(offset)
}
}