mirror of https://github.com/rwf2/Rocket.git
Initial implementation of typed URIs.
This is a breaking change. All Rocket applications using code generation must now additionally declare usage of the 'decl_macro' feature.
This commit is contained in:
parent
322c02f654
commit
084481a84e
|
@ -16,6 +16,7 @@ plugin = true
|
|||
|
||||
[dependencies]
|
||||
rocket = { version = "0.4.0-dev", path = "../lib/" }
|
||||
ordermap = "0.2"
|
||||
log = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
use std::collections::HashSet;
|
||||
use std::fmt::Display;
|
||||
|
||||
use ::{ROUTE_STRUCT_PREFIX, ROUTE_FN_PREFIX, PARAM_PREFIX};
|
||||
use ::{ROUTE_STRUCT_PREFIX, ROUTE_FN_PREFIX, PARAM_PREFIX, URI_INFO_MACRO_PREFIX};
|
||||
use ::{ROUTE_ATTR, ROUTE_INFO_ATTR};
|
||||
use parser::{Param, RouteParams};
|
||||
use utils::*;
|
||||
|
||||
use syntax::codemap::{Span, Spanned};
|
||||
use syntax::codemap::{Span, Spanned, dummy_spanned};
|
||||
use syntax::tokenstream::TokenTree;
|
||||
use syntax::ast::{Arg, Ident, Stmt, Expr, MetaItem, Path};
|
||||
use syntax::ast::{Arg, Ident, Item, Stmt, Expr, MetaItem, Path};
|
||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::parse::token;
|
||||
|
@ -43,7 +43,8 @@ impl RouteParams {
|
|||
fn missing_declared_err<T: Display>(&self, ecx: &ExtCtxt, arg: &Spanned<T>) {
|
||||
let (fn_span, fn_name) = (self.annotated_fn.span(), self.annotated_fn.ident());
|
||||
ecx.struct_span_err(arg.span, &format!("unused dynamic parameter: `{}`", arg.node))
|
||||
.span_note(fn_span, &format!("expected argument named `{}` in `{}`", arg.node, fn_name))
|
||||
.span_note(fn_span, &format!("expected argument named `{}` in `{}` handler",
|
||||
arg.node, fn_name))
|
||||
.emit();
|
||||
}
|
||||
|
||||
|
@ -127,10 +128,12 @@ impl RouteParams {
|
|||
// an error/debug message if parsing a parameter fails.
|
||||
fn generate_param_statements(&self, ecx: &ExtCtxt) -> Vec<Stmt> {
|
||||
let mut fn_param_statements = vec![];
|
||||
let params = Param::parse_many(ecx, self.uri.node.path(), self.uri.span.trim(1))
|
||||
.unwrap_or_else(|mut diag| { diag.emit(); vec![] });
|
||||
|
||||
// Generate a statement for every declared paramter in the path.
|
||||
let mut declared_set = HashSet::new();
|
||||
for (i, param) in self.path_params(ecx).enumerate() {
|
||||
for (i, param) in params.iter().enumerate() {
|
||||
declared_set.insert(param.ident().name);
|
||||
let ty = match self.annotated_fn.find_input(¶m.ident().name) {
|
||||
Some(arg) => strip_ty_lifetimes(arg.ty.clone()),
|
||||
|
@ -142,7 +145,7 @@ impl RouteParams {
|
|||
|
||||
// Note: the `None` case shouldn't happen if a route is matched.
|
||||
let ident = param.ident().prepend(PARAM_PREFIX);
|
||||
let expr = match param {
|
||||
let expr = match *param {
|
||||
Param::Single(_) => quote_expr!(ecx, match __req.get_param_str($i) {
|
||||
Some(s) => <$ty as ::rocket::request::FromParam>::from_param(s),
|
||||
None => return ::rocket::Outcome::Forward(__data)
|
||||
|
@ -213,6 +216,49 @@ impl RouteParams {
|
|||
sep_by_tok(ecx, &args, token::Comma)
|
||||
}
|
||||
|
||||
fn generate_uri_macro(&self, ecx: &ExtCtxt) -> P<Item> {
|
||||
let macro_args = parse_as_tokens(ecx, "$($token:tt)*");
|
||||
let macro_exp = parse_as_tokens(ecx, "$($token)*");
|
||||
let macro_name = self.annotated_fn.ident().prepend(URI_INFO_MACRO_PREFIX);
|
||||
|
||||
// What we return if we find an inconsistency throughout.
|
||||
let dummy = quote_item!(ecx, pub macro $macro_name($macro_args) { }).unwrap();
|
||||
|
||||
// Hacky check to see if the user's URI was valid.
|
||||
if self.uri.span == dummy_spanned(()).span {
|
||||
return dummy
|
||||
}
|
||||
|
||||
// Extract the route uri path and paramters from the uri.
|
||||
let route_path = self.uri.node.to_string();
|
||||
let params = match Param::parse_many(ecx, &route_path, self.uri.span.trim(1)) {
|
||||
Ok(params) => params,
|
||||
Err(mut diag) => {
|
||||
diag.cancel();
|
||||
return dummy;
|
||||
}
|
||||
};
|
||||
|
||||
// Generate the list of arguments for the URI.
|
||||
let mut fn_uri_args = vec![];
|
||||
for param in ¶ms {
|
||||
if let Some(arg) = self.annotated_fn.find_input(¶m.ident().name) {
|
||||
let (pat, ty) = (&arg.pat, &arg.ty);
|
||||
fn_uri_args.push(quote_tokens!(ecx, $pat: $ty))
|
||||
} else {
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the call to the internal URI macro with all the info.
|
||||
let args = sep_by_tok(ecx, &fn_uri_args, token::Comma);
|
||||
quote_item!(ecx,
|
||||
pub macro $macro_name($macro_args) {
|
||||
rocket_internal_uri!($route_path, ($args), $macro_exp)
|
||||
}
|
||||
).expect("consistent uri macro item")
|
||||
}
|
||||
|
||||
fn explode(&self, ecx: &ExtCtxt) -> (InternedString, &str, Path, P<Expr>, P<Expr>) {
|
||||
let name = self.annotated_fn.ident().name.as_str();
|
||||
let path = &self.uri.node.as_str();
|
||||
|
@ -242,6 +288,7 @@ fn generic_route_decorator(known_method: Option<Spanned<Method>>,
|
|||
let query_statement = route.generate_query_statement(ecx);
|
||||
let data_statement = route.generate_data_statement(ecx);
|
||||
let fn_arguments = route.generate_fn_arguments(ecx);
|
||||
let uri_macro = route.generate_uri_macro(ecx);
|
||||
|
||||
// Generate and emit the wrapping function with the Rocket handler signature.
|
||||
let user_fn_name = route.annotated_fn.ident();
|
||||
|
@ -288,6 +335,9 @@ fn generic_route_decorator(known_method: Option<Spanned<Method>>,
|
|||
let route_attr = quote_attr!(ecx, #[$attr_name($struct_name)]);
|
||||
attach_and_emit(&mut output, route_attr, annotated);
|
||||
|
||||
// Emit the per-route URI macro.
|
||||
emit_item(&mut output, uri_macro);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,7 @@ extern crate syntax;
|
|||
extern crate syntax_ext;
|
||||
extern crate rustc_plugin;
|
||||
extern crate rocket;
|
||||
extern crate ordermap;
|
||||
|
||||
#[macro_use] mod utils;
|
||||
mod parser;
|
||||
|
@ -166,6 +167,7 @@ const ROUTE_STRUCT_PREFIX: &'static str = "static_rocket_route_info_for_";
|
|||
const CATCH_STRUCT_PREFIX: &'static str = "static_rocket_catch_info_for_";
|
||||
const ROUTE_FN_PREFIX: &'static str = "rocket_route_fn_";
|
||||
const CATCH_FN_PREFIX: &'static str = "rocket_catch_fn_";
|
||||
const URI_INFO_MACRO_PREFIX: &'static str = "rocket_uri_for_";
|
||||
|
||||
const ROUTE_ATTR: &'static str = "rocket_route";
|
||||
const ROUTE_INFO_ATTR: &'static str = "rocket_route_info";
|
||||
|
@ -188,6 +190,12 @@ macro_rules! register_derives {
|
|||
)
|
||||
}
|
||||
|
||||
macro_rules! register_macros {
|
||||
($reg:expr, $($n:expr => $f:ident),+) => (
|
||||
$($reg.register_macro($n, macros::$f);)+
|
||||
)
|
||||
}
|
||||
|
||||
/// Compiler hook for Rust to register plugins.
|
||||
#[plugin_registrar]
|
||||
pub fn plugin_registrar(reg: &mut Registry) {
|
||||
|
@ -196,8 +204,12 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
|||
::rocket::logger::init(::rocket::config::LoggingLevel::Debug);
|
||||
}
|
||||
|
||||
reg.register_macro("routes", macros::routes);
|
||||
reg.register_macro("errors", macros::errors);
|
||||
register_macros!(reg,
|
||||
"routes" => routes,
|
||||
"errors" => errors,
|
||||
"uri" => uri,
|
||||
"rocket_internal_uri" => uri_internal
|
||||
);
|
||||
|
||||
register_derives!(reg,
|
||||
"derive_FromForm" => from_form_derive
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
mod uri;
|
||||
|
||||
use {ROUTE_STRUCT_PREFIX, CATCH_STRUCT_PREFIX};
|
||||
use utils::{sep_by_tok, ParserExt, IdentExt};
|
||||
|
||||
|
@ -8,39 +10,48 @@ use syntax::ext::base::{DummyResult, ExtCtxt, MacResult, MacEager};
|
|||
use syntax::parse::token::Token;
|
||||
use syntax::ptr::P;
|
||||
|
||||
pub use self::uri::{uri, uri_internal};
|
||||
|
||||
#[inline]
|
||||
pub fn prefix_path(prefix: &str, path: &mut Path) {
|
||||
let last = path.segments.len() - 1;
|
||||
let last_seg = &mut path.segments[last];
|
||||
last_seg.identifier = last_seg.identifier.prepend(prefix);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn prefix_paths(prefix: &str, paths: &mut Vec<Path>) {
|
||||
for p in paths {
|
||||
let last = p.segments.len() - 1;
|
||||
let last_seg = &mut p.segments[last];
|
||||
last_seg.identifier = last_seg.identifier.prepend(prefix);
|
||||
prefix_path(prefix, p);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prefixing_vec_macro<F>(prefix: &str,
|
||||
mut to_expr: F,
|
||||
ecx: &mut ExtCtxt,
|
||||
sp: Span,
|
||||
args: &[TokenTree])
|
||||
-> Box<MacResult + 'static>
|
||||
where F: FnMut(&ExtCtxt, Path) -> P<Expr>
|
||||
pub fn prefixing_vec_macro<F>(
|
||||
prefix: &str,
|
||||
mut to_expr: F,
|
||||
ecx: &mut ExtCtxt,
|
||||
sp: Span,
|
||||
args: &[TokenTree]) -> Box<MacResult + 'static>
|
||||
where F: FnMut(&ExtCtxt, Path) -> P<Expr>
|
||||
{
|
||||
let mut parser = ecx.new_parser_from_tts(args);
|
||||
let paths = parser.parse_paths();
|
||||
if let Ok(mut paths) = paths {
|
||||
// Prefix each path terminator and build up the P<Expr> for each path.
|
||||
prefix_paths(prefix, &mut paths);
|
||||
let path_exprs: Vec<P<Expr>> = paths.into_iter()
|
||||
.map(|path| to_expr(ecx, path))
|
||||
.collect();
|
||||
match parser.parse_paths() {
|
||||
Ok(mut paths) => {
|
||||
// Prefix each path terminator and build up the P<Expr> for each path.
|
||||
prefix_paths(prefix, &mut paths);
|
||||
let path_exprs: Vec<P<Expr>> = paths.into_iter()
|
||||
.map(|path| to_expr(ecx, path))
|
||||
.collect();
|
||||
|
||||
// Now put them all in one vector and return the thing.
|
||||
let path_list = sep_by_tok(ecx, &path_exprs, Token::Comma);
|
||||
let output = quote_expr!(ecx, vec![$path_list]).unwrap();
|
||||
MacEager::expr(P(output))
|
||||
} else {
|
||||
paths.unwrap_err().emit();
|
||||
DummyResult::expr(sp)
|
||||
// Now put them all in one vector and return the thing.
|
||||
let path_list = sep_by_tok(ecx, &path_exprs, Token::Comma);
|
||||
let output = quote_expr!(ecx, vec![$path_list]).unwrap();
|
||||
MacEager::expr(P(output))
|
||||
}
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
DummyResult::expr(sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
extern crate syntax_pos;
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use URI_INFO_MACRO_PREFIX;
|
||||
use super::prefix_path;
|
||||
|
||||
use parser::{UriParams, InternalUriParams, Validation};
|
||||
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ext::base::{DummyResult, ExtCtxt, MacEager, MacResult};
|
||||
use syntax::tokenstream::{TokenStream, TokenTree};
|
||||
use syntax::ast::{self, Ident};
|
||||
use syntax::parse::PResult;
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::ptr::P;
|
||||
|
||||
/// FIXME: Implement `MultiSpan::From<Vec<Span>>`.
|
||||
use self::syntax_pos::MultiSpan as MS;
|
||||
|
||||
pub fn uri(
|
||||
ecx: &mut ExtCtxt,
|
||||
sp: Span,
|
||||
args: &[TokenTree],
|
||||
) -> Box<MacResult + 'static> {
|
||||
// Generate the path to the internal macro.
|
||||
let mut parser = ecx.new_parser_from_tts(args);
|
||||
let (_, mut macro_path) = try_parse!(sp, UriParams::parse_prelude(&mut parser));
|
||||
prefix_path(URI_INFO_MACRO_PREFIX, &mut macro_path);
|
||||
|
||||
// It's incredibly important we use `sp` as the Span for the generated code
|
||||
// so that errors from the `internal` call show up on the user's code.
|
||||
let expr = parser.mk_mac_expr(sp,
|
||||
ast::Mac_ {
|
||||
path: macro_path,
|
||||
tts: args.to_vec().into_iter().collect::<TokenStream>().into(),
|
||||
},
|
||||
::syntax::util::ThinVec::new(),
|
||||
);
|
||||
|
||||
MacEager::expr(expr)
|
||||
}
|
||||
|
||||
fn extract_exprs<'a>(
|
||||
ecx: &ExtCtxt<'a>,
|
||||
internal: &InternalUriParams,
|
||||
) -> PResult<'a, Vec<P<ast::Expr>>> {
|
||||
let route_name = &internal.uri_params.route_path;
|
||||
match internal.validate() {
|
||||
Validation::Ok(exprs) => Ok(exprs),
|
||||
Validation::Unnamed(expected, actual) => {
|
||||
let mut diag = ecx.struct_span_err(internal.uri_params.args_span(),
|
||||
&format!("`{}` route uri expects {} but {} supplied",
|
||||
route_name, p!(expected, "parameter"), p!(actual, "was")));
|
||||
|
||||
if expected > 0 {
|
||||
let ps = p!("parameter", expected);
|
||||
diag.note(&format!("expected {}: {}", ps, internal.fn_args_str()));
|
||||
}
|
||||
|
||||
Err(diag)
|
||||
}
|
||||
Validation::Named(missing, extra, dup) => {
|
||||
let ps = p!("parameter", internal.fn_args.len());
|
||||
let e = &format!("invalid {} for `{}` route uri", ps, route_name);
|
||||
let mut diag = ecx.struct_span_err(internal.uri_params.args_span(), e);
|
||||
diag.note(&format!("expected {}: {}", ps, internal.fn_args_str()));
|
||||
|
||||
fn join<S: Display, T: Iterator<Item = S>>(iter: T) -> (&'static str, String) {
|
||||
let items: Vec<_> = iter.map(|i| format!("`{}`", i)).collect();
|
||||
(p!("parameter", items.len()), items.join(", "))
|
||||
}
|
||||
|
||||
if !extra.is_empty() {
|
||||
let (ps, msg) = join(extra.iter().map(|id| id.node));
|
||||
let sp: Vec<_> = extra.iter().map(|ident| ident.span).collect();
|
||||
diag.span_help(MS::from_spans(sp), &format!("unknown {}: {}", ps, msg));
|
||||
}
|
||||
|
||||
if !dup.is_empty() {
|
||||
let (ps, msg) = join(dup.iter().map(|id| id.node));
|
||||
let sp: Vec<_> = dup.iter().map(|ident| ident.span).collect();
|
||||
diag.span_help(MS::from_spans(sp), &format!("duplicate {}: {}", ps, msg));
|
||||
}
|
||||
|
||||
if !missing.is_empty() {
|
||||
let (ps, msg) = join(missing.iter());
|
||||
diag.help(&format!("missing {}: {}", ps, msg));
|
||||
}
|
||||
|
||||
Err(diag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub fn uri_internal(
|
||||
ecx: &mut ExtCtxt,
|
||||
sp: Span,
|
||||
tt: &[TokenTree],
|
||||
) -> Box<MacResult + 'static> {
|
||||
// Parse the internal invocation and the user's URI param expressions.
|
||||
let mut parser = ecx.new_parser_from_tts(tt);
|
||||
let internal = try_parse!(sp, InternalUriParams::parse(ecx, &mut parser));
|
||||
let exprs = try_parse!(sp, extract_exprs(ecx, &internal));
|
||||
|
||||
// Generate the statements to typecheck each parameter. First, the mount.
|
||||
let mut argument_stmts = vec![];
|
||||
let mut format_assign_tokens = vec![];
|
||||
if let Some(mount_point) = internal.uri_params.mount_point {
|
||||
// TODO: Should all expressions, not just string literals, be allowed?
|
||||
// let as_ref = ecx.expr_method_call(span, expr, Ident::from_str("as_ref"), v![]);
|
||||
let mount_string = mount_point.node;
|
||||
argument_stmts.push(ecx.stmt_let_typed(
|
||||
mount_point.span,
|
||||
false,
|
||||
Ident::from_str("mount"),
|
||||
quote_ty!(ecx, &str),
|
||||
quote_expr!(ecx, $mount_string),
|
||||
));
|
||||
|
||||
format_assign_tokens.push(quote_tokens!(ecx, mount = mount,));
|
||||
} else {
|
||||
format_assign_tokens.push(quote_tokens!(ecx, mount = "/",));
|
||||
}
|
||||
|
||||
// Now the user's parameters.
|
||||
for (i, &(ident, ref ty)) in internal.fn_args.iter().enumerate() {
|
||||
let (span, expr) = (exprs[i].span, exprs[i].clone());
|
||||
let into = ecx.expr_method_call(span, expr, Ident::from_str("into"), vec![]);
|
||||
let stmt = ecx.stmt_let_typed(span, false, ident.node, ty.clone(), into);
|
||||
|
||||
argument_stmts.push(stmt);
|
||||
format_assign_tokens.push(quote_tokens!(ecx,
|
||||
$ident = &$ident as &::rocket::http::uri::UriDisplay,
|
||||
));
|
||||
}
|
||||
|
||||
let user_path = internal.uri.node.replace('<', "{").replace('>', "}");
|
||||
let route_uri = "{mount}".to_string() + &user_path;
|
||||
MacEager::expr(quote_expr!(ecx, {
|
||||
$argument_stmts
|
||||
::rocket::http::uri::URI::from(format!($route_uri, $format_assign_tokens))
|
||||
}))
|
||||
}
|
|
@ -4,9 +4,11 @@ mod error;
|
|||
mod param;
|
||||
mod function;
|
||||
mod uri;
|
||||
mod uri_macro;
|
||||
|
||||
pub use self::keyvalue::KVSpanned;
|
||||
pub use self::route::RouteParams;
|
||||
pub use self::error::ErrorParams;
|
||||
pub use self::param::{Param, ParamIter};
|
||||
pub use self::param::Param;
|
||||
pub use self::function::Function;
|
||||
pub use self::uri_macro::{Args, InternalUriParams, UriParams, Validation};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use syntax::ast::Ident;
|
||||
use syntax::codemap::{Span, Spanned};
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::codemap::{Span, Spanned, BytePos};
|
||||
|
||||
use utils::span;
|
||||
use utils::SpanExt;
|
||||
use syntax::parse::PResult;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Param {
|
||||
|
@ -22,64 +22,45 @@ impl Param {
|
|||
Param::Single(ref ident) | Param::Many(ref ident) => &ident.node,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ParamIter<'s, 'a, 'c: 'a> {
|
||||
ctxt: &'a ExtCtxt<'c>,
|
||||
span: Span,
|
||||
string: &'s str,
|
||||
}
|
||||
pub fn parse_many<'a>(
|
||||
ecx: &ExtCtxt<'a>,
|
||||
mut string: &str,
|
||||
mut span: Span
|
||||
) -> PResult<'a, Vec<Param>> {
|
||||
let err = |sp, msg| { Err(ecx.struct_span_err(sp, msg)) };
|
||||
|
||||
impl<'s, 'a, 'c: 'a> ParamIter<'s, 'a, 'c> {
|
||||
pub fn new(c: &'a ExtCtxt<'c>, s: &'s str, p: Span) -> ParamIter<'s, 'a, 'c> {
|
||||
ParamIter { ctxt: c, span: p, string: s }
|
||||
}
|
||||
}
|
||||
let mut params = vec![];
|
||||
loop {
|
||||
// Find the start and end indexes for the next parameter, if any.
|
||||
let (start, end) = match string.find('<') {
|
||||
Some(i) => match string.find('>') {
|
||||
Some(j) if j > i => (i, j),
|
||||
Some(_) => return err(span, "malformed parameters"),
|
||||
None => return err(span, "malformed parameters")
|
||||
},
|
||||
_ => return Ok(params)
|
||||
};
|
||||
|
||||
impl<'s, 'a, 'c> Iterator for ParamIter<'s, 'a, 'c> {
|
||||
type Item = Param;
|
||||
// Calculate the parameter's ident and span.
|
||||
let param_span = span.expand(start, end + 1);
|
||||
let full_param = &string[(start + 1)..end];
|
||||
let (is_many, param) = if full_param.ends_with("..") {
|
||||
(true, &full_param[..(full_param.len() - 2)])
|
||||
} else {
|
||||
(false, full_param)
|
||||
};
|
||||
|
||||
fn next(&mut self) -> Option<Param> {
|
||||
let err = |ecx: &ExtCtxt, sp: Span, msg: &str| {
|
||||
ecx.span_err(sp, msg);
|
||||
None
|
||||
};
|
||||
// Advance the string and span.
|
||||
string = &string[(end + 1)..];
|
||||
span = span.trim_left(end + 1);
|
||||
|
||||
// Find the start and end indexes for the next parameter, if any.
|
||||
let (start, end) = match self.string.find('<') {
|
||||
Some(i) => match self.string.find('>') {
|
||||
Some(j) => (i, j),
|
||||
None => return err(self.ctxt, self.span, "malformed parameters")
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
// Ensure we found a valid parameter.
|
||||
if end <= start {
|
||||
return err(self.ctxt, self.span, "malformed parameters");
|
||||
}
|
||||
|
||||
// Calculate the parameter's ident.
|
||||
let full_param = &self.string[(start + 1)..end];
|
||||
let (is_many, param) = if full_param.ends_with("..") {
|
||||
(true, &full_param[..(full_param.len() - 2)])
|
||||
} else {
|
||||
(false, full_param)
|
||||
};
|
||||
|
||||
let mut param_span = self.span;
|
||||
param_span.lo = self.span.lo + BytePos(start as u32);
|
||||
param_span.hi = self.span.lo + BytePos((end + 1) as u32);
|
||||
|
||||
// Advance the string and span.
|
||||
self.string = &self.string[(end + 1)..];
|
||||
self.span.lo = self.span.lo + BytePos((end + 1) as u32);
|
||||
|
||||
let spanned_ident = span(Ident::from_str(param), param_span);
|
||||
if is_many {
|
||||
Some(Param::Many(spanned_ident))
|
||||
} else {
|
||||
Some(Param::Single(spanned_ident))
|
||||
let spanned_ident = param_span.wrap(Ident::from_str(param));
|
||||
if is_many {
|
||||
params.push(Param::Many(spanned_ident))
|
||||
} else {
|
||||
params.push(Param::Single(spanned_ident))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use syntax::ext::base::{ExtCtxt, Annotatable};
|
|||
use syntax::codemap::{Span, Spanned, dummy_spanned};
|
||||
|
||||
use utils::{span, MetaItemExt, SpanExt, is_valid_ident};
|
||||
use super::{Function, ParamIter};
|
||||
use super::Function;
|
||||
use super::keyvalue::KVSpanned;
|
||||
use super::uri::validate_uri;
|
||||
use rocket::http::{Method, MediaType};
|
||||
|
@ -33,12 +33,13 @@ impl RouteParams {
|
|||
/// Parses the route attribute from the given decorator context. If the
|
||||
/// parse is not successful, this function exits early with the appropriate
|
||||
/// error message to the user.
|
||||
pub fn from(ecx: &mut ExtCtxt,
|
||||
sp: Span,
|
||||
known_method: Option<Spanned<Method>>,
|
||||
meta_item: &MetaItem,
|
||||
annotated: &Annotatable)
|
||||
-> RouteParams {
|
||||
pub fn from(
|
||||
ecx: &mut ExtCtxt,
|
||||
sp: Span,
|
||||
known_method: Option<Spanned<Method>>,
|
||||
meta_item: &MetaItem,
|
||||
annotated: &Annotatable
|
||||
) -> RouteParams {
|
||||
let function = Function::from(annotated).unwrap_or_else(|item_sp| {
|
||||
ecx.span_err(sp, "this attribute can only be used on functions...");
|
||||
ecx.span_fatal(item_sp, "...but was applied to the item above.");
|
||||
|
@ -125,12 +126,6 @@ impl RouteParams {
|
|||
annotated_fn: function,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_params<'s, 'a, 'c: 'a>(&'s self,
|
||||
ecx: &'a ExtCtxt<'c>)
|
||||
-> ParamIter<'s, 'a, 'c> {
|
||||
ParamIter::new(ecx, self.uri.node.path(), self.uri.span.trim(1))
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid_method(method: Method) -> bool {
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
use utils::{self, ParserExt, SpanExt};
|
||||
|
||||
use syntax::codemap::{Spanned, Span};
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::symbol::InternedString;
|
||||
use syntax::ast::{self, Expr, Name, Ident, Path};
|
||||
use syntax::parse::PResult;
|
||||
use syntax::parse::token::{DelimToken, Token};
|
||||
use syntax::parse::common::SeqSep;
|
||||
use syntax::parse::parser::{Parser, PathStyle};
|
||||
use syntax::print::pprust::ty_to_string;
|
||||
use syntax::ptr::P;
|
||||
|
||||
use ordermap::OrderMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Arg {
|
||||
Unnamed(P<Expr>),
|
||||
Named(Spanned<Ident>, P<Expr>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Args {
|
||||
Unnamed(Vec<P<Expr>>),
|
||||
Named(Vec<(Spanned<Ident>, P<Expr>)>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UriParams {
|
||||
pub mount_point: Option<Spanned<InternedString>>,
|
||||
pub route_path: Path,
|
||||
pub arguments: Option<Spanned<Args>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InternalUriParams {
|
||||
pub uri: Spanned<String>,
|
||||
pub fn_args: Vec<(Spanned<ast::Ident>, P<ast::Ty>)>,
|
||||
pub uri_params: UriParams,
|
||||
}
|
||||
|
||||
impl Arg {
|
||||
fn is_named(&self) -> bool {
|
||||
match *self {
|
||||
Arg::Named(..) => true,
|
||||
Arg::Unnamed(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn unnamed(self) -> P<Expr> {
|
||||
match self {
|
||||
Arg::Unnamed(expr) => expr,
|
||||
_ => panic!("Called Arg::unnamed() on an Arg::named!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn named(self) -> (Spanned<Ident>, P<Expr>) {
|
||||
match self {
|
||||
Arg::Named(ident, expr) => (ident, expr),
|
||||
_ => panic!("Called Arg::named() on an Arg::Unnamed!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UriParams {
|
||||
// Parses the mount point, if any, and route identifier.
|
||||
pub fn parse_prelude<'a>(
|
||||
parser: &mut Parser<'a>
|
||||
) -> PResult<'a, (Option<Spanned<InternedString>>, Path)> {
|
||||
// Parse the mount point and suffixing ',', if any.
|
||||
let mount_point = match parser.parse_optional_str() {
|
||||
Some((symbol, _, _)) => {
|
||||
let string = symbol.as_str();
|
||||
let span = parser.prev_span;
|
||||
parser.expect(&Token::Comma)?;
|
||||
Some(span.wrap(string))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
// Parse the route identifier, which must always exist.
|
||||
let route_path = parser.parse_path(PathStyle::Mod)?;
|
||||
Ok((mount_point, route_path))
|
||||
}
|
||||
|
||||
/// The Span to use when referring to all of the arguments.
|
||||
pub fn args_span(&self) -> Span {
|
||||
match self.arguments {
|
||||
Some(ref args) => args.span,
|
||||
None => self.route_path.span
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse<'a>( ecx: &'a ExtCtxt, parser: &mut Parser<'a>,) -> PResult<'a, UriParams> {
|
||||
// Parse the mount point and suffixing ',', if any.
|
||||
let (mount_point, route_path) = Self::parse_prelude(parser)?;
|
||||
|
||||
// If there are no arguments, finish early.
|
||||
if !parser.eat(&Token::Colon) {
|
||||
parser.expect(&Token::Eof)?;
|
||||
let arguments = None;
|
||||
return Ok(UriParams { mount_point, route_path, arguments, });
|
||||
}
|
||||
|
||||
// Parse arguments.
|
||||
let mut args_span = parser.span;
|
||||
let comma = SeqSep::trailing_allowed(Token::Comma);
|
||||
let arguments = parser.parse_seq_to_end(&Token::Eof, comma, |parser| {
|
||||
let has_key = parser.look_ahead(1, |token| *token == Token::Eq);
|
||||
|
||||
if has_key {
|
||||
let inner_ident = parser.parse_ident()?;
|
||||
let ident = parser.prev_span.wrap(inner_ident);
|
||||
parser.expect(&Token::Eq)?;
|
||||
|
||||
let expr = parser.parse_expr()?;
|
||||
Ok(Arg::Named(ident, expr))
|
||||
} else {
|
||||
let expr = parser.parse_expr()?;
|
||||
Ok(Arg::Unnamed(expr))
|
||||
}
|
||||
})?;
|
||||
|
||||
// Set the end of the args_span to be the end of the args.
|
||||
args_span.hi = parser.prev_span.hi;
|
||||
|
||||
// A 'colon' was used but there are no arguments.
|
||||
if arguments.is_empty() {
|
||||
return Err(ecx.struct_span_err(parser.prev_span,
|
||||
"expected argument list after `:`"));
|
||||
}
|
||||
|
||||
// Ensure that both types of arguments were not used at once.
|
||||
let (mut homogeneous_args, mut prev_named) = (true, None);
|
||||
for arg in arguments.iter() {
|
||||
match prev_named {
|
||||
Some(prev_named) => homogeneous_args = prev_named == arg.is_named(),
|
||||
None => prev_named = Some(arg.is_named()),
|
||||
}
|
||||
}
|
||||
|
||||
if !homogeneous_args {
|
||||
return Err(ecx.struct_span_err(args_span,
|
||||
"named and unnamed parameters cannot be mixed"));
|
||||
}
|
||||
|
||||
// Create the `Args` enum, which properly types one-kind-of-argument-ness.
|
||||
let args = if prev_named.unwrap() {
|
||||
Args::Named(arguments.into_iter().map(|arg| arg.named()).collect())
|
||||
} else {
|
||||
Args::Unnamed(arguments.into_iter().map(|arg| arg.unnamed()).collect())
|
||||
};
|
||||
|
||||
let arguments = Some(args_span.wrap(args));
|
||||
Ok(UriParams { mount_point, route_path, arguments, })
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Validation {
|
||||
// Number expected, what we actually got.
|
||||
Unnamed(usize, usize),
|
||||
// (Missing, Extra, Duplicate)
|
||||
Named(Vec<Name>, Vec<Spanned<Ident>>, Vec<Spanned<Ident>>),
|
||||
// Everything is okay.
|
||||
Ok(Vec<P<Expr>>)
|
||||
}
|
||||
|
||||
impl InternalUriParams {
|
||||
pub fn parse<'a>(
|
||||
ecx: &'a ExtCtxt,
|
||||
parser: &mut Parser<'a>,
|
||||
) -> PResult<'a, InternalUriParams> {
|
||||
let uri_str = parser.parse_str_lit().map(|(s, _)| s.as_str().to_string())?;
|
||||
let uri = parser.prev_span.wrap(uri_str);
|
||||
parser.expect(&Token::Comma)?;
|
||||
|
||||
let start = Token::OpenDelim(DelimToken::Paren);
|
||||
let end = Token::CloseDelim(DelimToken::Paren);
|
||||
let comma = SeqSep::trailing_allowed(Token::Comma);
|
||||
let fn_args = parser
|
||||
.parse_seq(&start, &end, comma, |parser| {
|
||||
let param = parser.parse_ident_inc_pat()?;
|
||||
parser.expect(&Token::Colon)?;
|
||||
let ty = utils::strip_ty_lifetimes(parser.parse_ty()?);
|
||||
Ok((param, ty))
|
||||
})?
|
||||
.node;
|
||||
|
||||
parser.expect(&Token::Comma)?;
|
||||
let uri_params = UriParams::parse(ecx, parser)?;
|
||||
Ok(InternalUriParams { uri, fn_args, uri_params, })
|
||||
}
|
||||
|
||||
pub fn fn_args_str(&self) -> String {
|
||||
self.fn_args.iter()
|
||||
.map(|&(ident, ref ty)| format!("{}: {}", ident.node, ty_to_string(&ty)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> Validation {
|
||||
let unnamed = |args: &Vec<P<Expr>>| -> Validation {
|
||||
let (expected, actual) = (self.fn_args.len(), args.len());
|
||||
if expected != actual { Validation::Unnamed(expected, actual) }
|
||||
else { Validation::Ok(args.clone()) }
|
||||
};
|
||||
|
||||
match self.uri_params.arguments {
|
||||
None => unnamed(&vec![]),
|
||||
Some(Spanned { node: Args::Unnamed(ref args), .. }) => unnamed(args),
|
||||
Some(Spanned { node: Args::Named(ref args), .. }) => {
|
||||
let mut params: OrderMap<Name, Option<P<Expr>>> = self.fn_args.iter()
|
||||
.map(|&(ident, _)| (ident.node.name, None))
|
||||
.collect();
|
||||
|
||||
let (mut extra, mut dup) = (vec![], vec![]);
|
||||
for &(ident, ref expr) in args {
|
||||
match params.get_mut(&ident.node.name) {
|
||||
Some(ref entry) if entry.is_some() => dup.push(ident),
|
||||
Some(entry) => *entry = Some(expr.clone()),
|
||||
None => extra.push(ident),
|
||||
}
|
||||
}
|
||||
|
||||
let (mut missing, mut exprs) = (vec![], vec![]);
|
||||
for (name, expr) in params.into_iter() {
|
||||
match expr {
|
||||
Some(expr) => exprs.push(expr),
|
||||
None => missing.push(name)
|
||||
}
|
||||
}
|
||||
|
||||
if (extra.len() + dup.len() + missing.len()) == 0 {
|
||||
Validation::Ok(exprs)
|
||||
} else {
|
||||
Validation::Named(missing, extra, dup)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -70,23 +70,11 @@ pub fn attach_and_emit(out: &mut Vec<Annotatable>, attr: Attribute, to: Annotata
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! quote_enum {
|
||||
($ecx:expr, $var:expr => $(::$root:ident)+
|
||||
{ $($variant:ident),+ ; $($extra:pat => $result:expr),* }) => ({
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use syntax::ast::Ident;
|
||||
use $(::$root)+::*;
|
||||
let root_idents = vec![$(Ident::from_str(stringify!($root))),+];
|
||||
match $var {
|
||||
$($variant => {
|
||||
let variant = Ident::from_str(stringify!($variant));
|
||||
let mut idents = root_idents.clone();
|
||||
idents.push(variant);
|
||||
$ecx.path_global(DUMMY_SP, idents)
|
||||
})+
|
||||
$($extra => $result),*
|
||||
}
|
||||
})
|
||||
pub fn parse_as_tokens(ecx: &ExtCtxt, string: &str) -> Vec<TokenTree> {
|
||||
use syntax::parse::parse_stream_from_source_str as parse_stream;
|
||||
|
||||
let stream = parse_stream("<_>".into(), string.into(), ecx.parse_sess, None);
|
||||
stream.into_trees().collect()
|
||||
}
|
||||
|
||||
pub struct TyLifetimeRemover;
|
||||
|
@ -140,3 +128,45 @@ pub fn is_valid_ident<S: AsRef<str>>(s: S) -> bool {
|
|||
|
||||
true
|
||||
}
|
||||
|
||||
macro_rules! quote_enum {
|
||||
($ecx:expr, $var:expr => $(::$root:ident)+
|
||||
{ $($variant:ident),+ ; $($extra:pat => $result:expr),* }) => ({
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use syntax::ast::Ident;
|
||||
use $(::$root)+::*;
|
||||
let root_idents = vec![$(Ident::from_str(stringify!($root))),+];
|
||||
match $var {
|
||||
$($variant => {
|
||||
let variant = Ident::from_str(stringify!($variant));
|
||||
let mut idents = root_idents.clone();
|
||||
idents.push(variant);
|
||||
$ecx.path_global(DUMMY_SP, idents)
|
||||
})+
|
||||
$($extra => $result),*
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! try_parse {
|
||||
($sp:expr, $parse:expr) => (
|
||||
match $parse {
|
||||
Ok(v) => v,
|
||||
Err(mut e) => { e.emit(); return DummyResult::expr($sp); }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! p {
|
||||
("parameter", $num:expr) => (
|
||||
if $num == 1 { "parameter" } else { "parameters" }
|
||||
);
|
||||
|
||||
($num:expr, "was") => (
|
||||
if $num == 1 { "1 was".into() } else { format!("{} were", $num) }
|
||||
);
|
||||
|
||||
($num:expr, "parameter") => (
|
||||
if $num == 1 { "1 parameter".into() } else { format!("{} parameters", $num) }
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
use super::SpanExt;
|
||||
|
||||
use syntax::parse::parser::{PathStyle, Parser};
|
||||
use syntax::parse::PResult;
|
||||
use syntax::ast::Path;
|
||||
use syntax::ast::{self, Path, StrStyle, Ident};
|
||||
use syntax::parse::token::Token::{Eof, Comma};
|
||||
use syntax::parse::common::SeqSep;
|
||||
use syntax::codemap::Spanned;
|
||||
use syntax::symbol::Symbol;
|
||||
|
||||
pub trait ParserExt<'a> {
|
||||
// Parse a comma-seperated list of paths: `a::b, b::c`.
|
||||
fn parse_paths(&mut self) -> PResult<'a, Vec<Path>>;
|
||||
|
||||
// Just like `parse_str` but takes into account interpolated expressions.
|
||||
fn parse_str_lit(&mut self) -> PResult<'a, (Symbol, StrStyle)>;
|
||||
|
||||
// Like `parse_ident` but also looks for an `ident` in a `Pat`.
|
||||
fn parse_ident_inc_pat(&mut self) -> PResult<'a, Spanned<Ident>>;
|
||||
}
|
||||
|
||||
impl<'a> ParserExt<'a> for Parser<'a> {
|
||||
|
@ -14,4 +25,36 @@ impl<'a> ParserExt<'a> for Parser<'a> {
|
|||
SeqSep::trailing_allowed(Comma),
|
||||
|p| p.parse_path(PathStyle::Mod))
|
||||
}
|
||||
|
||||
fn parse_str_lit(&mut self) -> PResult<'a, (Symbol, StrStyle)> {
|
||||
self.parse_str()
|
||||
.or_else(|mut e| {
|
||||
let expr = self.parse_expr().map_err(|i| { e.cancel(); i })?;
|
||||
let string_lit = match expr.node {
|
||||
ast::ExprKind::Lit(ref lit) => match lit.node {
|
||||
ast::LitKind::Str(symbol, style) => (symbol, style),
|
||||
_ => return Err(e)
|
||||
}
|
||||
_ => return Err(e)
|
||||
};
|
||||
|
||||
e.cancel();
|
||||
Ok(string_lit)
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_ident_inc_pat(&mut self) -> PResult<'a, Spanned<Ident>> {
|
||||
self.parse_ident()
|
||||
.map(|ident| self.prev_span.wrap(ident))
|
||||
.or_else(|mut e| {
|
||||
let pat = self.parse_pat().map_err(|i| { e.cancel(); i })?;
|
||||
let ident = match pat.node {
|
||||
ast::PatKind::Ident(_, ident, _) => ident,
|
||||
_ => return Err(e)
|
||||
};
|
||||
|
||||
e.cancel();
|
||||
Ok(ident)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use syntax::codemap::{Span, BytePos};
|
||||
use syntax::codemap::{Span, Spanned, BytePos};
|
||||
|
||||
pub trait SpanExt {
|
||||
/// Trim the span on the left and right by `length`.
|
||||
|
@ -15,6 +15,12 @@ pub trait SpanExt {
|
|||
|
||||
// Trim from the left so that the span is `length` in size.
|
||||
fn shorten_upto(self, length: usize) -> Span;
|
||||
|
||||
// Wrap `T` into a `Spanned<T>` with `self` as the span.
|
||||
fn wrap<T>(self, node: T) -> Spanned<T>;
|
||||
|
||||
/// Expand the span on the left by `left` and right by `right`.
|
||||
fn expand(self, left: usize, right: usize) -> Span;
|
||||
}
|
||||
|
||||
impl SpanExt for Span {
|
||||
|
@ -43,4 +49,14 @@ impl SpanExt for Span {
|
|||
self.hi = self.hi - BytePos(length);
|
||||
self
|
||||
}
|
||||
|
||||
fn wrap<T>(self, node: T) -> Spanned<T> {
|
||||
Spanned { node: node, span: self }
|
||||
}
|
||||
|
||||
fn expand(mut self, left: usize, right: usize) -> Span {
|
||||
self.lo = self.lo + BytePos(left as u32);
|
||||
self.hi = self.lo + BytePos(right as u32);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
#[get("a")] //~ ERROR absolute
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
#[get("/a/b/c//d")] //~ ERROR paths cannot contain empty segments
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
#[derive(FromForm)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
#[get("/<name>")] //~ ERROR unused dynamic parameter: `name`
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
#[get("/><")] //~ ERROR malformed
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
#[get("/<param>")] //~ ERROR unused dynamic parameter: `param`
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket_contrib;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket_contrib;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate crossbeam;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
extern crate rocket;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket_contrib;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive, const_fn)]
|
||||
#![feature(plugin, decl_macro, custom_derive, const_fn)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -35,7 +35,7 @@ use yansi::Color::*;
|
|||
/// declared using the `error` decorator, as follows:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(plugin)]
|
||||
/// #![feature(plugin, decl_macro)]
|
||||
/// #![plugin(rocket_codegen)]
|
||||
///
|
||||
/// extern crate rocket;
|
||||
|
|
|
@ -156,7 +156,7 @@ impl<'a, S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
|
|||
/// ```rust
|
||||
/// # #![allow(unused_attributes)]
|
||||
/// # #![allow(unused_variables)]
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// #
|
||||
|
|
|
@ -35,7 +35,7 @@ use http::Header;
|
|||
/// a handler to retrieve the value of a "message" cookie.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::http::Cookies;
|
||||
|
@ -56,7 +56,7 @@ use http::Header;
|
|||
/// [private cookie]: /rocket/http/enum.Cookies.html#private-cookies
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// #
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
//! Borrowed and owned string types for absolute URIs.
|
||||
|
||||
use std::convert::From;
|
||||
use std::fmt;
|
||||
use std::convert::From;
|
||||
use std::borrow::Cow;
|
||||
use std::str::Utf8Error;
|
||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||
|
||||
use http::RawStr;
|
||||
|
||||
use url;
|
||||
|
||||
/// Index (start, end) into a string, to prevent borrowing.
|
||||
|
@ -346,6 +348,45 @@ impl<'a> fmt::Display for URI<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait UriDisplay {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
|
||||
}
|
||||
|
||||
impl<T: fmt::Display> UriDisplay for T {
|
||||
#[inline(always)]
|
||||
default fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
<Self as fmt::Display>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for &'a UriDisplay {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
(**self).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UriDisplay for &'a RawStr {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", URI::percent_encode((*self).as_str()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UriDisplay for &'a str {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", URI::percent_encode(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UriDisplay for String {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", URI::percent_encode(self.as_str()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over the segments of an absolute URI path. Skips empty segments.
|
||||
///
|
||||
/// ### Examples
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#![feature(conservative_impl_trait)]
|
||||
#![feature(drop_types_in_const)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![feature(never_type)]
|
||||
#![feature(try_trait)]
|
||||
|
||||
|
@ -55,7 +55,7 @@
|
|||
//! Then, add the following to the top of your `main.rs` file:
|
||||
//!
|
||||
//! ```rust
|
||||
//! #![feature(plugin)]
|
||||
//! #![feature(plugin, decl_macro)]
|
||||
//! # #![allow(unused_attributes)]
|
||||
//! #![plugin(rocket_codegen)]
|
||||
//!
|
||||
|
@ -66,7 +66,7 @@
|
|||
//! write Rocket applications. Here's a simple example to get you started:
|
||||
//!
|
||||
//! ```rust
|
||||
//! #![feature(plugin)]
|
||||
//! #![feature(plugin, decl_macro)]
|
||||
//! #![plugin(rocket_codegen)]
|
||||
//!
|
||||
//! extern crate rocket;
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
//! consider the following complete "Hello, world!" application, with testing.
|
||||
//!
|
||||
//! ```rust
|
||||
//! #![feature(plugin)]
|
||||
//! #![feature(plugin, decl_macro)]
|
||||
//! #![plugin(rocket_codegen)]
|
||||
//!
|
||||
//! extern crate rocket;
|
||||
|
|
|
@ -49,7 +49,7 @@ use request::form::{FromForm, FormItems};
|
|||
/// The simplest data structure with a reference into form data looks like this:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![allow(deprecated, dead_code, unused_attributes)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
|
@ -65,7 +65,7 @@ use request::form::{FromForm, FormItems};
|
|||
/// a string. A handler for this type can be written as:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![allow(deprecated, unused_attributes)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
|
@ -91,7 +91,7 @@ use request::form::{FromForm, FormItems};
|
|||
/// The owned analog of the `UserInput` type above is:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![allow(deprecated, dead_code, unused_attributes)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
|
@ -105,7 +105,7 @@ use request::form::{FromForm, FormItems};
|
|||
/// The handler is written similarly:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![allow(deprecated, unused_attributes)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
|
@ -170,7 +170,7 @@ impl<'f, T: FromForm<'f> + 'f> Form<'f, T> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::request::Form;
|
||||
|
@ -198,7 +198,7 @@ impl<'f, T: FromForm<'f> + 'f> Form<'f, T> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::request::Form;
|
||||
|
@ -269,7 +269,7 @@ impl<'f, T: FromForm<'f> + 'static> Form<'f, T> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::request::Form;
|
||||
|
|
|
@ -14,7 +14,7 @@ use request::FormItems;
|
|||
/// validation.
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(plugin, custom_derive)]
|
||||
/// #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// #![plugin(rocket_codegen)]
|
||||
/// # #![allow(deprecated, dead_code, unused_attributes)]
|
||||
///
|
||||
|
@ -34,7 +34,7 @@ use request::FormItems;
|
|||
/// data via the `data` parameter and `Form` type.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![allow(deprecated, dead_code, unused_attributes)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
|
|
|
@ -56,7 +56,7 @@ impl<'f, T: FromForm<'f> + 'f> LenientForm<'f, T> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::request::LenientForm;
|
||||
|
@ -84,7 +84,7 @@ impl<'f, T: FromForm<'f> + 'f> LenientForm<'f, T> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::request::LenientForm;
|
||||
|
@ -114,7 +114,7 @@ impl<'f, T: FromForm<'f> + 'static> LenientForm<'f, T> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin, custom_derive)]
|
||||
/// # #![feature(plugin, decl_macro, custom_derive)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::request::LenientForm;
|
||||
|
|
|
@ -167,7 +167,7 @@ impl<S, E> IntoOutcome<S, (Status, E), ()> for Result<S, E> {
|
|||
/// `senstive` handler.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// #
|
||||
|
|
|
@ -20,7 +20,7 @@ use http::RawStr;
|
|||
/// handler for the dynamic `"/<id>"` path:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// #[get("/<id>")]
|
||||
|
@ -56,7 +56,7 @@ use http::RawStr;
|
|||
/// parameter as follows:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// # use rocket::http::RawStr;
|
||||
|
@ -163,7 +163,7 @@ use http::RawStr;
|
|||
/// dynamic path segment:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// # use rocket::request::FromParam;
|
||||
|
|
|
@ -21,7 +21,7 @@ use http::Status;
|
|||
/// following example does just this:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::State;
|
||||
|
|
|
@ -46,7 +46,7 @@ const FLASH_COOKIE_NAME: &'static str = "_flash";
|
|||
/// message on both the request and response sides.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// #
|
||||
/// # extern crate rocket;
|
||||
|
|
|
@ -137,7 +137,7 @@ use request::Request;
|
|||
/// following `Responder` implementation accomplishes this:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// #
|
||||
|
|
|
@ -448,7 +448,7 @@ impl Rocket {
|
|||
/// dispatched to the `hi` route.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// #
|
||||
|
@ -514,7 +514,7 @@ impl Rocket {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(plugin)]
|
||||
/// #![feature(plugin, decl_macro)]
|
||||
/// #![plugin(rocket_codegen)]
|
||||
///
|
||||
/// extern crate rocket;
|
||||
|
@ -573,7 +573,7 @@ impl Rocket {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::State;
|
||||
|
@ -609,7 +609,7 @@ impl Rocket {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::Rocket;
|
||||
|
@ -711,7 +711,7 @@ impl Rocket {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::Rocket;
|
||||
|
@ -748,7 +748,7 @@ impl Rocket {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![feature(plugin, decl_macro)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// use rocket::Rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![feature(plugin, decl_macro, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(plugin)]
|
||||
#![feature(plugin, decl_macro)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue