1use std::collections::HashMap;
2
3use crate::body::Body;
4use crate::value::Value;
5
6#[derive(Debug, Clone)]
8pub struct Message {
9 pub headers: HashMap<String, Value>,
12 pub body: Body,
14}
15
16impl Default for Message {
17 fn default() -> Self {
18 Self {
19 headers: HashMap::new(),
20 body: Body::Empty,
21 }
22 }
23}
24
25impl Message {
26 pub fn new(body: impl Into<Body>) -> Self {
28 Self {
29 headers: HashMap::new(),
30 body: body.into(),
31 }
32 }
33
34 pub fn header(&self, key: &str) -> Option<&Value> {
36 self.headers.get(key)
37 }
38
39 pub fn header_ic(&self, key: &str) -> Option<&Value> {
41 self.headers
42 .iter()
43 .find(|(k, _)| k.eq_ignore_ascii_case(key))
44 .map(|(_, v)| v)
45 }
46
47 pub fn set_header(&mut self, key: impl Into<String>, value: impl Into<Value>) {
49 self.headers.insert(key.into(), value.into());
50 }
51
52 pub fn set_header_normalized(&mut self, key: impl Into<String>, value: impl Into<Value>) {
54 self.headers
55 .insert(key.into().to_ascii_lowercase(), value.into());
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn test_message_default() {
65 let msg = Message::default();
66 assert!(msg.body.is_empty());
67 assert!(msg.headers.is_empty());
68 }
69
70 #[test]
71 fn test_message_new_with_body() {
72 let msg = Message::new("hello");
73 assert_eq!(msg.body.as_text(), Some("hello"));
74 }
75
76 #[test]
77 fn test_message_headers() {
78 let mut msg = Message::default();
79 msg.set_header("key", Value::String("value".into()));
80 assert_eq!(msg.header("key"), Some(&Value::String("value".into())));
81 assert_eq!(msg.header("missing"), None);
82 }
83
84 #[test]
85 fn test_header_ic_case_insensitive() {
86 let mut msg = Message::default();
87 msg.set_header("Content-Type", Value::String("application/json".into()));
88 assert_eq!(
89 msg.header_ic("content-type"),
90 Some(&Value::String("application/json".into()))
91 );
92 assert_eq!(
93 msg.header_ic("CONTENT-TYPE"),
94 Some(&Value::String("application/json".into()))
95 );
96 }
97
98 #[test]
99 fn test_set_header_normalized_lowercases_key() {
100 let mut msg = Message::default();
101 msg.set_header_normalized("X-Request-Id", Value::String("abc-123".into()));
102
103 assert!(msg.headers.contains_key("x-request-id"));
104 assert_eq!(
105 msg.header("x-request-id"),
106 Some(&Value::String("abc-123".into()))
107 );
108 }
109}