From 02226d24f83daea3988bfd263198a37041ee56e8 Mon Sep 17 00:00:00 2001 From: SunDoge <384813529@qq.com> Date: Fri, 25 Aug 2023 21:45:25 +0800 Subject: [PATCH 1/9] save --- simdjson-sys/build.rs | 1 + simdjson-sys/src/simdjson_c_api.cpp | 18 +++++++ simdjson-sys/src/simdjson_c_api.h | 74 +++++++++++++++++++++++++++++ src/dom/element.rs | 16 +++++++ src/dom/mod.rs | 2 + src/dom/parser.rs | 38 +++++++++++++++ src/lib.rs | 1 + src/macros.rs | 28 +++++++++++ 8 files changed, 178 insertions(+) create mode 100644 src/dom/element.rs create mode 100644 src/dom/mod.rs create mode 100644 src/dom/parser.rs diff --git a/simdjson-sys/build.rs b/simdjson-sys/build.rs index 1470318..60d00e4 100644 --- a/simdjson-sys/build.rs +++ b/simdjson-sys/build.rs @@ -7,6 +7,7 @@ fn main() { .flag_if_supported("/std:c++17") .flag_if_supported("-pthread") .flag_if_supported("-O3") + .flag("-DNDEBUG") .include("simdjson/singleheader") .file("src/simdjson_c_api.cpp") .file("simdjson/singleheader/simdjson.cpp") diff --git a/simdjson-sys/src/simdjson_c_api.cpp b/simdjson-sys/src/simdjson_c_api.cpp index 77a3f71..3645b8e 100644 --- a/simdjson-sys/src/simdjson_c_api.cpp +++ b/simdjson-sys/src/simdjson_c_api.cpp @@ -287,4 +287,22 @@ IMPL_GET_PRIMITIVE(SJ_OD_number, ondemand::number, double, get_double) int SJ_OD_number_get_number_type(SJ_OD_number *self) { return static_cast( reinterpret_cast(self)->get_number_type()); +} + +// New macros for dom +#define IMPL_HANDLE(name, type) \ + void name##_free(name *r) { delete reinterpret_cast(r); } \ + type *cast_ptr(name *r) { return reinterpret_cast(r); } + +IMPL_HANDLE(SJ_DOM_parser, dom::parser) + +SJ_DOM_parser *SJ_DOM_parser_new(size_t max_capacity) { + return object_to_pointer(dom::parser(max_capacity)); +} + +SJ_DOM_element_result SJ_DOM_parser_parse(SJ_DOM_parser *parser, + const char *json, size_t len) { + auto result = cast_ptr(parser)->parse(json, len, false); + return {static_cast(result.error()), + object_to_pointer(std::move(result.value()))}; } \ No newline at end of file diff --git a/simdjson-sys/src/simdjson_c_api.h b/simdjson-sys/src/simdjson_c_api.h index 4110a5b..d370991 100644 --- a/simdjson-sys/src/simdjson_c_api.h +++ b/simdjson-sys/src/simdjson_c_api.h @@ -169,6 +169,80 @@ DEFINE_GET_PRIMITIVE(SJ_OD_number, uint64_t, get_uint64) DEFINE_GET_PRIMITIVE(SJ_OD_number, int64_t, get_int64) DEFINE_GET_PRIMITIVE(SJ_OD_number, double, get_double) +// New macros for dom + +#define DEFINE_HANDLE(name) \ + typedef struct name name; \ + void name##_free(name *r); + +#define DEFINE_HANDLE_RESULT(name) \ + typedef struct name##_result { \ + int error; \ + name *value; \ + } name##_result; + +#define DEFINE_PRIMITIVE_RESULT(name) \ + typedef struct SJ_##name##_result { \ + int error; \ + name value; \ + } name##_result; + +#define DEFINE_GET_V2(self, value, method) value self##_##method(self *r); + +DEFINE_HANDLE(SJ_DOM_parser) + +DEFINE_HANDLE(SJ_DOM_element) +DEFINE_HANDLE_RESULT(SJ_DOM_element) +DEFINE_HANDLE(SJ_DOM_array) +DEFINE_HANDLE_RESULT(SJ_DOM_array) +DEFINE_HANDLE(SJ_DOM_object) +DEFINE_HANDLE_RESULT(SJ_DOM_object) + +DEFINE_PRIMITIVE_RESULT(uint64_t) +DEFINE_PRIMITIVE_RESULT(int64_t) +DEFINE_PRIMITIVE_RESULT(double) +DEFINE_PRIMITIVE_RESULT(bool) +DEFINE_PRIMITIVE_RESULT(size_t) +DEFINE_PRIMITIVE_RESULT(int) + +typedef struct SJ_string_view { + const char *data; + size_t len; +} SJ_string_view; + +typedef struct SJ_string_view_result { + int error; + SJ_string_view value; +} SJ_string_view_result; + +typedef struct SJ_DOM_key_value_pair { + SJ_string_view key; + SJ_DOM_element *value; +} SJ_DOM_key_value_pair; + +typedef struct SJ_DOM_key_value_pair_result { + int error; + SJ_DOM_key_value_pair value; +} SJ_DOM_key_value_pair_result; + +// dom::parser +SJ_DOM_parser *SJ_DOM_parser_new(size_t max_capacity); +SJ_DOM_element_result SJ_DOM_parser_parse(SJ_DOM_parser *parser, + const char *json, size_t len); + +// dom::element +DEFINE_GET_V2(SJ_DOM_element, int, type) +DEFINE_GET_V2(SJ_DOM_element, SJ_DOM_array_result, get_array) +DEFINE_GET_V2(SJ_DOM_element, SJ_DOM_object_result, get_object) +DEFINE_GET_V2(SJ_DOM_element, SJ_string_view_result, get_string) +DEFINE_GET_V2(SJ_DOM_element, SJ_int64_t_result, get_int64) +DEFINE_GET_V2(SJ_DOM_element, SJ_uint64_t_result, get_uint64) +DEFINE_GET_V2(SJ_DOM_element, SJ_double_result, get_double) +DEFINE_GET_V2(SJ_DOM_element, SJ_bool_result, get_bool) + +// dom::array + + #ifdef __cplusplus } #endif diff --git a/src/dom/element.rs b/src/dom/element.rs new file mode 100644 index 0000000..812cf92 --- /dev/null +++ b/src/dom/element.rs @@ -0,0 +1,16 @@ +use simdjson_sys as ffi; +use std::ptr::NonNull; + +use crate::macros::impl_drop; + +pub struct Element { + ptr: NonNull, +} + +impl Element { + pub fn new(ptr: NonNull) -> Self { + Self { ptr } + } +} + +impl_drop!(Element, ffi::SJ_DOM_element_free); diff --git a/src/dom/mod.rs b/src/dom/mod.rs new file mode 100644 index 0000000..5c1f668 --- /dev/null +++ b/src/dom/mod.rs @@ -0,0 +1,2 @@ +mod element; +mod parser; diff --git a/src/dom/parser.rs b/src/dom/parser.rs new file mode 100644 index 0000000..cb86438 --- /dev/null +++ b/src/dom/parser.rs @@ -0,0 +1,38 @@ +use std::ptr::NonNull; + +use simdjson_sys as ffi; + +use crate::{ + macros::{impl_drop, map_ptr_result}, + Result, +}; + +use super::element::Element; + +pub struct Parser { + ptr: NonNull, +} + +impl Default for Parser { + fn default() -> Self { + Self::new(ffi::SIMDJSON_MAXSIZE_BYTES) + } +} + +impl Parser { + pub fn new(max_capacity: usize) -> Self { + let ptr = unsafe { NonNull::new_unchecked(ffi::SJ_DOM_parser_new(max_capacity)) }; + Self { ptr } + } + + pub fn parse(&mut self, padded_string: &String) -> Result { + map_ptr_result!(ffi::SJ_DOM_parser_parse( + self.ptr.as_ptr(), + padded_string.as_ptr().cast(), + padded_string.len() + )) + .map(Element::new) + } +} + +impl_drop!(Parser, ffi::SJ_DOM_parser_free); diff --git a/src/lib.rs b/src/lib.rs index e84303a..bdf072e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ mod macros; +pub mod dom; mod error; pub mod ondemand; pub mod padded_string; diff --git a/src/macros.rs b/src/macros.rs index a05a3f7..9090b5f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -44,5 +44,33 @@ macro_rules! map_result { }; } +macro_rules! map_ptr_result { + ($call:expr) => { + unsafe { + let res = $call; + if res.error == 0 { + Ok(std::ptr::NonNull::new_unchecked(res.value)) + } else { + Err(crate::error::SimdJsonError::from(res.error)) + } + } + }; +} + +macro_rules! map_primitive_result { + ($call:expr) => { + unsafe { + let res = $call; + if res.error == 0 { + Ok(res.value) + } else { + Err(crate::error::SimdJsonError::from(res.error)) + } + } + }; +} + pub(crate) use impl_drop; +pub(crate) use map_primitive_result; +pub(crate) use map_ptr_result; pub(crate) use map_result; From 36f9539a2d245dc572360a701b618446af90bff4 Mon Sep 17 00:00:00 2001 From: SunDoge <384813529@qq.com> Date: Fri, 25 Aug 2023 21:47:24 +0800 Subject: [PATCH 2/9] fix compile --- simdjson-sys/src/simdjson_c_api.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/simdjson-sys/src/simdjson_c_api.h b/simdjson-sys/src/simdjson_c_api.h index d370991..b99cd0d 100644 --- a/simdjson-sys/src/simdjson_c_api.h +++ b/simdjson-sys/src/simdjson_c_api.h @@ -181,11 +181,12 @@ DEFINE_GET_PRIMITIVE(SJ_OD_number, double, get_double) name *value; \ } name##_result; -#define DEFINE_PRIMITIVE_RESULT(name) \ +// Add prefix SJ_ so we can use allowlist. +#define DEFINE_PRIMITIVE_RESULT_V2(name) \ typedef struct SJ_##name##_result { \ int error; \ name value; \ - } name##_result; + } SJ_##name##_result; #define DEFINE_GET_V2(self, value, method) value self##_##method(self *r); @@ -198,12 +199,12 @@ DEFINE_HANDLE_RESULT(SJ_DOM_array) DEFINE_HANDLE(SJ_DOM_object) DEFINE_HANDLE_RESULT(SJ_DOM_object) -DEFINE_PRIMITIVE_RESULT(uint64_t) -DEFINE_PRIMITIVE_RESULT(int64_t) -DEFINE_PRIMITIVE_RESULT(double) -DEFINE_PRIMITIVE_RESULT(bool) -DEFINE_PRIMITIVE_RESULT(size_t) -DEFINE_PRIMITIVE_RESULT(int) +DEFINE_PRIMITIVE_RESULT_V2(uint64_t) +DEFINE_PRIMITIVE_RESULT_V2(int64_t) +DEFINE_PRIMITIVE_RESULT_V2(double) +DEFINE_PRIMITIVE_RESULT_V2(bool) +DEFINE_PRIMITIVE_RESULT_V2(size_t) +DEFINE_PRIMITIVE_RESULT_V2(int) typedef struct SJ_string_view { const char *data; @@ -242,7 +243,6 @@ DEFINE_GET_V2(SJ_DOM_element, SJ_bool_result, get_bool) // dom::array - #ifdef __cplusplus } #endif From 76cfc835101a7654b2ae41947ab4fddc5ab28e4d Mon Sep 17 00:00:00 2001 From: SunDoge <384813529@qq.com> Date: Sat, 26 Aug 2023 00:09:47 +0800 Subject: [PATCH 3/9] add dom api --- examples/simple.rs | 8 ++ simdjson-sys/src/simdjson_c_api.cpp | 151 +++++++++++++++++++++++++++- simdjson-sys/src/simdjson_c_api.h | 41 +++++++- src/dom/array.rs | 103 +++++++++++++++++++ src/dom/element.rs | 78 +++++++++++++- src/dom/mod.rs | 7 ++ src/dom/object.rs | 77 ++++++++++++++ src/utils.rs | 8 ++ 8 files changed, 463 insertions(+), 10 deletions(-) create mode 100644 src/dom/array.rs create mode 100644 src/dom/object.rs diff --git a/examples/simple.rs b/examples/simple.rs index 6c6a4e5..816c8a5 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -8,5 +8,13 @@ fn main() -> simdjson_rust::Result<()> { for (index, value) in array.iter()?.enumerate() { assert_eq!(index as u64, value?.get_uint64()?); } + + let mut dom_parser = simdjson_rust::dom::Parser::default(); + let elem = dom_parser.parse(&ps)?; + let arr = elem.get_array()?; + for (index, value) in arr.iter().enumerate() { + assert_eq!(index as u64, value.get_uint64()?); + } + Ok(()) } diff --git a/simdjson-sys/src/simdjson_c_api.cpp b/simdjson-sys/src/simdjson_c_api.cpp index 3645b8e..2a276fe 100644 --- a/simdjson-sys/src/simdjson_c_api.cpp +++ b/simdjson-sys/src/simdjson_c_api.cpp @@ -292,17 +292,160 @@ int SJ_OD_number_get_number_type(SJ_OD_number *self) { // New macros for dom #define IMPL_HANDLE(name, type) \ void name##_free(name *r) { delete reinterpret_cast(r); } \ - type *cast_ptr(name *r) { return reinterpret_cast(r); } + type *cast_to_type(name *r) { return reinterpret_cast(r); } \ + name *move_to_handle(type &&r) { \ + return object_to_pointer(std::move(r)); \ + } IMPL_HANDLE(SJ_DOM_parser, dom::parser) +IMPL_HANDLE(SJ_DOM_array, dom::array) +IMPL_HANDLE(SJ_DOM_element, dom::element) +IMPL_HANDLE(SJ_DOM_object, dom::object) +IMPL_HANDLE(SJ_DOM_array_iterator, dom::array::iterator) +IMPL_HANDLE(SJ_DOM_object_iterator, dom::object::iterator) +// dom::parser SJ_DOM_parser *SJ_DOM_parser_new(size_t max_capacity) { return object_to_pointer(dom::parser(max_capacity)); } SJ_DOM_element_result SJ_DOM_parser_parse(SJ_DOM_parser *parser, const char *json, size_t len) { - auto result = cast_ptr(parser)->parse(json, len, false); - return {static_cast(result.error()), - object_to_pointer(std::move(result.value()))}; + dom::element value; + const auto error = reinterpret_cast(parser) + ->parse(json, len, false) + .get(value); // The string is padded, so false. + return {static_cast(error), move_to_handle(std::move(value))}; +} + +// dom::element +int SJ_DOM_element_type(SJ_DOM_element *self) { + return static_cast(reinterpret_cast(self)->type()); +} + +SJ_DOM_array_result SJ_DOM_element_get_array(SJ_DOM_element *self) { + dom::array res; + const error_code error = cast_to_type(self)->get_array().get(res); + return {static_cast(error), move_to_handle(std::move(res))}; +} +SJ_DOM_object_result SJ_DOM_element_get_object(SJ_DOM_element *self) { + dom::object res; + const error_code error = cast_to_type(self)->get_object().get(res); + return {static_cast(error), move_to_handle(std::move(res))}; +} + +SJ_string_view_result SJ_DOM_element_get_string(SJ_DOM_element *self) { + std::string_view res; + const error_code error = cast_to_type(self)->get_string().get(res); + return {static_cast(error), {.data = res.data(), .len = res.size()}}; +} + +SJ_uint64_t_result SJ_DOM_element_get_uint64(SJ_DOM_element *self) { + uint64_t res = 0; + const error_code error = cast_to_type(self)->get_uint64().get(res); + return {static_cast(error), res}; +} +SJ_int64_t_result SJ_DOM_element_get_int64(SJ_DOM_element *self) { + int64_t res = 0; + const error_code error = cast_to_type(self)->get_int64().get(res); + return {static_cast(error), res}; +} +SJ_double_result SJ_DOM_element_get_double(SJ_DOM_element *self) { + double res = 0.0; + const error_code error = cast_to_type(self)->get_double().get(res); + return {static_cast(error), res}; +} +SJ_DOM_element_result SJ_DOM_element_at_pointer(SJ_DOM_element *self, + const char *json, size_t len) { + dom::element res; + const error_code error = + cast_to_type(self)->at_pointer(std::string_view(json, len)).get(res); + return {static_cast(error), move_to_handle(std::move(res))}; +} + +// dom::array +SJ_DOM_array_iterator *SJ_DOM_array_begin(SJ_DOM_array *self) { + return move_to_handle(cast_to_type(self)->begin()); +} +SJ_DOM_array_iterator *SJ_DOM_array_end(SJ_DOM_array *self) { + return move_to_handle(cast_to_type(self)->end()); +} +size_t SJ_DOM_array_size(SJ_DOM_array *self) { + return cast_to_type(self)->size(); +} +size_t SJ_DOM_array_number_of_slots(SJ_DOM_array *self) { + return cast_to_type(self)->number_of_slots(); +} +SJ_DOM_element_result SJ_DOM_array_at(SJ_DOM_array *self, size_t index) { + dom::element res; + const error_code error = cast_to_type(self)->at(index).get(res); + return {static_cast(error), move_to_handle(std::move(res))}; +} +SJ_DOM_element_result SJ_DOM_array_at_pointer(SJ_DOM_array *self, + const char *json, size_t len) { + dom::element res; + const error_code error = + cast_to_type(self)->at_pointer(std::string_view(json, len)).get(res); + return {static_cast(error), move_to_handle(std::move(res))}; +} + +// dom::array::iterator +SJ_DOM_element *SJ_DOM_array_iterator_get(SJ_DOM_array_iterator *self) { + return move_to_handle(**cast_to_type(self)); +} +bool SJ_DOM_array_iterator_not_equal(SJ_DOM_array_iterator *lhs, + SJ_DOM_array_iterator *rhs) { + return *cast_to_type(lhs) != *cast_to_type(rhs); +} +void SJ_DOM_array_iterator_step(SJ_DOM_array_iterator *self) { + ++(*cast_to_type(self)); +} + +// dom::object +SJ_DOM_object_iterator *SJ_DOM_object_begin(SJ_DOM_object *self) { + return move_to_handle(cast_to_type(self)->begin()); +} +SJ_DOM_object_iterator *SJ_DOM_object_end(SJ_DOM_object *self) { + return move_to_handle(cast_to_type(self)->end()); +} +size_t SJ_DOM_object_size(SJ_DOM_object *self) { + return cast_to_type(self)->size(); +} +SJ_DOM_element_result SJ_DOM_object_at_pointer(SJ_DOM_object *self, + const char *json, size_t len) { + dom::element res; + const error_code error = + cast_to_type(self)->at_pointer(std::string_view(json, len)).get(res); + return {static_cast(error), move_to_handle(std::move(res))}; +} +SJ_DOM_element_result SJ_DOM_object_at_key(SJ_DOM_object *self, + const char *json, size_t len) { + dom::element res; + const error_code error = + cast_to_type(self)->at_key(std::string_view(json, len)).get(res); + return {static_cast(error), move_to_handle(std::move(res))}; +} +SJ_DOM_element_result SJ_DOM_object_at_key_case_insensitive(SJ_DOM_object *self, + const char *json, + size_t len) { + dom::element res; + const error_code error = + cast_to_type(self) + ->at_key_case_insensitive(std::string_view(json, len)) + .get(res); + return {static_cast(error), move_to_handle(std::move(res))}; +} + +// dom::object::iterator +SJ_DOM_key_value_pair SJ_DOM_object_iterator_get(SJ_DOM_object_iterator *self) { + dom::key_value_pair pair = **cast_to_type(self); + return {.key = {.data = pair.key.data(), .len = pair.key.size()}, + .value = move_to_handle(std::move(pair.value))}; +} +bool SJ_DOM_object_iterator_not_equal(SJ_DOM_object_iterator *lhs, + SJ_DOM_object_iterator *rhs) { + return *cast_to_type(lhs) != *cast_to_type(rhs); +} +void SJ_DOM_object_iterator_step(SJ_DOM_object_iterator *self) { + ++(*cast_to_type(self)); } \ No newline at end of file diff --git a/simdjson-sys/src/simdjson_c_api.h b/simdjson-sys/src/simdjson_c_api.h index b99cd0d..81c3ca7 100644 --- a/simdjson-sys/src/simdjson_c_api.h +++ b/simdjson-sys/src/simdjson_c_api.h @@ -198,6 +198,8 @@ DEFINE_HANDLE(SJ_DOM_array) DEFINE_HANDLE_RESULT(SJ_DOM_array) DEFINE_HANDLE(SJ_DOM_object) DEFINE_HANDLE_RESULT(SJ_DOM_object) +DEFINE_HANDLE(SJ_DOM_array_iterator) +DEFINE_HANDLE(SJ_DOM_object_iterator) DEFINE_PRIMITIVE_RESULT_V2(uint64_t) DEFINE_PRIMITIVE_RESULT_V2(int64_t) @@ -221,11 +223,6 @@ typedef struct SJ_DOM_key_value_pair { SJ_DOM_element *value; } SJ_DOM_key_value_pair; -typedef struct SJ_DOM_key_value_pair_result { - int error; - SJ_DOM_key_value_pair value; -} SJ_DOM_key_value_pair_result; - // dom::parser SJ_DOM_parser *SJ_DOM_parser_new(size_t max_capacity); SJ_DOM_element_result SJ_DOM_parser_parse(SJ_DOM_parser *parser, @@ -240,8 +237,42 @@ DEFINE_GET_V2(SJ_DOM_element, SJ_int64_t_result, get_int64) DEFINE_GET_V2(SJ_DOM_element, SJ_uint64_t_result, get_uint64) DEFINE_GET_V2(SJ_DOM_element, SJ_double_result, get_double) DEFINE_GET_V2(SJ_DOM_element, SJ_bool_result, get_bool) +SJ_DOM_element_result SJ_DOM_element_at_pointer(SJ_DOM_element *element, + const char *s, size_t len); // dom::array +DEFINE_GET_V2(SJ_DOM_array, SJ_DOM_array_iterator *, begin) +DEFINE_GET_V2(SJ_DOM_array, SJ_DOM_array_iterator *, end) +DEFINE_GET_V2(SJ_DOM_array, size_t, size) +DEFINE_GET_V2(SJ_DOM_array, size_t, number_of_slots) + +SJ_DOM_element_result SJ_DOM_array_at(SJ_DOM_array *array, size_t index); +SJ_DOM_element_result SJ_DOM_array_at_pointer(SJ_DOM_array *array, + const char *s, size_t len); + +// dom::object +DEFINE_GET_V2(SJ_DOM_object, SJ_DOM_object_iterator *, begin) +DEFINE_GET_V2(SJ_DOM_object, SJ_DOM_object_iterator *, end) +DEFINE_GET_V2(SJ_DOM_object, size_t, size) + +SJ_DOM_element_result SJ_DOM_object_at_pointer(SJ_DOM_object *object, + const char *s, size_t len); +SJ_DOM_element_result SJ_DOM_object_at_key(SJ_DOM_object *object, const char *s, + size_t len); +SJ_DOM_element_result +SJ_DOM_object_at_key_case_insensitive(SJ_DOM_object *object, const char *s, + size_t len); + +// dom::iterator +DEFINE_GET_V2(SJ_DOM_array_iterator, SJ_DOM_element *, get) +DEFINE_GET_V2(SJ_DOM_array_iterator, void, step) +bool SJ_DOM_array_iterator_not_equal(SJ_DOM_array_iterator *lhs, + SJ_DOM_array_iterator *rhs); + +DEFINE_GET_V2(SJ_DOM_object_iterator, SJ_DOM_key_value_pair, get) +DEFINE_GET_V2(SJ_DOM_object_iterator, void, step) +bool SJ_DOM_object_iterator_not_equal(SJ_DOM_object_iterator *lhs, + SJ_DOM_object_iterator *rhs); #ifdef __cplusplus } diff --git a/src/dom/array.rs b/src/dom/array.rs new file mode 100644 index 0000000..7cde669 --- /dev/null +++ b/src/dom/array.rs @@ -0,0 +1,103 @@ +use crate::macros::{impl_drop, map_ptr_result}; +use simdjson_sys as ffi; +use std::ptr::NonNull; + +use super::element::Element; +use crate::Result; + +pub struct Array { + ptr: NonNull, +} + +impl Array { + pub fn new(ptr: NonNull) -> Self { + Self { ptr } + } + + pub fn iter(&self) -> ArrayIter { + let begin = unsafe { NonNull::new_unchecked(ffi::SJ_DOM_array_begin(self.ptr.as_ptr())) }; + let end = unsafe { NonNull::new_unchecked(ffi::SJ_DOM_array_end(self.ptr.as_ptr())) }; + ArrayIter::new(begin, end) + } + + pub fn size(&self) -> usize { + unsafe { ffi::SJ_DOM_array_size(self.ptr.as_ptr()) } + } + + pub fn number_of_slots(&self) -> usize { + unsafe { ffi::SJ_DOM_array_number_of_slots(self.ptr.as_ptr()) } + } + + pub fn at_pointer(&self, json_pointer: &str) -> Result { + map_ptr_result!(ffi::SJ_DOM_array_at_pointer( + self.ptr.as_ptr(), + json_pointer.as_ptr().cast(), + json_pointer.len() + )) + .map(Element::new) + } + + pub fn at(&self, index: usize) -> Result { + map_ptr_result!(ffi::SJ_DOM_array_at(self.ptr.as_ptr(), index)).map(Element::new) + } +} + +impl_drop!(Array, ffi::SJ_DOM_array_free); + +pub struct ArrayIter { + begin: NonNull, + end: NonNull, + running: bool, +} + +impl ArrayIter { + pub fn new( + begin: NonNull, + end: NonNull, + ) -> Self { + Self { + begin, + end, + running: false, + } + } + + pub fn get(&self) -> Element { + let ptr = unsafe { ffi::SJ_DOM_array_iterator_get(self.begin.as_ptr()) }; + Element::new(unsafe { NonNull::new_unchecked(ptr) }) + } + + pub fn step(&mut self) { + unsafe { ffi::SJ_DOM_array_iterator_step(self.begin.as_ptr()) } + } + + pub fn not_equal(&self) -> bool { + unsafe { ffi::SJ_DOM_array_iterator_not_equal(self.begin.as_ptr(), self.end.as_ptr()) } + } +} + +impl Drop for ArrayIter { + fn drop(&mut self) { + unsafe { + ffi::SJ_DOM_array_iterator_free(self.begin.as_ptr()); + ffi::SJ_DOM_array_iterator_free(self.end.as_ptr()); + } + } +} + +impl Iterator for ArrayIter { + type Item = Element; + + fn next(&mut self) -> Option { + if self.running { + self.step(); + } + + if self.not_equal() { + self.running = true; + Some(self.get()) + } else { + None + } + } +} diff --git a/src/dom/element.rs b/src/dom/element.rs index 812cf92..d4de08c 100644 --- a/src/dom/element.rs +++ b/src/dom/element.rs @@ -1,7 +1,41 @@ use simdjson_sys as ffi; use std::ptr::NonNull; -use crate::macros::impl_drop; +use crate::{ + macros::{impl_drop, map_primitive_result, map_ptr_result}, + utils::string_view_struct_to_str, + Result, +}; + +use super::{array::Array, object::Object}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ElementType { + Array = '[' as _, + Object = '{' as _, + Int64 = 'l' as _, + UInt64 = 'u' as _, + Double = 'd' as _, + String = '"' as _, + Bool = 't' as _, + NullValue = 'n' as _, +} + +impl From for ElementType { + fn from(value: i32) -> Self { + match value as u8 as char { + '[' => Self::Array, + '{' => Self::Object, + 'l' => Self::Int64, + 'u' => Self::UInt64, + 'd' => Self::Double, + '"' => Self::String, + 't' => Self::Bool, + 'n' => Self::NullValue, + _ => unreachable!(), + } + } +} pub struct Element { ptr: NonNull, @@ -11,6 +45,48 @@ impl Element { pub fn new(ptr: NonNull) -> Self { Self { ptr } } + + pub fn get_type(&self) -> ElementType { + unsafe { ElementType::from(ffi::SJ_DOM_element_type(self.ptr.as_ptr())) } + } + + pub fn get_array(&self) -> Result { + map_ptr_result!(ffi::SJ_DOM_element_get_array(self.ptr.as_ptr())).map(Array::new) + } + + pub fn get_object(&self) -> Result { + map_ptr_result!(ffi::SJ_DOM_element_get_object(self.ptr.as_ptr())).map(Object::new) + } + + pub fn get_string(&self) -> Result<&str> { + map_primitive_result!(ffi::SJ_DOM_element_get_string(self.ptr.as_ptr())) + .map(|sv| string_view_struct_to_str(sv)) + } + + pub fn get_int64(&self) -> Result { + map_primitive_result!(ffi::SJ_DOM_element_get_int64(self.ptr.as_ptr())) + } + + pub fn get_uint64(&self) -> Result { + map_primitive_result!(ffi::SJ_DOM_element_get_uint64(self.ptr.as_ptr())) + } + + pub fn get_double(&self) -> Result { + map_primitive_result!(ffi::SJ_DOM_element_get_double(self.ptr.as_ptr())) + } + + pub fn get_bool(&self) -> Result { + map_primitive_result!(ffi::SJ_DOM_element_get_bool(self.ptr.as_ptr())) + } + + pub fn at_pointer(&self, json_pointer: &str) -> Result { + map_ptr_result!(ffi::SJ_DOM_element_at_pointer( + self.ptr.as_ptr(), + json_pointer.as_ptr().cast(), + json_pointer.len() + )) + .map(Element::new) + } } impl_drop!(Element, ffi::SJ_DOM_element_free); diff --git a/src/dom/mod.rs b/src/dom/mod.rs index 5c1f668..3bf9adf 100644 --- a/src/dom/mod.rs +++ b/src/dom/mod.rs @@ -1,2 +1,9 @@ +mod array; mod element; +mod object; mod parser; + +pub use array::Array; +pub use element::{Element, ElementType}; +pub use object::Object; +pub use parser::Parser; diff --git a/src/dom/object.rs b/src/dom/object.rs new file mode 100644 index 0000000..d63a42d --- /dev/null +++ b/src/dom/object.rs @@ -0,0 +1,77 @@ +use crate::{macros::impl_drop, utils::string_view_struct_to_str}; +use simdjson_sys as ffi; +use std::ptr::NonNull; + +use super::Element; + +pub struct Object { + ptr: NonNull, +} + +impl Object { + pub fn new(ptr: NonNull) -> Self { + Self { ptr } + } +} + +pub struct ObjectIter { + begin: NonNull, + end: NonNull, + running: bool, +} + +impl ObjectIter { + pub fn new( + begin: NonNull, + end: NonNull, + ) -> Self { + Self { + begin, + end, + running: false, + } + } + + pub fn get(&self) -> (&'static str, Element) { + let kv = unsafe { ffi::SJ_DOM_object_iterator_get(self.begin.as_ptr()) }; + let key = string_view_struct_to_str(kv.key); + let value = Element::new(unsafe { NonNull::new_unchecked(kv.value) }); + (key, value) + } + + pub fn step(&mut self) { + unsafe { ffi::SJ_DOM_object_iterator_step(self.begin.as_ptr()) } + } + + pub fn not_equal(&self) -> bool { + unsafe { ffi::SJ_DOM_object_iterator_not_equal(self.begin.as_ptr(), self.end.as_ptr()) } + } +} + +impl Drop for ObjectIter { + fn drop(&mut self) { + unsafe { + ffi::SJ_DOM_object_iterator_free(self.begin.as_ptr()); + ffi::SJ_DOM_object_iterator_free(self.end.as_ptr()); + } + } +} + +impl Iterator for ObjectIter { + type Item = (&'static str, Element); + + fn next(&mut self) -> Option { + if self.running { + self.step(); + } + + if self.not_equal() { + self.running = true; + Some(self.get()) + } else { + None + } + } +} + +impl_drop!(Object, ffi::SJ_DOM_object_free); diff --git a/src/utils.rs b/src/utils.rs index 9845465..6e667d1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -14,3 +14,11 @@ pub fn string_view_to_str<'a>(sv: NonNull) -> &'a str { unsafe { ffi::STD_string_view_free(sv.as_ptr()) }; s } + +#[inline] +pub fn string_view_struct_to_str<'a>(sv: ffi::SJ_string_view) -> &'a str { + unsafe { + let s = std::slice::from_raw_parts(sv.data.cast(), sv.len); + std::str::from_utf8_unchecked(s) + } +} From 7a7e454562cc156b69fc8d32f9470e422c0cce2c Mon Sep 17 00:00:00 2001 From: SunDoge <384813529@qq.com> Date: Sat, 26 Aug 2023 00:42:01 +0800 Subject: [PATCH 4/9] liftetime should tie to document --- src/dom/array.rs | 41 +++++++++++++++++++++++++---------------- src/dom/document.rs | 1 + src/dom/element.rs | 34 +++++++++++++++++++--------------- src/dom/mod.rs | 1 + src/dom/object.rs | 33 ++++++++++++++++++++------------- src/dom/parser.rs | 3 +-- 6 files changed, 67 insertions(+), 46 deletions(-) create mode 100644 src/dom/document.rs diff --git a/src/dom/array.rs b/src/dom/array.rs index 7cde669..3379ed8 100644 --- a/src/dom/array.rs +++ b/src/dom/array.rs @@ -1,17 +1,24 @@ -use crate::macros::{impl_drop, map_ptr_result}; +use std::{marker::PhantomData, ptr::NonNull}; + use simdjson_sys as ffi; -use std::ptr::NonNull; -use super::element::Element; -use crate::Result; +use super::{element::Element, Parser}; +use crate::{ + macros::{impl_drop, map_ptr_result}, + Result, +}; -pub struct Array { +pub struct Array<'a> { ptr: NonNull, + _parser: PhantomData<&'a Parser>, } -impl Array { +impl<'a> Array<'a> { pub fn new(ptr: NonNull) -> Self { - Self { ptr } + Self { + ptr, + _parser: PhantomData, + } } pub fn iter(&self) -> ArrayIter { @@ -28,7 +35,7 @@ impl Array { unsafe { ffi::SJ_DOM_array_number_of_slots(self.ptr.as_ptr()) } } - pub fn at_pointer(&self, json_pointer: &str) -> Result { + pub fn at_pointer(&self, json_pointer: &str) -> Result> { map_ptr_result!(ffi::SJ_DOM_array_at_pointer( self.ptr.as_ptr(), json_pointer.as_ptr().cast(), @@ -37,20 +44,21 @@ impl Array { .map(Element::new) } - pub fn at(&self, index: usize) -> Result { + pub fn at(&self, index: usize) -> Result> { map_ptr_result!(ffi::SJ_DOM_array_at(self.ptr.as_ptr(), index)).map(Element::new) } } -impl_drop!(Array, ffi::SJ_DOM_array_free); +impl_drop!(Array<'a>, ffi::SJ_DOM_array_free); -pub struct ArrayIter { +pub struct ArrayIter<'a> { begin: NonNull, end: NonNull, running: bool, + _parser: PhantomData<&'a Parser>, } -impl ArrayIter { +impl<'a> ArrayIter<'a> { pub fn new( begin: NonNull, end: NonNull, @@ -59,10 +67,11 @@ impl ArrayIter { begin, end, running: false, + _parser: PhantomData, } } - pub fn get(&self) -> Element { + pub fn get(&self) -> Element<'a> { let ptr = unsafe { ffi::SJ_DOM_array_iterator_get(self.begin.as_ptr()) }; Element::new(unsafe { NonNull::new_unchecked(ptr) }) } @@ -76,7 +85,7 @@ impl ArrayIter { } } -impl Drop for ArrayIter { +impl<'a> Drop for ArrayIter<'a> { fn drop(&mut self) { unsafe { ffi::SJ_DOM_array_iterator_free(self.begin.as_ptr()); @@ -85,8 +94,8 @@ impl Drop for ArrayIter { } } -impl Iterator for ArrayIter { - type Item = Element; +impl<'a> Iterator for ArrayIter<'a> { + type Item = Element<'a>; fn next(&mut self) -> Option { if self.running { diff --git a/src/dom/document.rs b/src/dom/document.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/dom/document.rs @@ -0,0 +1 @@ + diff --git a/src/dom/element.rs b/src/dom/element.rs index d4de08c..80d71f8 100644 --- a/src/dom/element.rs +++ b/src/dom/element.rs @@ -1,23 +1,23 @@ +use std::{marker::PhantomData, ptr::NonNull}; + use simdjson_sys as ffi; -use std::ptr::NonNull; +use super::{array::Array, object::Object, Parser}; use crate::{ macros::{impl_drop, map_primitive_result, map_ptr_result}, utils::string_view_struct_to_str, Result, }; -use super::{array::Array, object::Object}; - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ElementType { - Array = '[' as _, - Object = '{' as _, - Int64 = 'l' as _, - UInt64 = 'u' as _, - Double = 'd' as _, - String = '"' as _, - Bool = 't' as _, + Array = '[' as _, + Object = '{' as _, + Int64 = 'l' as _, + UInt64 = 'u' as _, + Double = 'd' as _, + String = '"' as _, + Bool = 't' as _, NullValue = 'n' as _, } @@ -37,13 +37,17 @@ impl From for ElementType { } } -pub struct Element { +pub struct Element<'a> { ptr: NonNull, + _parser: PhantomData<&'a Parser>, } -impl Element { +impl<'a> Element<'a> { pub fn new(ptr: NonNull) -> Self { - Self { ptr } + Self { + ptr, + _parser: PhantomData, + } } pub fn get_type(&self) -> ElementType { @@ -58,7 +62,7 @@ impl Element { map_ptr_result!(ffi::SJ_DOM_element_get_object(self.ptr.as_ptr())).map(Object::new) } - pub fn get_string(&self) -> Result<&str> { + pub fn get_string(&self) -> Result<&'a str> { map_primitive_result!(ffi::SJ_DOM_element_get_string(self.ptr.as_ptr())) .map(|sv| string_view_struct_to_str(sv)) } @@ -89,4 +93,4 @@ impl Element { } } -impl_drop!(Element, ffi::SJ_DOM_element_free); +impl_drop!(Element<'a>, ffi::SJ_DOM_element_free); diff --git a/src/dom/mod.rs b/src/dom/mod.rs index 3bf9adf..eaf25fa 100644 --- a/src/dom/mod.rs +++ b/src/dom/mod.rs @@ -1,4 +1,5 @@ mod array; +mod document; mod element; mod object; mod parser; diff --git a/src/dom/object.rs b/src/dom/object.rs index d63a42d..7e7e258 100644 --- a/src/dom/object.rs +++ b/src/dom/object.rs @@ -1,26 +1,32 @@ -use crate::{macros::impl_drop, utils::string_view_struct_to_str}; +use std::{marker::PhantomData, ptr::NonNull}; + use simdjson_sys as ffi; -use std::ptr::NonNull; -use super::Element; +use super::{Element, Parser}; +use crate::{macros::impl_drop, utils::string_view_struct_to_str}; -pub struct Object { +pub struct Object<'a> { ptr: NonNull, + _parser: PhantomData<&'a Parser>, } -impl Object { +impl<'a> Object<'a> { pub fn new(ptr: NonNull) -> Self { - Self { ptr } + Self { + ptr, + _parser: PhantomData, + } } } -pub struct ObjectIter { +pub struct ObjectIter<'a> { begin: NonNull, end: NonNull, running: bool, + _parser: PhantomData<&'a Parser>, } -impl ObjectIter { +impl<'a> ObjectIter<'a> { pub fn new( begin: NonNull, end: NonNull, @@ -29,10 +35,11 @@ impl ObjectIter { begin, end, running: false, + _parser: PhantomData, } } - pub fn get(&self) -> (&'static str, Element) { + pub fn get(&self) -> (&'a str, Element<'a>) { let kv = unsafe { ffi::SJ_DOM_object_iterator_get(self.begin.as_ptr()) }; let key = string_view_struct_to_str(kv.key); let value = Element::new(unsafe { NonNull::new_unchecked(kv.value) }); @@ -48,7 +55,7 @@ impl ObjectIter { } } -impl Drop for ObjectIter { +impl<'a> Drop for ObjectIter<'a> { fn drop(&mut self) { unsafe { ffi::SJ_DOM_object_iterator_free(self.begin.as_ptr()); @@ -57,8 +64,8 @@ impl Drop for ObjectIter { } } -impl Iterator for ObjectIter { - type Item = (&'static str, Element); +impl<'a> Iterator for ObjectIter<'a> { + type Item = (&'a str, Element<'a>); fn next(&mut self) -> Option { if self.running { @@ -74,4 +81,4 @@ impl Iterator for ObjectIter { } } -impl_drop!(Object, ffi::SJ_DOM_object_free); +impl_drop!(Object<'a>, ffi::SJ_DOM_object_free); diff --git a/src/dom/parser.rs b/src/dom/parser.rs index cb86438..59e5bbf 100644 --- a/src/dom/parser.rs +++ b/src/dom/parser.rs @@ -2,13 +2,12 @@ use std::ptr::NonNull; use simdjson_sys as ffi; +use super::element::Element; use crate::{ macros::{impl_drop, map_ptr_result}, Result, }; -use super::element::Element; - pub struct Parser { ptr: NonNull, } From c07b292330425ba0a8e26cc29064145ba88ffac9 Mon Sep 17 00:00:00 2001 From: SunDoge <384813529@qq.com> Date: Sat, 26 Aug 2023 09:58:33 +0800 Subject: [PATCH 5/9] update dom api --- simdjson-sys/src/lib.rs | 1 + simdjson-sys/src/simdjson_c_api.cpp | 69 ++++++++++++++++++++++- simdjson-sys/src/simdjson_c_api.h | 23 ++++++++ src/dom/array.rs | 10 ++-- src/dom/document.rs | 29 ++++++++++ src/dom/document_stream.rs | 85 +++++++++++++++++++++++++++++ src/dom/element.rs | 20 +++---- src/dom/mod.rs | 1 + src/dom/object.rs | 10 ++-- src/dom/parser.rs | 35 +++++++++++- 10 files changed, 259 insertions(+), 24 deletions(-) create mode 100644 src/dom/document_stream.rs diff --git a/simdjson-sys/src/lib.rs b/simdjson-sys/src/lib.rs index 343ac7a..705b3b1 100644 --- a/simdjson-sys/src/lib.rs +++ b/simdjson-sys/src/lib.rs @@ -6,3 +6,4 @@ include!(concat!(env!("OUT_DIR"), "/bindings.rs")); pub const SIMDJSON_PADDING: usize = 64; pub const SIMDJSON_MAXSIZE_BYTES: usize = 0xFFFFFFFF; +pub const DEFAULT_BATCH_SIZE: usize = 1000000; diff --git a/simdjson-sys/src/simdjson_c_api.cpp b/simdjson-sys/src/simdjson_c_api.cpp index 2a276fe..d57f8ef 100644 --- a/simdjson-sys/src/simdjson_c_api.cpp +++ b/simdjson-sys/src/simdjson_c_api.cpp @@ -12,6 +12,14 @@ template inline U object_to_pointer(T &&t) { return reinterpret_cast(new T(std::move(t))); } +// template +// auto simdjson_result_to_struct(simdjson_result &&sr) { +// T value; +// const error_code error = std::move(sr).get(value); +// return {static_cast(error), +// reinterpret_cast(new T(std::move(value)))}; +// } + // template // inline int enum_result_to_number_result(simdjson_result&& enum_result) { // T inner; @@ -292,8 +300,8 @@ int SJ_OD_number_get_number_type(SJ_OD_number *self) { // New macros for dom #define IMPL_HANDLE(name, type) \ void name##_free(name *r) { delete reinterpret_cast(r); } \ - type *cast_to_type(name *r) { return reinterpret_cast(r); } \ - name *move_to_handle(type &&r) { \ + inline type *cast_to_type(name *r) { return reinterpret_cast(r); } \ + inline name *move_to_handle(type &&r) { \ return object_to_pointer(std::move(r)); \ } @@ -303,6 +311,9 @@ IMPL_HANDLE(SJ_DOM_element, dom::element) IMPL_HANDLE(SJ_DOM_object, dom::object) IMPL_HANDLE(SJ_DOM_array_iterator, dom::array::iterator) IMPL_HANDLE(SJ_DOM_object_iterator, dom::object::iterator) +IMPL_HANDLE(SJ_DOM_document, dom::document) +IMPL_HANDLE(SJ_DOM_document_stream, dom::document_stream) +IMPL_HANDLE(SJ_DOM_document_stream_iterator, dom::document_stream::iterator) // dom::parser SJ_DOM_parser *SJ_DOM_parser_new(size_t max_capacity) { @@ -317,6 +328,26 @@ SJ_DOM_element_result SJ_DOM_parser_parse(SJ_DOM_parser *parser, .get(value); // The string is padded, so false. return {static_cast(error), move_to_handle(std::move(value))}; } +SJ_DOM_element_result SJ_DOM_parser_parse_into_document(SJ_DOM_parser *parser, + SJ_DOM_document *doc, + const char *json, + size_t len) { + dom::element value; + const auto error = cast_to_type(parser) + ->parse_into_document( + *reinterpret_cast(doc), json, len) + .get(value); + return {static_cast(error), move_to_handle(std::move(value))}; +} +SJ_DOM_document_stream_result SJ_DOM_parser_parse_many(SJ_DOM_parser *parser, + const char *json, + size_t len, + size_t batch_size) { + dom::document_stream value; + const auto error = + cast_to_type(parser)->parse_many(json, len, batch_size).get(value); + return {static_cast(error), move_to_handle(std::move(value))}; +} // dom::element int SJ_DOM_element_type(SJ_DOM_element *self) { @@ -448,4 +479,36 @@ bool SJ_DOM_object_iterator_not_equal(SJ_DOM_object_iterator *lhs, } void SJ_DOM_object_iterator_step(SJ_DOM_object_iterator *self) { ++(*cast_to_type(self)); -} \ No newline at end of file +} + +// dom::document +SJ_DOM_document *SJ_DOM_document_new() { + return object_to_pointer(dom::document()); +} + +SJ_DOM_element *SJ_DOM_document_root(SJ_DOM_document *self) { + return move_to_handle(cast_to_type(self)->root()); +} +SJ_DOM_document_stream_iterator * +SJ_DOM_document_stream_begin(SJ_DOM_document_stream *self) { + return move_to_handle(cast_to_type(self)->begin()); +} +SJ_DOM_document_stream_iterator * +SJ_DOM_document_stream_end(SJ_DOM_document_stream *self) { + return move_to_handle(cast_to_type(self)->end()); +} +SJ_DOM_element_result +SJ_DOM_document_stream_iterator_get(SJ_DOM_document_stream_iterator *self) { + dom::element res; + const error_code error = cast_to_type(self)->operator*().get(res); + return {static_cast(error), move_to_handle(std::move(res))}; +} +void SJ_DOM_document_stream_iterator_step( + SJ_DOM_document_stream_iterator *self) { + ++(*cast_to_type(self)); +} +bool SJ_DOM_document_stream_iterator_not_equal( + SJ_DOM_document_stream_iterator *lhs, + SJ_DOM_document_stream_iterator *rhs) { + return *cast_to_type(lhs) != *cast_to_type(rhs); +} diff --git a/simdjson-sys/src/simdjson_c_api.h b/simdjson-sys/src/simdjson_c_api.h index 81c3ca7..fb0e1a7 100644 --- a/simdjson-sys/src/simdjson_c_api.h +++ b/simdjson-sys/src/simdjson_c_api.h @@ -200,6 +200,11 @@ DEFINE_HANDLE(SJ_DOM_object) DEFINE_HANDLE_RESULT(SJ_DOM_object) DEFINE_HANDLE(SJ_DOM_array_iterator) DEFINE_HANDLE(SJ_DOM_object_iterator) +DEFINE_HANDLE(SJ_DOM_document) +DEFINE_HANDLE_RESULT(SJ_DOM_document) +DEFINE_HANDLE(SJ_DOM_document_stream) +DEFINE_HANDLE_RESULT(SJ_DOM_document_stream) +DEFINE_HANDLE(SJ_DOM_document_stream_iterator) DEFINE_PRIMITIVE_RESULT_V2(uint64_t) DEFINE_PRIMITIVE_RESULT_V2(int64_t) @@ -227,6 +232,14 @@ typedef struct SJ_DOM_key_value_pair { SJ_DOM_parser *SJ_DOM_parser_new(size_t max_capacity); SJ_DOM_element_result SJ_DOM_parser_parse(SJ_DOM_parser *parser, const char *json, size_t len); +SJ_DOM_element_result SJ_DOM_parser_parse_into_document(SJ_DOM_parser *parser, + SJ_DOM_document *doc, + const char *json, + size_t len); +SJ_DOM_document_stream_result SJ_DOM_parser_parse_many(SJ_DOM_parser *parser, + const char *json, + size_t len, + size_t batch_size); // dom::element DEFINE_GET_V2(SJ_DOM_element, int, type) @@ -274,6 +287,16 @@ DEFINE_GET_V2(SJ_DOM_object_iterator, void, step) bool SJ_DOM_object_iterator_not_equal(SJ_DOM_object_iterator *lhs, SJ_DOM_object_iterator *rhs); +// dom::document +SJ_DOM_document *SJ_DOM_document_new(); +DEFINE_GET_V2(SJ_DOM_document, SJ_DOM_element *, root) +DEFINE_GET_V2(SJ_DOM_document_stream, SJ_DOM_document_stream_iterator *, begin) +DEFINE_GET_V2(SJ_DOM_document_stream, SJ_DOM_document_stream_iterator *, end) +DEFINE_GET_V2(SJ_DOM_document_stream_iterator, SJ_DOM_element_result, get) +DEFINE_GET_V2(SJ_DOM_document_stream_iterator, void, step) +bool SJ_DOM_document_stream_iterator_not_equal( + SJ_DOM_document_stream_iterator *lhs, SJ_DOM_document_stream_iterator *rhs); + #ifdef __cplusplus } #endif diff --git a/src/dom/array.rs b/src/dom/array.rs index 3379ed8..56d0d1c 100644 --- a/src/dom/array.rs +++ b/src/dom/array.rs @@ -2,7 +2,7 @@ use std::{marker::PhantomData, ptr::NonNull}; use simdjson_sys as ffi; -use super::{element::Element, Parser}; +use super::{document::Document, element::Element, Parser}; use crate::{ macros::{impl_drop, map_ptr_result}, Result, @@ -10,14 +10,14 @@ use crate::{ pub struct Array<'a> { ptr: NonNull, - _parser: PhantomData<&'a Parser>, + _doc: PhantomData<&'a Document>, } impl<'a> Array<'a> { pub fn new(ptr: NonNull) -> Self { Self { ptr, - _parser: PhantomData, + _doc: PhantomData, } } @@ -55,7 +55,7 @@ pub struct ArrayIter<'a> { begin: NonNull, end: NonNull, running: bool, - _parser: PhantomData<&'a Parser>, + _doc: PhantomData<&'a Document>, } impl<'a> ArrayIter<'a> { @@ -67,7 +67,7 @@ impl<'a> ArrayIter<'a> { begin, end, running: false, - _parser: PhantomData, + _doc: PhantomData, } } diff --git a/src/dom/document.rs b/src/dom/document.rs index 8b13789..b6b503c 100644 --- a/src/dom/document.rs +++ b/src/dom/document.rs @@ -1 +1,30 @@ +use std::{marker::PhantomData, ptr::NonNull}; +use simdjson_sys as ffi; + +use super::{Element, Parser}; +use crate::{macros::impl_drop, utils::string_view_struct_to_str}; + +pub struct Document { + ptr: NonNull, +} + +impl Document { + pub fn new() -> Self { + Self { + ptr: unsafe { NonNull::new_unchecked(ffi::SJ_DOM_document_new()) }, + } + } + + pub fn root(&self) -> Element<'_> { + Element::new(unsafe { + NonNull::new_unchecked(ffi::SJ_DOM_document_root(self.ptr.as_ptr())) + }) + } + + pub fn as_ptr(&self) -> *mut ffi::SJ_DOM_document { + self.ptr.as_ptr() + } +} + +impl_drop!(Document, ffi::SJ_DOM_document_free); diff --git a/src/dom/document_stream.rs b/src/dom/document_stream.rs new file mode 100644 index 0000000..66e5096 --- /dev/null +++ b/src/dom/document_stream.rs @@ -0,0 +1,85 @@ +use std::{marker::PhantomData, ptr::NonNull}; + +use simdjson_sys as ffi; + +use super::{Element, Parser}; +use crate::{ + macros::{impl_drop, map_ptr_result}, + utils::string_view_struct_to_str, + Result, +}; + +pub struct DocumentStream { + ptr: NonNull, +} + +impl DocumentStream { + pub fn new(ptr: NonNull) -> Self { + Self { ptr } + } + + pub fn iter(&self) -> DocumentStreamIter { + let begin = + unsafe { NonNull::new_unchecked(ffi::SJ_DOM_document_stream_begin(self.ptr.as_ptr())) }; + let end = + unsafe { NonNull::new_unchecked(ffi::SJ_DOM_document_stream_end(self.ptr.as_ptr())) }; + DocumentStreamIter::new(begin, end) + } +} + +impl_drop!(DocumentStream, ffi::SJ_DOM_document_stream_free); + +pub struct DocumentStreamIter<'a> { + begin: NonNull, + end: NonNull, + running: bool, + _parser: PhantomData<&'a DocumentStream>, +} + +impl<'a> DocumentStreamIter<'a> { + pub fn new( + begin: NonNull, + end: NonNull, + ) -> Self { + Self { + begin, + end, + running: false, + _parser: PhantomData, + } + } + + pub fn get(&self) -> Result> { + map_ptr_result!(ffi::SJ_DOM_document_stream_iterator_get( + self.begin.as_ptr() + )) + .map(Element::new) + } + + pub fn step(&mut self) { + unsafe { ffi::SJ_DOM_document_stream_iterator_step(self.begin.as_ptr()) } + } + + pub fn not_equal(&self) -> bool { + unsafe { + ffi::SJ_DOM_document_stream_iterator_not_equal(self.begin.as_ptr(), self.end.as_ptr()) + } + } +} + +impl<'a> Iterator for DocumentStreamIter<'a> { + type Item = Result>; + + fn next(&mut self) -> Option { + if self.running { + self.step(); + } + + if self.not_equal() { + self.running = true; + Some(self.get()) + } else { + None + } + } +} diff --git a/src/dom/element.rs b/src/dom/element.rs index 80d71f8..5d48d9f 100644 --- a/src/dom/element.rs +++ b/src/dom/element.rs @@ -2,7 +2,7 @@ use std::{marker::PhantomData, ptr::NonNull}; use simdjson_sys as ffi; -use super::{array::Array, object::Object, Parser}; +use super::{array::Array, document::Document, object::Object, Parser}; use crate::{ macros::{impl_drop, map_primitive_result, map_ptr_result}, utils::string_view_struct_to_str, @@ -11,13 +11,13 @@ use crate::{ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ElementType { - Array = '[' as _, - Object = '{' as _, - Int64 = 'l' as _, - UInt64 = 'u' as _, - Double = 'd' as _, - String = '"' as _, - Bool = 't' as _, + Array = '[' as _, + Object = '{' as _, + Int64 = 'l' as _, + UInt64 = 'u' as _, + Double = 'd' as _, + String = '"' as _, + Bool = 't' as _, NullValue = 'n' as _, } @@ -39,14 +39,14 @@ impl From for ElementType { pub struct Element<'a> { ptr: NonNull, - _parser: PhantomData<&'a Parser>, + _doc: PhantomData<&'a Document>, } impl<'a> Element<'a> { pub fn new(ptr: NonNull) -> Self { Self { ptr, - _parser: PhantomData, + _doc: PhantomData, } } diff --git a/src/dom/mod.rs b/src/dom/mod.rs index eaf25fa..4336a9f 100644 --- a/src/dom/mod.rs +++ b/src/dom/mod.rs @@ -1,5 +1,6 @@ mod array; mod document; +mod document_stream; mod element; mod object; mod parser; diff --git a/src/dom/object.rs b/src/dom/object.rs index 7e7e258..b2dbd4f 100644 --- a/src/dom/object.rs +++ b/src/dom/object.rs @@ -2,19 +2,19 @@ use std::{marker::PhantomData, ptr::NonNull}; use simdjson_sys as ffi; -use super::{Element, Parser}; +use super::{document::Document, Element, Parser}; use crate::{macros::impl_drop, utils::string_view_struct_to_str}; pub struct Object<'a> { ptr: NonNull, - _parser: PhantomData<&'a Parser>, + _doc: PhantomData<&'a Document>, } impl<'a> Object<'a> { pub fn new(ptr: NonNull) -> Self { Self { ptr, - _parser: PhantomData, + _doc: PhantomData, } } } @@ -23,7 +23,7 @@ pub struct ObjectIter<'a> { begin: NonNull, end: NonNull, running: bool, - _parser: PhantomData<&'a Parser>, + _doc: PhantomData<&'a Document>, } impl<'a> ObjectIter<'a> { @@ -35,7 +35,7 @@ impl<'a> ObjectIter<'a> { begin, end, running: false, - _parser: PhantomData, + _doc: PhantomData, } } diff --git a/src/dom/parser.rs b/src/dom/parser.rs index 59e5bbf..5f0a252 100644 --- a/src/dom/parser.rs +++ b/src/dom/parser.rs @@ -1,8 +1,9 @@ use std::ptr::NonNull; +use ffi::DEFAULT_BATCH_SIZE; use simdjson_sys as ffi; -use super::element::Element; +use super::{document::Document, document_stream::DocumentStream, element::Element}; use crate::{ macros::{impl_drop, map_ptr_result}, Result, @@ -32,6 +33,38 @@ impl Parser { )) .map(Element::new) } + + pub fn parse_into_document( + &mut self, + doc: &mut Document, + padded_string: &String, + ) -> Result { + map_ptr_result!(ffi::SJ_DOM_parser_parse_into_document( + self.ptr.as_ptr(), + doc.as_ptr(), + padded_string.as_ptr().cast(), + padded_string.len() + )) + .map(Element::new) + } + + pub fn parse_many(&mut self, padded_string: &String) -> Result { + self.parse_batch(padded_string, DEFAULT_BATCH_SIZE) + } + + pub fn parse_batch( + &mut self, + padded_string: &String, + batch_size: usize, + ) -> Result { + map_ptr_result!(ffi::SJ_DOM_parser_parse_many( + self.ptr.as_ptr(), + padded_string.as_ptr().cast(), + padded_string.len(), + batch_size + )) + .map(DocumentStream::new) + } } impl_drop!(Parser, ffi::SJ_DOM_parser_free); From 71dd4cc1f720008007b8c5caace5611bcd8699dc Mon Sep 17 00:00:00 2001 From: SunDoge <384813529@qq.com> Date: Sat, 26 Aug 2023 09:59:23 +0800 Subject: [PATCH 6/9] bump version --- Cargo.toml | 4 ++-- simdjson-sys/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 40bcbad..1d4ba67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,10 +17,10 @@ resolver = "2" members = ["simdjson-sys"] [workspace.package] -version = "0.3.0-alpha.1" +version = "0.3.0-alpha.2" [workspace.dependencies] -simdjson-sys = { path = "simdjson-sys", version = "0.1.0-alpha.1" } +simdjson-sys = { path = "simdjson-sys", version = "0.1.0-alpha.2" } [dependencies] diff --git a/simdjson-sys/Cargo.toml b/simdjson-sys/Cargo.toml index 1e05427..63efe30 100644 --- a/simdjson-sys/Cargo.toml +++ b/simdjson-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simdjson-sys" -version = "0.1.0-alpha.1" +version = "0.1.0-alpha.2" edition = "2021" authors = ["SunDoge <384813529@qq.com>"] license = "Apache-2.0" From 8bc4aa3a94d626dc4796175691305eb9b34648ae Mon Sep 17 00:00:00 2001 From: SunDoge <384813529@qq.com> Date: Sat, 26 Aug 2023 10:01:37 +0800 Subject: [PATCH 7/9] fix ci --- simdjson-sys/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simdjson-sys/build.rs b/simdjson-sys/build.rs index 60d00e4..da5b3ca 100644 --- a/simdjson-sys/build.rs +++ b/simdjson-sys/build.rs @@ -4,7 +4,7 @@ fn main() { cc::Build::new() .cpp(true) .flag_if_supported("-std=c++17") - .flag_if_supported("/std:c++17") + .flag_if_supported("/std:c++20") // error C7555: use of designated initializers requires at least '/std:c++20' .flag_if_supported("-pthread") .flag_if_supported("-O3") .flag("-DNDEBUG") From 3dfd5fba676bf97139286ef6d7d843c4eef508f4 Mon Sep 17 00:00:00 2001 From: SunDoge <384813529@qq.com> Date: Sat, 26 Aug 2023 10:46:08 +0800 Subject: [PATCH 8/9] update api --- README.md | 62 +++++++++++++++++++++++++++++++++++----- examples/simple.rs | 28 +++++++++++------- src/dom/mod.rs | 6 ++-- src/dom/parser.rs | 39 ++++++++++++++++++++++--- src/ondemand/document.rs | 1 + src/prelude.rs | 5 ++-- 6 files changed, 115 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 5183b5d..8741b70 100644 --- a/README.md +++ b/README.md @@ -20,22 +20,70 @@ Add this to your `Cargo.toml` ```toml # In the `[dependencies]` section -simdjson-rust = {git = "https://github.com/SunDoge/simdjson-rust"} +simdjson-rust = "0.3.0" ``` Then, get started. ```rust -use simdjson_rust::{ondemand::Parser, prelude::*}; +use simdjson_rust::prelude::*; +use simdjson_rust::{dom, ondemand}; fn main() -> simdjson_rust::Result<()> { - let mut parser = Parser::default(); let ps = make_padded_string("[0,1,2,3]"); - let mut doc = parser.iterate(&ps)?; - let mut array = doc.get_array()?; - for (index, value) in array.iter()?.enumerate() { - assert_eq!(index as u64, value?.get_uint64()?); + + // ondemand api. + { + let mut parser = ondemand::Parser::default(); + let mut doc = parser.iterate(&ps)?; + let mut array = doc.get_array()?; + for (index, value) in array.iter()?.enumerate() { + assert_eq!(index as u64, value?.get_uint64()?); + } + } + + // dom api. + { + let mut parser = dom::Parser::default(); + let elem = parser.parse(&ps)?; + let arr = elem.get_array()?; + for (index, value) in arr.iter().enumerate() { + assert_eq!(index as u64, value.get_uint64()?); + } } + + Ok(()) +} +``` + +### `dom` and `ondemand` + +`simdjson` now offer two kinds of API, `dom` and `ondemand`. +`dom` will parsed the whole string while `ondemand` only parse what you request. +Due to `ffi`, the overhead of `ondemand` API is relatively high. I have tested `lto` but it only improves a little :( + +Thus it is suggestted that + +- use `ondemand` if you only want to access a specific part of a large json, +- use `dom` if you want to parse the whole json. + + +### `padded_string` + +`simdjson` requires the input string to be padded. We must provide a string with `capacity = len + SIMDJSON_PADDING`. +We provide utils to do so. + +```rust +use simdjson_rust::prelude::*; + +fn main() -> simdjson_rust::Result<()> { + let ps = make_padded_string("[0,1,2,3]"); + let ps = "[0,1,2,3]".to_padded_string(); + // or reuse a buffer. + let unpadded = String::from("[1,2,3,4]"); + let ps = unpadded.into_padded_string(); + // or load from file. + let ps = load_padded_string("test.json")?; Ok(()) } ``` diff --git a/examples/simple.rs b/examples/simple.rs index 816c8a5..f6ddd5b 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,19 +1,27 @@ use simdjson_rust::prelude::*; +use simdjson_rust::{dom, ondemand}; fn main() -> simdjson_rust::Result<()> { - let mut parser = ondemand::Parser::default(); let ps = make_padded_string("[0,1,2,3]"); - let mut doc = parser.iterate(&ps)?; - let mut array = doc.get_array()?; - for (index, value) in array.iter()?.enumerate() { - assert_eq!(index as u64, value?.get_uint64()?); + + // ondemand api. + { + let mut parser = ondemand::Parser::default(); + let mut doc = parser.iterate(&ps)?; + let mut array = doc.get_array()?; + for (index, value) in array.iter()?.enumerate() { + assert_eq!(index as u64, value?.get_uint64()?); + } } - let mut dom_parser = simdjson_rust::dom::Parser::default(); - let elem = dom_parser.parse(&ps)?; - let arr = elem.get_array()?; - for (index, value) in arr.iter().enumerate() { - assert_eq!(index as u64, value.get_uint64()?); + // dom api. + { + let mut parser = dom::Parser::default(); + let elem = parser.parse(&ps)?; + let arr = elem.get_array()?; + for (index, value) in arr.iter().enumerate() { + assert_eq!(index as u64, value.get_uint64()?); + } } Ok(()) diff --git a/src/dom/mod.rs b/src/dom/mod.rs index 4336a9f..0b8da53 100644 --- a/src/dom/mod.rs +++ b/src/dom/mod.rs @@ -5,7 +5,9 @@ mod element; mod object; mod parser; -pub use array::Array; +pub use array::{Array, ArrayIter}; +pub use document::Document; +pub use document_stream::{DocumentStream, DocumentStreamIter}; pub use element::{Element, ElementType}; -pub use object::Object; +pub use object::{Object, ObjectIter}; pub use parser::Parser; diff --git a/src/dom/parser.rs b/src/dom/parser.rs index 5f0a252..7d5651b 100644 --- a/src/dom/parser.rs +++ b/src/dom/parser.rs @@ -34,11 +34,11 @@ impl Parser { .map(Element::new) } - pub fn parse_into_document( - &mut self, - doc: &mut Document, + pub fn parse_into_document<'d>( + &self, + doc: &'d mut Document, padded_string: &String, - ) -> Result { + ) -> Result> { map_ptr_result!(ffi::SJ_DOM_parser_parse_into_document( self.ptr.as_ptr(), doc.as_ptr(), @@ -68,3 +68,34 @@ impl Parser { } impl_drop!(Parser, ffi::SJ_DOM_parser_free); + +#[cfg(test)] +mod tests { + use super::*; + use crate::prelude::*; + + #[test] + fn parse() { + let ps = "1".to_padded_string(); + let mut parser = Parser::default(); + let elem = parser.parse(&ps).unwrap(); + assert_eq!(elem.get_uint64().unwrap(), 1); + } + + #[test] + fn parse_into_document() { + let ps = "[1,2,3]".to_padded_string(); + let parser = Parser::default(); + let mut doc = Document::new(); + let elem = parser.parse_into_document(&mut doc, &ps).unwrap(); + assert_eq!( + elem.get_array() + .unwrap() + .at(0) + .unwrap() + .get_uint64() + .unwrap(), + 1 + ); + } +} diff --git a/src/ondemand/document.rs b/src/ondemand/document.rs index 322dbb4..e1873a0 100644 --- a/src/ondemand/document.rs +++ b/src/ondemand/document.rs @@ -150,6 +150,7 @@ impl_drop!(Document<'p, 's>, ffi::SJ_OD_document_free); #[cfg(test)] mod tests { + use crate::ondemand; use crate::prelude::*; #[test] diff --git a/src/prelude.rs b/src/prelude.rs index 3ff7085..f519ca8 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,4 +1,3 @@ -pub use crate::{ - ondemand, - padded_string::{load_padded_string, make_padded_string, IntoPaddedString, ToPaddedString}, +pub use crate::padded_string::{ + load_padded_string, make_padded_string, IntoPaddedString, ToPaddedString, }; From 61c4c6c3dde0d457d67d704ea22235f0894b6ff6 Mon Sep 17 00:00:00 2001 From: SunDoge <384813529@qq.com> Date: Sat, 26 Aug 2023 10:48:34 +0800 Subject: [PATCH 9/9] clippy fix --- examples/simple.rs | 3 +-- src/dom/array.rs | 2 +- src/dom/document.rs | 16 +++++++++++----- src/dom/document_stream.rs | 3 +-- src/dom/element.rs | 18 +++++++++--------- src/dom/object.rs | 2 +- src/dom/parser.rs | 2 +- src/ondemand/document.rs | 7 +++---- 8 files changed, 28 insertions(+), 25 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index f6ddd5b..61160ef 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,5 +1,4 @@ -use simdjson_rust::prelude::*; -use simdjson_rust::{dom, ondemand}; +use simdjson_rust::{dom, ondemand, prelude::*}; fn main() -> simdjson_rust::Result<()> { let ps = make_padded_string("[0,1,2,3]"); diff --git a/src/dom/array.rs b/src/dom/array.rs index 56d0d1c..4cc50b3 100644 --- a/src/dom/array.rs +++ b/src/dom/array.rs @@ -2,7 +2,7 @@ use std::{marker::PhantomData, ptr::NonNull}; use simdjson_sys as ffi; -use super::{document::Document, element::Element, Parser}; +use super::{document::Document, element::Element}; use crate::{ macros::{impl_drop, map_ptr_result}, Result, diff --git a/src/dom/document.rs b/src/dom/document.rs index b6b503c..44f190c 100644 --- a/src/dom/document.rs +++ b/src/dom/document.rs @@ -1,20 +1,26 @@ -use std::{marker::PhantomData, ptr::NonNull}; +use std::ptr::NonNull; use simdjson_sys as ffi; -use super::{Element, Parser}; -use crate::{macros::impl_drop, utils::string_view_struct_to_str}; +use super::Element; +use crate::macros::impl_drop; pub struct Document { ptr: NonNull, } -impl Document { - pub fn new() -> Self { +impl Default for Document { + fn default() -> Self { Self { ptr: unsafe { NonNull::new_unchecked(ffi::SJ_DOM_document_new()) }, } } +} + +impl Document { + pub fn new(ptr: NonNull) -> Self { + Self { ptr } + } pub fn root(&self) -> Element<'_> { Element::new(unsafe { diff --git a/src/dom/document_stream.rs b/src/dom/document_stream.rs index 66e5096..b326847 100644 --- a/src/dom/document_stream.rs +++ b/src/dom/document_stream.rs @@ -2,10 +2,9 @@ use std::{marker::PhantomData, ptr::NonNull}; use simdjson_sys as ffi; -use super::{Element, Parser}; +use super::Element; use crate::{ macros::{impl_drop, map_ptr_result}, - utils::string_view_struct_to_str, Result, }; diff --git a/src/dom/element.rs b/src/dom/element.rs index 5d48d9f..15beade 100644 --- a/src/dom/element.rs +++ b/src/dom/element.rs @@ -2,7 +2,7 @@ use std::{marker::PhantomData, ptr::NonNull}; use simdjson_sys as ffi; -use super::{array::Array, document::Document, object::Object, Parser}; +use super::{array::Array, document::Document, object::Object}; use crate::{ macros::{impl_drop, map_primitive_result, map_ptr_result}, utils::string_view_struct_to_str, @@ -11,13 +11,13 @@ use crate::{ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ElementType { - Array = '[' as _, - Object = '{' as _, - Int64 = 'l' as _, - UInt64 = 'u' as _, - Double = 'd' as _, - String = '"' as _, - Bool = 't' as _, + Array = '[' as _, + Object = '{' as _, + Int64 = 'l' as _, + UInt64 = 'u' as _, + Double = 'd' as _, + String = '"' as _, + Bool = 't' as _, NullValue = 'n' as _, } @@ -64,7 +64,7 @@ impl<'a> Element<'a> { pub fn get_string(&self) -> Result<&'a str> { map_primitive_result!(ffi::SJ_DOM_element_get_string(self.ptr.as_ptr())) - .map(|sv| string_view_struct_to_str(sv)) + .map(string_view_struct_to_str) } pub fn get_int64(&self) -> Result { diff --git a/src/dom/object.rs b/src/dom/object.rs index b2dbd4f..871a717 100644 --- a/src/dom/object.rs +++ b/src/dom/object.rs @@ -2,7 +2,7 @@ use std::{marker::PhantomData, ptr::NonNull}; use simdjson_sys as ffi; -use super::{document::Document, Element, Parser}; +use super::{document::Document, Element}; use crate::{macros::impl_drop, utils::string_view_struct_to_str}; pub struct Object<'a> { diff --git a/src/dom/parser.rs b/src/dom/parser.rs index 7d5651b..8b8baa0 100644 --- a/src/dom/parser.rs +++ b/src/dom/parser.rs @@ -86,7 +86,7 @@ mod tests { fn parse_into_document() { let ps = "[1,2,3]".to_padded_string(); let parser = Parser::default(); - let mut doc = Document::new(); + let mut doc = Document::default(); let elem = parser.parse_into_document(&mut doc, &ps).unwrap(); assert_eq!( elem.get_array() diff --git a/src/ondemand/document.rs b/src/ondemand/document.rs index e1873a0..9953d87 100644 --- a/src/ondemand/document.rs +++ b/src/ondemand/document.rs @@ -150,8 +150,7 @@ impl_drop!(Document<'p, 's>, ffi::SJ_OD_document_free); #[cfg(test)] mod tests { - use crate::ondemand; - use crate::prelude::*; + use crate::{ondemand, prelude::*}; #[test] fn get_bool() { @@ -160,12 +159,12 @@ mod tests { { let json = "true".to_padded_string(); let mut doc = parser.iterate(&json).unwrap(); - assert_eq!(doc.get_bool().unwrap(), true); + assert!(doc.get_bool().unwrap()); } { let json = "false".to_padded_string(); let mut doc = parser.iterate(&json).unwrap(); - assert_eq!(doc.get_bool().unwrap(), false); + assert!(!doc.get_bool().unwrap()); } { let json = "1".to_padded_string();