use std::fmt;
#[derive(Clone, Debug, PartialEq)]
pub struct ContentRange {
range: Option<(u64, u64)>,
complete_length: Option<u64>,
}
impl ContentRange {
pub fn bytes(first_byte: u64, last_byte: u64, complete_length: impl Into<Option<u64>>) -> ContentRange {
let complete_length = complete_length.into();
ContentRange {
range: Some((first_byte, last_byte)),
complete_length,
}
}
pub fn unsatisfied_bytes(complete_length: u64) -> Self {
ContentRange {
range: None,
complete_length: Some(complete_length),
}
}
pub fn bytes_range(&self) -> Option<(u64, u64)> {
self.range
}
pub fn bytes_len(&self) -> Option<u64> {
self.complete_length
}
}
impl ::Header for ContentRange {
const NAME: &'static ::HeaderName = &::http::header::CONTENT_RANGE;
fn decode(values: &mut ::Values) -> Option<Self> {
let s = values
.next()?
.to_str()
.ok()?;
let (unit, spec) = split_in_two(s, ' ')?;
if unit != "bytes" {
return None;
}
let (range, complete_length) = split_in_two(spec, '/')?;
let complete_length = if complete_length == "*" {
None
} else {
Some(complete_length.parse().ok()?)
};
let range = if range == "*" {
None
} else {
let (first_byte, last_byte) = split_in_two(range, '-')?;
let first_byte = first_byte.parse().ok()?;
let last_byte = last_byte.parse().ok()?;
if last_byte < first_byte {
return None;
}
Some((first_byte, last_byte))
};
Some(ContentRange {
range,
complete_length,
})
}
fn encode(&self, values: &mut ::ToValues) {
values.append_fmt(&Adapter(self));
struct Adapter<'a>(&'a ContentRange);
impl<'a> fmt::Display for Adapter<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("bytes ")?;
if let Some((first_byte, last_byte)) = self.0.range {
write!(f, "{}-{}", first_byte, last_byte)?;
} else {
f.write_str("*")?;
}
f.write_str("/")?;
if let Some(v) = self.0.complete_length {
write!(f, "{}", v)
} else {
f.write_str("*")
}
}
}
}
}
fn split_in_two(s: &str, separator: char) -> Option<(&str, &str)> {
let mut iter = s.splitn(2, separator);
match (iter.next(), iter.next()) {
(Some(a), Some(b)) => Some((a, b)),
_ => None
}
}