azure_storage_blobs/options/
ba512_range.rsuse azure_core::{
error::{Error, ErrorKind, ResultExt},
headers::{self, Header},
prelude::Range,
};
use std::{fmt, str::FromStr};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BA512Range {
start: u64,
end: u64,
}
impl BA512Range {
pub fn start(&self) -> u64 {
self.start
}
pub fn end(&self) -> u64 {
self.end
}
pub fn new(start: u64, end: u64) -> azure_core::Result<Self> {
if start % 512 != 0 {
return Err(Error::with_message(ErrorKind::Other, || {
format!("start range not 512-byte aligned: {start}")
}));
}
if (end + 1) % 512 != 0 {
return Err(Error::with_message(ErrorKind::Other, || {
format!("end range not 512-byte aligned: {end}")
}));
}
Ok(Self { start, end })
}
#[inline]
pub fn size(&self) -> u64 {
self.end - self.start + 1
}
}
impl From<BA512Range> for Range {
fn from(range: BA512Range) -> Self {
(range.start()..range.end()).into()
}
}
impl TryFrom<Range> for BA512Range {
type Error = Error;
fn try_from(r: Range) -> azure_core::Result<Self> {
match r {
Range::Range(r) => BA512Range::new(r.start, r.end),
Range::RangeFrom(r) => Err(Error::with_message(ErrorKind::DataConversion, || {
format!("error converting RangeFrom<{:?}> into BA512Range", r)
})),
}
}
}
impl TryFrom<(u64, u64)> for BA512Range {
type Error = Error;
fn try_from((start, end): (u64, u64)) -> azure_core::Result<Self> {
BA512Range::new(start, end)
}
}
impl Header for BA512Range {
fn name(&self) -> headers::HeaderName {
headers::RANGE
}
fn value(&self) -> headers::HeaderValue {
self.to_string().into()
}
}
impl FromStr for BA512Range {
type Err = Error;
fn from_str(s: &str) -> azure_core::Result<BA512Range> {
let v = s.split('/').collect::<Vec<&str>>();
if v.len() != 2 {
return Err(Error::message(ErrorKind::Other, "split not found"));
}
let cp_start = v[0]
.parse::<u64>()
.with_context(ErrorKind::DataConversion, || {
format!("error parsing '{}' into u64", v[0])
})?;
let cp_end = v[1]
.parse::<u64>()
.with_context(ErrorKind::DataConversion, || {
format!("error parsing '{}' into u64", v[1])
})?;
BA512Range::new(cp_start, cp_end)
}
}
impl fmt::Display for BA512Range {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "bytes={}-{}", self.start, self.end)
}
}
impl<'a> From<&'a BA512Range> for Range {
fn from(ba: &'a BA512Range) -> Range {
(ba.start()..ba.end()).into()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_512range_parse() {
let range = "0/511".parse::<BA512Range>().unwrap();
assert_eq!(range.start, 0);
assert_eq!(range.end, 511);
}
#[test]
fn test_512range_parse_panic_1() {
let err = "abba/2000".parse::<BA512Range>().unwrap_err();
assert!(matches!(err.kind(), ErrorKind::DataConversion));
}
#[test]
fn test_512range_parse_panic_2() {
let err = "1000-2000".parse::<BA512Range>().unwrap_err();
assert!(matches!(err.kind(), ErrorKind::Other));
}
#[test]
fn test_512range_invalid_start_range() {
let err = "7/511".parse::<BA512Range>().unwrap_err();
assert!(matches!(err.kind(), ErrorKind::Other));
}
#[test]
fn test_512range_invalid_end_range() {
let err = "0/100".parse::<BA512Range>().unwrap_err();
assert!(matches!(err.kind(), ErrorKind::Other));
}
#[test]
fn test_512range_display() {
let range = BA512Range { start: 0, end: 511 };
let txt = format!("{range}");
assert_eq!(txt, "bytes=0-511");
}
}