cjson_binding/
cjson_utils.rs1extern crate alloc;
26
27use alloc::ffi::CString;
28use alloc::string::String;
29use core::ffi::{CStr, c_char};
30
31use crate::cjson::{CJson, CJsonError, CJsonResult};
32use crate::cjson_ffi::cJSON;
33use crate::cjson_utils_ffi::*;
34
35pub struct JsonPointer;
37
38impl JsonPointer {
39 pub fn get(object: &CJson, pointer: &str) -> CJsonResult<CJsonRef> {
48 let c_pointer = CString::new(pointer).map_err(|_| CJsonError::InvalidUtf8)?;
49 let ptr = unsafe {
50 cJSONUtils_GetPointer(object.as_ptr() as *mut cJSON, c_pointer.as_ptr() as *const i8)
51 };
52 unsafe { CJsonRef::from_ptr(ptr) }.map_err(|_| CJsonError::NotFound)
53 }
54
55 pub fn get_case_sensitive(object: &CJson, pointer: &str) -> CJsonResult<CJsonRef> {
64 let c_pointer = CString::new(pointer).map_err(|_| CJsonError::InvalidUtf8)?;
65 let ptr = unsafe {
66 cJSONUtils_GetPointerCaseSensitive(
67 object.as_ptr() as *mut cJSON,
68 c_pointer.as_ptr() as *const i8,
69 )
70 };
71 unsafe { CJsonRef::from_ptr(ptr) }.map_err(|_| CJsonError::NotFound)
72 }
73
74 pub fn find_from_object_to(object: &CJson, target: &CJson) -> CJsonResult<String> {
83 let ptr = unsafe {
84 cJSONUtils_FindPointerFromObjectTo(object.as_ptr(), target.as_ptr())
85 };
86 if ptr.is_null() {
87 return Err(CJsonError::NotFound);
88 }
89 let path = unsafe { CStr::from_ptr(ptr as *const c_char).to_string_lossy().into_owned() };
90 unsafe { crate::cjson_ffi::cJSON_free(ptr as *mut core::ffi::c_void) };
91 Ok(path)
92 }
93}
94
95pub struct JsonPatch;
97
98impl JsonPatch {
99 pub fn generate(from: &mut CJson, to: &mut CJson) -> CJsonResult<CJson> {
110 let ptr = unsafe {
111 cJSONUtils_GeneratePatches(from.as_mut_ptr(), to.as_mut_ptr())
112 };
113 unsafe { CJson::from_ptr(ptr) }
114 }
115
116 pub fn generate_case_sensitive(from: &mut CJson, to: &mut CJson) -> CJsonResult<CJson> {
127 let ptr = unsafe {
128 cJSONUtils_GeneratePatchesCaseSensitive(from.as_mut_ptr(), to.as_mut_ptr())
129 };
130 unsafe { CJson::from_ptr(ptr) }
131 }
132
133 pub fn apply(object: &mut CJson, patches: &CJson) -> CJsonResult<()> {
142 let result = unsafe {
143 cJSONUtils_ApplyPatches(object.as_mut_ptr(), patches.as_ptr())
144 };
145 if result == 0 {
146 Ok(())
147 } else {
148 Err(CJsonError::InvalidOperation)
149 }
150 }
151
152 pub fn apply_case_sensitive(object: &mut CJson, patches: &CJson) -> CJsonResult<()> {
161 let result = unsafe {
162 cJSONUtils_ApplyPatchesCaseSensitive(object.as_mut_ptr(), patches.as_ptr())
163 };
164 if result == 0 {
165 Ok(())
166 } else {
167 Err(CJsonError::InvalidOperation)
168 }
169 }
170
171 pub fn add_to_array(
179 array: &mut CJson,
180 operation: &str,
181 path: &str,
182 value: Option<&CJson>,
183 ) -> CJsonResult<()> {
184 if !array.is_array() {
185 return Err(CJsonError::TypeError);
186 }
187
188 let c_operation = CString::new(operation).map_err(|_| CJsonError::InvalidUtf8)?;
189 let c_path = CString::new(path).map_err(|_| CJsonError::InvalidUtf8)?;
190
191 let value_ptr = value.map(|v| v.as_ptr()).unwrap_or(core::ptr::null());
192
193 unsafe {
194 cJSONUtils_AddPatchToArray(
195 array.as_mut_ptr(),
196 c_operation.as_ptr() as *const i8,
197 c_path.as_ptr() as *const i8,
198 value_ptr,
199 );
200 }
201 Ok(())
202 }
203}
204
205pub struct JsonMergePatch;
207
208impl JsonMergePatch {
209 pub fn apply(target: &mut CJson, patch: &CJson) -> CJsonResult<CJson> {
218 let ptr = unsafe {
219 cJSONUtils_MergePatch(target.as_mut_ptr(), patch.as_ptr())
220 };
221 unsafe { CJson::from_ptr(ptr) }
222 }
223
224 pub fn apply_case_sensitive(target: &mut CJson, patch: &CJson) -> CJsonResult<CJson> {
233 let ptr = unsafe {
234 cJSONUtils_MergePatchCaseSensitive(target.as_mut_ptr(), patch.as_ptr())
235 };
236 unsafe { CJson::from_ptr(ptr) }
237 }
238
239 pub fn generate(from: &mut CJson, to: &mut CJson) -> CJsonResult<CJson> {
250 let ptr = unsafe {
251 cJSONUtils_GenerateMergePatch(from.as_mut_ptr(), to.as_mut_ptr())
252 };
253 unsafe { CJson::from_ptr(ptr) }
254 }
255
256 pub fn generate_case_sensitive(from: &mut CJson, to: &mut CJson) -> CJsonResult<CJson> {
267 let ptr = unsafe {
268 cJSONUtils_GenerateMergePatchCaseSensitive(from.as_mut_ptr(), to.as_mut_ptr())
269 };
270 unsafe { CJson::from_ptr(ptr) }
271 }
272}
273
274pub struct JsonUtils;
276
277impl JsonUtils {
278 pub fn sort_object(object: &mut CJson) -> CJsonResult<()> {
283 if !object.is_object() {
284 return Err(CJsonError::TypeError);
285 }
286 unsafe { cJSONUtils_SortObject(object.as_mut_ptr()) };
287 Ok(())
288 }
289
290 pub fn sort_object_case_sensitive(object: &mut CJson) -> CJsonResult<()> {
295 if !object.is_object() {
296 return Err(CJsonError::TypeError);
297 }
298 unsafe { cJSONUtils_SortObjectCaseSensitive(object.as_mut_ptr()) };
299 Ok(())
300 }
301}
302
303pub use crate::cjson::CJsonRef;
305
306#[cfg(test)]
307mod tests {
308 use super::*;
309 use crate::cjson::CJson;
310
311 #[test]
312 fn test_json_pointer_get() {
313 let json = r#"{"foo":{"bar":[1,2,3]}}"#;
314 let obj = CJson::parse(json).unwrap();
315
316 let result = JsonPointer::get(&obj, "/foo/bar/1").unwrap();
317 assert_eq!(result.get_number_value().unwrap(), 2.0);
318 }
319
320 #[test]
321 fn test_json_pointer_get_case_sensitive() {
322 let json = r#"{"Foo":{"Bar":"test"}}"#;
323 let obj = CJson::parse(json).unwrap();
324
325 let result = JsonPointer::get_case_sensitive(&obj, "/Foo/Bar").unwrap();
326 assert_eq!(result.get_string_value().unwrap(), "test");
327 }
328
329 #[test]
330 fn test_json_pointer_not_found() {
331 let json = r#"{"foo":"bar"}"#;
332 let obj = CJson::parse(json).unwrap();
333
334 assert!(JsonPointer::get(&obj, "/nonexistent").is_err());
335 }
336
337 #[test]
338 fn test_json_patch_generate_and_apply() {
339 let from_json = r#"{"name":"John","age":30}"#;
340 let to_json = r#"{"name":"John","age":31,"city":"NYC"}"#;
341
342 let mut from = CJson::parse(from_json).unwrap();
343 let mut to = CJson::parse(to_json).unwrap();
344
345 let patches = JsonPatch::generate(&mut from, &mut to).unwrap();
346 assert!(patches.is_array());
347 }
348
349 #[test]
350 fn test_json_patch_apply() {
351 let obj_json = r#"{"name":"John","age":30}"#;
352 let patch_json = r#"[{"op":"replace","path":"/age","value":31}]"#;
353
354 let mut obj = CJson::parse(obj_json).unwrap();
355 let patches = CJson::parse(patch_json).unwrap();
356
357 JsonPatch::apply(&mut obj, &patches).unwrap();
358
359 let age = obj.get_object_item("age").unwrap();
360 assert_eq!(age.get_number_value().unwrap(), 31.0);
361 }
362
363 #[test]
364 fn test_json_merge_patch_apply() {
365 let target_json = r#"{"name":"John","age":30}"#;
366 let patch_json = r#"{"age":31,"city":"NYC"}"#;
367
368 let mut target = CJson::parse(target_json).unwrap();
369 let patch = CJson::parse(patch_json).unwrap();
370
371 let result = JsonMergePatch::apply(&mut target, &patch).unwrap();
372 core::mem::forget(target); let age = result.get_object_item("age").unwrap();
376 assert_eq!(age.get_number_value().unwrap(), 31.0);
377
378 let city = result.get_object_item("city").unwrap();
379 assert_eq!(city.get_string_value().unwrap(), "NYC");
380 }
381
382 #[test]
383 fn test_json_merge_patch_generate() {
384 let from_json = r#"{"name":"John","age":30}"#;
385 let to_json = r#"{"name":"John","age":31}"#;
386
387 let mut from = CJson::parse(from_json).unwrap();
388 let mut to = CJson::parse(to_json).unwrap();
389
390 let patch = JsonMergePatch::generate(&mut from, &mut to).unwrap();
391 assert!(patch.is_object());
392 }
393
394 #[test]
395 fn test_json_utils_sort_object() {
396 let json = r#"{"z":"last","a":"first","m":"middle"}"#;
397 let mut obj = CJson::parse(json).unwrap();
398
399 JsonUtils::sort_object(&mut obj).unwrap();
400
401 assert!(obj.is_object());
403 assert!(obj.has_object_item("a"));
404 assert!(obj.has_object_item("m"));
405 assert!(obj.has_object_item("z"));
406 }
407
408 #[test]
409 fn test_json_utils_sort_object_case_sensitive() {
410 let json = r#"{"Z":"last","a":"first","M":"middle"}"#;
411 let mut obj = CJson::parse(json).unwrap();
412
413 JsonUtils::sort_object_case_sensitive(&mut obj).unwrap();
414
415 assert!(obj.is_object());
416 assert!(obj.has_object_item("a"));
417 assert!(obj.has_object_item("M"));
418 assert!(obj.has_object_item("Z"));
419 }
420
421 #[test]
422 fn test_pointer_find_from_object_to() {
423 let json = r#"{"foo":{"bar":"test"}}"#;
424 let obj = CJson::parse(json).unwrap();
425
426 let target_owned = CJson::parse(r#"{"bar":"test"}"#).unwrap();
428
429 let _ = JsonPointer::find_from_object_to(&obj, &target_owned);
432 }
433
434 #[test]
435 fn test_json_patch_add_to_array() {
436 let mut patches = CJson::create_array().unwrap();
437
438 let value = CJson::create_string("test").unwrap();
439 JsonPatch::add_to_array(&mut patches, "add", "/foo", Some(&value)).unwrap();
440
441 assert!(patches.is_array());
442 assert_eq!(patches.get_array_size().unwrap(), 1);
443 }
444
445 #[test]
446 fn test_complex_pointer_path() {
447 let json = r#"{"users":[{"name":"Alice","age":25},{"name":"Bob","age":30}]}"#;
448 let obj = CJson::parse(json).unwrap();
449
450 let result = JsonPointer::get(&obj, "/users/0/name").unwrap();
451 assert_eq!(result.get_string_value().unwrap(), "Alice");
452
453 let result = JsonPointer::get(&obj, "/users/1/age").unwrap();
454 assert_eq!(result.get_number_value().unwrap(), 30.0);
455 }
456
457 #[test]
458 fn test_merge_patch_null_removal() {
459 let target_json = r#"{"name":"John","age":30,"city":"NYC"}"#;
460 let patch_json = r#"{"city":null}"#;
461
462 let mut target = CJson::parse(target_json).unwrap();
463 let patch = CJson::parse(patch_json).unwrap();
464
465 let result = JsonMergePatch::apply(&mut target, &patch).unwrap();
466 core::mem::forget(target); assert!(result.get_object_item("city").is_err());
470 assert!(result.has_object_item("name"));
471 assert!(result.has_object_item("age"));
472 }
473}