-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
364 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# A collections of bindings for sonic-rs | ||
|
||
1. ffi: the low-level APIs of sonic-rs, should not used directly | ||
2. cpp: the C++ bindings of sonic-rs | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
edition = "2021" | ||
name = "sonic_rs_ffi" | ||
version = "0.1.0" | ||
|
||
[dependencies] | ||
sonic-rs = { path = "../../" } | ||
|
||
[build] | ||
lib = ["staticlib"] | ||
|
||
[build-dependencies] | ||
cbindgen = "0.27" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
use std::env; | ||
|
||
use cbindgen::Language::C; | ||
|
||
fn main() { | ||
setup_cbindgen(); | ||
} | ||
|
||
fn setup_cbindgen() { | ||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); | ||
cbindgen::Builder::new() | ||
.with_crate(crate_dir) | ||
.with_language(C) | ||
.generate() | ||
.expect("Unable to generate bindings") | ||
.write_to_file("include/sonic_ffi.h"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
# This is a template cbindgen.toml file with all of the default values. | ||
# Some values are commented out because their absence is the real default. | ||
# | ||
# See https://github.com/mozilla/cbindgen/blob/master/docs.md#cbindgentoml | ||
# for detailed documentation of every option here. | ||
|
||
|
||
language = "C" | ||
|
||
|
||
############## Options for Wrapping the Contents of the Header ################# | ||
|
||
# header = "/* Text to put at the beginning of the generated file. Probably a license. */" | ||
# trailer = "/* Text to put at the end of the generated file */" | ||
# include_guard = "my_bindings_h" | ||
# pragma_once = true | ||
# autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" | ||
include_version = false | ||
# namespace = "my_namespace" | ||
includes = [] | ||
namespaces = ["sonic_rs_ffi"] | ||
no_includes = false | ||
sys_includes = [] | ||
using_namespaces = [] | ||
# cpp_compat = true | ||
after_includes = "" | ||
|
||
|
||
############################ Code Style Options ################################ | ||
|
||
braces = "SameLine" | ||
documentation = true | ||
documentation_length = "full" | ||
documentation_style = "auto" | ||
line_endings = "LF" # also "CR", "CRLF", "Native" | ||
line_length = 100 | ||
tab_width = 2 | ||
|
||
|
||
############################# Codegen Options ################################## | ||
|
||
sort_by = "Name" # default for `fn.sort_by` and `const.sort_by` | ||
style = "both" | ||
usize_is_size_t = true | ||
|
||
|
||
[defines] | ||
# "target_os = freebsd" = "DEFINE_FREEBSD" | ||
# "feature = serde" = "DEFINE_SERDE" | ||
|
||
|
||
[export] | ||
exclude = [] | ||
include = [] | ||
# prefix = "CAPI_" | ||
item_types = [] | ||
renaming_overrides_prefixing = false | ||
|
||
|
||
[export.rename] | ||
|
||
|
||
[export.body] | ||
|
||
|
||
[export.mangle] | ||
|
||
|
||
[fn] | ||
rename_args = "None" | ||
# must_use = "MUST_USE_FUNC" | ||
# deprecated = "DEPRECATED_FUNC" | ||
# deprecated_with_note = "DEPRECATED_FUNC_WITH_NOTE" | ||
# no_return = "NO_RETURN" | ||
# prefix = "START_FUNC" | ||
# postfix = "END_FUNC" | ||
args = "auto" | ||
sort_by = "Name" | ||
|
||
|
||
[struct] | ||
rename_fields = "None" | ||
# must_use = "MUST_USE_STRUCT" | ||
# deprecated = "DEPRECATED_STRUCT" | ||
# deprecated_with_note = "DEPRECATED_STRUCT_WITH_NOTE" | ||
derive_constructor = false | ||
derive_eq = false | ||
derive_gt = false | ||
derive_gte = false | ||
derive_lt = false | ||
derive_lte = false | ||
derive_neq = false | ||
|
||
|
||
[enum] | ||
rename_variants = "None" | ||
# must_use = "MUST_USE_ENUM" | ||
# deprecated = "DEPRECATED_ENUM" | ||
# deprecated_with_note = "DEPRECATED_ENUM_WITH_NOTE" | ||
add_sentinel = false | ||
derive_const_casts = false | ||
derive_helper_methods = false | ||
derive_mut_casts = false | ||
prefix_with_name = false | ||
# cast_assert_name = "ASSERT" | ||
derive_tagged_enum_copy_constructor = false | ||
derive_tagged_enum_destructor = false | ||
enum_class = true | ||
private_default_tagged_enum_constructor = false | ||
|
||
|
||
[const] | ||
allow_constexpr = false | ||
allow_static_const = true | ||
sort_by = "Name" | ||
|
||
|
||
[macro_expansion] | ||
bitflags = false | ||
|
||
|
||
############## Options for How Your Rust library Should Be Parsed ############## | ||
|
||
[parse] | ||
parse_deps = false | ||
# include = [] | ||
clean = false | ||
exclude = [] | ||
extra_bindings = [] | ||
|
||
|
||
[parse.expand] | ||
all_features = false | ||
crates = [] | ||
default_features = true | ||
features = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#include <stdarg.h> | ||
#include <stdbool.h> | ||
#include <stdint.h> | ||
#include <stdlib.h> | ||
|
||
#define SONIC_RS_DESERIALIZE_USE_RAW 1 | ||
|
||
#define SONIC_RS_DESERIALIZE_USE_RAWNUMBER 2 | ||
|
||
#define SONIC_RS_DESERIALIZE_UTF8_LOSSY 4 | ||
|
||
#define SONIC_RS_SERIALIZE_PRETTY 1 | ||
|
||
typedef struct SonicCString { | ||
const void *buf; | ||
uintptr_t len; | ||
} SonicCString; | ||
|
||
typedef struct SonicDeserializeRet { | ||
const void *value; | ||
struct SonicCString err; | ||
} SonicDeserializeRet; | ||
|
||
typedef struct SonicSerializeRet { | ||
struct SonicCString json; | ||
struct SonicCString err; | ||
} SonicSerializeRet; | ||
|
||
/** | ||
* # Safety | ||
* | ||
* The caller should drop the returned `value` or `err`. | ||
*/ | ||
struct SonicDeserializeRet sonic_rs_deserialize_value(const char *json, | ||
uintptr_t len, | ||
uint64_t cfg); | ||
|
||
/** | ||
* # Safety | ||
* | ||
* The caller should drop the returned `json` or `err`. | ||
*/ | ||
struct SonicSerializeRet sonic_rs_serialize_value(const void *value, uint64_t cfg); | ||
|
||
/** | ||
* # Safety | ||
*/ | ||
void sonic_rs_drop_value(void *value); | ||
|
||
/** | ||
* # Safety | ||
*/ | ||
void sonic_rs_drop_string(void *buf, uint64_t len); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
use std::{ffi::c_char, mem::ManuallyDrop, os::raw::c_void}; | ||
|
||
use sonic_rs::Value; | ||
|
||
/// A string allocated in Rust, ending with `\0`. Used for serialize output and error message. | ||
#[derive(Debug)] | ||
#[repr(C)] | ||
pub struct SonicCString { | ||
buf: *const c_void, | ||
len: usize, | ||
} | ||
|
||
impl Default for SonicCString { | ||
fn default() -> Self { | ||
SonicCString { | ||
buf: std::ptr::null(), | ||
len: 0, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
#[repr(C)] | ||
pub struct SonicDeserializeRet { | ||
value: *const c_void, | ||
err: SonicCString, | ||
} | ||
|
||
pub const SONIC_RS_DESERIALIZE_USE_RAW: u64 = 1; | ||
pub const SONIC_RS_DESERIALIZE_USE_RAWNUMBER: u64 = 2; | ||
pub const SONIC_RS_DESERIALIZE_UTF8_LOSSY: u64 = 4; | ||
|
||
/// # Safety | ||
/// | ||
/// The caller should drop the returned `value` or `err`. | ||
#[no_mangle] | ||
pub unsafe extern "C" fn sonic_rs_deserialize_value( | ||
json: *const c_char, | ||
len: usize, | ||
cfg: u64, | ||
) -> SonicDeserializeRet { | ||
let json = std::slice::from_raw_parts(json as *const u8, len); | ||
let mut de = sonic_rs::serde::Deserializer::from_slice(json); | ||
|
||
if cfg & SONIC_RS_DESERIALIZE_USE_RAWNUMBER != 0 { | ||
de = de.use_rawnumber(); | ||
} | ||
|
||
if cfg & SONIC_RS_DESERIALIZE_USE_RAW != 0 { | ||
de = de.use_raw(); | ||
} | ||
|
||
if cfg & SONIC_RS_DESERIALIZE_UTF8_LOSSY != 0 { | ||
de = de.utf8_lossy(); | ||
} | ||
|
||
match de.deserialize::<Value>() { | ||
Ok(value) => SonicDeserializeRet { | ||
value: Box::into_raw(Box::new(value)) as *const _, | ||
err: SonicCString::default(), | ||
}, | ||
Err(e) => { | ||
// messega always end with '\0' | ||
let msg = ManuallyDrop::new(format!("{}\0", e)); | ||
let err = SonicCString { | ||
buf: msg.as_ptr() as *const c_void, | ||
len: msg.len(), | ||
}; | ||
SonicDeserializeRet { | ||
value: std::ptr::null_mut(), | ||
err, | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
#[repr(C)] | ||
pub struct SonicSerializeRet { | ||
json: SonicCString, | ||
err: SonicCString, | ||
} | ||
|
||
pub const SONIC_RS_SERIALIZE_PRETTY: u64 = 1; | ||
|
||
/// # Safety | ||
/// | ||
/// The caller should drop the returned `json` or `err`. | ||
#[no_mangle] | ||
pub unsafe extern "C" fn sonic_rs_serialize_value( | ||
value: *const c_void, | ||
cfg: u64, | ||
) -> SonicSerializeRet { | ||
let value = unsafe { &*(value as *const Value) }; | ||
let ret = if cfg & SONIC_RS_SERIALIZE_PRETTY != 0 { | ||
sonic_rs::to_string_pretty(value) | ||
} else { | ||
sonic_rs::to_string(value) | ||
}; | ||
|
||
match ret { | ||
Ok(json) => { | ||
let json = ManuallyDrop::new(json); | ||
let json = SonicCString { | ||
buf: json.as_ptr() as *const c_void, | ||
len: json.len(), | ||
}; | ||
SonicSerializeRet { | ||
json, | ||
err: SonicCString::default(), | ||
} | ||
} | ||
Err(e) => { | ||
// NOTE: should be dropped manually in the foreign caller | ||
let msg = ManuallyDrop::new(format!("{}\0", e)); | ||
let err = SonicCString { | ||
buf: msg.as_ptr() as *const c_void, | ||
len: msg.len(), | ||
}; | ||
SonicSerializeRet { | ||
json: SonicCString::default(), | ||
err, | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// # Safety | ||
#[no_mangle] | ||
pub unsafe extern "C" fn sonic_rs_drop_value(value: *mut c_void) { | ||
std::mem::drop(Box::from_raw(value as *mut Value)); | ||
} | ||
|
||
/// # Safety | ||
#[no_mangle] | ||
pub unsafe extern "C" fn sonic_rs_drop_string(buf: *mut c_void, len: u64) { | ||
let s = Vec<u8>::from_raw_parts(buf as *mut u8, len, len); | ||
std::mem::drop(s); | ||
} |