diff options
Diffstat (limited to 'components/shared/net/quality.rs')
-rw-r--r-- | components/shared/net/quality.rs | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/components/shared/net/quality.rs b/components/shared/net/quality.rs new file mode 100644 index 00000000000..095cd121bad --- /dev/null +++ b/components/shared/net/quality.rs @@ -0,0 +1,87 @@ +/* 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 std::{fmt, str}; + +use http::header::HeaderValue; +use mime::Mime; + +/// 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<T> { + pub item: T, + pub quality: Quality, +} + +impl<T> QualityItem<T> { + /// Creates a new quality item. + pub fn new(item: T, quality: Quality) -> QualityItem<T> { + QualityItem { item, quality } + } +} + +impl<T> fmt::Display for QualityItem<T> +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<QualityItem<Mime>>) -> HeaderValue { + HeaderValue::from_str( + &q.iter() + .map(|q| q.to_string()) + .collect::<Vec<String>>() + .join(", "), + ) + .unwrap() +} |