1use std::ops::Deref;
2
3use indexmap::IndexMap;
4use devise::{Spanned, ext::TypeExt};
5use quote::{ToTokens, TokenStreamExt};
6use syn::{Expr, Ident, LitStr, Path, Token, Type};
7use syn::parse::{self, Parse, ParseStream, Parser};
8use syn::punctuated::Punctuated;
9use proc_macro2::{TokenStream, TokenTree, Span};
10use rocket_http::uri::{Error, Reference};
11
12use crate::http::uri::{Uri, Origin, Absolute, fmt};
13use crate::http::ext::IntoOwned;
14use crate::proc_macro_ext::StringLit;
15use crate::attribute::param::{Parameter, Dynamic};
16use crate::name::Name;
17
18#[derive(Debug)]
21pub enum ArgExpr {
22 Expr(Expr),
23 Ignored(Token![_]),
24}
25
26#[derive(Debug)]
27pub enum Arg {
28 Unnamed(ArgExpr),
29 Named(Name, Ident, Token![=], ArgExpr),
30}
31
32#[derive(Debug)]
33pub enum Args {
34 Unnamed(Punctuated<Arg, Token![,]>),
35 Named(Punctuated<Arg, Token![,]>),
36}
37
38#[derive(Debug)]
40pub struct UriLit(Uri<'static>, Span);
41
42#[derive(Debug)]
44pub enum UriExpr {
45 Uri(UriLit),
47 Expr(Expr),
49}
50
51#[derive(Debug)]
53pub struct RouteInvocation {
54 pub path: Path,
55 pub args: Args,
56}
57
58#[derive(Debug)]
60pub struct RoutedUri {
61 pub prefix: Option<UriExpr>,
62 pub route: RouteInvocation,
63 pub suffix: Option<UriExpr>,
64}
65
66#[derive(Debug)]
80pub enum UriMacro {
81 Literal(UriLit),
82 Routed(RoutedUri),
83}
84
85#[derive(Debug)]
86pub enum Validation<'a> {
87 NamedIgnored(Vec<&'a Dynamic>),
89 Unnamed(usize, usize),
91 Named(Vec<&'a Name>, Vec<&'a Ident>, Vec<&'a Ident>),
93 Ok(Vec<&'a ArgExpr>)
95}
96
97#[derive(Debug)]
115pub struct InternalUriParams {
116 pub route_uri: Origin<'static>,
117 pub path_params: Vec<Parameter>,
118 pub query_params: Vec<Parameter>,
119 pub fn_args: Vec<FnArg>,
120 pub uri_mac: RoutedUri,
121}
122
123#[derive(Debug)]
124pub struct FnArg {
125 pub ident: Ident,
126 pub ty: Type,
127}
128
129fn err<T, S: AsRef<str>>(span: Span, s: S) -> parse::Result<T> {
130 Err(parse::Error::new(span, s.as_ref()))
131}
132
133impl Parse for ArgExpr {
134 fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
135 if input.peek(Token![_]) {
136 return Ok(ArgExpr::Ignored(input.parse::<Token![_]>()?));
137 }
138
139 input.parse::<Expr>().map(ArgExpr::Expr)
140 }
141}
142
143impl Parse for Arg {
144 fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
145 let has_key = input.peek2(Token![=]);
146 if has_key {
147 let ident = input.parse::<Ident>()?;
148 let eq_token = input.parse::<Token![=]>()?;
149 let expr = input.parse::<ArgExpr>()?;
150 Ok(Arg::Named(Name::from(&ident), ident, eq_token, expr))
151 } else {
152 let expr = input.parse::<ArgExpr>()?;
153 Ok(Arg::Unnamed(expr))
154 }
155 }
156}
157
158impl Parse for Args {
159 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
160 if input.cursor().eof() {
162 return Ok(Args::Unnamed(Punctuated::new()));
163 }
164
165 let args = input.parse_terminated(Arg::parse, Token![,])?;
167 let mut first_is_named = None;
168 for arg in &args {
169 if let Some(first_is_named) = first_is_named {
170 if first_is_named != arg.is_named() {
171 return err(args.span(), "named and unnamed parameters cannot be mixed");
172 }
173 } else {
174 first_is_named = Some(arg.is_named());
175 }
176 }
177
178 match first_is_named {
180 Some(true) => Ok(Args::Named(args)),
181 _ => Ok(Args::Unnamed(args))
182 }
183 }
184}
185
186impl Parse for RouteInvocation {
187 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
188 let path = input.parse()?;
189 let args = if input.peek(syn::token::Paren) {
190 let args;
191 syn::parenthesized!(args in input);
192 args.parse()?
193 } else {
194 Args::Unnamed(Punctuated::new())
195 };
196
197 Ok(RouteInvocation { path, args })
198 }
199}
200
201impl Parse for UriLit {
202 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
203 let string = input.parse::<StringLit>()?;
204 let uri = match Uri::parse_any(&string) {
205 Ok(uri) => uri.into_owned(),
206 Err(e) => {
207 let span = string.subspan(e.index() + 1..(e.index() + 2));
208 return err(span, format!("invalid URI: {}", e));
209 }
210 };
211
212 Ok(UriLit(uri, string.span()))
213 }
214}
215
216impl UriMacro {
217 fn unary(input: ParseStream<'_>) -> parse::Result<Self> {
218 if input.peek(LitStr) {
219 Ok(UriMacro::Literal(input.parse()?))
220 } else {
221 Ok(UriMacro::Routed(RoutedUri {
222 prefix: None,
223 route: input.parse()?,
224 suffix: None,
225 }))
226 }
227 }
228
229 fn binary(prefix: TokenStream, middle: TokenStream) -> parse::Result<Self> {
230 Ok(UriMacro::Routed(RoutedUri {
231 prefix: UriExpr::parse_prefix.parse2(prefix)?,
232 route: syn::parse2(middle)?,
233 suffix: None,
234 }))
235 }
236
237 fn ternary(prefix: TokenStream, mid: TokenStream, suffix: TokenStream) -> parse::Result<Self> {
238 Ok(UriMacro::Routed(RoutedUri {
239 prefix: UriExpr::parse_prefix.parse2(prefix)?,
240 route: syn::parse2(mid)?,
241 suffix: UriExpr::parse_suffix.parse2(suffix)?
242 }))
243 }
244}
245
246impl Parse for UriMacro {
247 fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
248 use syn::buffer::Cursor;
249 use parse::{StepCursor, Result};
250
251 fn stream<'c>(cursor: StepCursor<'c, '_>) -> Result<(Option<TokenStream>, Cursor<'c>)> {
252 let mut stream = TokenStream::new();
253 let mut cursor = *cursor;
254 while let Some((tt, next)) = cursor.token_tree() {
255 cursor = next;
256 match tt {
257 TokenTree::Punct(p) if p.as_char() == ',' => break,
258 _ => stream.append(tt)
259 }
260 }
261
262 stream.is_empty()
263 .then(|| Ok((None, cursor)))
264 .unwrap_or(Ok((Some(stream), cursor)))
265 }
266
267 let mut args = vec![];
268 while let Some(tokens) = input.step(stream)? {
269 args.push(tokens);
270 }
271
272 let (arg_count, mut iter) = (args.len(), args.into_iter());
273 let mut next = || iter.next().unwrap();
274 match arg_count {
275 0 => err(Span::call_site(), "expected at least 1 argument, found none"),
276 1 => UriMacro::unary.parse2(next()),
277 2 => UriMacro::binary(next(), next()),
278 3 => UriMacro::ternary(next(), next(), next()),
279 n => err(iter.nth(3).unwrap().span(),
280 format!("expected 1, 2, or 3 arguments, found {}", n))
281 }
282 }
283}
284
285impl Parse for RoutedUri {
286 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
287 match UriMacro::parse(input)? {
288 UriMacro::Routed(route) => Ok(route),
289 UriMacro::Literal(uri) => err(uri.span(), "expected route URI, found literal")
290 }
291 }
292}
293
294impl Parse for FnArg {
295 fn parse(input: ParseStream<'_>) -> parse::Result<FnArg> {
296 let ident = input.parse::<Ident>()?;
297 input.parse::<Token![:]>()?;
298 let mut ty = input.parse::<Type>()?;
299 ty.strip_lifetimes();
300 Ok(FnArg { ident, ty })
301 }
302}
303
304impl Parse for InternalUriParams {
305 fn parse(input: ParseStream<'_>) -> parse::Result<InternalUriParams> {
306 let route_uri_str = input.parse::<StringLit>()?;
307 input.parse::<Token![,]>()?;
308
309 let route_uri = Origin::parse_route(&route_uri_str)
312 .map(|o| o.into_normalized().into_owned())
313 .map_err(|_| input.error("internal error: invalid route URI"))?;
314
315 let content;
316 syn::parenthesized!(content in input);
317 let fn_args = content.parse_terminated(FnArg::parse, Token![,])?;
318 let fn_args = fn_args.into_iter().collect();
319
320 input.parse::<Token![,]>()?;
321 let uri_params = input.parse::<RoutedUri>()?;
322
323 let span = route_uri_str.subspan(1..route_uri.path().len() + 1);
324 let path_params = Parameter::parse_many::<fmt::Path>(route_uri.path().as_str(), span)
325 .map(|p| p.expect("internal error: invalid path parameter"))
326 .collect::<Vec<_>>();
327
328 let query = route_uri.query();
329 let query_params = query.map(|query| {
330 let i = route_uri.path().len() + 2;
331 let span = route_uri_str.subspan(i..(i + query.len()));
332 Parameter::parse_many::<fmt::Query>(query.as_str(), span)
333 .map(|p| p.expect("internal error: invalid query parameter"))
334 .collect::<Vec<_>>()
335 }).unwrap_or_default();
336
337 Ok(InternalUriParams {
338 route_uri,
339 path_params,
340 query_params,
341 fn_args,
342 uri_mac: uri_params
343 })
344 }
345}
346
347impl InternalUriParams {
348 pub fn fn_args_str(&self) -> String {
349 self.fn_args.iter()
350 .map(|FnArg { ident, ty }| {
351 let ty = ty.with_stripped_lifetimes();
352 let ty_str = quote!(#ty).to_string();
353 let ty_str: String = ty_str.chars().filter(|c| !c.is_whitespace()).collect();
354 format!("{}: {}", ident, ty_str)
355 })
356 .collect::<Vec<_>>()
357 .join(", ")
358 }
359
360 pub fn dynamic_path_params(&self) -> impl Iterator<Item = &Dynamic> + Clone {
361 self.path_params.iter()
362 .filter_map(|p| p.dynamic().or_else(|| p.ignored()))
363 }
364
365 pub fn dynamic_query_params(&self) -> impl Iterator<Item = &Dynamic> + Clone {
366 self.query_params.iter().filter_map(|p| p.dynamic())
367 }
368
369 pub fn validate(&self) -> Validation<'_> {
370 let args = &self.uri_mac.route.args;
371 let all_params = self.dynamic_path_params().chain(self.dynamic_query_params());
372 match args {
373 Args::Unnamed(args) => {
374 let (expected, actual) = (all_params.count(), args.len());
375 let unnamed_args = args.iter().map(|arg| arg.unnamed());
376 match expected == actual {
377 true => Validation::Ok(unnamed_args.collect()),
378 false => Validation::Unnamed(expected, actual)
379 }
380 },
381 Args::Named(args) => {
382 let ignored = all_params.clone().filter(|p| p.is_wild());
383 if ignored.clone().count() > 0 {
384 return Validation::NamedIgnored(ignored.collect());
385 }
386
387 let mut params = all_params.map(|p| (&p.name, None))
388 .collect::<IndexMap<&Name, Option<&ArgExpr>>>();
389
390 let (mut extra, mut dup) = (vec![], vec![]);
391 let named_args = args.iter().map(|arg| arg.named());
392 for (name, ident, expr) in named_args {
393 match params.get_mut(name) {
394 Some(ref entry) if entry.is_some() => dup.push(ident),
395 Some(entry) => *entry = Some(expr),
396 None => extra.push(ident),
397 }
398 }
399
400 let (mut missing, mut exprs) = (vec![], vec![]);
401 for (name, expr) in params {
402 match expr {
403 Some(expr) => exprs.push(expr),
404 None => missing.push(name)
405 }
406 }
407
408 if (extra.len() + dup.len() + missing.len()) == 0 {
409 Validation::Ok(exprs)
410 } else {
411 Validation::Named(missing, extra, dup)
412 }
413 }
414 }
415 }
416}
417
418impl RoutedUri {
419 pub fn args_span(&self) -> Span {
421 match self.route.args.num() {
422 0 => self.route.path.span(),
423 _ => self.route.args.span()
424 }
425 }
426}
427
428impl Arg {
429 fn is_named(&self) -> bool {
430 match *self {
431 Arg::Named(..) => true,
432 _ => false
433 }
434 }
435
436 fn unnamed(&self) -> &ArgExpr {
437 match self {
438 Arg::Unnamed(expr) => expr,
439 _ => panic!("Called Arg::unnamed() on an Arg::Named!"),
440 }
441 }
442
443 fn named(&self) -> (&Name, &Ident, &ArgExpr) {
444 match self {
445 Arg::Named(name, ident, _, expr) => (name, ident, expr),
446 _ => panic!("Called Arg::named() on an Arg::Unnamed!"),
447 }
448 }
449}
450
451impl Args {
452 fn num(&self) -> usize {
453 match self {
454 Args::Named(inner) | Args::Unnamed(inner) => inner.len(),
455 }
456 }
457}
458
459impl ArgExpr {
460 pub fn as_expr(&self) -> Option<&Expr> {
461 match self {
462 ArgExpr::Expr(expr) => Some(expr),
463 _ => None
464 }
465 }
466
467 pub fn unwrap_expr(&self) -> &Expr {
468 match self {
469 ArgExpr::Expr(expr) => expr,
470 _ => panic!("Called ArgExpr::expr() on ArgExpr::Ignored!"),
471 }
472 }
473}
474
475fn uri_err<T>(lit: &StringLit, error: Error<'_>) -> parse::Result<T> {
476 let span = lit.subspan(error.index() + 1..(error.index() + 2));
477 err(span, format!("invalid URI: {}", error))
478}
479
480impl UriExpr {
481 fn parse_prefix(input: ParseStream<'_>) -> syn::Result<Option<Self>> {
482 if input.parse::<Token![_]>().is_ok() {
483 return Ok(None);
484 }
485
486 if !input.peek(LitStr) {
487 return input.parse::<Expr>().map(|e| Some(UriExpr::Expr(e)));
488 }
489
490 let lit = input.parse::<StringLit>()?;
491 let uri = Uri::parse::<Origin<'_>>(&lit)
492 .or_else(|e| Uri::parse::<Absolute<'_>>(&lit).map_err(|e2| (e, e2)))
493 .map_err(|(e1, e2)| lit.starts_with('/').then(|| e1).unwrap_or(e2))
494 .or_else(|e| uri_err(&lit, e))?;
495
496 if matches!(&uri, Uri::Origin(o) if o.query().is_some())
497 || matches!(&uri, Uri::Absolute(a) if a.query().is_some())
498 {
499 return err(lit.span(), "URI prefix cannot contain query part");
500 }
501
502 Ok(Some(UriExpr::Uri(UriLit(uri.into_owned(), lit.span()))))
503 }
504
505 fn parse_suffix(input: ParseStream<'_>) -> syn::Result<Option<Self>> {
506 if input.parse::<Token![_]>().is_ok() {
507 return Ok(None);
508 }
509
510 if !input.peek(LitStr) {
511 return input.parse::<Expr>().map(|e| Some(UriExpr::Expr(e)));
512 }
513
514 let lit = input.parse::<StringLit>()?;
515 let uri = Reference::parse(&lit).or_else(|e| uri_err(&lit, e))?;
516 if uri.scheme().is_some() || uri.authority().is_some() || !uri.path().is_empty() {
517 return err(lit.span(), "URI suffix must contain only query and/or fragment");
518 }
519
520 let uri = match uri.fragment() {
530 None => {
531 let query = uri.query().map(|q| q.as_str());
532 Uri::Absolute(Absolute::const_new("", None, "", query))
533 }
534 Some(_) => Uri::Reference(uri)
535 };
536
537 Ok(Some(UriExpr::Uri(UriLit(uri.into_owned(), lit.span()))))
538 }
539}
540
541impl Deref for UriLit {
542 type Target = Uri<'static>;
543
544 fn deref(&self) -> &Self::Target {
545 &self.0
546 }
547}
548
549impl ToTokens for UriLit {
550 fn to_tokens(&self, t: &mut TokenStream) {
551 use crate::http_codegen::*;
552
553 let (uri, span) = (&self.0, self.1);
554 match uri {
555 Uri::Origin(o) => Origin(o, span).to_tokens(t),
556 Uri::Absolute(o) => Absolute(o, span).to_tokens(t),
557 Uri::Authority(o) => Authority(o, span).to_tokens(t),
558 Uri::Reference(r) => Reference(r, span).to_tokens(t),
559 Uri::Asterisk(a) => Asterisk(*a, span).to_tokens(t),
560 }
561 }
562}
563
564impl ToTokens for UriExpr {
565 fn to_tokens(&self, t: &mut TokenStream) {
566 match self {
567 UriExpr::Uri(uri) => uri.to_tokens(t),
568 UriExpr::Expr(e) => e.to_tokens(t),
569 }
570 }
571}
572
573impl ToTokens for ArgExpr {
574 fn to_tokens(&self, tokens: &mut TokenStream) {
575 match self {
576 ArgExpr::Expr(e) => e.to_tokens(tokens),
577 ArgExpr::Ignored(e) => e.to_tokens(tokens)
578 }
579 }
580}
581
582impl ToTokens for Arg {
583 fn to_tokens(&self, tokens: &mut TokenStream) {
584 match self {
585 Arg::Unnamed(e) => e.to_tokens(tokens),
586 Arg::Named(_, ident, eq, expr) => {
587 ident.to_tokens(tokens);
588 eq.to_tokens(tokens);
589 expr.to_tokens(tokens);
590 }
591 }
592 }
593}
594
595impl ToTokens for Args {
596 fn to_tokens(&self, tokens: &mut TokenStream) {
597 match self {
598 Args::Unnamed(e) | Args::Named(e) => e.to_tokens(tokens)
599 }
600 }
601}