azure_core/request_options/
range.rs

1use crate::error::{Error, ErrorKind, ResultExt};
2use crate::headers::{self, AsHeaders, HeaderName, HeaderValue};
3use std::fmt;
4use std::ops::{Range as StdRange, RangeFrom};
5use std::str::FromStr;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum Range {
9    Range(StdRange<u64>),
10    RangeFrom(RangeFrom<u64>),
11}
12
13impl Range {
14    pub fn new(start: u64, end: u64) -> Range {
15        (start..end).into()
16    }
17
18    fn optional_len(&self) -> Option<u64> {
19        match self {
20            Range::Range(r) => Some(r.end - r.start),
21            Range::RangeFrom(_) => None,
22        }
23    }
24}
25
26impl From<StdRange<u64>> for Range {
27    fn from(r: StdRange<u64>) -> Self {
28        Self::Range(r)
29    }
30}
31
32impl From<RangeFrom<u64>> for Range {
33    fn from(r: RangeFrom<u64>) -> Self {
34        Self::RangeFrom(r)
35    }
36}
37
38impl From<StdRange<usize>> for Range {
39    fn from(r: StdRange<usize>) -> Self {
40        (r.start as u64..r.end as u64).into()
41    }
42}
43
44impl From<RangeFrom<usize>> for Range {
45    fn from(r: RangeFrom<usize>) -> Self {
46        (r.start as u64..).into()
47    }
48}
49
50impl AsHeaders for Range {
51    type Iter = std::vec::IntoIter<(HeaderName, HeaderValue)>;
52
53    fn as_headers(&self) -> Self::Iter {
54        let mut headers = vec![(headers::MS_RANGE, format!("{self}").into())];
55        if let Some(len) = self.optional_len() {
56            if len < 1024 * 1024 * 4 {
57                headers.push((
58                    headers::RANGE_GET_CONTENT_CRC64,
59                    HeaderValue::from_static("true"),
60                ));
61            }
62        }
63        headers.into_iter()
64    }
65}
66
67impl FromStr for Range {
68    type Err = Error;
69    fn from_str(s: &str) -> crate::Result<Range> {
70        let v = s.split('/').collect::<Vec<&str>>();
71        if v.len() != 2 {
72            return Err(Error::with_message(ErrorKind::Other, || {
73                format!(
74                    "expected token \"{}\" not found when parsing Range from \"{}\"",
75                    "/", s
76                )
77            }));
78        }
79
80        let cp_start = v[0].parse::<u64>().map_kind(ErrorKind::DataConversion)?;
81        let cp_end = v[1].parse::<u64>().map_kind(ErrorKind::DataConversion)? + 1;
82
83        Ok((cp_start..cp_end).into())
84    }
85}
86
87impl fmt::Display for Range {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self {
90            Range::Range(r) => write!(f, "bytes={}-{}", r.start, r.end - 1),
91            Range::RangeFrom(r) => write!(f, "bytes={}-", r.start),
92        }
93    }
94}
95
96#[cfg(test)]
97mod test {
98    use super::*;
99
100    #[test]
101    fn test_range_parse() {
102        let range = "1000/2000".parse::<Range>().unwrap();
103        assert_eq!(range, Range::new(1000, 2001));
104    }
105
106    #[test]
107    fn test_range_parse_panic_1() {
108        "abba/2000".parse::<Range>().unwrap_err();
109    }
110
111    #[test]
112    fn test_range_parse_panic_2() {
113        "1000-2000".parse::<Range>().unwrap_err();
114    }
115
116    #[test]
117    fn test_range_display() {
118        let range = Range::new(100, 501);
119        let txt = format!("{range}");
120        assert_eq!(txt, "bytes=100-500");
121    }
122}