mirror of https://github.com/rwf2/Rocket.git
Use upstream 'Literal::subspan()'.
This commit is contained in:
parent
ed4055925d
commit
543b07a4ba
|
@ -8,8 +8,8 @@ use yansi::Color::{Red, Yellow, Blue};
|
||||||
use version_check::{supports_features, is_min_version, is_min_date};
|
use version_check::{supports_features, is_min_version, is_min_date};
|
||||||
|
|
||||||
// Specifies the minimum nightly version needed to compile Rocket.
|
// Specifies the minimum nightly version needed to compile Rocket.
|
||||||
const MIN_DATE: &'static str = "2018-10-05";
|
const MIN_DATE: &'static str = "2018-11-23";
|
||||||
const MIN_VERSION: &'static str = "1.31.0-nightly";
|
const MIN_VERSION: &'static str = "1.32.0-nightly";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let ok_channel = supports_features();
|
let ok_channel = supports_features();
|
||||||
|
|
|
@ -3,7 +3,7 @@ use proc_macro2::TokenStream as TokenStream2;
|
||||||
use devise::{syn, Spanned, SpanWrapped, Result, FromMeta, ext::TypeExt};
|
use devise::{syn, Spanned, SpanWrapped, Result, FromMeta, ext::TypeExt};
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
|
|
||||||
use proc_macro_ext::{Diagnostics, SpanExt};
|
use proc_macro_ext::{Diagnostics, StringLit};
|
||||||
use syn_ext::{syn_to_diag, IdentExt};
|
use syn_ext::{syn_to_diag, IdentExt};
|
||||||
use self::syn::{Attribute, parse::Parser};
|
use self::syn::{Attribute, parse::Parser};
|
||||||
|
|
||||||
|
@ -426,7 +426,10 @@ fn incomplete_route(
|
||||||
) -> Result<TokenStream> {
|
) -> Result<TokenStream> {
|
||||||
let method_str = method.to_string().to_lowercase();
|
let method_str = method.to_string().to_lowercase();
|
||||||
// FIXME(proc_macro): there should be a way to get this `Span`.
|
// FIXME(proc_macro): there should be a way to get this `Span`.
|
||||||
let method_span = Span::call_site().subspan(2..2 + method_str.len()).unwrap();
|
let method_span = StringLit::new(format!("#[{}]", method), Span::call_site())
|
||||||
|
.subspan(2..2 + method_str.len())
|
||||||
|
.unwrap_or(Span::call_site());
|
||||||
|
|
||||||
let method_ident = syn::Ident::new(&method_str, method_span.into());
|
let method_ident = syn::Ident::new(&method_str, method_span.into());
|
||||||
|
|
||||||
let function: syn::ItemFn = syn::parse(input).map_err(syn_to_diag)
|
let function: syn::ItemFn = syn::parse(input).map_err(syn_to_diag)
|
||||||
|
|
|
@ -4,7 +4,7 @@ use devise::syn;
|
||||||
use proc_macro::{Span, Diagnostic};
|
use proc_macro::{Span, Diagnostic};
|
||||||
|
|
||||||
use http::route::RouteSegment;
|
use http::route::RouteSegment;
|
||||||
use proc_macro_ext::{SpanExt, Diagnostics, PResult, DResult};
|
use proc_macro_ext::{Diagnostics, StringLit, PResult, DResult};
|
||||||
|
|
||||||
crate use http::route::{Error, Kind, Source};
|
crate use http::route::{Error, Kind, Source};
|
||||||
|
|
||||||
|
@ -52,15 +52,16 @@ impl Hash for Segment {
|
||||||
|
|
||||||
fn subspan(needle: &str, haystack: &str, span: Span) -> Option<Span> {
|
fn subspan(needle: &str, haystack: &str, span: Span) -> Option<Span> {
|
||||||
let index = needle.as_ptr() as usize - haystack.as_ptr() as usize;
|
let index = needle.as_ptr() as usize - haystack.as_ptr() as usize;
|
||||||
span.subspan(index..index + needle.len())
|
StringLit::new(haystack, span).subspan(index..index + needle.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trailspan(needle: &str, haystack: &str, span: Span) -> Option<Span> {
|
fn trailspan(needle: &str, haystack: &str, span: Span) -> Option<Span> {
|
||||||
let index = needle.as_ptr() as usize - haystack.as_ptr() as usize;
|
let index = needle.as_ptr() as usize - haystack.as_ptr() as usize;
|
||||||
|
let lit = StringLit::new(haystack, span);
|
||||||
if needle.as_ptr() as usize > haystack.as_ptr() as usize {
|
if needle.as_ptr() as usize > haystack.as_ptr() as usize {
|
||||||
span.subspan((index - 1)..)
|
lit.subspan((index - 1)..)
|
||||||
} else {
|
} else {
|
||||||
span.subspan(index..)
|
lit.subspan(index..)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use devise::{FromMeta, MetaItem, Result, ext::Split2};
|
||||||
use http::{self, ext::IntoOwned};
|
use http::{self, ext::IntoOwned};
|
||||||
use attribute::segments::{parse_segments, parse_segment, Segment, Kind, Source};
|
use attribute::segments::{parse_segments, parse_segment, Segment, Kind, Source};
|
||||||
|
|
||||||
use proc_macro_ext::SpanExt;
|
use proc_macro_ext::StringLit;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
crate struct ContentType(crate http::ContentType);
|
crate struct ContentType(crate http::ContentType);
|
||||||
|
@ -27,6 +27,12 @@ crate struct DataSegment(crate Segment);
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
crate struct Optional<T>(crate Option<T>);
|
crate struct Optional<T>(crate Option<T>);
|
||||||
|
|
||||||
|
impl FromMeta for StringLit {
|
||||||
|
fn from_meta(meta: MetaItem) -> Result<Self> {
|
||||||
|
Ok(StringLit::new(String::from_meta(meta)?, meta.value_span()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
crate struct RoutePath {
|
crate struct RoutePath {
|
||||||
crate origin: Origin,
|
crate origin: Origin,
|
||||||
|
@ -159,14 +165,13 @@ impl ToTokens for Method {
|
||||||
|
|
||||||
impl FromMeta for Origin {
|
impl FromMeta for Origin {
|
||||||
fn from_meta(meta: MetaItem) -> Result<Self> {
|
fn from_meta(meta: MetaItem) -> Result<Self> {
|
||||||
let string = String::from_meta(meta)?;
|
let string = StringLit::from_meta(meta)?;
|
||||||
let span = meta.value_span();
|
|
||||||
|
|
||||||
let uri = http::uri::Origin::parse_route(&string)
|
let uri = http::uri::Origin::parse_route(&string)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
let span = e.index()
|
let span = e.index()
|
||||||
.map(|i| span.subspan(i + 1..).expect("origin"))
|
.map(|i| string.subspan(i + 1..).expect("origin"))
|
||||||
.unwrap_or(span);
|
.unwrap_or(string.span());
|
||||||
|
|
||||||
span.error(format!("invalid path URI: {}", e))
|
span.error(format!("invalid path URI: {}", e))
|
||||||
.help("expected path in origin form: \"/path/<param>\"")
|
.help("expected path in origin form: \"/path/<param>\"")
|
||||||
|
@ -174,7 +179,7 @@ impl FromMeta for Origin {
|
||||||
|
|
||||||
if !uri.is_normalized() {
|
if !uri.is_normalized() {
|
||||||
let normalized = uri.to_normalized();
|
let normalized = uri.to_normalized();
|
||||||
return Err(span.error("paths cannot contain empty segments")
|
return Err(string.span().error("paths cannot contain empty segments")
|
||||||
.note(format!("expected '{}', found '{}'", normalized, uri)));
|
.note(format!("expected '{}', found '{}'", normalized, uri)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,9 +189,8 @@ impl FromMeta for Origin {
|
||||||
|
|
||||||
impl FromMeta for Segment {
|
impl FromMeta for Segment {
|
||||||
fn from_meta(meta: MetaItem) -> Result<Self> {
|
fn from_meta(meta: MetaItem) -> Result<Self> {
|
||||||
let string = String::from_meta(meta)?;
|
let string = StringLit::from_meta(meta)?;
|
||||||
let span = meta.value_span()
|
let span = string.subspan(1..(string.len() + 1))
|
||||||
.subspan(1..(string.len() + 1))
|
|
||||||
.expect("segment");
|
.expect("segment");
|
||||||
|
|
||||||
let segment = parse_segment(&string, span)?;
|
let segment = parse_segment(&string, span)?;
|
||||||
|
@ -210,15 +214,15 @@ impl FromMeta for DataSegment {
|
||||||
|
|
||||||
impl FromMeta for RoutePath {
|
impl FromMeta for RoutePath {
|
||||||
fn from_meta(meta: MetaItem) -> Result<Self> {
|
fn from_meta(meta: MetaItem) -> Result<Self> {
|
||||||
let (origin, span) = (Origin::from_meta(meta)?, meta.value_span());
|
let (origin, string) = (Origin::from_meta(meta)?, StringLit::from_meta(meta)?);
|
||||||
let path_span = span.subspan(1..origin.0.path().len() + 1).expect("path");
|
let path_span = string.subspan(1..origin.0.path().len() + 1).expect("path");
|
||||||
let path = parse_segments(origin.0.path(), '/', Source::Path, path_span);
|
let path = parse_segments(origin.0.path(), '/', Source::Path, path_span);
|
||||||
|
|
||||||
let query = origin.0.query()
|
let query = origin.0.query()
|
||||||
.map(|q| {
|
.map(|q| {
|
||||||
let len_to_q = 1 + origin.0.path().len() + 1;
|
let len_to_q = 1 + origin.0.path().len() + 1;
|
||||||
let end_of_q = len_to_q + q.len();
|
let end_of_q = len_to_q + q.len();
|
||||||
let query_span = span.subspan(len_to_q..end_of_q).expect("query");
|
let query_span = string.subspan(len_to_q..end_of_q).expect("query");
|
||||||
if q.starts_with('&') || q.contains("&&") || q.ends_with('&') {
|
if q.starts_with('&') || q.contains("&&") || q.ends_with('&') {
|
||||||
// TODO: Show a help message with what's expected.
|
// TODO: Show a help message with what's expected.
|
||||||
Err(query_span.error("query cannot contain empty segments").into())
|
Err(query_span.error("query cannot contain empty segments").into())
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#[macro_use] extern crate quote;
|
#[macro_use] extern crate quote;
|
||||||
#[macro_use] extern crate devise;
|
extern crate devise;
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
extern crate rocket_http as http;
|
extern crate rocket_http as http;
|
||||||
extern crate indexmap;
|
extern crate indexmap;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::ops::{Bound, RangeBounds};
|
use std::ops::{Bound, RangeBounds};
|
||||||
|
|
||||||
use proc_macro::{Span, Diagnostic, /* MultiSpan */};
|
use proc_macro::{Span, Diagnostic, Literal};
|
||||||
use syntax_pos::{Span as InnerSpan, Pos, BytePos};
|
use syntax_pos::{Span as InnerSpan, Pos, BytePos};
|
||||||
|
|
||||||
pub type PResult<T> = ::std::result::Result<T, Diagnostic>;
|
pub type PResult<T> = ::std::result::Result<T, Diagnostic>;
|
||||||
|
@ -62,42 +62,31 @@ impl From<Vec<Diagnostic>> for Diagnostics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SpanExt {
|
use std::ops::Deref;
|
||||||
fn subspan<R: RangeBounds<usize>>(self, range: R) -> Option<Span>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SpanExt for Span {
|
pub struct StringLit(crate String, crate Literal);
|
||||||
/// Create a `subspan` from `start` to `end`.
|
|
||||||
fn subspan<R: RangeBounds<usize>>(self, range: R) -> Option<Span> {
|
|
||||||
let inner: InnerSpan = unsafe { ::std::mem::transmute(self) };
|
|
||||||
let length = inner.hi().to_usize() - inner.lo().to_usize();
|
|
||||||
|
|
||||||
let start = match range.start_bound() {
|
impl Deref for StringLit {
|
||||||
Bound::Included(&lo) => lo,
|
type Target = str;
|
||||||
Bound::Excluded(&lo) => lo + 1,
|
|
||||||
Bound::Unbounded => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let end = match range.end_bound() {
|
fn deref(&self) -> &str {
|
||||||
Bound::Included(&hi) => hi + 1,
|
&self.0
|
||||||
Bound::Excluded(&hi) => hi,
|
}
|
||||||
Bound::Unbounded => length,
|
}
|
||||||
};
|
|
||||||
|
impl StringLit {
|
||||||
// Bounds check the values, preventing addition overflow and OOB spans.
|
pub fn new<S: Into<String>>(string: S, span: Span) -> Self {
|
||||||
if start > u32::max_value() as usize
|
let string = string.into();
|
||||||
|| end > u32::max_value() as usize
|
let mut lit = Literal::string(&string);
|
||||||
|| (u32::max_value() - start as u32) < inner.lo().to_u32()
|
lit.set_span(span);
|
||||||
|| (u32::max_value() - end as u32) < inner.lo().to_u32()
|
StringLit(string, lit)
|
||||||
|| start >= end
|
}
|
||||||
|| end > length
|
|
||||||
{
|
pub fn span(&self) -> Span {
|
||||||
return None;
|
self.1.span()
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_lo = inner.lo() + BytePos(start as u32);
|
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
|
||||||
let new_hi = inner.lo() + BytePos(end as u32);
|
self.1.subspan(range)
|
||||||
let new_inner = inner.with_lo(new_lo).with_hi(new_hi);
|
|
||||||
Some(unsafe { ::std::mem::transmute(new_inner) })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue