azure_storage_blobs/options/
ba512_range.rs
1use azure_core::{
2 error::{Error, ErrorKind, ResultExt},
3 headers::{self, Header},
4 prelude::Range,
5};
6use std::{fmt, str::FromStr};
7
8#[derive(Debug, Copy, Clone, PartialEq, Eq)]
12pub struct BA512Range {
13 start: u64,
14 end: u64,
15}
16
17impl BA512Range {
18 pub fn start(&self) -> u64 {
19 self.start
20 }
21 pub fn end(&self) -> u64 {
22 self.end
23 }
24
25 pub fn new(start: u64, end: u64) -> azure_core::Result<Self> {
26 if start % 512 != 0 {
27 return Err(Error::with_message(ErrorKind::Other, || {
28 format!("start range not 512-byte aligned: {start}")
29 }));
30 }
31 if (end + 1) % 512 != 0 {
32 return Err(Error::with_message(ErrorKind::Other, || {
33 format!("end range not 512-byte aligned: {end}")
34 }));
35 }
36
37 Ok(Self { start, end })
38 }
39
40 #[inline]
41 pub fn size(&self) -> u64 {
42 self.end - self.start + 1
43 }
44}
45
46impl From<BA512Range> for Range {
47 fn from(range: BA512Range) -> Self {
48 (range.start()..range.end()).into()
49 }
50}
51
52impl TryFrom<Range> for BA512Range {
53 type Error = Error;
54
55 fn try_from(r: Range) -> azure_core::Result<Self> {
56 match r {
57 Range::Range(r) => BA512Range::new(r.start, r.end),
58 Range::RangeFrom(r) => Err(Error::with_message(ErrorKind::DataConversion, || {
59 format!("error converting RangeFrom<{:?}> into BA512Range", r)
60 })),
61 }
62 }
63}
64
65impl TryFrom<(u64, u64)> for BA512Range {
66 type Error = Error;
67
68 fn try_from((start, end): (u64, u64)) -> azure_core::Result<Self> {
69 BA512Range::new(start, end)
70 }
71}
72
73impl Header for BA512Range {
74 fn name(&self) -> headers::HeaderName {
75 headers::RANGE
76 }
77
78 fn value(&self) -> headers::HeaderValue {
79 self.to_string().into()
80 }
81}
82
83impl FromStr for BA512Range {
84 type Err = Error;
85 fn from_str(s: &str) -> azure_core::Result<BA512Range> {
86 let v = s.split('/').collect::<Vec<&str>>();
87 if v.len() != 2 {
88 return Err(Error::message(ErrorKind::Other, "split not found"));
89 }
90
91 let cp_start = v[0]
92 .parse::<u64>()
93 .with_context(ErrorKind::DataConversion, || {
94 format!("error parsing '{}' into u64", v[0])
95 })?;
96 let cp_end = v[1]
97 .parse::<u64>()
98 .with_context(ErrorKind::DataConversion, || {
99 format!("error parsing '{}' into u64", v[1])
100 })?;
101
102 BA512Range::new(cp_start, cp_end)
103 }
104}
105
106impl fmt::Display for BA512Range {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 write!(f, "bytes={}-{}", self.start, self.end)
109 }
110}
111
112impl<'a> From<&'a BA512Range> for Range {
113 fn from(ba: &'a BA512Range) -> Range {
114 (ba.start()..ba.end()).into()
115 }
116}
117
118#[cfg(test)]
119mod test {
120 use super::*;
121
122 #[test]
123 fn test_512range_parse() {
124 let range = "0/511".parse::<BA512Range>().unwrap();
125
126 assert_eq!(range.start, 0);
127 assert_eq!(range.end, 511);
128 }
129
130 #[test]
131 fn test_512range_parse_panic_1() {
132 let err = "abba/2000".parse::<BA512Range>().unwrap_err();
133 assert!(matches!(err.kind(), ErrorKind::DataConversion));
134 }
135
136 #[test]
137 fn test_512range_parse_panic_2() {
138 let err = "1000-2000".parse::<BA512Range>().unwrap_err();
139 assert!(matches!(err.kind(), ErrorKind::Other));
140 }
141
142 #[test]
143 fn test_512range_invalid_start_range() {
144 let err = "7/511".parse::<BA512Range>().unwrap_err();
145 assert!(matches!(err.kind(), ErrorKind::Other));
146 }
147
148 #[test]
149 fn test_512range_invalid_end_range() {
150 let err = "0/100".parse::<BA512Range>().unwrap_err();
151 assert!(matches!(err.kind(), ErrorKind::Other));
152 }
153
154 #[test]
155 fn test_512range_display() {
156 let range = BA512Range { start: 0, end: 511 };
157
158 let txt = format!("{range}");
159
160 assert_eq!(txt, "bytes=0-511");
161 }
162}