1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-06-25 06:39:22 +02:00

wrap LanguageTags type in new AnyOrSome type to support wildcards (#2480)

This commit is contained in:
Rob Ede
2021-12-02 13:59:25 +00:00
committed by GitHub
parent c4b20df56a
commit 075d871e63
9 changed files with 469 additions and 136 deletions

View File

@ -55,7 +55,7 @@ pub trait Header: IntoHeaderValue {
fn name() -> HeaderName;
/// Parse a header
fn parse<T: HttpMessage>(msg: &T) -> Result<Self, ParseError>;
fn parse<M: HttpMessage>(msg: &M) -> Result<Self, ParseError>;
}
/// Convert `http::HeaderMap` to our `HeaderMap`.

View File

@ -1,8 +1,7 @@
use std::{
cmp,
convert::{TryFrom, TryInto},
fmt,
str::{self, FromStr},
fmt, str,
};
use derive_more::{Display, Error};
@ -83,16 +82,17 @@ impl TryFrom<f32> for Quality {
/// in [RFC 7231 §5.3.1](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1).
#[derive(Clone, PartialEq, Debug)]
pub struct QualityItem<T> {
/// The actual contents of the field.
/// The wrapped contents of the field.
pub item: T,
/// The quality (client or server preference) for the value.
pub quality: Quality,
}
impl<T> QualityItem<T> {
/// Creates a new `QualityItem` from an item and a quality.
/// The item can be of any type.
/// The quality should be a value in the range [0, 1].
/// Constructs a new `QualityItem` from an item and a quality value.
///
/// The item can be of any type. The quality should be a value in the range [0, 1].
pub fn new(item: T, quality: Quality) -> QualityItem<T> {
QualityItem { item, quality }
}
@ -116,7 +116,7 @@ impl<T: fmt::Display> fmt::Display for QualityItem<T> {
}
}
impl<T: FromStr> FromStr for QualityItem<T> {
impl<T: str::FromStr> str::FromStr for QualityItem<T> {
type Err = ParseError;
fn from_str(qitem_str: &str) -> Result<Self, Self::Err> {
@ -128,6 +128,7 @@ impl<T: FromStr> FromStr for QualityItem<T> {
let mut raw_item = qitem_str;
let mut quality = 1f32;
// TODO: MSRV(1.52): use rsplit_once
let parts: Vec<_> = qitem_str.rsplitn(2, ';').map(str::trim).collect();
if parts.len() == 2 {

View File

@ -12,7 +12,8 @@ where
I: Iterator<Item = &'a HeaderValue> + 'a,
T: FromStr,
{
let mut result = Vec::new();
let size_guess = all.size_hint().1.unwrap_or(2);
let mut result = Vec::with_capacity(size_guess);
for h in all {
let s = h.to_str().map_err(|_| ParseError::Header)?;
@ -26,6 +27,7 @@ where
.filter_map(|x| x.trim().parse().ok()),
)
}
Ok(result)
}
@ -34,10 +36,12 @@ where
pub fn from_one_raw_str<T: FromStr>(val: Option<&HeaderValue>) -> Result<T, ParseError> {
if let Some(line) = val {
let line = line.to_str().map_err(|_| ParseError::Header)?;
if !line.is_empty() {
return T::from_str(line).or(Err(ParseError::Header));
}
}
Err(ParseError::Header)
}
@ -48,13 +52,16 @@ where
T: fmt::Display,
{
let mut iter = parts.iter();
if let Some(part) = iter.next() {
fmt::Display::fmt(part, f)?;
}
for part in iter {
f.write_str(", ")?;
fmt::Display::fmt(part, f)?;
}
Ok(())
}
@ -65,3 +72,25 @@ pub fn http_percent_encode(f: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Res
let encoded = percent_encoding::percent_encode(bytes, HTTP_VALUE);
fmt::Display::fmt(&encoded, f)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn comma_delimited_parsing() {
let headers = vec![];
let res: Vec<usize> = from_comma_delimited(headers.iter()).unwrap();
assert_eq!(res, vec![0; 0]);
let headers = vec![
HeaderValue::from_static(""),
HeaderValue::from_static(","),
HeaderValue::from_static(" "),
HeaderValue::from_static("1 ,"),
HeaderValue::from_static(""),
];
let res: Vec<usize> = from_comma_delimited(headers.iter()).unwrap();
assert_eq!(res, vec![1]);
}
}