notedthat_core/
conditional.rs1#[derive(Debug, Clone, Default, PartialEq, Eq)]
14pub struct ConditionalHeaders {
15 pub if_match: Option<String>,
17 pub if_none_match: Option<String>,
19 pub if_modified_since: Option<String>,
21 pub if_unmodified_since: Option<String>,
23}
24
25impl ConditionalHeaders {
26 pub fn is_empty(&self) -> bool {
28 self.if_match.is_none()
29 && self.if_none_match.is_none()
30 && self.if_modified_since.is_none()
31 && self.if_unmodified_since.is_none()
32 }
33
34 pub fn from_header_map(headers: &http::HeaderMap) -> Self {
38 Self {
39 if_match: headers
40 .get(http::header::IF_MATCH)
41 .and_then(|v| v.to_str().ok())
42 .map(String::from),
43 if_none_match: headers
44 .get(http::header::IF_NONE_MATCH)
45 .and_then(|v| v.to_str().ok())
46 .map(String::from),
47 if_modified_since: headers
48 .get(http::header::IF_MODIFIED_SINCE)
49 .and_then(|v| v.to_str().ok())
50 .map(String::from),
51 if_unmodified_since: headers
52 .get(http::header::IF_UNMODIFIED_SINCE)
53 .and_then(|v| v.to_str().ok())
54 .map(String::from),
55 }
56 }
57}
58
59fn _assert_bounds()
61where
62 ConditionalHeaders: Send + Sync + Clone + std::fmt::Debug,
63{
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn test_default_all_none() {
72 let headers = ConditionalHeaders::default();
73 assert_eq!(headers.if_match, None);
74 assert_eq!(headers.if_none_match, None);
75 assert_eq!(headers.if_modified_since, None);
76 assert_eq!(headers.if_unmodified_since, None);
77 }
78
79 #[test]
80 fn test_default_is_empty() {
81 let headers = ConditionalHeaders::default();
82 assert!(headers.is_empty());
83 }
84
85 #[test]
86 fn test_is_empty_false_with_if_match() {
87 let headers = ConditionalHeaders {
88 if_match: Some("\"abc123\"".to_string()),
89 if_none_match: None,
90 if_modified_since: None,
91 if_unmodified_since: None,
92 };
93 assert!(!headers.is_empty());
94 }
95
96 #[test]
97 fn test_is_empty_false_with_if_none_match() {
98 let headers = ConditionalHeaders {
99 if_match: None,
100 if_none_match: Some("\"xyz789\"".to_string()),
101 if_modified_since: None,
102 if_unmodified_since: None,
103 };
104 assert!(!headers.is_empty());
105 }
106
107 #[test]
108 fn test_from_header_map_extracts_if_match() {
109 let mut map = http::HeaderMap::new();
110 map.insert(
111 http::header::IF_MATCH,
112 http::HeaderValue::from_static("\"etag-value\""),
113 );
114 let headers = ConditionalHeaders::from_header_map(&map);
115 assert_eq!(headers.if_match, Some("\"etag-value\"".to_string()));
116 assert_eq!(headers.if_none_match, None);
117 assert_eq!(headers.if_modified_since, None);
118 assert_eq!(headers.if_unmodified_since, None);
119 }
120
121 #[test]
122 fn test_from_header_map_missing_headers() {
123 let map = http::HeaderMap::new();
124 let headers = ConditionalHeaders::from_header_map(&map);
125 assert_eq!(headers, ConditionalHeaders::default());
126 }
127
128 #[test]
129 fn test_from_header_map_empty_map_is_empty() {
130 let map = http::HeaderMap::new();
131 let headers = ConditionalHeaders::from_header_map(&map);
132 assert!(headers.is_empty());
133 }
134
135 #[test]
136 fn test_from_header_map_all_four_headers() {
137 let mut map = http::HeaderMap::new();
138 map.insert(
139 http::header::IF_MATCH,
140 http::HeaderValue::from_static("\"match-etag\""),
141 );
142 map.insert(
143 http::header::IF_NONE_MATCH,
144 http::HeaderValue::from_static("\"none-match-etag\""),
145 );
146 map.insert(
147 http::header::IF_MODIFIED_SINCE,
148 http::HeaderValue::from_static("Wed, 21 Oct 2015 07:28:00 GMT"),
149 );
150 map.insert(
151 http::header::IF_UNMODIFIED_SINCE,
152 http::HeaderValue::from_static("Wed, 21 Oct 2015 07:28:00 GMT"),
153 );
154
155 let headers = ConditionalHeaders::from_header_map(&map);
156 assert_eq!(headers.if_match, Some("\"match-etag\"".to_string()));
157 assert_eq!(
158 headers.if_none_match,
159 Some("\"none-match-etag\"".to_string())
160 );
161 assert_eq!(
162 headers.if_modified_since,
163 Some("Wed, 21 Oct 2015 07:28:00 GMT".to_string())
164 );
165 assert_eq!(
166 headers.if_unmodified_since,
167 Some("Wed, 21 Oct 2015 07:28:00 GMT".to_string())
168 );
169 assert!(!headers.is_empty());
170 }
171
172 #[test]
173 fn test_trait_bounds_send_sync_clone_debug() {
174 fn assert_send_sync_clone_debug<T: Send + Sync + Clone + std::fmt::Debug>() {}
177 assert_send_sync_clone_debug::<ConditionalHeaders>();
178 }
179}