braid_http/types/
content_range.rs1use std::fmt;
4use std::str::FromStr;
5
6#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
8pub struct ContentRange {
9 pub unit: String,
11 pub range: String,
13}
14
15impl ContentRange {
16 #[inline]
17 #[must_use]
18 pub fn new(unit: impl Into<String>, range: impl Into<String>) -> Self {
19 ContentRange {
20 unit: unit.into(),
21 range: range.into(),
22 }
23 }
24
25 #[inline]
26 #[must_use]
27 pub fn json(range: impl Into<String>) -> Self {
28 Self::new("json", range)
29 }
30 #[inline]
31 #[must_use]
32 pub fn bytes(range: impl Into<String>) -> Self {
33 Self::new("bytes", range)
34 }
35 #[inline]
36 #[must_use]
37 pub fn text(range: impl Into<String>) -> Self {
38 Self::new("text", range)
39 }
40 #[inline]
41 #[must_use]
42 pub fn lines(range: impl Into<String>) -> Self {
43 Self::new("lines", range)
44 }
45
46 #[inline]
47 #[must_use]
48 pub fn is_json(&self) -> bool {
49 self.unit == "json"
50 }
51 #[inline]
52 #[must_use]
53 pub fn is_bytes(&self) -> bool {
54 self.unit == "bytes"
55 }
56
57 #[must_use]
58 pub fn to_header_value(&self) -> String {
59 format!("{} {}", self.unit, self.range)
60 }
61
62 pub fn from_header_value(value: &str) -> Result<Self, String> {
63 let parts: Vec<&str> = value.splitn(2, ' ').collect();
64 if parts.len() != 2 {
65 return Err(format!(
66 "Invalid Content-Range: expected 'unit range', got '{}'",
67 value
68 ));
69 }
70 Ok(ContentRange {
71 unit: parts[0].to_string(),
72 range: parts[1].to_string(),
73 })
74 }
75}
76
77impl Default for ContentRange {
78 fn default() -> Self {
79 ContentRange {
80 unit: "bytes".to_string(),
81 range: "0:0".to_string(),
82 }
83 }
84}
85
86impl fmt::Display for ContentRange {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 write!(f, "{} {}", self.unit, self.range)
89 }
90}
91
92impl FromStr for ContentRange {
93 type Err = String;
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 Self::from_header_value(s)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_content_range_basic() {
105 let range = ContentRange::new("json", ".field");
106 assert_eq!(range.to_header_value(), "json .field");
107 let parsed = ContentRange::from_header_value("json .field").unwrap();
108 assert_eq!(parsed, range);
109 }
110}