/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //TODO(eijebong): Remove this once typed headers figure out quality // This is copy pasted from the old hyper headers to avoid hardcoding everything // (I would probably also make some silly mistakes while migrating...) use http::header::HeaderValue; use mime::Mime; use std::{fmt, str}; /// A quality value, as specified in [RFC7231]. /// /// Quality values are decimal numbers between 0 and 1 (inclusive) with up to 3 fractional digits of precision. /// /// [RFC7231]: https://tools.ietf.org/html/rfc7231#section-5.3.1 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct Quality(u16); impl Quality { /// Creates a quality value from a value between 0 and 1000 inclusive. /// /// This is semantically divided by 1000 to produce a value between 0 and 1. /// /// # Panics /// /// Panics if the value is greater than 1000. pub fn from_u16(quality: u16) -> Quality { assert!(quality <= 1000); Quality(quality) } } /// A value paired with its "quality" as defined in [RFC7231]. /// /// Quality items are used in content negotiation headers such as `Accept` and `Accept-Encoding`. /// /// [RFC7231]: https://tools.ietf.org/html/rfc7231#section-5.3 #[derive(Clone, Debug, PartialEq)] pub struct QualityItem { pub item: T, pub quality: Quality, } impl QualityItem { /// Creates a new quality item. pub fn new(item: T, quality: Quality) -> QualityItem { QualityItem { item, quality } } } impl fmt::Display for QualityItem where T: fmt::Display, { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.item, fmt)?; match self.quality.0 { 1000 => Ok(()), 0 => fmt.write_str("; q=0"), mut x => { fmt.write_str("; q=0.")?; let mut digits = *b"000"; digits[2] = (x % 10) as u8 + b'0'; x /= 10; digits[1] = (x % 10) as u8 + b'0'; x /= 10; digits[0] = (x % 10) as u8 + b'0'; let s = str::from_utf8(&digits[..]).unwrap(); fmt.write_str(s.trim_end_matches('0')) }, } } } pub fn quality_to_value(q: Vec>) -> HeaderValue { HeaderValue::from_str( &q.iter() .map(|q| q.to_string()) .collect::>() .join(", "), ) .unwrap() }