cogo_http/header/common/accept_ranges.rs
1use std::fmt::{self, Display};
2use std::str::FromStr;
3
4header! {
5    /// `Accept-Ranges` header, defined in
6    /// [RFC7233](http://tools.ietf.org/html/rfc7233#section-2.3)
7    ///
8    /// The `Accept-Ranges` header field allows a server to indicate that it
9    /// supports range requests for the target resource.
10    ///
11    /// # ABNF
12    /// ```plain
13    /// Accept-Ranges     = acceptable-ranges
14    /// acceptable-ranges = 1#range-unit / \"none\"
15    ///
16    /// # Example values
17    /// * `bytes`
18    /// * `none`
19    /// * `unknown-unit`
20    /// ```
21    ///
22    /// # Examples
23    /// ```
24    /// use cogo_http::header::{Headers, AcceptRanges, RangeUnit};
25    ///
26    /// let mut headers = Headers::new();
27    /// headers.set(AcceptRanges(vec![RangeUnit::Bytes]));
28    /// ```
29    /// ```
30    /// use cogo_http::header::{Headers, AcceptRanges, RangeUnit};
31    ///
32    /// let mut headers = Headers::new();
33    /// headers.set(AcceptRanges(vec![RangeUnit::None]));
34    /// ```
35    /// ```
36    /// use cogo_http::header::{Headers, AcceptRanges, RangeUnit};
37    ///
38    /// let mut headers = Headers::new();
39    /// headers.set(
40    ///     AcceptRanges(vec![
41    ///         RangeUnit::Unregistered("nibbles".to_owned()),
42    ///         RangeUnit::Bytes,
43    ///         RangeUnit::Unregistered("doublets".to_owned()),
44    ///         RangeUnit::Unregistered("quadlets".to_owned()),
45    ///     ])
46    /// );
47    /// ```
48    (AcceptRanges, "Accept-Ranges") => (RangeUnit)+
49
50    test_acccept_ranges {
51        test_header!(test1, vec![b"bytes"]);
52        test_header!(test2, vec![b"none"]);
53        test_header!(test3, vec![b"unknown-unit"]);
54        test_header!(test4, vec![b"bytes, unknown-unit"]);
55    }
56}
57
58/// Range Units, described in [RFC7233](http://tools.ietf.org/html/rfc7233#section-2)
59///
60/// A representation can be partitioned into subranges according to
61/// various structural units, depending on the structure inherent in the
62/// representation's media type.
63///
64/// # ABNF
65/// ```plain
66/// range-unit       = bytes-unit / other-range-unit
67/// bytes-unit       = "bytes"
68/// other-range-unit = token
69/// ```
70#[derive(Clone, Debug, Eq, PartialEq)]
71pub enum RangeUnit {
72    /// Indicating byte-range requests are supported.
73    Bytes,
74    /// Reserved as keyword, indicating no ranges are supported.
75    None,
76    /// The given range unit is not registered at IANA.
77    Unregistered(String),
78}
79
80
81impl FromStr for RangeUnit {
82    type Err = crate::Error;
83    fn from_str(s: &str) -> crate::Result<Self> {
84        match s {
85            "bytes" => Ok(RangeUnit::Bytes),
86            "none" => Ok(RangeUnit::None),
87            // FIXME: Check if s is really a Token
88            _ => Ok(RangeUnit::Unregistered(s.to_owned())),
89        }
90    }
91}
92
93impl Display for RangeUnit {
94    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95        match *self {
96            RangeUnit::Bytes => f.write_str("bytes"),
97            RangeUnit::None => f.write_str("none"),
98            RangeUnit::Unregistered(ref x) => f.write_str(&x),
99        }
100    }
101}