1use serde::{Deserialize, Serialize};
2use std::fs;
3
4pub fn json_dumps<T: Serialize>(
6 data: &T,
7 pretty: bool,
8) -> Result<String, Box<dyn std::error::Error>> {
9 if pretty {
10 Ok(serde_json::to_string_pretty(data)?)
11 } else {
12 Ok(serde_json::to_string(data)?)
13 }
14}
15
16pub fn json_loads<T: for<'de> Deserialize<'de>>(
18 json_str: &str,
19) -> Result<T, Box<dyn std::error::Error>> {
20 Ok(serde_json::from_str(json_str)?)
21}
22
23pub fn json_dump<T: Serialize>(
25 data: &T,
26 filepath: &str,
27 pretty: bool,
28) -> Result<(), Box<dyn std::error::Error>> {
29 let json_str = json_dumps(data, pretty)?;
30 fs::write(filepath, json_str)?;
31 Ok(())
32}
33
34pub fn json_load<T: for<'de> Deserialize<'de>>(
36 filepath: &str,
37) -> Result<T, Box<dyn std::error::Error>> {
38 let json_str = fs::read_to_string(filepath)?;
39 json_loads(&json_str)
40}
41
42pub fn encode_value<T: Serialize>(
45 value: &T,
46) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
47 Ok(serde_json::to_value(value)?)
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use crate::line::Line;
54 use crate::point::Point;
55 use crate::vector::Vector;
56
57 #[test]
58 fn test_json_dump_and_load() {
59 let mut original = Point::new(1.5, 2.5, 3.5);
60 original.name = "test_point".to_string();
61
62 let filepath = "test_encoders_point.json";
63 json_dump(&original, filepath, true).unwrap();
64
65 let loaded: Point = json_load(filepath).unwrap();
66
67 assert_eq!(loaded.x(), original.x());
68 assert_eq!(loaded.y(), original.y());
69 assert_eq!(loaded.z(), original.z());
70 assert_eq!(loaded.name, original.name);
71
72 std::fs::remove_file(filepath).ok();
73 }
74
75 #[test]
76 fn test_json_dumps_and_loads() {
77 let mut original = Vector::new(42.1, 84.2, 126.3);
78 original.name = "test_vector".to_string();
79
80 let json_str = json_dumps(&original, true).unwrap();
81 assert!(!json_str.is_empty());
82 assert!(json_str.contains("Vector"));
83
84 let loaded: Vector = json_loads(&json_str).unwrap();
85
86 assert_eq!(loaded.x(), original.x());
87 assert_eq!(loaded.y(), original.y());
88 assert_eq!(loaded.z(), original.z());
89 assert_eq!(loaded.name, original.name);
90 }
91
92 #[test]
93 fn test_encode_collection() {
94 let points = vec![
95 Point::new(1.0, 2.0, 3.0),
96 Point::new(4.0, 5.0, 6.0),
97 Point::new(7.0, 8.0, 9.0),
98 ];
99
100 let json_str = json_dumps(&points, true).unwrap();
101 assert!(!json_str.is_empty());
102
103 let loaded: Vec<Point> = json_loads(&json_str).unwrap();
104 assert_eq!(loaded.len(), 3);
105 assert_eq!(loaded[0].x(), 1.0);
106 assert_eq!(loaded[1].y(), 5.0);
107 assert_eq!(loaded[2].z(), 9.0);
108 }
109
110 #[test]
111 fn test_nested_collections() {
112 let lines = vec![
113 Line::new(0.0, 0.0, 0.0, 1.0, 0.0, 0.0),
114 Line::new(0.0, 0.0, 0.0, 0.0, 1.0, 0.0),
115 ];
116
117 let json_str = json_dumps(&lines, true).unwrap();
118 let loaded: Vec<Line> = json_loads(&json_str).unwrap();
119
120 assert_eq!(loaded.len(), 2);
121 assert_eq!(loaded[0].end().x(), 1.0);
122 assert_eq!(loaded[1].end().y(), 1.0);
123 }
124
125 #[test]
126 fn test_roundtrip_with_file() {
127 let vectors = vec![
128 Vector::new(1.0, 0.0, 0.0),
129 Vector::new(0.0, 1.0, 0.0),
130 Vector::new(0.0, 0.0, 1.0),
131 ];
132
133 let filepath = "test_encoders_collection.json";
134 json_dump(&vectors, filepath, true).unwrap();
135
136 let loaded: Vec<Vector> = json_load(filepath).unwrap();
137
138 assert_eq!(loaded.len(), 3);
139 assert_eq!(loaded[0].x(), 1.0);
140 assert_eq!(loaded[1].y(), 1.0);
141 assert_eq!(loaded[2].z(), 1.0);
142
143 std::fs::remove_file(filepath).ok();
144 }
145
146 #[test]
147 fn test_pretty_vs_compact() {
148 let point = Point::new(1.0, 2.0, 3.0);
149
150 let pretty = json_dumps(&point, true).unwrap();
151 let compact = json_dumps(&point, false).unwrap();
152
153 assert!(pretty.len() > compact.len());
154 assert!(pretty.contains("\n"));
155 assert!(!compact.contains("\n"));
156
157 let loaded_pretty: Point = json_loads(&pretty).unwrap();
158 let loaded_compact: Point = json_loads(&compact).unwrap();
159
160 assert_eq!(loaded_pretty.x(), 1.0);
161 assert_eq!(loaded_compact.x(), 1.0);
162 }
163
164 #[test]
165 fn test_decode_primitives() {
166 let num: i32 = 42;
167 let json_str = json_dumps(&num, false).unwrap();
168 let loaded: i32 = json_loads(&json_str).unwrap();
169 assert_eq!(loaded, 42);
170
171 let float: f64 = 2.5;
172 let json_str = json_dumps(&float, false).unwrap();
173 let loaded: f64 = json_loads(&json_str).unwrap();
174 assert_eq!(loaded, 2.5);
175
176 let text = "hello";
177 let json_str = json_dumps(&text, false).unwrap();
178 let loaded: String = json_loads(&json_str).unwrap();
179 assert_eq!(loaded, "hello");
180
181 let flag = true;
182 let json_str = json_dumps(&flag, false).unwrap();
183 let loaded: bool = json_loads(&json_str).unwrap();
184 assert!(loaded);
185 }
186
187 #[test]
188 fn test_decode_list() {
189 let data = vec![1, 2, 3];
190 let json_str = json_dumps(&data, false).unwrap();
191 let loaded: Vec<i32> = json_loads(&json_str).unwrap();
192 assert_eq!(loaded, vec![1, 2, 3]);
193
194 let points = vec![Point::new(1.0, 2.0, 3.0), Point::new(4.0, 5.0, 6.0)];
195 let json_str = json_dumps(&points, false).unwrap();
196 let loaded: Vec<Point> = json_loads(&json_str).unwrap();
197 assert_eq!(loaded.len(), 2);
198 assert_eq!(loaded[0].x(), 1.0);
199 assert_eq!(loaded[1].x(), 4.0);
200 }
201
202 #[test]
203 fn test_decode_dict() {
204 use std::collections::HashMap;
205
206 let mut data = HashMap::new();
207 data.insert("a".to_string(), 1);
208 data.insert("b".to_string(), 2);
209 let json_str = json_dumps(&data, false).unwrap();
210 let loaded: HashMap<String, i32> = json_loads(&json_str).unwrap();
211 assert_eq!(loaded.get("a"), Some(&1));
212 assert_eq!(loaded.get("b"), Some(&2));
213
214 let vec = Vector::new(1.0, 2.0, 3.0);
215 let json_str = json_dumps(&vec, false).unwrap();
216 let loaded: Vector = json_loads(&json_str).unwrap();
217 assert_eq!(loaded.x(), 1.0);
218 }
219
220 #[test]
221 fn test_list_in_list_in_list() {
222 let data = vec![vec![vec![1, 2], vec![3, 4]], vec![vec![5, 6], vec![7, 8]]];
223 let json_str = json_dumps(&data, false).unwrap();
224 let loaded: Vec<Vec<Vec<i32>>> = json_loads(&json_str).unwrap();
225
226 assert_eq!(loaded[0][0][0], 1);
227 assert_eq!(loaded[1][1][1], 8);
228 assert_eq!(loaded.len(), 2);
229 }
230
231 #[test]
232 fn test_dict_of_lists() {
233 use serde_json::json;
234
235 let points = vec![Point::new(1.0, 0.0, 0.0), Point::new(0.0, 1.0, 0.0)];
236
237 let data = json!({
238 "numbers": [1, 2, 3],
239 "letters": ["a", "b", "c"],
240 "points": points
241 });
242
243 let json_str = data.to_string();
244 let loaded: serde_json::Value = json_loads(&json_str).unwrap();
245
246 assert_eq!(loaded["numbers"].as_array().unwrap().len(), 3);
247 assert_eq!(loaded["letters"][0], "a");
248
249 let loaded_points: Vec<Point> = serde_json::from_value(loaded["points"].clone()).unwrap();
250 assert_eq!(loaded_points.len(), 2);
251 assert_eq!(loaded_points[0].x(), 1.0);
252 }
253
254 #[test]
255 fn test_list_of_dict() {
256 use serde_json::json;
257
258 let point = Point::new(1.0, 2.0, 3.0);
259
260 let data = json!([
261 {"name": "point1", "value": 10},
262 {"name": "point2", "value": 20},
263 {"geometry": point}
264 ]);
265
266 let json_str = data.to_string();
267 let loaded: serde_json::Value = json_loads(&json_str).unwrap();
268
269 assert_eq!(loaded.as_array().unwrap().len(), 3);
270 assert_eq!(loaded[0]["name"], "point1");
271 assert_eq!(loaded[1]["value"], 20);
272
273 let loaded_point: Point = serde_json::from_value(loaded[2]["geometry"].clone()).unwrap();
274 assert_eq!(loaded_point.z(), 3.0);
275 }
276
277 #[test]
278 fn test_dict_of_dicts() {
279 use serde_json::json;
280
281 let point = Point::new(1.0, 2.0, 3.0);
282 let vec = Vector::new(0.0, 0.0, 1.0);
283
284 let data = json!({
285 "config": {
286 "tolerance": 0.001,
287 "scale": 1000
288 },
289 "geometry": {
290 "point": point,
291 "vector": vec
292 }
293 });
294
295 let json_str = data.to_string();
296 let loaded: serde_json::Value = json_loads(&json_str).unwrap();
297
298 assert_eq!(loaded["config"]["tolerance"], 0.001);
299 assert_eq!(loaded["config"]["scale"], 1000);
300
301 let loaded_point: Point =
302 serde_json::from_value(loaded["geometry"]["point"].clone()).unwrap();
303 let loaded_vec: Vector =
304 serde_json::from_value(loaded["geometry"]["vector"].clone()).unwrap();
305 assert_eq!(loaded_point.x(), 1.0);
306 assert_eq!(loaded_vec.z(), 1.0);
307 }
308}