1use std::ffi::{CStr, CString};
2use std::os::raw::{c_char, c_void};
3
4use {parser, select, select_as_str};
5
6const INVALID_PATH: &str = "invalid path";
7const INVALID_JSON: &str = "invalud json";
8
9fn to_str(v: *const c_char, err_msg: &str) -> &str {
10 unsafe { CStr::from_ptr(v) }.to_str().expect(err_msg)
11}
12
13fn to_char_ptr(v: &str) -> *const c_char {
14 let s: CString = CString::new(v).unwrap_or_else(|_| panic!("invalid string: {}", v));
15 let ptr: *const i8 = s.as_ptr();
16 std::mem::forget(s);
17 ptr
18}
19
20#[no_mangle]
21pub extern "C" fn ffi_select(json_str: *const c_char, path: *const c_char) -> *const c_char {
22 let json_str: &str = to_str(v:json_str, INVALID_JSON);
23 let path: &str = to_str(v:path, INVALID_PATH);
24 match select_as_str(json_str, path) {
25 Ok(v: String) => to_char_ptr(v.as_str()),
26 Err(e: JsonPathError) => {
27 panic!("{:?}", e);
28 }
29 }
30}
31
32#[no_mangle]
33#[allow(clippy::forget_copy)]
34pub extern "C" fn ffi_path_compile(path: *const c_char) -> *mut c_void {
35 let path: &str = to_str(v:path, INVALID_PATH);
36 let ref_node: *mut Node = Box::into_raw(Box::new(parser::Parser::compile(input:path).unwrap()));
37 let ptr: *mut c_void = ref_node as *mut c_void;
38 std::mem::forget(ref_node);
39 ptr
40}
41
42#[no_mangle]
43pub extern "C" fn ffi_select_with_compiled_path(
44 path_ptr: *mut c_void,
45 json_ptr: *const c_char,
46) -> *const c_char {
47 let node: Box = unsafe { Box::from_raw(path_ptr as *mut parser::Node) };
48 let json_str: &str = to_str(v:json_ptr, INVALID_JSON);
49 let json: Value = serde_json::from_str(json_str)
50 .unwrap_or_else(|_| panic!("invalid json string: {}", json_str));
51
52 let mut selector: Selector<'_, '_> = select::Selector::default();
53 let found: Vec<&Value> = selector.compiled_path(&node).value(&json).select().unwrap();
54 std::mem::forget(node);
55
56 let result: String = serde_json::to_string(&found)
57 .unwrap_or_else(|_| panic!("json serialize error: {:?}", found));
58 to_char_ptr(result.as_str())
59}
60