1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Copyright (C) 2020 - 2022, J2 Innovations

//!
//! C API for working JSON encoding.
//!

use super::err::{new_error, update_last_error};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;

use crate::haystack::val::Value;

/// Encodes a [Value](crate::val::Value) to a JSON string
/// # Arguments
/// - val Value to encode as a JSON string
/// # Return
/// a `C string` with the JSON encoded value
/// or `null` if there was an error, in which case the [last_error_message](super::err::last_error_message)
/// can be called to get the error message.
/// # Safety
/// Panics on invalid input data
#[no_mangle]
pub unsafe extern "C" fn haystack_value_to_json_string(val: *const Value) -> *const c_char {
    match val.as_ref() {
        Some(val) => match serde_json::to_string(val) {
            Ok(str) => match CString::new(str.as_str()) {
                Ok(str) => str.into_raw(),
                Err(err) => {
                    update_last_error(err);
                    std::ptr::null()
                }
            },
            Err(err) => {
                update_last_error(err);
                std::ptr::null()
            }
        },
        None => {
            new_error("Invalid value");
            std::ptr::null()
        }
    }
}

/// Decodes a [Value](crate::val::Value) from a JSON string
/// # Arguments
/// - val `C string` with the JSON encoded value
/// # Return
/// the decoded [Value](crate::val::Value) or `null` if there was an error,
/// in which case the [last_error_message](super::err::last_error_message)
/// can be called to get the error message.
/// # Safety
/// Panics on invalid input data
#[no_mangle]
pub unsafe extern "C" fn haystack_value_from_json_string(
    input: *const c_char,
) -> Option<Box<Value>> {
    if input.is_null() {
        new_error("Invalid null argument(s)");
        return None;
    }
    match CStr::from_ptr(input).to_str() {
        Ok(c_str) => match serde_json::from_str::<Value>(c_str) {
            Ok(val) => Some(Box::new(val)),
            Err(err) => {
                update_last_error(err);
                None
            }
        },
        Err(err) => {
            new_error(&format!("Invalid C string. {err}"));
            None
        }
    }
}