forked from async-graphql/async-graphql
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.rs
141 lines (133 loc) · 4.83 KB
/
utils.rs
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use crate::{Error, Pos, Result};
use arrayvec::ArrayVec;
use pest::iterators::Pair;
use pest::RuleType;
use std::iter::Peekable;
use std::str::Chars;
pub struct PositionCalculator<'a> {
input: Peekable<Chars<'a>>,
pos: usize,
line: usize,
column: usize,
}
impl<'a> PositionCalculator<'a> {
pub fn new(input: &'a str) -> PositionCalculator<'a> {
Self {
input: input.chars().peekable(),
pos: 0,
line: 1,
column: 1,
}
}
pub fn step<R: RuleType>(&mut self, pair: &Pair<R>) -> Pos {
let pos = pair.as_span().start();
debug_assert!(pos >= self.pos);
for _ in 0..pos - self.pos {
match self.input.next() {
Some('\r') => {
if let Some(&'\n') = self.input.peek() {
self.input.next();
self.line += 1;
self.column = 1;
} else {
self.column += 1;
}
}
Some('\n') => {
self.line += 1;
self.column = 1;
}
Some(_) => {
self.column += 1;
}
None => break,
}
}
self.pos = pos;
Pos {
line: self.line,
column: self.column,
}
}
}
pub fn unquote_string(s: &str, pos: Pos) -> Result<String> {
let s = if s.starts_with(r#"""""#) {
&s[3..s.len() - 3]
} else if s.starts_with('"') {
&s[1..s.len() - 1]
} else {
unreachable!()
};
let mut chars = s.chars();
let mut res = String::with_capacity(s.len());
let mut temp_code_point = ArrayVec::<[u8; 4]>::new();
while let Some(c) = chars.next() {
match c {
'\\' => {
match chars.next().expect("slash cant be at the end") {
c @ '"' | c @ '\\' | c @ '/' => res.push(c),
'b' => res.push('\u{0010}'),
'f' => res.push('\u{000C}'),
'n' => res.push('\n'),
'r' => res.push('\r'),
't' => res.push('\t'),
'u' => {
temp_code_point.clear();
for _ in 0..4 {
match chars.next() {
Some(inner_c) if inner_c.is_digit(16) => {
temp_code_point.push(inner_c as u8)
}
Some(inner_c) => {
return Err(Error {
pos,
message: format!(
"{} is not a valid unicode code point",
inner_c
),
});
}
None => {
return Err(Error {
pos,
message: format!(
"{} must have 4 characters after it",
std::str::from_utf8(temp_code_point.as_slice())
.unwrap()
),
});
}
}
}
// convert our hex string into a u32, then convert that into a char
match u32::from_str_radix(
std::str::from_utf8(temp_code_point.as_slice()).unwrap(),
16,
)
.map(std::char::from_u32)
{
Ok(Some(unicode_char)) => res.push(unicode_char),
_ => {
return Err(Error {
pos,
message: format!(
"{} is not a valid unicode code point",
std::str::from_utf8(temp_code_point.as_slice()).unwrap()
),
});
}
}
}
c => {
return Err(Error {
pos,
message: format!("bad escaped char {:?}", c),
});
}
}
}
c => res.push(c),
}
}
Ok(res)
}