braid_http/protocol/
formatter.rs1use crate::error::Result;
7use crate::protocol::constants::headers;
8use crate::protocol;
9use crate::types::{Update, Patch};
10use bytes::{Bytes, BytesMut};
11
12pub fn format_update(update: &Update) -> Result<Bytes> {
25 let mut buffer = BytesMut::new();
26
27 if !update.version.is_empty() {
29 write_header(&mut buffer, headers::VERSION.as_str(), &protocol::format_version_header(&update.version));
30 }
31
32 if !update.parents.is_empty() {
33 write_header(&mut buffer, headers::PARENTS.as_str(), &protocol::format_version_header(&update.parents));
34 }
35
36 if let Some(merge_type) = &update.merge_type {
37 write_header(&mut buffer, headers::MERGE_TYPE.as_str(), merge_type);
38 }
39
40 for (k, v) in &update.extra_headers {
41 write_header(&mut buffer, k, v);
42 }
43
44 if let Some(body) = &update.body {
46 write_header(&mut buffer, headers::CONTENT_LENGTH.as_str(), &body.len().to_string());
47 if let Some(ct) = &update.content_type {
48 write_header(&mut buffer, headers::CONTENT_TYPE.as_str(), ct);
49 }
50 buffer.extend_from_slice(b"\r\n"); buffer.extend_from_slice(body);
52 } else if let Some(patches) = &update.patches {
53 if !patches.is_empty() {
54 write_header(&mut buffer, headers::PATCHES.as_str(), &patches.len().to_string());
55 buffer.extend_from_slice(b"\r\n"); for patch in patches {
59 format_patch(&mut buffer, patch)?;
60 }
61 } else {
62 write_header(&mut buffer, headers::CONTENT_LENGTH.as_str(), "0");
63 buffer.extend_from_slice(b"\r\n");
64 }
65 } else {
66 write_header(&mut buffer, headers::CONTENT_LENGTH.as_str(), "0");
68 buffer.extend_from_slice(b"\r\n");
69 }
70
71 Ok(buffer.freeze())
72}
73
74fn write_header(buffer: &mut BytesMut, key: &str, value: &str) {
75 buffer.extend_from_slice(key.as_bytes());
76 buffer.extend_from_slice(b": ");
77 buffer.extend_from_slice(value.as_bytes());
78 buffer.extend_from_slice(b"\r\n");
79}
80
81fn format_patch(buffer: &mut BytesMut, patch: &Patch) -> Result<()> {
82 write_header(buffer, headers::CONTENT_LENGTH.as_str(), &patch.content.len().to_string());
83
84 let content_range = format!("{} {}", patch.unit, patch.range);
85 write_header(buffer, headers::CONTENT_RANGE.as_str(), &content_range);
86
87 buffer.extend_from_slice(b"\r\n"); buffer.extend_from_slice(&patch.content);
89
90 Ok(())
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use crate::types::Version;
97
98 #[test]
99 fn test_format_snapshot() {
100 let update = Update::snapshot(Version::new("v1"), "data");
101 let bytes = format_update(&update).unwrap();
102 let s = std::str::from_utf8(&bytes).unwrap();
103
104 assert!(s.contains("version: \"v1\""));
105 assert!(s.contains("content-length: 4"));
106 assert!(s.ends_with("\r\ndata"));
107 }
108}