1use std::{
4 fmt::{self, Display, Formatter},
5 str::FromStr,
6};
7
8use crate::{Error, header::HeaderFieldValue};
9
10#[derive(Copy, Clone)]
12pub struct SpeedHeader {
13 min: Option<f32>,
14 max: f32,
15}
16
17impl SpeedHeader {
18 #[inline]
23 pub const fn new_v10(max: f32) -> Self {
24 assert!(max > 0f32);
25
26 Self { min: None, max }
27 }
28
29 #[inline]
35 pub const fn new_v20(min: f32, max: f32) -> Self {
36 assert!(min > 0f32);
37 assert!(max > 0f32);
38 assert!(min <= max);
39
40 Self {
41 min: Some(min),
42 max,
43 }
44 }
45
46 #[inline]
48 pub fn min(&self) -> f32 {
49 self.min.unwrap_or(self.max)
50 }
51
52 #[inline]
54 pub fn max(&self) -> f32 {
55 self.max
56 }
57}
58
59impl Display for SpeedHeader {
60 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
61 if let Some(min) = self.min {
62 write!(f, "{}-{}", min, self.max)
63 } else {
64 Display::fmt(&self.max, f)
65 }
66 }
67}
68
69impl From<SpeedHeader> for HeaderFieldValue {
70 #[inline]
71 fn from(value: SpeedHeader) -> Self {
72 HeaderFieldValue::from(value.to_string())
73 }
74}
75
76impl FromStr for SpeedHeader {
77 type Err = Error;
78
79 fn from_str(s: &str) -> Result<Self, Self::Err> {
80 if let Some((min, max)) = s.split_once('-') {
81 let min = min
82 .parse()
83 .map_err(|_| Error::from_static_msg("invalid speed header"))?;
84
85 let max = max
86 .parse()
87 .map_err(|_| Error::from_static_msg("invalid speed header"))?;
88
89 if min <= 0f32 || max <= 0f32 || min > max {
90 return Err(Error::from_static_msg("speed out of bounds"));
91 }
92
93 let res = Self {
94 min: Some(min),
95 max,
96 };
97
98 Ok(res)
99 } else {
100 let max = s
101 .parse()
102 .map_err(|_| Error::from_static_msg("invalid speed header"))?;
103
104 if max <= 0f32 {
105 return Err(Error::from_static_msg("speed out of bounds"));
106 }
107
108 let res = Self { min: None, max };
109
110 Ok(res)
111 }
112 }
113}
114
115impl TryFrom<&HeaderFieldValue> for SpeedHeader {
116 type Error = Error;
117
118 fn try_from(value: &HeaderFieldValue) -> Result<Self, Self::Error> {
119 value
120 .to_str()
121 .map_err(|_| Error::from_static_msg("header field is not UTF-8 encoded"))?
122 .parse()
123 }
124}