mirror of https://github.com/rwf2/Rocket.git
Add 'const' constructor for 'MediaType'.
This commit is contained in:
parent
079e458b62
commit
5cf249581f
|
@ -70,8 +70,8 @@ impl FromMeta for ContentType {
|
||||||
|
|
||||||
impl ToTokens for ContentType {
|
impl ToTokens for ContentType {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
// Yeah, yeah. (((((i))).kn0w()))
|
let http_media_type = self.0.media_type().clone();
|
||||||
let media_type = MediaType((self.0).clone().0);
|
let media_type = MediaType(http_media_type);
|
||||||
tokens.extend(quote!(::rocket::http::ContentType(#media_type)));
|
tokens.extend(quote!(::rocket::http::ContentType(#media_type)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,27 +94,13 @@ impl FromMeta for MediaType {
|
||||||
|
|
||||||
impl ToTokens for MediaType {
|
impl ToTokens for MediaType {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
use std::iter::repeat;
|
|
||||||
let (top, sub) = (self.0.top().as_str(), self.0.sub().as_str());
|
let (top, sub) = (self.0.top().as_str(), self.0.sub().as_str());
|
||||||
let (keys, values) = self.0.params().split2();
|
let (keys, values) = self.0.params().split2();
|
||||||
|
let http = quote!(::rocket::http);
|
||||||
|
|
||||||
let cow = quote!(::std::borrow::Cow);
|
tokens.extend(quote! {
|
||||||
let (pub_http, http) = (quote!(::rocket::http), quote!(::rocket::http::private));
|
#http::MediaType::const_new(#top, #sub, &[#((#keys, #values)),*])
|
||||||
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!(#pub_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))
|
|
||||||
)),*
|
|
||||||
])
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ log = "0.4"
|
||||||
ref-cast = "1.0"
|
ref-cast = "1.0"
|
||||||
uncased = "0.9"
|
uncased = "0.9"
|
||||||
parking_lot = "0.11"
|
parking_lot = "0.11"
|
||||||
|
either = "1"
|
||||||
|
|
||||||
[dependencies.cookie]
|
[dependencies.cookie]
|
||||||
git = "https://github.com/SergioBenitez/cookie-rs.git"
|
git = "https://github.com/SergioBenitez/cookie-rs.git"
|
||||||
|
|
|
@ -3,120 +3,12 @@ use std::str::FromStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
use either::Either;
|
||||||
|
|
||||||
use crate::{Header, MediaType};
|
use crate::{Header, MediaType};
|
||||||
use crate::ext::IntoCollection;
|
use crate::ext::IntoCollection;
|
||||||
use crate::parse::parse_accept;
|
use crate::parse::parse_accept;
|
||||||
|
|
||||||
/// A `MediaType` with an associated quality value.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct QMediaType(pub MediaType, pub Option<f32>);
|
|
||||||
|
|
||||||
impl QMediaType {
|
|
||||||
/// Retrieve the weight of the media type, if there is any.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate rocket;
|
|
||||||
/// use rocket::http::{MediaType, QMediaType};
|
|
||||||
///
|
|
||||||
/// let q_type = QMediaType(MediaType::HTML, Some(0.3));
|
|
||||||
/// assert_eq!(q_type.weight(), Some(0.3));
|
|
||||||
/// ```
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn weight(&self) -> Option<f32> {
|
|
||||||
self.1
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve the weight of the media type or a given default value.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate rocket;
|
|
||||||
/// use rocket::http::{MediaType, QMediaType};
|
|
||||||
///
|
|
||||||
/// let q_type = QMediaType(MediaType::HTML, Some(0.3));
|
|
||||||
/// assert_eq!(q_type.weight_or(0.9), 0.3);
|
|
||||||
///
|
|
||||||
/// let q_type = QMediaType(MediaType::HTML, None);
|
|
||||||
/// assert_eq!(q_type.weight_or(0.9), 0.9);
|
|
||||||
/// ```
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn weight_or(&self, default: f32) -> f32 {
|
|
||||||
self.1.unwrap_or(default)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Borrow the internal `MediaType`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate rocket;
|
|
||||||
/// use rocket::http::{MediaType, QMediaType};
|
|
||||||
///
|
|
||||||
/// let q_type = QMediaType(MediaType::HTML, Some(0.3));
|
|
||||||
/// assert_eq!(q_type.media_type(), &MediaType::HTML);
|
|
||||||
/// ```
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn media_type(&self) -> &MediaType {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MediaType> for QMediaType {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from(media_type: MediaType) -> QMediaType {
|
|
||||||
QMediaType(media_type, None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for QMediaType {
|
|
||||||
type Target = MediaType;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn deref(&self) -> &MediaType {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: `Static` is needed for `const` items. Need `const SmallVec::new`.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum AcceptParams {
|
|
||||||
Static(&'static [QMediaType]),
|
|
||||||
Dynamic(SmallVec<[QMediaType; 1]>)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for AcceptParams {
|
|
||||||
fn default() -> Self {
|
|
||||||
AcceptParams::Dynamic(SmallVec::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.extend(iter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for AcceptParams {
|
|
||||||
fn eq(&self, other: &AcceptParams) -> bool {
|
|
||||||
#[inline(always)]
|
|
||||||
fn inner_types(params: &AcceptParams) -> &[QMediaType] {
|
|
||||||
match *params {
|
|
||||||
AcceptParams::Static(params) => params,
|
|
||||||
AcceptParams::Dynamic(ref vec) => vec,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner_types(self) == inner_types(other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The HTTP Accept header.
|
/// The HTTP Accept header.
|
||||||
///
|
///
|
||||||
/// An `Accept` header is composed of zero or more media types, each of which
|
/// An `Accept` header is composed of zero or more media types, each of which
|
||||||
|
@ -160,9 +52,20 @@ impl PartialEq for AcceptParams {
|
||||||
///
|
///
|
||||||
/// let response = Response::build().header(Accept::JSON).finalize();
|
/// let response = Response::build().header(Accept::JSON).finalize();
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Accept(pub(crate) AcceptParams);
|
pub struct Accept(pub(crate) AcceptParams);
|
||||||
|
|
||||||
|
/// A `MediaType` with an associated quality value.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct QMediaType(pub MediaType, pub Option<f32>);
|
||||||
|
|
||||||
|
// NOTE: `Static` is needed for `const` items. Need `const SmallVec::new`.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum AcceptParams {
|
||||||
|
Static(QMediaType),
|
||||||
|
Dynamic(SmallVec<[QMediaType; 1]>)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! accept_constructor {
|
macro_rules! accept_constructor {
|
||||||
($($name:ident ($check:ident): $str:expr, $t:expr,
|
($($name:ident ($check:ident): $str:expr, $t:expr,
|
||||||
$s:expr $(; $k:expr => $v:expr)*,)+) => {
|
$s:expr $(; $k:expr => $v:expr)*,)+) => {
|
||||||
|
@ -173,19 +76,12 @@ macro_rules! accept_constructor {
|
||||||
#[doc="</i>"]
|
#[doc="</i>"]
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
pub const $name: Accept = Accept(
|
pub const $name: Accept = Accept(
|
||||||
AcceptParams::Static(&[QMediaType(MediaType::$name, None)])
|
AcceptParams::Static(QMediaType(MediaType::$name, None))
|
||||||
);
|
);
|
||||||
)+
|
)+
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: IntoCollection<MediaType>> From<T> for Accept {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from(items: T) -> Accept {
|
|
||||||
Accept(AcceptParams::Dynamic(items.mapped(|item| item.into())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Accept {
|
impl Accept {
|
||||||
/// Constructs a new `Accept` header from one or more media types.
|
/// Constructs a new `Accept` header from one or more media types.
|
||||||
///
|
///
|
||||||
|
@ -314,12 +210,10 @@ impl Accept {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a QMediaType> + 'a {
|
pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a QMediaType> + 'a {
|
||||||
let slice = match self.0 {
|
match self.0 {
|
||||||
AcceptParams::Static(slice) => slice,
|
AcceptParams::Static(ref val) => Either::Left(Some(val).into_iter()),
|
||||||
AcceptParams::Dynamic(ref vec) => &vec[..],
|
AcceptParams::Dynamic(ref vec) => Either::Right(vec.iter())
|
||||||
};
|
}
|
||||||
|
|
||||||
slice.iter()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all of the (bare) media types in `self`. Media
|
/// Returns an iterator over all of the (bare) media types in `self`. Media
|
||||||
|
@ -351,6 +245,19 @@ impl Accept {
|
||||||
known_media_types!(accept_constructor);
|
known_media_types!(accept_constructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: IntoCollection<MediaType>> From<T> for Accept {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(items: T) -> Accept {
|
||||||
|
Accept(AcceptParams::Dynamic(items.mapped(|item| item.into())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Accept {
|
||||||
|
fn eq(&self, other: &Accept) -> bool {
|
||||||
|
self.iter().eq(other.iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Accept {
|
impl fmt::Display for Accept {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
for (i, media_type) in self.iter().enumerate() {
|
for (i, media_type) in self.iter().enumerate() {
|
||||||
|
@ -384,6 +291,90 @@ impl Into<Header<'static>> for Accept {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl QMediaType {
|
||||||
|
/// Retrieve the weight of the media type, if there is any.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate rocket;
|
||||||
|
/// use rocket::http::{MediaType, QMediaType};
|
||||||
|
///
|
||||||
|
/// let q_type = QMediaType(MediaType::HTML, Some(0.3));
|
||||||
|
/// assert_eq!(q_type.weight(), Some(0.3));
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn weight(&self) -> Option<f32> {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the weight of the media type or a given default value.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate rocket;
|
||||||
|
/// use rocket::http::{MediaType, QMediaType};
|
||||||
|
///
|
||||||
|
/// let q_type = QMediaType(MediaType::HTML, Some(0.3));
|
||||||
|
/// assert_eq!(q_type.weight_or(0.9), 0.3);
|
||||||
|
///
|
||||||
|
/// let q_type = QMediaType(MediaType::HTML, None);
|
||||||
|
/// assert_eq!(q_type.weight_or(0.9), 0.9);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn weight_or(&self, default: f32) -> f32 {
|
||||||
|
self.1.unwrap_or(default)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Borrow the internal `MediaType`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate rocket;
|
||||||
|
/// use rocket::http::{MediaType, QMediaType};
|
||||||
|
///
|
||||||
|
/// let q_type = QMediaType(MediaType::HTML, Some(0.3));
|
||||||
|
/// assert_eq!(q_type.media_type(), &MediaType::HTML);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn media_type(&self) -> &MediaType {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MediaType> for QMediaType {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(media_type: MediaType) -> QMediaType {
|
||||||
|
QMediaType(media_type, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for QMediaType {
|
||||||
|
type Target = MediaType;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &MediaType {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AcceptParams {
|
||||||
|
fn default() -> Self {
|
||||||
|
AcceptParams::Dynamic(SmallVec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.extend(iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{Accept, MediaType};
|
use crate::{Accept, MediaType};
|
||||||
|
|
|
@ -49,21 +49,17 @@ pub mod uncased {
|
||||||
#[doc(inline)] pub use uncased::*;
|
#[doc(inline)] pub use uncased::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Types that we expose for use by core.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod private {
|
pub mod private {
|
||||||
// We need to export these for codegen, but otherwise it's unnecessary.
|
|
||||||
// TODO: Expose a `const fn` from ContentType when possible. (see RFC#1817)
|
|
||||||
pub use crate::parse::Indexed;
|
pub use crate::parse::Indexed;
|
||||||
pub use crate::media_type::{MediaParams, Source};
|
|
||||||
pub use smallvec::{SmallVec, Array};
|
pub use smallvec::{SmallVec, Array};
|
||||||
|
|
||||||
// These we need to expose for core.
|
|
||||||
pub mod cookie {
|
pub mod cookie {
|
||||||
pub use cookie::*;
|
pub use cookie::*;
|
||||||
pub use crate::cookies::Key;
|
pub use crate::cookies::Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These as well.
|
|
||||||
pub use crate::listener::{Incoming, Listener, Connection, bind_tcp};
|
pub use crate::listener::{Incoming, Listener, Connection, bind_tcp};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,72 +3,14 @@ use std::str::FromStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
use either::Either;
|
||||||
|
|
||||||
use crate::ext::IntoCollection;
|
use crate::ext::IntoCollection;
|
||||||
use crate::uncased::UncasedStr;
|
use crate::uncased::UncasedStr;
|
||||||
use crate::parse::{Indexed, IndexedString, parse_media_type};
|
use crate::parse::{Indexed, IndexedString, parse_media_type};
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
struct MediaParam {
|
|
||||||
key: IndexedString,
|
|
||||||
value: IndexedString,
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: `Static` is needed for `const` items. Need `const SmallVec::new`.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum MediaParams {
|
|
||||||
Static(&'static [(IndexedString, IndexedString)]),
|
|
||||||
Dynamic(SmallVec<[(IndexedString, IndexedString); 2]>)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for MediaParams {
|
|
||||||
fn default() -> Self {
|
|
||||||
MediaParams::Dynamic(SmallVec::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.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),
|
|
||||||
Custom(Cow<'static, str>),
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Source {
|
|
||||||
#[inline]
|
|
||||||
fn as_str(&self) -> Option<&str> {
|
|
||||||
match *self {
|
|
||||||
Source::Known(s) => Some(s),
|
|
||||||
Source::Custom(ref s) => Some(s.borrow()),
|
|
||||||
Source::None => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An HTTP media type.
|
/// An HTTP media type.
|
||||||
///
|
///
|
||||||
/// # Usage
|
/// # Usage
|
||||||
|
@ -110,21 +52,33 @@ impl Source {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MediaType {
|
pub struct MediaType {
|
||||||
/// Storage for the entire media type string.
|
/// Storage for the entire media type string.
|
||||||
#[doc(hidden)]
|
pub(crate) source: Source,
|
||||||
pub source: Source,
|
|
||||||
/// The top-level type.
|
/// The top-level type.
|
||||||
#[doc(hidden)]
|
pub(crate) top: IndexedString,
|
||||||
pub top: IndexedString,
|
|
||||||
/// The subtype.
|
/// The subtype.
|
||||||
#[doc(hidden)]
|
pub(crate) sub: IndexedString,
|
||||||
pub sub: IndexedString,
|
|
||||||
/// The parameters, if any.
|
/// The parameters, if any.
|
||||||
#[doc(hidden)]
|
pub(crate) params: MediaParams
|
||||||
pub params: MediaParams
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! media_str {
|
#[derive(Debug, Clone)]
|
||||||
($string:expr) => (Indexed::Concrete(Cow::Borrowed($string)))
|
struct MediaParam {
|
||||||
|
key: IndexedString,
|
||||||
|
value: IndexedString,
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: `Static` is needed for `const` items. Need `const SmallVec::new`.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) enum MediaParams {
|
||||||
|
Static(&'static [(&'static str, &'static str)]),
|
||||||
|
Dynamic(SmallVec<[(IndexedString, IndexedString); 2]>)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub(crate) enum Source {
|
||||||
|
Known(&'static str),
|
||||||
|
Custom(Cow<'static, str>),
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! media_types {
|
macro_rules! media_types {
|
||||||
|
@ -136,12 +90,10 @@ macro_rules! media_types {
|
||||||
$(; @{$k}! @[=]! @{$v}!)* @{"`"}!.
|
$(; @{$k}! @[=]! @{$v}!)* @{"`"}!.
|
||||||
];
|
];
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
pub const $name: MediaType = MediaType {
|
pub const $name: MediaType = MediaType::new_known(
|
||||||
source: Source::Known(concat!($t, "/", $s, $("; ", $k, "=", $v),*)),
|
concat!($t, "/", $s, $("; ", $k, "=", $v),*),
|
||||||
top: media_str!($t),
|
$t, $s, &[$(($k, $v)),*]
|
||||||
sub: media_str!($s),
|
);
|
||||||
params: MediaParams::Static(&[$((media_str!($k), media_str!($v))),*])
|
|
||||||
};
|
|
||||||
);
|
);
|
||||||
)+
|
)+
|
||||||
|
|
||||||
|
@ -357,6 +309,50 @@ impl MediaType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A `const` variant of [`MediaType::with_params()`]. Creates a new
|
||||||
|
/// `MediaType` with top-level type `top`, subtype `sub`, and parameters
|
||||||
|
/// `params`, which may be empty.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// Create a custom `application/x-person` media type:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use rocket::http::MediaType;
|
||||||
|
///
|
||||||
|
/// let custom = MediaType::const_new("application", "x-person", &[]);
|
||||||
|
/// assert_eq!(custom.top(), "application");
|
||||||
|
/// assert_eq!(custom.sub(), "x-person");
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub const fn const_new(
|
||||||
|
top: &'static str,
|
||||||
|
sub: &'static str,
|
||||||
|
params: &'static [(&'static str, &'static str)]
|
||||||
|
) -> MediaType {
|
||||||
|
MediaType {
|
||||||
|
source: Source::None,
|
||||||
|
top: Indexed::Concrete(Cow::Borrowed(top)),
|
||||||
|
sub: Indexed::Concrete(Cow::Borrowed(sub)),
|
||||||
|
params: MediaParams::Static(params),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) const fn new_known(
|
||||||
|
source: &'static str,
|
||||||
|
top: &'static str,
|
||||||
|
sub: &'static str,
|
||||||
|
params: &'static [(&'static str, &'static str)]
|
||||||
|
) -> MediaType {
|
||||||
|
MediaType {
|
||||||
|
source: Source::Known(source),
|
||||||
|
top: Indexed::Concrete(Cow::Borrowed(top)),
|
||||||
|
sub: Indexed::Concrete(Cow::Borrowed(sub)),
|
||||||
|
params: MediaParams::Static(params),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
known_shorthands!(parse_flexible);
|
known_shorthands!(parse_flexible);
|
||||||
|
|
||||||
known_extensions!(from_extension);
|
known_extensions!(from_extension);
|
||||||
|
@ -501,16 +497,15 @@ impl MediaType {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn params<'a>(&'a self) -> impl Iterator<Item=(&'a str, &'a str)> + 'a {
|
pub fn params<'a>(&'a self) -> impl Iterator<Item=(&'a str, &'a str)> + 'a {
|
||||||
let param_slice = match self.params {
|
match self.params {
|
||||||
MediaParams::Static(slice) => slice,
|
MediaParams::Static(ref slice) => Either::Left(slice.iter().cloned()),
|
||||||
MediaParams::Dynamic(ref vec) => &vec[..],
|
MediaParams::Dynamic(ref vec) => {
|
||||||
};
|
Either::Right(vec.iter().map(move |&(ref key, ref val)| {
|
||||||
|
|
||||||
param_slice.iter()
|
|
||||||
.map(move |&(ref key, ref val)| {
|
|
||||||
let source_str = self.source.as_str();
|
let source_str = self.source.as_str();
|
||||||
(key.from_source(source_str), val.from_source(source_str))
|
(key.from_source(source_str), val.from_source(source_str))
|
||||||
})
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
known_media_types!(media_types);
|
known_media_types!(media_types);
|
||||||
|
@ -561,3 +556,29 @@ impl fmt::Display for MediaType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for MediaParams {
|
||||||
|
fn default() -> Self {
|
||||||
|
MediaParams::Dynamic(SmallVec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.extend(iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source {
|
||||||
|
#[inline]
|
||||||
|
fn as_str(&self) -> Option<&str> {
|
||||||
|
match *self {
|
||||||
|
Source::Known(s) => Some(s),
|
||||||
|
Source::Custom(ref s) => Some(s.borrow()),
|
||||||
|
Source::None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,5 +8,4 @@ pub use self::accept::*;
|
||||||
|
|
||||||
pub mod uri;
|
pub mod uri;
|
||||||
|
|
||||||
// Exposed for codegen.
|
pub use self::indexed::*;
|
||||||
#[doc(hidden)] pub use self::indexed::*;
|
|
||||||
|
|
Loading…
Reference in New Issue