2018-08-07 02:58:07 +00:00
|
|
|
use quote::ToTokens;
|
|
|
|
use proc_macro2::TokenStream as TokenStream2;
|
2018-09-15 06:15:31 +00:00
|
|
|
use derive_utils::{FromMeta, MetaItem, Result, ext::Split2};
|
2018-08-07 02:58:07 +00:00
|
|
|
use rocket_http as http;
|
|
|
|
|
2018-09-16 07:33:16 +00:00
|
|
|
#[derive(Debug)]
|
2018-08-07 02:58:07 +00:00
|
|
|
pub struct ContentType(http::ContentType);
|
|
|
|
|
2018-09-16 07:33:16 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Status(pub http::Status);
|
2018-08-07 02:58:07 +00:00
|
|
|
|
2018-09-16 07:33:16 +00:00
|
|
|
#[derive(Debug)]
|
2018-08-07 02:58:07 +00:00
|
|
|
struct MediaType(http::MediaType);
|
|
|
|
|
|
|
|
impl FromMeta for Status {
|
2018-09-15 06:15:31 +00:00
|
|
|
fn from_meta(meta: MetaItem) -> Result<Self> {
|
|
|
|
let num = usize::from_meta(meta)?;
|
|
|
|
if num < 100 || num >= 600 {
|
2018-09-16 07:33:16 +00:00
|
|
|
return Err(meta.value_span().error("status must be in range [100, 599]"));
|
2018-08-07 02:58:07 +00:00
|
|
|
}
|
|
|
|
|
2018-09-15 06:15:31 +00:00
|
|
|
Ok(Status(http::Status::raw(num as u16)))
|
2018-08-07 02:58:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToTokens for Status {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
|
|
|
let (code, reason) = (self.0.code, self.0.reason);
|
2018-09-16 07:33:16 +00:00
|
|
|
tokens.extend(quote!(rocket::http::Status { code: #code, reason: #reason }));
|
2018-08-07 02:58:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromMeta for ContentType {
|
2018-09-15 06:15:31 +00:00
|
|
|
fn from_meta(meta: MetaItem) -> Result<Self> {
|
|
|
|
http::ContentType::parse_flexible(&String::from_meta(meta)?)
|
|
|
|
.map(ContentType)
|
|
|
|
.ok_or(meta.value_span().error("invalid or unknown content-type"))
|
2018-08-07 02:58:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToTokens for ContentType {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
|
|
|
// Yeah, yeah. (((((i))).kn0w()))
|
|
|
|
let media_type = MediaType((self.0).clone().0);
|
|
|
|
tokens.extend(quote!(::rocket::http::ContentType(#media_type)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToTokens for MediaType {
|
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
|
|
|
use std::iter::repeat;
|
|
|
|
let (top, sub) = (self.0.top().as_str(), self.0.sub().as_str());
|
|
|
|
let (keys, values) = self.0.params().split2();
|
|
|
|
|
|
|
|
let (http, cow) = (quote!(::rocket::http), quote!(::std::borrow::Cow));
|
|
|
|
let (http_, http__) = (repeat(&http), repeat(&http));
|
|
|
|
let (cow_, cow__) = (repeat(&cow), repeat(&cow));
|
|
|
|
|
|
|
|
// TODO: Produce less code when possible (for known media types).
|
|
|
|
tokens.extend(quote!(#http::MediaType {
|
|
|
|
source: #http::Source::None,
|
|
|
|
top: #http::Indexed::Concrete(#cow::Borrowed(#top)),
|
|
|
|
sub: #http::Indexed::Concrete(#cow::Borrowed(#sub)),
|
|
|
|
params: #http::MediaParams::Static(&[
|
|
|
|
#((
|
|
|
|
#http_::Indexed::Concrete(#cow_::Borrowed(#keys)),
|
|
|
|
#http__::Indexed::Concrete(#cow__::Borrowed(#values))
|
|
|
|
)),*
|
|
|
|
])
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|