mirror of
https://github.com/rwf2/Rocket.git
synced 2025-01-17 23:19:06 +00:00
Update Pear to 0.2.
This commit is contained in:
parent
27b26188c4
commit
95a4b442cc
@ -175,10 +175,7 @@ impl FromMeta for Origin {
|
||||
|
||||
let uri = http::uri::Origin::parse_route(&string)
|
||||
.map_err(|e| {
|
||||
let span = e.index()
|
||||
.map(|i| string.subspan(i + 1..))
|
||||
.unwrap_or(string.span());
|
||||
|
||||
let span = string.subspan(e.index() + 1..);
|
||||
span.error(format!("invalid path URI: {}", e))
|
||||
.help("expected path in origin form: \"/path/<param>\"")
|
||||
})?;
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: invalid path URI: expected token '/' but found 'a' at index 0
|
||||
error: invalid path URI: expected token / but found a at index 0
|
||||
--> $DIR/route-path-bad-syntax.rs:5:8
|
||||
|
|
||||
5 | #[get("a")] //~ ERROR invalid path URI
|
||||
@ -6,7 +6,7 @@ error: invalid path URI: expected token '/' but found 'a' at index 0
|
||||
|
|
||||
= help: expected path in origin form: "/path/<param>"
|
||||
|
||||
error: invalid path URI: expected token '/' but none was found at index 0
|
||||
error: invalid path URI: expected token / but none was found at index 0
|
||||
--> $DIR/route-path-bad-syntax.rs:9:8
|
||||
|
|
||||
9 | #[get("")] //~ ERROR invalid path URI
|
||||
@ -14,7 +14,7 @@ error: invalid path URI: expected token '/' but none was found at index 0
|
||||
|
|
||||
= help: expected path in origin form: "/path/<param>"
|
||||
|
||||
error: invalid path URI: expected token '/' but found 'a' at index 0
|
||||
error: invalid path URI: expected token / but found a at index 0
|
||||
--> $DIR/route-path-bad-syntax.rs:13:8
|
||||
|
|
||||
13 | #[get("a/b/c")] //~ ERROR invalid path URI
|
||||
@ -50,7 +50,7 @@ error: paths cannot contain empty segments
|
||||
|
|
||||
= note: expected '/a/b', found '/a/b//'
|
||||
|
||||
error: invalid path URI: expected EOF but found '#' at index 3
|
||||
error: invalid path URI: expected EOF but found # at index 3
|
||||
--> $DIR/route-path-bad-syntax.rs:33:11
|
||||
|
|
||||
33 | #[get("/!@#$%^&*()")] //~ ERROR invalid path URI
|
||||
|
@ -31,10 +31,13 @@ state = "0.4"
|
||||
tokio-rustls = { version = "0.14.0", optional = true }
|
||||
tokio = { version = "0.2.9", features = ["sync", "tcp", "time"] }
|
||||
cookie = { version = "0.14.0", features = ["percent-encode"] }
|
||||
pear = "0.1"
|
||||
unicode-xid = "0.2"
|
||||
log = "0.4"
|
||||
ref-cast = "1.0"
|
||||
|
||||
[dependencies.pear]
|
||||
git = "https://github.com/SergioBenitez/Pear.git"
|
||||
rev = "faee7c7e"
|
||||
|
||||
[dev-dependencies]
|
||||
rocket = { version = "0.5.0-dev", path = "../lib" }
|
||||
|
@ -88,17 +88,17 @@ pub enum AcceptParams {
|
||||
Dynamic(SmallVec<[QMediaType; 1]>)
|
||||
}
|
||||
|
||||
impl pear::parsers::Collection for AcceptParams {
|
||||
type Item = QMediaType;
|
||||
|
||||
fn new() -> Self {
|
||||
impl Default for AcceptParams {
|
||||
fn default() -> Self {
|
||||
AcceptParams::Dynamic(SmallVec::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&mut self, item: Self::Item) {
|
||||
match *self {
|
||||
impl Extend<QMediaType> for AcceptParams {
|
||||
fn extend<T: IntoIterator<Item = QMediaType>>(&mut self, iter: T) {
|
||||
match self {
|
||||
AcceptParams::Static(..) => panic!("can't add to static collection!"),
|
||||
AcceptParams::Dynamic(ref mut v) => v.push(item)
|
||||
AcceptParams::Dynamic(ref mut v) => v.extend(iter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,21 +22,35 @@ pub enum MediaParams {
|
||||
Dynamic(SmallVec<[(IndexedString, IndexedString); 2]>)
|
||||
}
|
||||
|
||||
impl pear::parsers::Collection for MediaParams {
|
||||
type Item = (IndexedString, IndexedString);
|
||||
|
||||
fn new() -> Self {
|
||||
impl Default for MediaParams {
|
||||
fn default() -> Self {
|
||||
MediaParams::Dynamic(SmallVec::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&mut self, item: Self::Item) {
|
||||
match *self {
|
||||
impl Extend<(IndexedString, IndexedString)> for MediaParams {
|
||||
fn extend<T: IntoIterator<Item = (IndexedString, IndexedString)>>(&mut self, iter: T) {
|
||||
match self {
|
||||
MediaParams::Static(..) => panic!("can't add to static collection!"),
|
||||
MediaParams::Dynamic(ref mut v) => v.push(item)
|
||||
MediaParams::Dynamic(ref mut v) => v.extend(iter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for MediaParams {
|
||||
fn eq(&self, other: &MediaParams) -> bool {
|
||||
#[inline(always)]
|
||||
fn inner_types(params: &MediaParams) -> &[(IndexedString, IndexedString)] {
|
||||
match *params {
|
||||
MediaParams::Static(params) => params,
|
||||
MediaParams::Dynamic(ref vec) => vec,
|
||||
}
|
||||
}
|
||||
|
||||
inner_types(self) == inner_types(other)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Source {
|
||||
Known(&'static str),
|
||||
|
@ -1,22 +1,22 @@
|
||||
use pear::parser;
|
||||
use pear::parsers::*;
|
||||
use pear::macros::{parser, parse_error};
|
||||
use pear::combinators::{series, surrounded};
|
||||
|
||||
use crate::{Accept, QMediaType};
|
||||
use crate::parse::checkers::is_whitespace;
|
||||
use crate::parse::media_type::media_type;
|
||||
|
||||
type Input<'a> = crate::parse::IndexedInput<'a, str>;
|
||||
type Result<'a, T> = pear::Result<T, Input<'a>>;
|
||||
type Input<'a> = pear::input::Pear<pear::input::Cursor<&'a str>>;
|
||||
type Result<'a, T> = pear::input::Result<T, Input<'a>>;
|
||||
|
||||
#[parser]
|
||||
fn weighted_media_type<'a>(input: &mut Input<'a>) -> Result<'a, QMediaType> {
|
||||
let media_type = media_type()?;
|
||||
let weight = match media_type.params().next() {
|
||||
Some(("q", value)) if value.len() <= 5 => match value.parse::<f32>().ok() {
|
||||
Some(q) if q > 1. => return Err(pear_error!("q value must be <= 1")),
|
||||
Some(q) if q < 0. => return Err(pear_error!("q value must be > 0")),
|
||||
Some(q) if q > 1. => parse_error!("q value must be <= 1")?,
|
||||
Some(q) if q < 0. => parse_error!("q value must be > 0")?,
|
||||
Some(q) => Some(q),
|
||||
None => return Err(pear_error!("invalid media-type weight"))
|
||||
None => parse_error!("invalid media-type weight")?
|
||||
},
|
||||
_ => None
|
||||
};
|
||||
@ -26,11 +26,11 @@ fn weighted_media_type<'a>(input: &mut Input<'a>) -> Result<'a, QMediaType> {
|
||||
|
||||
#[parser]
|
||||
fn accept<'a>(input: &mut Input<'a>) -> Result<'a, Accept> {
|
||||
Accept(series(false, ',', is_whitespace, weighted_media_type)?)
|
||||
Accept(series(|i| surrounded(i, weighted_media_type, is_whitespace), ',')?)
|
||||
}
|
||||
|
||||
pub fn parse_accept(input: &str) -> Result<'_, Accept> {
|
||||
parse!(accept: &mut input.into())
|
||||
parse!(accept: Input::new(input))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,10 +1,10 @@
|
||||
#[inline(always)]
|
||||
pub fn is_whitespace(byte: char) -> bool {
|
||||
pub fn is_whitespace(&byte: &char) -> bool {
|
||||
byte == ' ' || byte == '\t'
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_valid_token(c: char) -> bool {
|
||||
pub fn is_valid_token(&c: &char) -> bool {
|
||||
match c {
|
||||
'0'..='9' | 'A'..='Z' | '^'..='~' | '#'..='\''
|
||||
| '!' | '*' | '+' | '-' | '.' => true,
|
||||
|
@ -4,10 +4,12 @@ use std::borrow::Cow;
|
||||
use std::ops::{Index, Range};
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
use pear::{Input, Length};
|
||||
use pear::input::Length;
|
||||
|
||||
use crate::ext::IntoOwned;
|
||||
|
||||
pub use pear::input::Extent;
|
||||
|
||||
pub type IndexedString = Indexed<'static, str>;
|
||||
pub type IndexedStr<'a> = Indexed<'a, str>;
|
||||
pub type IndexedBytes<'a> = Indexed<'a, [u8]>;
|
||||
@ -36,9 +38,15 @@ pub enum Indexed<'a, T: ?Sized + ToOwned> {
|
||||
Concrete(Cow<'a, T>)
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + ToOwned + 'a, C: Into<Cow<'a, T>>> From<C> for Indexed<'a, T> {
|
||||
impl<A, T: ?Sized + ToOwned> From<Extent<A>> for Indexed<'_, T> {
|
||||
fn from(e: Extent<A>) -> Self {
|
||||
Indexed::Indexed(e.start, e.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + ToOwned + 'a> From<Cow<'a, T>> for Indexed<'a, T> {
|
||||
#[inline(always)]
|
||||
fn from(value: C) -> Indexed<'a, T> {
|
||||
fn from(value: Cow<'a, T>) -> Indexed<'a, T> {
|
||||
Indexed::Concrete(value.into())
|
||||
}
|
||||
}
|
||||
@ -213,130 +221,3 @@ impl<'a, T: ?Sized + Length + ToOwned + 'a> Length for Indexed<'a, T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IndexedInput<'a, T: ?Sized> {
|
||||
source: &'a T,
|
||||
current: &'a T
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + 'a> IndexedInput<'a, T> {
|
||||
#[inline(always)]
|
||||
pub fn source(&self) -> &T {
|
||||
self.source
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ToOwned + ?Sized + 'a> IndexedInput<'a, T> {
|
||||
#[inline(always)]
|
||||
pub fn cow_source(&self) -> Cow<'a, T> {
|
||||
Cow::Borrowed(self.source)
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexedInput<'_, [u8]> {
|
||||
pub fn backtrack(&mut self, n: usize) -> pear::Result<(), Self> {
|
||||
let source_addr = self.source.as_ptr() as usize;
|
||||
let current_addr = self.current.as_ptr() as usize;
|
||||
if current_addr > n && (current_addr - n) >= source_addr {
|
||||
let forward = (current_addr - n) - source_addr;
|
||||
self.current = &self.source[forward..];
|
||||
Ok(())
|
||||
} else {
|
||||
let diag = format!("({}, {:x} in {:x})", n, current_addr, source_addr);
|
||||
Err(pear_error!([backtrack; self] "internal error: {}", diag))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.source.len()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_indexed_input {
|
||||
($T:ty, token = $token:ty) => (
|
||||
impl<'a> From<&'a $T> for IndexedInput<'a, $T> {
|
||||
#[inline(always)]
|
||||
fn from(source: &'a $T) -> Self {
|
||||
IndexedInput { source: source, current: source }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Input for IndexedInput<'a, $T> {
|
||||
type Token = $token;
|
||||
type InSlice = &'a $T;
|
||||
type Slice = Indexed<'static, $T>;
|
||||
type Many = Indexed<'static, $T>;
|
||||
type Context = Context;
|
||||
|
||||
#[inline(always)]
|
||||
fn peek(&mut self) -> Option<Self::Token> {
|
||||
self.current.peek()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn peek_slice(&mut self, slice: Self::InSlice) -> Option<Self::Slice> {
|
||||
self.current.peek_slice(slice)
|
||||
.map(|slice| unsafe {
|
||||
Indexed::unchecked_from(slice, self.source)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn skip_many<F>(&mut self, cond: F) -> usize
|
||||
where F: FnMut(Self::Token) -> bool
|
||||
{
|
||||
self.current.skip_many(cond)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn take_many<F>(&mut self, cond: F) -> Self::Many
|
||||
where F: FnMut(Self::Token) -> bool
|
||||
{
|
||||
let many = self.current.take_many(cond);
|
||||
unsafe { Indexed::unchecked_from(many, self.source) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn advance(&mut self, count: usize) {
|
||||
self.current.advance(count)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_empty(&mut self) -> bool {
|
||||
self.current.is_empty()
|
||||
}
|
||||
|
||||
fn context(&mut self) -> Option<Context> {
|
||||
let offset = self.source.len() - self.current.len();
|
||||
let bytes: &[u8] = self.current.as_ref();
|
||||
let string = String::from_utf8(bytes.into()).ok()?;
|
||||
Some(Context { offset, string })
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||
pub struct Context {
|
||||
pub offset: usize,
|
||||
pub string: String
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Context {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
const LIMIT: usize = 7;
|
||||
write!(f, "[{}:]", self.offset)?;
|
||||
|
||||
if self.string.len() > LIMIT {
|
||||
write!(f, " {}..", &self.string[..LIMIT])
|
||||
} else if !self.string.is_empty() {
|
||||
write!(f, " {}", &self.string)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_indexed_input!([u8], token = u8);
|
||||
impl_indexed_input!(str, token = char);
|
||||
|
@ -1,21 +1,22 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use pear::{parser, switch};
|
||||
use pear::input::Extent;
|
||||
use pear::combinators::{prefixed_series, surrounded};
|
||||
use pear::macros::{parser, switch, parse};
|
||||
use pear::parsers::*;
|
||||
|
||||
use crate::media_type::{MediaType, Source};
|
||||
use crate::parse::checkers::{is_whitespace, is_valid_token};
|
||||
use crate::parse::IndexedStr;
|
||||
|
||||
type Input<'a> = crate::parse::IndexedInput<'a, str>;
|
||||
type Result<'a, T> = pear::Result<T, Input<'a>>;
|
||||
type Input<'a> = pear::input::Pear<pear::input::Cursor<&'a str>>;
|
||||
type Result<'a, T> = pear::input::Result<T, Input<'a>>;
|
||||
|
||||
#[parser]
|
||||
fn quoted_string<'a>(input: &mut Input<'a>) -> Result<'a, IndexedStr<'a>> {
|
||||
fn quoted_string<'a>(input: &mut Input<'a>) -> Result<'a, Extent<&'a str>> {
|
||||
eat('"')?;
|
||||
|
||||
let mut is_escaped = false;
|
||||
let inner = take_while(|c| {
|
||||
let inner = take_while(|&c| {
|
||||
if is_escaped { is_escaped = false; return true; }
|
||||
if c == '\\' { is_escaped = true; return true; }
|
||||
c != '"'
|
||||
@ -26,7 +27,7 @@ fn quoted_string<'a>(input: &mut Input<'a>) -> Result<'a, IndexedStr<'a>> {
|
||||
}
|
||||
|
||||
#[parser]
|
||||
fn media_param<'a>(input: &mut Input<'a>) -> Result<'a, (IndexedStr<'a>, IndexedStr<'a>)> {
|
||||
fn media_param<'a>(input: &mut Input<'a>) -> Result<'a, (Extent<&'a str>, Extent<&'a str>)> {
|
||||
let key = (take_some_while_until(is_valid_token, '=')?, eat('=')?).0;
|
||||
let value = switch! {
|
||||
peek('"') => quoted_string()?,
|
||||
@ -41,21 +42,24 @@ pub fn media_type<'a>(input: &mut Input<'a>) -> Result<'a, MediaType> {
|
||||
let (top, sub, params) = {
|
||||
let top = (take_some_while_until(is_valid_token, '/')?, eat('/')?).0;
|
||||
let sub = take_some_while_until(is_valid_token, ';')?;
|
||||
let params = series(true, ';', is_whitespace, |i| {
|
||||
media_param(i).map(|(k, v)| (k.coerce_lifetime(), v.coerce_lifetime()))
|
||||
})?;
|
||||
let params = prefixed_series(';', |i| {
|
||||
let param = surrounded(i, media_param, is_whitespace)?;
|
||||
Ok((param.0.into(), param.1.into()))
|
||||
}, ';')?;
|
||||
|
||||
(top.coerce_lifetime(), sub.coerce_lifetime(), params)
|
||||
(top, sub, params)
|
||||
};
|
||||
|
||||
MediaType {
|
||||
source: Source::Custom(Cow::Owned(input.source().to_string())),
|
||||
top, sub, params
|
||||
params,
|
||||
source: Source::Custom(Cow::Owned(input.start.to_string())),
|
||||
top: top.into(),
|
||||
sub: sub.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_media_type(input: &str) -> Result<'_, MediaType> {
|
||||
parse!(media_type: &mut input.into())
|
||||
parse!(media_type: Input::new(input))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::fmt;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use pear::{ParseErr, Expected};
|
||||
use crate::parse::indexed::Context;
|
||||
use pear::error::Expected;
|
||||
use pear::input::ParseError;
|
||||
use crate::parse::uri::RawInput;
|
||||
use crate::ext::IntoOwned;
|
||||
|
||||
@ -14,32 +14,18 @@ use crate::ext::IntoOwned;
|
||||
/// `Display` implementation. In other words, by printing a value of this type.
|
||||
#[derive(Debug)]
|
||||
pub struct Error<'a> {
|
||||
expected: Expected<Or<char, u8>, Cow<'a, str>, String>,
|
||||
context: Option<Context>
|
||||
expected: Expected<u8, Cow<'a, [u8]>>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Or<L, R> {
|
||||
A(L),
|
||||
B(R)
|
||||
}
|
||||
|
||||
impl<'a> Error<'a> {
|
||||
pub(crate) fn from(src: &'a str, pear_error: ParseErr<RawInput<'a>>) -> Error<'a> {
|
||||
let new_expected = pear_error.expected.map(|token| {
|
||||
if token.is_ascii() && !token.is_ascii_control() {
|
||||
Or::A(token as char)
|
||||
} else {
|
||||
Or::B(token)
|
||||
}
|
||||
}, String::from_utf8_lossy, |indexed| {
|
||||
let src = Some(src.as_bytes());
|
||||
String::from_utf8_lossy(indexed.from_source(src)).to_string()
|
||||
});
|
||||
|
||||
Error { expected: new_expected, context: pear_error.context }
|
||||
impl<'a> From<ParseError<RawInput<'a>>> for Error<'a> {
|
||||
fn from(inner: ParseError<RawInput<'a>>) -> Self {
|
||||
let expected = inner.error.map(|t| t.into(), |v| v.values.into());
|
||||
Error { expected, index: inner.info.context.start }
|
||||
}
|
||||
}
|
||||
|
||||
impl Error<'_> {
|
||||
/// Returns the byte index into the text where the error occurred if it is
|
||||
/// known.
|
||||
///
|
||||
@ -50,41 +36,27 @@ impl<'a> Error<'a> {
|
||||
/// use rocket::http::uri::Origin;
|
||||
///
|
||||
/// let err = Origin::parse("/foo bar").unwrap_err();
|
||||
/// assert_eq!(err.index(), Some(4));
|
||||
/// assert_eq!(err.index(), 4);
|
||||
/// ```
|
||||
pub fn index(&self) -> Option<usize> {
|
||||
self.context.as_ref().map(|c| c.offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Or<char, u8> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Or::A(left) => write!(f, "'{}'", left),
|
||||
Or::B(right) => write!(f, "non-ASCII byte {}", right),
|
||||
}
|
||||
pub fn index(&self) -> usize {
|
||||
self.index
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// This relies on specialization of the `Display` impl for `Expected`.
|
||||
write!(f, "{}", self.expected)?;
|
||||
|
||||
if let Some(ref context) = self.context {
|
||||
write!(f, " at index {}", context.offset)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
write!(f, "{} at index {}", self.expected, self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoOwned for Error<'_> {
|
||||
type Owned = Error<'static>;
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
let expected = self.expected.map(|i| i, IntoOwned::into_owned, |i| i);
|
||||
Error { expected, context: self.context }
|
||||
fn into_owned(self) -> Error<'static> {
|
||||
Error {
|
||||
expected: self.expected.map(|t| t, |s| s.into_owned().into()),
|
||||
index: self.index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,8 +73,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn check_display() {
|
||||
check_err!("a" => "expected token '/' but found 'a' at index 0");
|
||||
check_err!("?" => "expected token '/' but found '?' at index 0");
|
||||
check_err!("这" => "expected token '/' but found non-ASCII byte 232 at index 0");
|
||||
check_err!("a" => "expected token / but found a at index 0");
|
||||
check_err!("?" => "expected token / but found ? at index 0");
|
||||
check_err!("这" => "expected token / but found byte 232 at index 0");
|
||||
}
|
||||
}
|
||||
|
@ -5,40 +5,35 @@ mod tables;
|
||||
#[cfg(test)] mod tests;
|
||||
|
||||
use crate::uri::{Uri, Origin, Absolute, Authority};
|
||||
use crate::parse::indexed::IndexedInput;
|
||||
|
||||
use self::parser::{uri, origin, authority_only, absolute_only, rocket_route_origin};
|
||||
|
||||
pub use self::tables::{is_pchar, PATH_SET};
|
||||
pub use self::error::Error;
|
||||
|
||||
type RawInput<'a> = IndexedInput<'a, [u8]>;
|
||||
type RawInput<'a> = pear::input::Pear<pear::input::Cursor<&'a [u8]>>;
|
||||
|
||||
#[inline]
|
||||
pub fn from_str(string: &str) -> Result<Uri<'_>, Error<'_>> {
|
||||
parse!(uri: &mut RawInput::from(string.as_bytes()))
|
||||
.map_err(|e| Error::from(string, e))
|
||||
pub fn from_str(s: &str) -> Result<Uri<'_>, Error<'_>> {
|
||||
Ok(parse!(uri: RawInput::new(s.as_bytes()))?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn origin_from_str(string: &str) -> Result<Origin<'_>, Error<'_>> {
|
||||
parse!(origin: &mut RawInput::from(string.as_bytes()))
|
||||
.map_err(|e| Error::from(string, e))
|
||||
pub fn origin_from_str(s: &str) -> Result<Origin<'_>, Error<'_>> {
|
||||
Ok(parse!(origin: RawInput::new(s.as_bytes()))?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn route_origin_from_str(string: &str) -> Result<Origin<'_>, Error<'_>> {
|
||||
parse!(rocket_route_origin: &mut RawInput::from(string.as_bytes()))
|
||||
.map_err(|e| Error::from(string, e))
|
||||
pub fn route_origin_from_str(s: &str) -> Result<Origin<'_>, Error<'_>> {
|
||||
Ok(parse!(rocket_route_origin: RawInput::new(s.as_bytes()))?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn authority_from_str(string: &str) -> Result<Authority<'_>, Error<'_>> {
|
||||
parse!(authority_only: &mut RawInput::from(string.as_bytes()))
|
||||
.map_err(|e| Error::from(string, e))
|
||||
pub fn authority_from_str(s: &str) -> Result<Authority<'_>, Error<'_>> {
|
||||
Ok(parse!(authority_only: RawInput::new(s.as_bytes()))?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn absolute_from_str(string: &str) -> Result<Absolute<'_>, Error<'_>> {
|
||||
parse!(absolute_only: &mut RawInput::from(string.as_bytes()))
|
||||
.map_err(|e| Error::from(string, e))
|
||||
pub fn absolute_from_str(s: &str) -> Result<Absolute<'_>, Error<'_>> {
|
||||
Ok(parse!(absolute_only: RawInput::new(s.as_bytes()))?)
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
use pear::parsers::*;
|
||||
use pear::{parser, switch};
|
||||
use pear::input::{Extent, Rewind};
|
||||
use pear::macros::{parser, switch, parse_current_marker, parse_error, parse_try};
|
||||
|
||||
use crate::uri::{Uri, Origin, Authority, Absolute, Host};
|
||||
use crate::parse::uri::tables::{is_reg_name_char, is_pchar, is_pchar_or_rchar};
|
||||
use crate::parse::uri::RawInput;
|
||||
use crate::parse::IndexedBytes;
|
||||
|
||||
type Result<'a, T> = pear::Result<T, RawInput<'a>>;
|
||||
type Result<'a, T> = pear::input::Result<T, RawInput<'a>>;
|
||||
|
||||
#[parser]
|
||||
pub fn uri<'a>(input: &mut RawInput<'a>) -> Result<'a, Uri<'a>> {
|
||||
match input.len() {
|
||||
0 => return Err(pear_error!("empty URI")),
|
||||
match input.items.len() {
|
||||
0 => parse_error!("empty URI")?,
|
||||
1 => switch! {
|
||||
eat(b'*') => Uri::Asterisk,
|
||||
eat(b'/') => Uri::Origin(Origin::new::<_, &str>("/", None)),
|
||||
_ => unsafe {
|
||||
// the `is_reg_name_char` guarantees ASCII
|
||||
let host = Host::Raw(take_n_if(1, is_reg_name_char)?);
|
||||
Uri::Authority(Authority::raw(input.cow_source(), None, host, None))
|
||||
Uri::Authority(Authority::raw(input.start.into(), None, host, None))
|
||||
}
|
||||
},
|
||||
_ => switch! {
|
||||
@ -40,39 +40,37 @@ pub fn rocket_route_origin<'a>(input: &mut RawInput<'a>) -> Result<'a, Origin<'a
|
||||
|
||||
#[parser]
|
||||
fn path_and_query<'a, F>(input: &mut RawInput<'a>, is_good_char: F) -> Result<'a, Origin<'a>>
|
||||
where F: Fn(u8) -> bool + Copy
|
||||
where F: Fn(&u8) -> bool + Copy
|
||||
{
|
||||
let path = take_while(is_good_char)?;
|
||||
|
||||
// FIXME(rustc): We should be able to use `pear_try`, but rustc...is broken.
|
||||
// FIXME: this works on nightly but not stable! `Span` issues?
|
||||
// let query = parse_try!(eat(b'?') => take_while(|c| is_good_char(c) || *c == b'?')?);
|
||||
let query = switch! {
|
||||
eat(b'?') => Some(take_while(|c| is_good_char(c) || c == b'?')?),
|
||||
eat(b'?') => Some(take_while(|c| is_good_char(c) || *c == b'?')?),
|
||||
_ => None
|
||||
};
|
||||
|
||||
if path.is_empty() && query.is_none() {
|
||||
Err(pear_error!("expected path or query, found neither"))
|
||||
parse_error!("expected path or query, found neither")?
|
||||
} else {
|
||||
// We know the string is ASCII because of the `is_good_char` checks above.
|
||||
Ok(unsafe { Origin::raw(input.cow_source(), path, query) })
|
||||
Ok(unsafe {Origin::raw(input.start.into(), path.into(), query.map(|q| q.into())) })
|
||||
}
|
||||
}
|
||||
|
||||
#[parser]
|
||||
fn port_from<'a>(input: &mut RawInput<'a>, bytes: &IndexedBytes<'a>) -> Result<'a, u16> {
|
||||
fn port_from<'a>(input: &mut RawInput<'a>, bytes: &[u8]) -> Result<'a, u16> {
|
||||
let mut port_num: u32 = 0;
|
||||
let source = Some(input.cow_source());
|
||||
let string = bytes.from_cow_source(&source);
|
||||
for (&b, i) in string.iter().rev().zip(&[1, 10, 100, 1000, 10000]) {
|
||||
for (b, i) in bytes.iter().rev().zip(&[1, 10, 100, 1000, 10000]) {
|
||||
if !b.is_ascii_digit() {
|
||||
return Err(pear_error!("port byte is out of range"));
|
||||
parse_error!("port byte is out of range")?;
|
||||
}
|
||||
|
||||
port_num += (b - b'0') as u32 * i;
|
||||
}
|
||||
|
||||
if port_num > u16::max_value() as u32 {
|
||||
return Err(pear_error!("port value out of range: {}", port_num));
|
||||
parse_error!("port out of range: {}", port_num)?;
|
||||
}
|
||||
|
||||
Ok(port_num as u16)
|
||||
@ -80,14 +78,14 @@ fn port_from<'a>(input: &mut RawInput<'a>, bytes: &IndexedBytes<'a>) -> Result<'
|
||||
|
||||
#[parser]
|
||||
fn port<'a>(input: &mut RawInput<'a>) -> Result<'a, u16> {
|
||||
let port_str = take_n_while(5, |c| c.is_ascii_digit())?;
|
||||
port_from(&port_str)?
|
||||
let port = take_n_while(5, |c| c.is_ascii_digit())?;
|
||||
port_from(&port)?
|
||||
}
|
||||
|
||||
#[parser]
|
||||
fn authority<'a>(
|
||||
input: &mut RawInput<'a>,
|
||||
user_info: Option<IndexedBytes<'a>>
|
||||
user_info: Option<Extent<&'a [u8]>>
|
||||
) -> Result<'a, Authority<'a>> {
|
||||
let host = switch! {
|
||||
peek(b'[') => Host::Bracketed(delimited(b'[', is_pchar, b']')?),
|
||||
@ -95,36 +93,37 @@ fn authority<'a>(
|
||||
};
|
||||
|
||||
// The `is_pchar`,`is_reg_name_char`, and `port()` functions ensure ASCII.
|
||||
let port = pear_try!(eat(b':') => port()?);
|
||||
unsafe { Authority::raw(input.cow_source(), user_info, host, port) }
|
||||
let port = parse_try!(eat(b':') => port()?);
|
||||
unsafe { Authority::raw(input.start.into(), user_info, host, port) }
|
||||
}
|
||||
|
||||
// Callers must ensure that `scheme` is actually ASCII.
|
||||
#[parser]
|
||||
fn absolute<'a>(
|
||||
input: &mut RawInput<'a>,
|
||||
scheme: IndexedBytes<'a>
|
||||
scheme: Extent<&'a [u8]>
|
||||
) -> Result<'a, Absolute<'a>> {
|
||||
let (authority, path_and_query) = switch! {
|
||||
eat_slice(b"://") => {
|
||||
let left = take_while(|c| is_reg_name_char(c) || c == b':')?;
|
||||
let before_auth = parse_current_marker!();
|
||||
let left = take_while(|c| is_reg_name_char(c) || *c == b':')?;
|
||||
let authority = switch! {
|
||||
eat(b'@') => authority(Some(left))?,
|
||||
_ => {
|
||||
input.backtrack(left.len())?;
|
||||
input.rewind_to(before_auth);
|
||||
authority(None)?
|
||||
}
|
||||
};
|
||||
|
||||
let path_and_query = pear_try!(path_and_query(is_pchar));
|
||||
let path_and_query = parse_try!(path_and_query(is_pchar));
|
||||
(Some(authority), path_and_query)
|
||||
},
|
||||
eat(b':') => (None, Some(path_and_query(is_pchar)?)),
|
||||
_ => return Err(pear_error!("expected ':' but none was found"))
|
||||
_ => parse_error!("expected ':' but none was found")?
|
||||
};
|
||||
|
||||
// `authority` and `path_and_query` parsers ensure ASCII.
|
||||
unsafe { Absolute::raw(input.cow_source(), scheme, authority, path_and_query) }
|
||||
unsafe { Absolute::raw(input.start.into(), scheme, authority, path_and_query) }
|
||||
}
|
||||
|
||||
#[parser]
|
||||
@ -132,7 +131,7 @@ pub fn authority_only<'a>(input: &mut RawInput<'a>) -> Result<'a, Authority<'a>>
|
||||
if let Uri::Authority(authority) = absolute_or_authority()? {
|
||||
Ok(authority)
|
||||
} else {
|
||||
Err(pear_error!("expected authority URI but found absolute URI"))
|
||||
parse_error!("expected authority URI but found absolute URI")?
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,7 +140,7 @@ pub fn absolute_only<'a>(input: &mut RawInput<'a>) -> Result<'a, Absolute<'a>> {
|
||||
if let Uri::Absolute(absolute) = absolute_or_authority()? {
|
||||
Ok(absolute)
|
||||
} else {
|
||||
Err(pear_error!("expected absolute URI but found authority URI"))
|
||||
parse_error!("expected absolute URI but found authority URI")?
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,17 +148,20 @@ pub fn absolute_only<'a>(input: &mut RawInput<'a>) -> Result<'a, Absolute<'a>> {
|
||||
fn absolute_or_authority<'a>(
|
||||
input: &mut RawInput<'a>,
|
||||
) -> Result<'a, Uri<'a>> {
|
||||
let start = parse_current_marker!();
|
||||
let left = take_while(is_reg_name_char)?;
|
||||
let mark_at_left = parse_current_marker!();
|
||||
switch! {
|
||||
peek_slice(b":/") => Uri::Absolute(absolute(left)?),
|
||||
eat(b'@') => Uri::Authority(authority(Some(left))?),
|
||||
colon@take_n_if(1, |b| b == b':') => {
|
||||
take_n_if(1, |b| *b == b':') => {
|
||||
// could be authority or an IP with ':' in it
|
||||
let rest = take_while(|c| is_reg_name_char(c) || c == b':')?;
|
||||
let rest = take_while(|c| is_reg_name_char(c) || *c == b':')?;
|
||||
let authority_here = parse_context!();
|
||||
switch! {
|
||||
eat(b'@') => Uri::Authority(authority(Some(left + colon + rest))?),
|
||||
eat(b'@') => Uri::Authority(authority(Some(authority_here))?),
|
||||
peek(b'/') => {
|
||||
input.backtrack(rest.len() + 1)?;
|
||||
input.rewind_to(mark_at_left);
|
||||
Uri::Absolute(absolute(left)?)
|
||||
},
|
||||
_ => unsafe {
|
||||
@ -168,22 +170,22 @@ fn absolute_or_authority<'a>(
|
||||
// parses. To settle the ambiguity, we assume that if it
|
||||
// looks like a port, it's a port. Otherwise a host. Unless
|
||||
// we have a query, in which case it's definitely a host.
|
||||
let query = pear_try!(eat(b'?') => take_while(is_pchar)?);
|
||||
let query = parse_try!(eat(b'?') => take_while(is_pchar)?);
|
||||
if query.is_some() || rest.is_empty() || rest.len() > 5 {
|
||||
Uri::raw_absolute(input.cow_source(), left, rest, query)
|
||||
Uri::raw_absolute(input.start.into(), left, rest, query)
|
||||
} else if let Ok(port) = port_from(input, &rest) {
|
||||
let host = Host::Raw(left);
|
||||
let source = input.cow_source();
|
||||
let source = input.start.into();
|
||||
let port = Some(port);
|
||||
Uri::Authority(Authority::raw(source, None, host, port))
|
||||
} else {
|
||||
Uri::raw_absolute(input.cow_source(), left, rest, query)
|
||||
Uri::raw_absolute(input.start.into(), left, rest, query)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
input.backtrack(left.len())?;
|
||||
input.rewind_to(start);
|
||||
Uri::Authority(authority(None)?)
|
||||
}
|
||||
}
|
||||
|
@ -68,12 +68,12 @@ pub const PATH_SET: AsciiSet;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_pchar(c: u8) -> bool {
|
||||
pub fn is_pchar(&c: &u8) -> bool {
|
||||
PATH_CHARS[c as usize] == c
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_pchar_or_rchar(c: u8) -> bool {
|
||||
pub fn is_pchar_or_rchar(&c: &u8) -> bool {
|
||||
PATH_CHARS[c as usize] != 0
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ const REG_CHARS: [u8; 256] = [
|
||||
];
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_reg_name_char(c: u8) -> bool {
|
||||
pub fn is_reg_name_char(&c: &u8) -> bool {
|
||||
REG_CHARS[c as usize] != 0
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use crate::ext::IntoOwned;
|
||||
use crate::parse::{Indexed, IndexedStr};
|
||||
use crate::parse::{Extent, IndexedStr};
|
||||
use crate::uri::{Authority, Origin, Error, as_utf8_unchecked};
|
||||
|
||||
/// A URI with a scheme, authority, path, and query:
|
||||
@ -46,15 +46,14 @@ impl<'a> Absolute<'a> {
|
||||
#[inline]
|
||||
pub(crate) unsafe fn raw(
|
||||
source: Cow<'a, [u8]>,
|
||||
scheme: Indexed<'a, [u8]>,
|
||||
scheme: Extent<&'a [u8]>,
|
||||
authority: Option<Authority<'a>>,
|
||||
origin: Option<Origin<'a>>,
|
||||
) -> Absolute<'a> {
|
||||
Absolute {
|
||||
authority, origin,
|
||||
source: Some(as_utf8_unchecked(source)),
|
||||
scheme: scheme.coerce(),
|
||||
authority: authority,
|
||||
origin: origin,
|
||||
scheme: scheme.into(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,7 +64,9 @@ impl<'a> Absolute<'a> {
|
||||
origin: Option<Origin<'a>>
|
||||
) -> Absolute<'a> {
|
||||
Absolute {
|
||||
source: None, scheme: scheme.into(), authority, origin
|
||||
authority, origin,
|
||||
source: None,
|
||||
scheme: Cow::Borrowed(scheme).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::ext::IntoOwned;
|
||||
use crate::parse::{Indexed, IndexedStr};
|
||||
use crate::parse::{Extent, IndexedStr};
|
||||
use crate::uri::{as_utf8_unchecked, Error};
|
||||
|
||||
/// A URI with an authority only: `user:pass@host:8000`.
|
||||
@ -57,14 +57,14 @@ impl IntoOwned for Authority<'_> {
|
||||
impl<'a> Authority<'a> {
|
||||
pub(crate) unsafe fn raw(
|
||||
source: Cow<'a, [u8]>,
|
||||
user_info: Option<Indexed<'a, [u8]>>,
|
||||
host: Host<Indexed<'a, [u8]>>,
|
||||
user_info: Option<Extent<&'a [u8]>>,
|
||||
host: Host<Extent<&'a [u8]>>,
|
||||
port: Option<u16>
|
||||
) -> Authority<'a> {
|
||||
Authority {
|
||||
source: Some(as_utf8_unchecked(source)),
|
||||
user_info: user_info.map(|u| u.coerce()),
|
||||
host: host.map_inner(|inner| inner.coerce()),
|
||||
user_info: user_info.map(IndexedStr::from),
|
||||
host: host.map_inner(IndexedStr::from),
|
||||
port: port
|
||||
}
|
||||
}
|
||||
@ -77,8 +77,8 @@ impl<'a> Authority<'a> {
|
||||
) -> Authority<'a> {
|
||||
Authority {
|
||||
source: None,
|
||||
user_info: user_info.map(|u| u.into()),
|
||||
host: host.map_inner(|inner| inner.into()),
|
||||
user_info: user_info.map(|u| Cow::Borrowed(u).into()),
|
||||
host: host.map_inner(|inner| Cow::Borrowed(inner).into()),
|
||||
port: port
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::ext::IntoOwned;
|
||||
use crate::parse::{Indexed, IndexedStr};
|
||||
use crate::parse::{Indexed, Extent, IndexedStr};
|
||||
use crate::uri::{as_utf8_unchecked, Error, Segments};
|
||||
|
||||
use state::Storage;
|
||||
@ -114,13 +114,13 @@ impl<'a> Origin<'a> {
|
||||
#[inline]
|
||||
pub(crate) unsafe fn raw(
|
||||
source: Cow<'a, [u8]>,
|
||||
path: Indexed<'a, [u8]>,
|
||||
query: Option<Indexed<'a, [u8]>>
|
||||
path: Extent<&'a [u8]>,
|
||||
query: Option<Extent<&'a [u8]>>
|
||||
) -> Origin<'a> {
|
||||
Origin {
|
||||
source: Some(as_utf8_unchecked(source)),
|
||||
path: path.coerce(),
|
||||
query: query.map(|q| q.coerce()),
|
||||
path: path.into(),
|
||||
query: query.map(|q| q.into()),
|
||||
segment_count: Storage::new()
|
||||
}
|
||||
}
|
||||
@ -134,8 +134,8 @@ impl<'a> Origin<'a> {
|
||||
{
|
||||
Origin {
|
||||
source: None,
|
||||
path: Indexed::from(path),
|
||||
query: query.map(Indexed::from),
|
||||
path: Indexed::from(path.into()),
|
||||
query: query.map(|q| Indexed::from(q.into())),
|
||||
segment_count: Storage::new()
|
||||
}
|
||||
}
|
||||
@ -340,13 +340,13 @@ impl<'a> Origin<'a> {
|
||||
#[inline]
|
||||
pub fn map_path<F: FnOnce(&str) -> String>(&self, f: F) -> Option<Self> {
|
||||
let path = f(self.path());
|
||||
if !path.starts_with('/') || !path.bytes().all(crate::parse::uri::is_pchar) {
|
||||
if !path.starts_with('/') || !path.bytes().all(|b| crate::parse::uri::is_pchar(&b)) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Origin {
|
||||
source: self.source.clone(),
|
||||
path: path.into(),
|
||||
path: Cow::from(path).into(),
|
||||
query: self.query.clone(),
|
||||
segment_count: Storage::new(),
|
||||
})
|
||||
|
@ -5,7 +5,7 @@ use std::str::Utf8Error;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::ext::IntoOwned;
|
||||
use crate::parse::Indexed;
|
||||
use crate::parse::Extent;
|
||||
use crate::uri::{Origin, Authority, Absolute, Error};
|
||||
use crate::uri::encoding::{percent_encode, DEFAULT_ENCODE_SET};
|
||||
|
||||
@ -64,9 +64,9 @@ impl<'a> Uri<'a> {
|
||||
#[inline]
|
||||
pub(crate) unsafe fn raw_absolute(
|
||||
source: Cow<'a, [u8]>,
|
||||
scheme: Indexed<'a, [u8]>,
|
||||
path: Indexed<'a, [u8]>,
|
||||
query: Option<Indexed<'a, [u8]>>,
|
||||
scheme: Extent<&'a [u8]>,
|
||||
path: Extent<&'a [u8]>,
|
||||
query: Option<Extent<&'a [u8]>>,
|
||||
) -> Uri<'a> {
|
||||
let origin = Origin::raw(source.clone(), path, query);
|
||||
Uri::Absolute(Absolute::raw(source.clone(), scheme, None, Some(origin)))
|
||||
|
@ -35,12 +35,15 @@ state = "0.4.1"
|
||||
time = "0.2.11"
|
||||
memchr = "2" # TODO: Use pear instead.
|
||||
binascii = "0.1"
|
||||
pear = "0.1"
|
||||
atty = "0.2"
|
||||
async-trait = "0.1"
|
||||
ref-cast = "1.0"
|
||||
atomic = "0.4"
|
||||
|
||||
[dependencies.pear]
|
||||
git = "https://github.com/SergioBenitez/Pear.git"
|
||||
rev = "faee7c7e"
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "0.2.9"
|
||||
features = ["fs", "io-std", "io-util", "rt-threaded", "sync", "signal", "macros"]
|
||||
|
@ -3,17 +3,20 @@ use std::result::Result as StdResult;
|
||||
|
||||
use crate::config::Value;
|
||||
|
||||
use pear::{Result, parser, switch};
|
||||
use pear::macros::{parse, parser, switch};
|
||||
use pear::parsers::*;
|
||||
use pear::combinators::*;
|
||||
|
||||
type Input<'a> = pear::input::Pear<&'a str>;
|
||||
type Result<'a, T> = pear::input::Result<T, Input<'a>>;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_whitespace(byte: char) -> bool {
|
||||
byte == ' ' || byte == '\t'
|
||||
pub fn is_whitespace(&byte: &char) -> bool {
|
||||
byte.is_ascii_whitespace()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_not_separator(byte: char) -> bool {
|
||||
fn is_not_separator(&byte: &char) -> bool {
|
||||
match byte {
|
||||
',' | '{' | '}' | '[' | ']' => false,
|
||||
_ => true
|
||||
@ -22,33 +25,33 @@ fn is_not_separator(byte: char) -> bool {
|
||||
|
||||
// FIXME: Be more permissive here?
|
||||
#[inline(always)]
|
||||
fn is_ident_char(byte: char) -> bool {
|
||||
fn is_ident_char(&byte: &char) -> bool {
|
||||
byte.is_ascii_alphanumeric() || byte == '_' || byte == '-'
|
||||
}
|
||||
|
||||
#[parser]
|
||||
fn array<'a>(input: &mut &'a str) -> Result<Value, &'a str> {
|
||||
Value::Array(collection('[', value, ',', ']')?)
|
||||
fn array<'a>(input: &mut Input<'a>) -> Result<'a, Value> {
|
||||
Value::Array(delimited_collect('[', value, ',', ']')?)
|
||||
}
|
||||
|
||||
#[parser]
|
||||
fn key<'a>(input: &mut &'a str) -> Result<String, &'a str> {
|
||||
fn key<'a>(input: &mut Input<'a>) -> Result<'a, String> {
|
||||
take_some_while(is_ident_char)?.to_string()
|
||||
}
|
||||
|
||||
#[parser]
|
||||
fn key_value<'a>(input: &mut &'a str) -> Result<(String, Value), &'a str> {
|
||||
fn key_value<'a>(input: &mut Input<'a>) -> Result<'a, (String, Value)> {
|
||||
let key = (surrounded(key, is_whitespace)?, eat('=')?).0.to_string();
|
||||
(key, surrounded(value, is_whitespace)?)
|
||||
}
|
||||
|
||||
#[parser]
|
||||
fn table<'a>(input: &mut &'a str) -> Result<Value, &'a str> {
|
||||
Value::Table(collection('{', key_value, ',', '}')?)
|
||||
fn table<'a>(input: &mut Input<'a>) -> Result<'a, Value> {
|
||||
Value::Table(delimited_collect('{', key_value, ',', '}')?)
|
||||
}
|
||||
|
||||
#[parser]
|
||||
fn value<'a>(input: &mut &'a str) -> Result<Value, &'a str> {
|
||||
fn value<'a>(input: &mut Input<'a>) -> Result<'a, Value> {
|
||||
skip_while(is_whitespace)?;
|
||||
let val = switch! {
|
||||
eat_slice("true") => Value::Boolean(true),
|
||||
@ -72,8 +75,8 @@ fn value<'a>(input: &mut &'a str) -> Result<Value, &'a str> {
|
||||
val
|
||||
}
|
||||
|
||||
pub fn parse_simple_toml_value(mut input: &str) -> StdResult<Value, String> {
|
||||
parse!(value: &mut input).map_err(|e| e.to_string())
|
||||
pub fn parse_simple_toml_value(input: &str) -> StdResult<Value, String> {
|
||||
parse!(value: input).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// A simple wrapper over a `Value` reference with a custom implementation of
|
||||
|
@ -90,7 +90,6 @@ pub use rocket_codegen::*;
|
||||
pub use async_trait::*;
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate pear;
|
||||
|
||||
pub use futures;
|
||||
pub use tokio;
|
||||
|
Loading…
Reference in New Issue
Block a user