oxihuman_export/
hal_export.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct HalLink {
11 pub rel: String,
12 pub href: String,
13 pub templated: bool,
14}
15
16#[allow(dead_code)]
18#[derive(Debug, Clone)]
19pub struct HalResource {
20 pub links: Vec<HalLink>,
21 pub properties: Vec<(String, String)>,
22 pub embedded: Vec<(String, Vec<HalResource>)>,
23}
24
25impl HalResource {
26 #[allow(dead_code)]
27 pub fn new() -> Self {
28 HalResource {
29 links: Vec::new(),
30 properties: Vec::new(),
31 embedded: Vec::new(),
32 }
33 }
34
35 #[allow(dead_code)]
36 pub fn add_link(&mut self, rel: &str, href: &str) {
37 self.links.push(HalLink {
38 rel: rel.to_string(),
39 href: href.to_string(),
40 templated: false,
41 });
42 }
43
44 #[allow(dead_code)]
45 pub fn add_property(&mut self, key: &str, val: &str) {
46 self.properties.push((key.to_string(), val.to_string()));
47 }
48
49 #[allow(dead_code)]
50 pub fn embed(&mut self, rel: &str, resources: Vec<HalResource>) {
51 self.embedded.push((rel.to_string(), resources));
52 }
53}
54
55impl Default for HalResource {
56 fn default() -> Self {
57 HalResource::new()
58 }
59}
60
61#[allow(dead_code)]
63pub fn serialize_hal(res: &HalResource) -> String {
64 let mut parts: Vec<String> = Vec::new();
65
66 if !res.links.is_empty() {
67 let link_parts: Vec<String> = res
68 .links
69 .iter()
70 .map(|l| {
71 format!(
72 r#""{}":{{"href":"{}","templated":{}}}"#,
73 l.rel, l.href, l.templated
74 )
75 })
76 .collect();
77 parts.push(format!(r#""_links":{{{}}}"#, link_parts.join(",")));
78 }
79
80 for (k, v) in &res.properties {
81 parts.push(format!(r#""{}":"{}""#, k, v));
82 }
83
84 if !res.embedded.is_empty() {
85 let emb_parts: Vec<String> = res
86 .embedded
87 .iter()
88 .map(|(rel, items)| {
89 let items_json: Vec<String> = items.iter().map(serialize_hal).collect();
90 format!(r#""{}":[{}]"#, rel, items_json.join(","))
91 })
92 .collect();
93 parts.push(format!(r#""_embedded":{{{}}}"#, emb_parts.join(",")));
94 }
95
96 format!("{{{}}}", parts.join(","))
97}
98
99#[allow(dead_code)]
101pub fn link_count(res: &HalResource) -> usize {
102 res.links.len()
103}
104
105#[allow(dead_code)]
107pub fn property_count(res: &HalResource) -> usize {
108 res.properties.len()
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn new_resource_empty() {
117 let res = HalResource::new();
118 assert!(res.links.is_empty() && res.properties.is_empty());
119 }
120
121 #[test]
122 fn add_link_count() {
123 let mut res = HalResource::new();
124 res.add_link("self", "/api/user/1");
125 assert_eq!(link_count(&res), 1);
126 }
127
128 #[test]
129 fn add_property_count() {
130 let mut res = HalResource::new();
131 res.add_property("name", "Alice");
132 assert_eq!(property_count(&res), 1);
133 }
134
135 #[test]
136 fn serialize_empty_is_braces() {
137 let res = HalResource::new();
138 assert_eq!(serialize_hal(&res), "{}");
139 }
140
141 #[test]
142 fn serialize_contains_links() {
143 let mut res = HalResource::new();
144 res.add_link("self", "/api/user/1");
145 let s = serialize_hal(&res);
146 assert!(s.contains("_links"));
147 }
148
149 #[test]
150 fn serialize_contains_href() {
151 let mut res = HalResource::new();
152 res.add_link("self", "/api/user/1");
153 let s = serialize_hal(&res);
154 assert!(s.contains("/api/user/1"));
155 }
156
157 #[test]
158 fn serialize_contains_property() {
159 let mut res = HalResource::new();
160 res.add_property("name", "Alice");
161 let s = serialize_hal(&res);
162 assert!(s.contains("Alice"));
163 }
164
165 #[test]
166 fn embed_in_output() {
167 let mut res = HalResource::new();
168 let mut child = HalResource::new();
169 child.add_property("id", "1");
170 res.embed("items", vec![child]);
171 let s = serialize_hal(&res);
172 assert!(s.contains("_embedded"));
173 }
174
175 #[test]
176 fn link_href_stored() {
177 let mut res = HalResource::new();
178 res.add_link("next", "/api/user/2");
179 assert_eq!(res.links[0].href, "/api/user/2");
180 }
181
182 #[test]
183 fn multiple_properties() {
184 let mut res = HalResource::new();
185 res.add_property("a", "1");
186 res.add_property("b", "2");
187 assert_eq!(property_count(&res), 2);
188 }
189}