diff --git a/Cargo.lock b/Cargo.lock index e774d739..420e6f8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,9 +18,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -131,9 +131,9 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "borrow-or-share" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" +checksum = "dc0b364ead1874514c8c2855ab558056ebfeb775653e7ae45ff72f28f8f3166c" [[package]] name = "bstr" @@ -165,9 +165,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.43" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "shlex", @@ -231,9 +231,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -241,9 +241,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -260,7 +260,7 @@ dependencies = [ "heck", "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -373,7 +373,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -543,9 +543,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -556,9 +556,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -569,11 +569,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -584,42 +583,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -738,9 +733,9 @@ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -982,9 +977,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -1124,7 +1119,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1242,7 +1237,7 @@ checksum = "d2ee4885492bb655bfa05d039cd9163eb8fe9f79ddebf00ca23a1637510c2fd2" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1284,7 +1279,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1362,9 +1357,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.108" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", @@ -1379,7 +1374,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1411,14 +1406,14 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -1460,9 +1455,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-xid" @@ -1586,7 +1581,7 @@ dependencies = [ "bumpalo", "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", "wasm-bindgen-shared", ] @@ -1639,7 +1634,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1650,7 +1645,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1777,9 +1772,9 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xtask" @@ -1794,11 +1789,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -1806,13 +1800,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", "synstructure", ] @@ -1833,7 +1827,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1853,15 +1847,15 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", "synstructure", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -1870,9 +1864,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -1881,11 +1875,11 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2 1.0.103", "quote 1.0.41", - "syn 2.0.108", + "syn 2.0.109", ] diff --git a/bindings/cpp/CMakeLists.txt b/bindings/cpp/CMakeLists.txt index df81fca4..f7d5a9af 100644 --- a/bindings/cpp/CMakeLists.txt +++ b/bindings/cpp/CMakeLists.txt @@ -52,6 +52,7 @@ INTERFACE set(regorus_ffi_HEADER_FILES regorus.hpp + regorus_value.hpp ../ffi/regorus.ffi.hpp ) @@ -79,7 +80,15 @@ install(FILES DESTINATION ${regorus_ffi_CONFIGDIR} ) -# test binary +# test binaries add_executable(regorus_test main.cpp) target_link_libraries(regorus_test regorus_ffi::regorus_ffi) + +add_executable(test_value_cpp test_value.cpp) +target_include_directories(test_value_cpp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(test_value_cpp regorus_ffi::regorus_ffi) + +# Add tests to CTest +enable_testing() +add_test(NAME cpp_value_test COMMAND test_value_cpp) diff --git a/bindings/cpp/main.cpp b/bindings/cpp/main.cpp index 2596d1c7..5184ec15 100644 --- a/bindings/cpp/main.cpp +++ b/bindings/cpp/main.cpp @@ -8,9 +8,9 @@ void example() engine.set_rego_v0(true); engine.set_enable_coverage(true); - + // Add policies. - engine.add_policy("objects.rego",R"(package objects + engine.add_policy("objects.rego", R"(package objects rect := {`width`: 2, "height": 4} cube := {"width": 3, `height`: 4, "depth": 5} @@ -65,67 +65,158 @@ f := e["dev"])"); // Eval query. auto result = engine.eval_query("[data.one, input.b, data.objects.sites[1]] = x"); - if (result) { - std::cout<" << std::endl; + } + } + } + + std::cout << "\n✓ Successfully navigated nested array/object structure using Value API" << std::endl; + } + + std::cout << "\n✓ Value API demo completed successfully!" << std::endl; } diff --git a/bindings/cpp/regorus.hpp b/bindings/cpp/regorus.hpp index 6a81dcc4..8e1046b3 100644 --- a/bindings/cpp/regorus.hpp +++ b/bindings/cpp/regorus.hpp @@ -5,120 +5,199 @@ #include #include "regorus.ffi.hpp" +#include "regorus_value.hpp" -namespace regorus { - - class Result { - public: - - operator bool() const { return result.status == RegorusStatus::Ok; } - bool operator !() const { return result.status != RegorusStatus::Ok; } - - const char* output() const { - if (*this && result.output) { - return result.output; - } else { - return ""; - } - } - - const char* error() const { - if (!*this && result.error_message) { - return result.error_message; - } else { - return ""; - } - } - - ~Result() { - regorus_result_drop(result); - } - - private: - friend class Engine; - RegorusResult result; - - Result(RegorusResult r) : result(r) {} - private: - Result(const Result&) = delete; - Result(Result&&) = delete; - Result& operator=(const Result&) = delete; - - }; - - class Engine { - public: - Engine() : Engine(regorus_engine_new()) {} - - std::unique_ptr clone() const { - return std::unique_ptr(new Engine(regorus_engine_clone(engine))); - } - - Result set_rego_v0(bool enable) { - return Result(regorus_engine_set_rego_v0(engine, enable)); - } - - Result add_policy(const char* path, const char* policy) { - return Result(regorus_engine_add_policy(engine, path, policy)); - } - - Result add_policy_from_file(const char* path) { - return Result(regorus_engine_add_policy_from_file(engine, path)); - } - - Result add_data_json(const char* data) { - return Result(regorus_engine_add_data_json(engine, data)); - } - - Result add_data_from_json_file(const char* path) { - return Result(regorus_engine_add_data_from_json_file(engine, path)); - } - - Result set_input_json(const char* input) { - return Result(regorus_engine_set_input_json(engine, input)); - } - - Result set_input_from_json_file(const char* path) { - return Result(regorus_engine_set_input_from_json_file(engine, path)); - } - - Result eval_query(const char* query) { - return Result(regorus_engine_eval_query(engine, query)); - } - - Result eval_rule(const char* rule) { - return Result(regorus_engine_eval_rule(engine, rule)); - } - - Result set_enable_coverage(bool enable) { - return Result(regorus_engine_set_enable_coverage(engine, enable)); - } - - Result clear_coverage_data() { - return Result(regorus_engine_clear_coverage_data(engine)); - } - - Result get_coverage_report() { - return Result(regorus_engine_get_coverage_report(engine)); - } - - Result get_coverage_report_pretty() { - return Result(regorus_engine_get_coverage_report_pretty(engine)); - } - - ~Engine() { - regorus_engine_drop(engine); - } - - - private: - RegorusEngine* engine; - private: - Engine(RegorusEngine* e) : engine(e) {} - Engine(const Engine&) = delete; - Engine(Engine&&) = delete; - Engine& operator=(const Engine&) = delete; - }; +namespace regorus +{ + + class Result + { + public: + operator bool() const { return result.status == RegorusStatus::Ok; } + bool operator!() const { return result.status != RegorusStatus::Ok; } + + const char *output() const + { + if (*this && result.output) + { + return result.output; + } + else + { + return ""; + } + } + + const char *error() const + { + if (!*this && result.error_message) + { + return result.error_message; + } + else + { + return ""; + } + } + + int64_t integer() const + { + if (*this) + { + return result.int_value; + } + else + { + return 0; + } + } + + Value value() const + { + if (*this && result.pointer_value) + { + // Clone the value directly without JSON conversion + auto clone_result = regorus_value_clone(result.pointer_value); + if (clone_result.status == RegorusStatus::Ok) + { + void *ptr = clone_result.pointer_value; + clone_result.pointer_value = nullptr; // Transfer ownership + regorus_result_drop(clone_result); + return Value(ptr); + } + regorus_result_drop(clone_result); + } + return Value::Null(); + } + ~Result() + { + regorus_result_drop(result); + } + + private: + friend class Engine; + RegorusResult result; + + Result(RegorusResult r) : result(r) {} + + private: + Result(const Result &) = delete; + Result(Result &&) = delete; + Result &operator=(const Result &) = delete; + }; + + class Engine + { + public: + Engine() : Engine(regorus_engine_new()) {} + + std::unique_ptr clone() const + { + return std::unique_ptr(new Engine(regorus_engine_clone(engine))); + } + + Result set_rego_v0(bool enable) + { + return Result(regorus_engine_set_rego_v0(engine, enable)); + } + + Result add_policy(const char *path, const char *policy) + { + return Result(regorus_engine_add_policy(engine, path, policy)); + } + + Result add_policy_from_file(const char *path) + { + return Result(regorus_engine_add_policy_from_file(engine, path)); + } + + Result add_data_json(const char *data) + { + return Result(regorus_engine_add_data_json(engine, data)); + } + + Result add_data_from_json_file(const char *path) + { + return Result(regorus_engine_add_data_from_json_file(engine, path)); + } + + Result set_input_json(const char *input) + { + return Result(regorus_engine_set_input_json(engine, input)); + } + + Result set_input_from_json_file(const char *path) + { + return Result(regorus_engine_set_input_from_json_file(engine, path)); + } + + Result eval_query(const char *query) + { + return Result(regorus_engine_eval_query(engine, query)); + } + + Result eval_rule(const char *rule) + { + return Result(regorus_engine_eval_rule(engine, rule)); + } + + // Value API methods - work with Value objects directly instead of JSON + Result set_input_value(const Value &value) + { + auto result = regorus_engine_set_input_value(engine, value.get_ptr()); + return Result(result); + } + + Result add_data_value(const Value &value) + { + auto result = regorus_engine_add_data_value(engine, value.get_ptr()); + return Result(result); + } + + Result eval_query_as_value(const char *query) + { + return Result(regorus_engine_eval_query_as_value(engine, query)); + } + + Result eval_rule_as_value(const char *rule) + { + return Result(regorus_engine_eval_rule_as_value(engine, rule)); + } + + Result set_enable_coverage(bool enable) + { + return Result(regorus_engine_set_enable_coverage(engine, enable)); + } + + Result clear_coverage_data() + { + return Result(regorus_engine_clear_coverage_data(engine)); + } + + Result get_coverage_report() + { + return Result(regorus_engine_get_coverage_report(engine)); + } + + Result get_coverage_report_pretty() + { + return Result(regorus_engine_get_coverage_report_pretty(engine)); + } + + ~Engine() + { + regorus_engine_drop(engine); + } + + private: + RegorusEngine *engine; + + private: + Engine(RegorusEngine *e) : engine(e) {} + Engine(const Engine &) = delete; + Engine(Engine &&) = delete; + Engine &operator=(const Engine &) = delete; + }; } #endif // REGORUS_WRAPPER_HPP diff --git a/bindings/cpp/regorus_value.hpp b/bindings/cpp/regorus_value.hpp new file mode 100644 index 00000000..8ae7dbbc --- /dev/null +++ b/bindings/cpp/regorus_value.hpp @@ -0,0 +1,298 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include + +// Include the C FFI header +#include "regorus.ffi.hpp" + +namespace regorus +{ + + class RegorusException : public std::runtime_error + { + public: + explicit RegorusException(const std::string &message) + : std::runtime_error(message) {} + }; + + // RAII wrapper for regorus::Value + class Value + { + private: + void *ptr_; + + // Private constructor from raw pointer (used internally) + explicit Value(void *ptr) : ptr_(ptr) + { + if (!ptr) + { + throw RegorusException("Null value pointer"); + } + } + + // Friend class to allow Result to construct Values + friend class Result; + + // Helper to check result and extract pointer + static void *extract_pointer(RegorusResult result) + { + if (result.status != RegorusStatus::Ok) + { // 0 = Ok + std::string error = result.error_message ? result.error_message : "Unknown error"; + regorus_result_drop(result); + throw RegorusException(error); + } + void *ptr = result.pointer_value; + result.pointer_value = nullptr; // Transfer ownership + regorus_result_drop(result); + return ptr; + } + + // Helper to check result and extract string + static std::string extract_string(RegorusResult result) + { + if (result.status != RegorusStatus::Ok) + { + std::string error = result.error_message ? result.error_message : "Unknown error"; + regorus_result_drop(result); + throw RegorusException(error); + } + // Copy the string before dropping the result (which frees the C string) + std::string str = result.output ? result.output : ""; + regorus_result_drop(result); // This frees result.output + return str; + } + + // Helper to check result and extract bool + static bool extract_bool(RegorusResult result) + { + if (result.status != RegorusStatus::Ok) + { + std::string error = result.error_message ? result.error_message : "Unknown error"; + regorus_result_drop(result); + throw RegorusException(error); + } + bool value = result.bool_value; + regorus_result_drop(result); + return value; + } + + // Helper to check void result + static void check_result(RegorusResult result) + { + if (result.status != RegorusStatus::Ok) + { + std::string error = result.error_message ? result.error_message : "Unknown error"; + regorus_result_drop(result); + throw RegorusException(error); + } + regorus_result_drop(result); + } + + public: + // Get the raw pointer (for FFI usage) + void *get_ptr() const { return ptr_; } + + // Factory methods for creating values + static Value Null() + { + return Value(extract_pointer(regorus_value_create_null())); + } + + static Value Bool(bool value) + { + return Value(extract_pointer(regorus_value_create_bool(value))); + } + + static Value Int(int64_t value) + { + return Value(extract_pointer(regorus_value_create_int(value))); + } + + static Value Float(double value) + { + return Value(extract_pointer(regorus_value_create_float(value))); + } + + static Value String(const std::string &value) + { + return Value(extract_pointer(regorus_value_create_string(value.c_str()))); + } + + static Value Array() + { + return Value(extract_pointer(regorus_value_create_array())); + } + + static Value Object() + { + return Value(extract_pointer(regorus_value_create_object())); + } + + static Value Set() + { + return Value(extract_pointer(regorus_value_create_set())); + } + + static Value FromJson(const std::string &json) + { + return Value(extract_pointer(regorus_value_from_json(json.c_str()))); + } + + // Move constructor + Value(Value &&other) noexcept : ptr_(other.ptr_) + { + other.ptr_ = nullptr; + } + + // Move assignment + Value &operator=(Value &&other) noexcept + { + if (this != &other) + { + if (ptr_) + { + regorus_value_drop(ptr_); + } + ptr_ = other.ptr_; + other.ptr_ = nullptr; + } + return *this; + } + + // Disable copy (use Clone() explicitly) + Value(const Value &) = delete; + Value &operator=(const Value &) = delete; + + // Destructor - noexcept to prevent termination during stack unwinding + ~Value() noexcept + { + if (ptr_) + { + regorus_value_drop(ptr_); + } + } + + // Get raw pointer (for internal use) + void *get() const { return ptr_; } + + // Release ownership (returns raw pointer, caller must manage memory) + void *release() + { + void *p = ptr_; + ptr_ = nullptr; + return p; + } + + // Type checking - noexcept because const query methods should not throw + // Returns false on error rather than throwing + bool is_null() const noexcept + { + RegorusResult result = regorus_value_is_null(ptr_); + bool value = (result.status == RegorusStatus::Ok) ? result.bool_value : false; + regorus_result_drop(result); + return value; + } + + bool is_object() const noexcept + { + RegorusResult result = regorus_value_is_object(ptr_); + bool value = (result.status == RegorusStatus::Ok) ? result.bool_value : false; + regorus_result_drop(result); + return value; + } + + bool is_string() const noexcept + { + RegorusResult result = regorus_value_is_string(ptr_); + bool value = (result.status == RegorusStatus::Ok) ? result.bool_value : false; + regorus_result_drop(result); + return value; + } + + // Clone - creates a deep copy + Value clone() const + { + return Value(extract_pointer(regorus_value_clone(ptr_))); + } + + // JSON serialization + std::string to_json() const + { + return extract_string(regorus_value_to_json(ptr_)); + } + + // Object operations + void object_insert(const std::string &key, const Value &value) + { + check_result(regorus_value_object_insert(ptr_, key.c_str(), value.get())); + } + + Value object_get(const std::string &key) const + { + return Value(extract_pointer(regorus_value_object_get(ptr_, key.c_str()))); + } + + // Array operations + void array_push(const Value &value) + { + check_result(regorus_value_array_push(ptr_, value.get())); + } + + int64_t array_len() const + { + RegorusResult result = regorus_value_array_len(ptr_); + if (result.status != RegorusStatus::Ok) + { + std::string error = result.error_message ? result.error_message : "Unknown error"; + regorus_result_drop(result); + throw RegorusException(error); + } + int64_t len = result.int_value; + regorus_result_drop(result); + return len; + } + + Value array_get(int64_t index) const + { + return Value(extract_pointer(regorus_value_array_get(ptr_, index))); + } + + // Set operations + void set_insert(const Value &value) + { + check_result(regorus_value_set_insert(ptr_, value.get())); + } + + // Typed accessors + bool as_bool() const + { + return extract_bool(regorus_value_as_bool(ptr_)); + } + + int64_t as_i64() const + { + RegorusResult result = regorus_value_as_i64(ptr_); + if (result.status != RegorusStatus::Ok) + { + std::string error = result.error_message ? result.error_message : "Unknown error"; + regorus_result_drop(result); + throw RegorusException(error); + } + int64_t val = result.int_value; + regorus_result_drop(result); + return val; + } + + std::string as_string() const + { + return extract_string(regorus_value_as_string(ptr_)); + } + }; +} // namespace regorus diff --git a/bindings/cpp/test_value.cpp b/bindings/cpp/test_value.cpp new file mode 100644 index 00000000..7dac430c --- /dev/null +++ b/bindings/cpp/test_value.cpp @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include +#include +#include + +#include "regorus_value.hpp" + +using regorus::RegorusException; +using regorus::Value; + +namespace { + +void test_scalar_roundtrip() { + Value truthy = Value::Bool(true); + assert(truthy.as_bool()); + + Value answer = Value::Int(42); + assert(answer.as_i64() == 42); + + Value greeting = Value::String("hello"); + assert(greeting.is_string()); + assert(greeting.as_string() == "hello"); +} + +void test_object_access() { + Value obj = Value::Object(); + obj.object_insert("flag", Value::Bool(false)); + obj.object_insert("answer", Value::Int(42)); + + Value flag = obj.object_get("flag"); + Value answer = obj.object_get("answer"); + + assert(flag.as_bool() == false); + assert(answer.as_i64() == 42); + + // Mutations should not change JSON representation unexpectedly. + std::string json = obj.to_json(); + assert(json.find("flag") != std::string::npos); + assert(json.find("answer") != std::string::npos); +} + +void test_array_helpers() { + Value array = Value::FromJson(R"([1, 2, 3])"); + assert(array.array_len() == 3); + + Value first = array.array_get(0); + Value third = array.array_get(2); + + assert(first.as_i64() == 1); + assert(third.as_i64() == 3); +} + +void test_clone() { + Value original = Value::FromJson(R"({"nested": [true, false]})"); + Value copy = original.clone(); + + assert(original.to_json() == copy.to_json()); + assert(original.get_ptr() != copy.get_ptr()); +} + +} // namespace + +int main() { + try { + test_scalar_roundtrip(); + test_object_access(); + test_array_helpers(); + test_clone(); + } catch (const RegorusException& ex) { + std::cerr << "regorus exception: " << ex.what() << '\n'; + return 1; + } catch (const std::exception& ex) { + std::cerr << "unexpected std::exception: " << ex.what() << '\n'; + return 1; + } + + std::cout << "regorus_value.hpp smoke tests passed" << std::endl; + return 0; +} diff --git a/bindings/csharp/Regorus.Tests/Regorus.Tests.csproj b/bindings/csharp/Regorus.Tests/Regorus.Tests.csproj index 6130a909..d3ef12ad 100644 --- a/bindings/csharp/Regorus.Tests/Regorus.Tests.csproj +++ b/bindings/csharp/Regorus.Tests/Regorus.Tests.csproj @@ -4,7 +4,8 @@ net8.0 true - true + + false true @@ -22,6 +23,6 @@ - + \ No newline at end of file diff --git a/bindings/csharp/Regorus.Tests/RegorusTests.cs b/bindings/csharp/Regorus.Tests/RegorusTests.cs index e1480916..3fcd1265 100644 --- a/bindings/csharp/Regorus.Tests/RegorusTests.cs +++ b/bindings/csharp/Regorus.Tests/RegorusTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Linq; using System.Text.Json.Nodes; using Microsoft.VisualStudio.TestTools.UnitTesting; using Regorus; @@ -215,42 +216,142 @@ public void GetPolicyParameters_succeeds() Assert.AreEqual("b", parameters![0]["modifiers"][0]["name"].ToString()); } - [TestMethod] - public void SetInputJson_has_negligible_allocations_after_warmup() - { - using var engine = new Engine(); - const string payload = "{}"; - - // Warm up the engine and JIT to ensure subsequent measurements are representative. - for (int i = 0; i < 16; i++) + [TestMethod] + public void SetInputJson_has_negligible_allocations_after_warmup() { - engine.SetInputJson(payload); - } + using var engine = new Engine(); + const string payload = "{}"; - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); + // Warm up the engine and JIT to ensure subsequent measurements are representative. + for (int i = 0; i < 16; i++) + { + engine.SetInputJson(payload); + } - const int iterations = 256; - var before = GC.GetAllocatedBytesForCurrentThread(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); - for (int i = 0; i < iterations; i++) - { - engine.SetInputJson(payload); + const int iterations = 256; + var before = GC.GetAllocatedBytesForCurrentThread(); + + for (int i = 0; i < iterations; i++) + { + engine.SetInputJson(payload); + } + + var after = GC.GetAllocatedBytesForCurrentThread(); + var allocated = Math.Max(0, after - before); + var bytesPerOp = allocated / (double)iterations; + + // Runtime bookkeeping (delegate caches, GC write barriers) differs across platforms, so + // we measure bytes per call rather than absolute totals and allow a small budget. + // CI will flag regressions where marshalling starts allocating per invocation. + + // Allow a small budget for delegates and runtime bookkeeping while still flagging regressions. + Assert.IsTrue( + bytesPerOp <= 512, + $"Expected ≤512 B/op after warmup, but observed {bytesPerOp:F2} B/op (total {allocated} bytes)." + ); } - var after = GC.GetAllocatedBytesForCurrentThread(); - var allocated = Math.Max(0, after - before); - var bytesPerOp = allocated / (double)iterations; + [TestMethod] + public void Value_api_roundtrips_objects_and_bools() + { + using var engine = new Engine(); - // Runtime bookkeeping (delegate caches, GC write barriers) differs across platforms, so - // we measure bytes per call rather than absolute totals and allow a small budget. - // CI will flag regressions where marshalling starts allocating per invocation. + const string policy = """ +package value_test - // Allow a small budget for delegates and runtime bookkeeping while still flagging regressions. - Assert.IsTrue( - bytesPerOp <= 512, - $"Expected ≤512 B/op after warmup, but observed {bytesPerOp:F2} B/op (total {allocated} bytes)." - ); +allow := { + "matches": matches, + "details": { + "input_flag": input.flag, + "config_flag": data.config.flag } +} if { + matches := input.flag == data.config.flag +} +"""; + engine.AddPolicy("value_test.rego", policy); + + using var dataRoot = Value.Object(); + using var config = Value.Object(); + config.ObjectInsert("flag", Value.Bool(true)); + dataRoot.ObjectInsert("config", config); + engine.AddDataValue(dataRoot); + + using var input = Value.Object(); + input.ObjectInsert("flag", Value.Bool(true)); + engine.SetInputValue(input); + + using var result = engine.EvalRuleAsValue("data.value_test.allow"); + Assert.IsTrue(result.IsObject); + + using var matches = result.ObjectGet("matches"); + Assert.IsTrue(matches.AsBool()); + + using var details = result.ObjectGet("details"); + Assert.IsTrue(details.IsObject); + + using var inputFlag = details.ObjectGet("input_flag"); + Assert.IsTrue(inputFlag.AsBool()); + + using var configFlag = details.ObjectGet("config_flag"); + Assert.IsTrue(configFlag.AsBool()); + + // Convert the native structure back to json to assert no extra keys sneak in. + var json = JsonNode.Parse(result.ToJson())!; + Assert.IsTrue(json.AsObject().ContainsKey("matches")); + Assert.IsTrue(json.AsObject().ContainsKey("details")); + Assert.AreEqual(true, json["matches"]!.GetValue()); + + var detailsNode = json["details"]!.AsObject(); + CollectionAssert.AreEquivalent(new[] { "input_flag", "config_flag" }, detailsNode.Select(kvp => kvp.Key).ToArray()); + Assert.AreEqual(true, detailsNode["input_flag"]!.GetValue()); + Assert.AreEqual(true, detailsNode["config_flag"]!.GetValue()); + } + + [TestMethod] + public void Value_inputs_can_be_reused_across_engines() + { + const string policy = """ + package reuse + + allow := input.flag == data.config.enabled + """; + + using var sharedData = Value.Object(); + using var config = Value.Object(); + config.ObjectInsert("enabled", Value.Bool(true)); + sharedData.ObjectInsert("config", config); + Assert.IsTrue(sharedData.IsObject); + + using var sharedInput = Value.Object(); + sharedInput.ObjectInsert("flag", Value.Bool(true)); + Assert.IsTrue(sharedInput.IsObject); + + using var engineA = new Engine(); + using var engineB = new Engine(); + + engineA.AddPolicy("reuse.rego", policy); + engineB.AddPolicy("reuse.rego", policy); + + engineA.AddDataValue(sharedData); + engineB.AddDataValue(sharedData); + + engineA.SetInputValue(sharedInput); + engineB.SetInputValue(sharedInput); + + Assert.AreEqual("true", engineA.EvalRule("data.reuse.allow")); + Assert.AreEqual("true", engineB.EvalRule("data.reuse.allow")); + + // Value remains usable after being supplied to multiple engines. + Assert.IsTrue(sharedInput.IsObject); + using var flag = sharedInput.ObjectGet("flag"); + Assert.IsTrue(flag.AsBool()); + + using var dataClone = sharedData.Clone(); + Assert.IsTrue(dataClone.IsObject); + } } \ No newline at end of file diff --git a/bindings/csharp/Regorus/CompiledPolicy.cs b/bindings/csharp/Regorus/CompiledPolicy.cs index 266afac0..31c6cc44 100644 --- a/bindings/csharp/Regorus/CompiledPolicy.cs +++ b/bindings/csharp/Regorus/CompiledPolicy.cs @@ -24,10 +24,10 @@ namespace Regorus /// public unsafe sealed class CompiledPolicy : IDisposable { - private RegorusCompiledPolicyHandle? _handle; - private readonly ManualResetEventSlim _idleEvent = new(initialState: true); - private int _isDisposed; - private int _activeEvaluations; + private RegorusCompiledPolicyHandle? _handle; + private readonly ManualResetEventSlim _idleEvent = new(initialState: true); + private int _isDisposed; + private int _activeEvaluations; internal CompiledPolicy(RegorusCompiledPolicyHandle handle) { @@ -94,7 +94,7 @@ public PolicyInfo GetPolicyInfo() return CheckAndDropResult(Internal.API.regorus_compiled_policy_get_policy_info((Internal.RegorusCompiledPolicy*)policyPtr)); } }); - + if (string.IsNullOrEmpty(jsonResult)) { throw new Exception("Failed to get policy info: empty response"); @@ -106,8 +106,8 @@ public PolicyInfo GetPolicyInfo() { PropertyNameCaseInsensitive = true }; - - return JsonSerializer.Deserialize(jsonResult!, options) + + return JsonSerializer.Deserialize(jsonResult!, options) ?? throw new Exception("Failed to deserialize policy info"); } catch (JsonException ex) @@ -130,7 +130,7 @@ private void Dispose(bool disposing) if (handle != null) { _idleEvent.Wait(); - + handle.Dispose(); _handle = null; } diff --git a/bindings/csharp/Regorus/Compiler.cs b/bindings/csharp/Regorus/Compiler.cs index 3870bac3..481d01f7 100644 --- a/bindings/csharp/Regorus/Compiler.cs +++ b/bindings/csharp/Regorus/Compiler.cs @@ -172,26 +172,10 @@ public static CompiledPolicy CompilePolicyForTarget(string dataJson, IEnumerable private static CompiledPolicy GetCompiledPolicyResult(Internal.RegorusResult result) { - try - { - if (result.status != Internal.RegorusStatus.Ok) - { - var message = StringFromUTF8((IntPtr)result.error_message); - throw new Exception(message ?? "Unknown compilation error occurred"); - } - - if (result.data_type != Internal.RegorusDataType.Pointer || result.pointer_value == null) - { - throw new Exception("Expected compiled policy pointer but got different data type"); - } - - var handle = RegorusCompiledPolicyHandle.FromPointer((IntPtr)result.pointer_value); - return new CompiledPolicy(handle); - } - finally - { - Internal.API.regorus_result_drop(result); - } + // The helper takes ownership of the pointer and ensures the native result dropper does not free it. + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerCompiledPolicy); + var handle = RegorusCompiledPolicyHandle.FromPointer(pointer); + return new CompiledPolicy(handle); } } } diff --git a/bindings/csharp/Regorus/Engine.cs b/bindings/csharp/Regorus/Engine.cs index 2d8ed11c..12250ef5 100644 --- a/bindings/csharp/Regorus/Engine.cs +++ b/bindings/csharp/Regorus/Engine.cs @@ -158,6 +158,25 @@ public void AddDataJson(string data) } + public void AddDataValue(Value value) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + ThrowIfDisposed(); + value.WithHandle(valuePtr => + { + UseHandle(enginePtr => + { + var result = Regorus.Internal.API.regorus_engine_add_data_value((Regorus.Internal.RegorusEngine*)enginePtr, (void*)valuePtr); + NativeResult.EnsureSuccess(result); + }); + }); + } + + public void AddDataFromJsonFile(string path) { ThrowIfDisposed(); @@ -213,6 +232,25 @@ public void SetInputFromJsonFile(string path) }); } + + public void SetInputValue(Value value) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + ThrowIfDisposed(); + value.WithHandle(valuePtr => + { + UseHandle(enginePtr => + { + var result = Regorus.Internal.API.regorus_engine_set_input_value((Regorus.Internal.RegorusEngine*)enginePtr, (void*)valuePtr); + NativeResult.EnsureSuccess(result); + }); + }); + } + public string? EvalQuery(string query) { ThrowIfDisposed(); @@ -231,6 +269,20 @@ public void SetInputFromJsonFile(string path) }); } + public Value EvalQueryAsValue(string query) + { + ThrowIfDisposed(); + return Utf8Marshaller.WithUtf8(query, queryPtr => + { + return UseHandle(enginePtr => + { + var result = Regorus.Internal.API.regorus_engine_eval_query_as_value((Regorus.Internal.RegorusEngine*)enginePtr, (byte*)queryPtr); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return Value.FromHandle(pointer); + }); + }); + } + public string? EvalRule(string rule) { ThrowIfDisposed(); @@ -249,6 +301,20 @@ public void SetInputFromJsonFile(string path) }); } + public Value EvalRuleAsValue(string rule) + { + ThrowIfDisposed(); + return Utf8Marshaller.WithUtf8(rule, rulePtr => + { + return UseHandle(enginePtr => + { + var result = Regorus.Internal.API.regorus_engine_eval_rule_as_value((Regorus.Internal.RegorusEngine*)enginePtr, (byte*)rulePtr); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return Value.FromHandle(pointer); + }); + }); + } + public void SetEnableCoverage(bool enable) { ThrowIfDisposed(); diff --git a/bindings/csharp/Regorus/Internal/NativeHelpers.cs b/bindings/csharp/Regorus/Internal/NativeHelpers.cs new file mode 100644 index 00000000..3e7f239e --- /dev/null +++ b/bindings/csharp/Regorus/Internal/NativeHelpers.cs @@ -0,0 +1,293 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using Regorus; + +#nullable enable + +namespace Regorus.Internal +{ + internal static class NativeUtf8 + { + internal static byte[] GetNullTerminatedBytes(string value) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + // Append a null terminator as expected by the native layer. + var byteCount = Encoding.UTF8.GetByteCount(value); + var buffer = new byte[byteCount + 1]; + Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, 0); + buffer[buffer.Length - 1] = 0; + return buffer; + } + + internal static string? PtrToString(IntPtr ptr) + { + if (ptr == IntPtr.Zero) + { + return null; + } + +#if NETSTANDARD2_1 + return Marshal.PtrToStringUTF8(ptr); +#else + int length = 0; + while (Marshal.ReadByte(ptr, length) != 0) + { + length++; + } + + if (length == 0) + { + return string.Empty; + } + + var buffer = new byte[length]; + Marshal.Copy(ptr, buffer, 0, length); + return Encoding.UTF8.GetString(buffer); +#endif + } + } + + internal static unsafe class NativeResult + { + private static RegorusException BuildError(RegorusResult result) + { + var message = NativeUtf8.PtrToString(new IntPtr(result.error_message)); + return new RegorusException(message ?? "Regorus native call failed."); + } + + internal static void EnsureSuccess(RegorusResult result) + { + try + { + if (result.status != RegorusStatus.Ok) + { + throw BuildError(result); + } + } + finally + { + API.regorus_result_drop(result); + } + } + + internal static string? GetStringAndDrop(RegorusResult result) + { + try + { + if (result.status != RegorusStatus.Ok) + { + throw BuildError(result); + } + + return NativeUtf8.PtrToString(new IntPtr(result.output)); + } + finally + { + API.regorus_result_drop(result); + } + } + + internal static bool GetBoolAndDrop(RegorusResult result) + { + try + { + if (result.status != RegorusStatus.Ok) + { + throw BuildError(result); + } + + return result.bool_value; + } + finally + { + API.regorus_result_drop(result); + } + } + + internal static long GetInt64AndDrop(RegorusResult result) + { + try + { + if (result.status != RegorusStatus.Ok) + { + throw BuildError(result); + } + + return result.int_value; + } + finally + { + API.regorus_result_drop(result); + } + } + + internal static ulong GetUInt64AndDrop(RegorusResult result) + { + try + { + if (result.status != RegorusStatus.Ok) + { + throw BuildError(result); + } + + return result.u64_value; + } + finally + { + API.regorus_result_drop(result); + } + } + + internal static IntPtr GetPointerAndDrop(RegorusResult result, RegorusPointerType expectedType) + { + if (result.status != RegorusStatus.Ok) + { + var error = BuildError(result); + API.regorus_result_drop(result); + throw error; + } + + if (result.data_type != RegorusDataType.Pointer) + { + var error = new RegorusException($"Expected pointer result but received {result.data_type}."); + API.regorus_result_drop(result); + throw error; + } + + if (expectedType != RegorusPointerType.PointerNone && result.pointer_type != expectedType) + { + var error = new RegorusException($"Unexpected pointer type {result.pointer_type}; expected {expectedType}."); + API.regorus_result_drop(result); + throw error; + } + + var pointer = new IntPtr(result.pointer_value); + + // Prevent the native drop helper from freeing the pointer we are taking ownership of. + result.pointer_value = null; + result.pointer_type = RegorusPointerType.PointerNone; + + API.regorus_result_drop(result); + return pointer; + } + } + + internal sealed unsafe class PinnedUtf8StringArray : IDisposable + { + private readonly GCHandle[] _stringHandles; + private readonly GCHandle _arrayHandle; + + internal PinnedUtf8StringArray(IEnumerable? values) + { + if (values is null) + { + _stringHandles = Array.Empty(); + _arrayHandle = default; + Length = 0; + return; + } + + var buffers = new List(); + foreach (var value in values) + { + if (value is null) + { + throw new ArgumentNullException(nameof(values), "Field names cannot contain null entries."); + } + + buffers.Add(NativeUtf8.GetNullTerminatedBytes(value)); + } + + _stringHandles = new GCHandle[buffers.Count]; + + if (buffers.Count > 0) + { + var pointerArray = new IntPtr[buffers.Count]; + for (int i = 0; i < buffers.Count; i++) + { + _stringHandles[i] = GCHandle.Alloc(buffers[i], GCHandleType.Pinned); + pointerArray[i] = _stringHandles[i].AddrOfPinnedObject(); + } + + _arrayHandle = GCHandle.Alloc(pointerArray, GCHandleType.Pinned); + Length = buffers.Count; + } + else + { + _arrayHandle = default; + Length = 0; + } + } + + internal byte** Pointer => _arrayHandle.IsAllocated ? (byte**)_arrayHandle.AddrOfPinnedObject().ToPointer() : null; + + internal UIntPtr LengthPtr => (UIntPtr)Length; + + internal int Length { get; } + + public void Dispose() + { + if (_arrayHandle.IsAllocated) + { + _arrayHandle.Free(); + } + + for (int i = 0; i < _stringHandles.Length; i++) + { + if (_stringHandles[i].IsAllocated) + { + _stringHandles[i].Free(); + } + } + } + } + + internal sealed unsafe class PinnedIntPtrArray : IDisposable + { + private readonly IntPtr[] _values; + private readonly GCHandle _handle; + + internal PinnedIntPtrArray(IReadOnlyList? values) + { + if (values is null || values.Count == 0) + { + _values = Array.Empty(); + _handle = default; + Length = 0; + return; + } + + _values = new IntPtr[values.Count]; + for (int i = 0; i < values.Count; i++) + { + _values[i] = values[i]; + } + + _handle = GCHandle.Alloc(_values, GCHandleType.Pinned); + Length = _values.Length; + } + + internal IntPtr* Pointer => _handle.IsAllocated ? (IntPtr*)_handle.AddrOfPinnedObject().ToPointer() : null; + + internal UIntPtr LengthPtr => (UIntPtr)Length; + + internal int Length { get; } + + public void Dispose() + { + if (_handle.IsAllocated) + { + _handle.Free(); + } + } + } +} diff --git a/bindings/csharp/Regorus/NativeMethods.cs b/bindings/csharp/Regorus/NativeMethods.cs index a13bb77e..53d360cb 100644 --- a/bindings/csharp/Regorus/NativeMethods.cs +++ b/bindings/csharp/Regorus/NativeMethods.cs @@ -126,6 +126,18 @@ internal static unsafe partial class API [DllImport(LibraryName, EntryPoint = "regorus_engine_eval_rule", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] internal static extern RegorusResult regorus_engine_eval_rule(RegorusEngine* engine, byte* rule); + [DllImport(LibraryName, EntryPoint = "regorus_engine_set_input_value", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_engine_set_input_value(RegorusEngine* engine, void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_engine_add_data_value", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_engine_add_data_value(RegorusEngine* engine, void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_engine_eval_query_as_value", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_engine_eval_query_as_value(RegorusEngine* engine, byte* query); + + [DllImport(LibraryName, EntryPoint = "regorus_engine_eval_rule_as_value", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_engine_eval_rule_as_value(RegorusEngine* engine, byte* rule); + /// /// Enable/disable coverage. /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage @@ -219,6 +231,85 @@ internal static unsafe partial class API #endregion + #region Value Methods + + [DllImport(LibraryName, EntryPoint = "regorus_value_create_null", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_create_null(); + + [DllImport(LibraryName, EntryPoint = "regorus_value_create_undefined", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_create_undefined(); + + [DllImport(LibraryName, EntryPoint = "regorus_value_create_bool", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_create_bool([MarshalAs(UnmanagedType.U1)] bool value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_create_int", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_create_int(long value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_create_float", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_create_float(double value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_create_string", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_create_string(byte* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_create_array", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_create_array(); + + [DllImport(LibraryName, EntryPoint = "regorus_value_create_object", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_create_object(); + + [DllImport(LibraryName, EntryPoint = "regorus_value_create_set", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_create_set(); + + [DllImport(LibraryName, EntryPoint = "regorus_value_from_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_from_json(byte* json); + + [DllImport(LibraryName, EntryPoint = "regorus_value_to_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_to_json(void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_is_null", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_is_null(void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_is_object", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_is_object(void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_is_string", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_is_string(void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_as_bool", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_as_bool(void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_as_i64", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_as_i64(void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_as_string", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_as_string(void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_object_insert", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_object_insert(void* obj, byte* key, void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_object_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_object_get(void* obj, byte* key); + + [DllImport(LibraryName, EntryPoint = "regorus_value_array_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_array_len(void* array); + + [DllImport(LibraryName, EntryPoint = "regorus_value_array_get", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_array_get(void* array, long index); + + [DllImport(LibraryName, EntryPoint = "regorus_value_array_push", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_array_push(void* array, void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_set_insert", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_set_insert(void* set, void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern RegorusResult regorus_value_clone(void* value); + + [DllImport(LibraryName, EntryPoint = "regorus_value_drop", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + internal static extern void regorus_value_drop(void* value); + + #endregion + #region Compilation Methods /// @@ -435,6 +526,16 @@ internal enum RegorusDataType : uint Pointer, } + /// + /// Type of pointer contained in RegorusResult. + /// + internal enum RegorusPointerType : uint + { + PointerNone, + PointerValue, + PointerCompiledPolicy, + } + /// /// Status of a call on RegorusEngine. /// @@ -505,11 +606,20 @@ internal unsafe partial struct RegorusResult /// public long int_value; /// + /// Unsigned 64-bit integer value. + /// Valid when data_type is Integer. + /// + public ulong u64_value; + /// /// Pointer value. /// Valid when data_type is Pointer. /// public void* pointer_value; /// + /// Type of pointer contained in pointer_value. + /// + public RegorusPointerType pointer_type; + /// /// Errors produced by the call. /// Owned by Rust. /// diff --git a/bindings/csharp/Regorus/Regorus.csproj b/bindings/csharp/Regorus/Regorus.csproj index e4964976..00548806 100644 --- a/bindings/csharp/Regorus/Regorus.csproj +++ b/bindings/csharp/Regorus/Regorus.csproj @@ -8,7 +8,7 @@ 10.0 - 0.8.0 + 0.8.1 $(VersionSuffix) README.md diff --git a/bindings/csharp/Regorus/RegorusException.cs b/bindings/csharp/Regorus/RegorusException.cs new file mode 100644 index 00000000..82775e7b --- /dev/null +++ b/bindings/csharp/Regorus/RegorusException.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; + +#nullable enable + +namespace Regorus +{ + /// + /// Represents errors originating from the native Regorus runtime. + /// + public sealed class RegorusException : Exception + { + public RegorusException() + { + } + + public RegorusException(string message) + : base(message) + { + } + + public RegorusException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/bindings/csharp/Regorus/SafeHandles.cs b/bindings/csharp/Regorus/SafeHandles.cs index 4fbcf178..097975ea 100644 --- a/bindings/csharp/Regorus/SafeHandles.cs +++ b/bindings/csharp/Regorus/SafeHandles.cs @@ -87,4 +87,60 @@ protected override bool ReleaseHandle() return true; } } + + internal sealed class RegorusValueHandle : SafeHandleZeroOrMinusOneIsInvalid + { + private RegorusValueHandle() : base(ownsHandle: true) + { + } + + internal static RegorusValueHandle FromPointer(IntPtr pointer) + { + if (pointer == IntPtr.Zero) + { + throw new ArgumentException("Pointer cannot be zero.", nameof(pointer)); + } + + var handle = new RegorusValueHandle(); + handle.SetHandle(pointer); + return handle; + } + + internal IntPtr Detach() + { + if (IsClosed || IsInvalid) + { + throw new ObjectDisposedException(nameof(RegorusValueHandle)); + } + + bool addedRef = false; + try + { + DangerousAddRef(ref addedRef); + var pointer = DangerousGetHandle(); + SetHandle(IntPtr.Zero); + return pointer; + } + finally + { + if (addedRef) + { + DangerousRelease(); + } + } + } + + protected override bool ReleaseHandle() + { + if (!IsInvalid && !IsClosed) + { + unsafe + { + Internal.API.regorus_value_drop((void*)handle); + } + SetHandle(IntPtr.Zero); + } + return true; + } + } } diff --git a/bindings/csharp/Regorus/Value.cs b/bindings/csharp/Regorus/Value.cs new file mode 100644 index 00000000..a07678f1 --- /dev/null +++ b/bindings/csharp/Regorus/Value.cs @@ -0,0 +1,353 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Threading; +using Regorus.Internal; + +#nullable enable + +namespace Regorus +{ + /// + /// Managed wrapper for the native regorus::Value type. + /// Instances own the underlying native value and must be disposed when no longer needed. + /// + public sealed unsafe class Value : IDisposable + { + private RegorusValueHandle? _handle; + private int _isDisposed; + + private Value(RegorusValueHandle handle) + { + _handle = handle ?? throw new ArgumentNullException(nameof(handle)); + } + + internal static Value FromHandle(IntPtr handle) => new Value(RegorusValueHandle.FromPointer(handle)); + + private RegorusValueHandle GetHandleForUse() + { + var handle = _handle; + if (handle is null || handle.IsClosed || handle.IsInvalid) + { + throw new ObjectDisposedException(nameof(Value)); + } + + return handle; + } + + private void UseHandle(Action action) + { + UseHandle(handlePtr => + { + action(handlePtr); + return null; + }); + } + + private T UseHandle(Func func) + { + var handle = GetHandleForUse(); + bool addedRef = false; + try + { + handle.DangerousAddRef(ref addedRef); + var pointer = handle.DangerousGetHandle(); + if (pointer == IntPtr.Zero) + { + throw new ObjectDisposedException(nameof(Value)); + } + + return func(pointer); + } + finally + { + if (addedRef) + { + handle.DangerousRelease(); + } + } + } + + internal void WithHandle(Action action) => UseHandle(action); + + internal T WithHandle(Func func) => UseHandle(func); + + public static Value Null() + { + var result = Internal.API.regorus_value_create_null(); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + + public static Value Undefined() + { + var result = Internal.API.regorus_value_create_undefined(); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + + public static Value Bool(bool value) + { + var result = Internal.API.regorus_value_create_bool(value); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + + public static Value Int(long value) + { + var result = Internal.API.regorus_value_create_int(value); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + + public static Value Float(double value) + { + var result = Internal.API.regorus_value_create_float(value); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + + public static Value String(string value) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + var bytes = NativeUtf8.GetNullTerminatedBytes(value); + fixed (byte* ptr = bytes) + { + var result = Internal.API.regorus_value_create_string(ptr); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + } + + public static Value Array() + { + var result = Internal.API.regorus_value_create_array(); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + + public static Value Object() + { + var result = Internal.API.regorus_value_create_object(); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + + public static Value Set() + { + var result = Internal.API.regorus_value_create_set(); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + + public static Value FromJson(string json) + { + if (json is null) + { + throw new ArgumentNullException(nameof(json)); + } + + var bytes = NativeUtf8.GetNullTerminatedBytes(json); + fixed (byte* ptr = bytes) + { + var result = Internal.API.regorus_value_from_json(ptr); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + } + + public Value Clone() + { + return UseHandle(handlePtr => + { + var result = Internal.API.regorus_value_clone((void*)handlePtr); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + }); + } + + public string ToJson() + { + return UseHandle(handlePtr => + { + var result = Internal.API.regorus_value_to_json((void*)handlePtr); + return NativeResult.GetStringAndDrop(result) ?? string.Empty; + }); + } + + public bool IsNull + { + get + { + return UseHandle(handlePtr => + { + return NativeResult.GetBoolAndDrop(Internal.API.regorus_value_is_null((void*)handlePtr)); + }); + } + } + + public bool IsObject + { + get + { + return UseHandle(handlePtr => + { + return NativeResult.GetBoolAndDrop(Internal.API.regorus_value_is_object((void*)handlePtr)); + }); + } + } + + public bool IsString + { + get + { + return UseHandle(handlePtr => + { + return NativeResult.GetBoolAndDrop(Internal.API.regorus_value_is_string((void*)handlePtr)); + }); + } + } + + public bool AsBool() + { + return UseHandle(handlePtr => + { + return NativeResult.GetBoolAndDrop(Internal.API.regorus_value_as_bool((void*)handlePtr)); + }); + } + + public long AsInt64() + { + return UseHandle(handlePtr => + { + return NativeResult.GetInt64AndDrop(Internal.API.regorus_value_as_i64((void*)handlePtr)); + }); + } + + public string AsString() + { + return UseHandle(handlePtr => + { + return NativeResult.GetStringAndDrop(Internal.API.regorus_value_as_string((void*)handlePtr)) ?? string.Empty; + }); + } + + public long ArrayLength() + { + return UseHandle(handlePtr => + { + return NativeResult.GetInt64AndDrop(Internal.API.regorus_value_array_len((void*)handlePtr)); + }); + } + + public Value ArrayGet(long index) + { + return UseHandle(handlePtr => + { + var result = Internal.API.regorus_value_array_get((void*)handlePtr, index); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + }); + } + + public void ArrayAppend(Value value) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + value.WithHandle(valuePtr => + { + UseHandle(handlePtr => + { + NativeResult.EnsureSuccess(Internal.API.regorus_value_array_push((void*)handlePtr, (void*)valuePtr)); + }); + }); + } + + public void ObjectInsert(string key, Value value) + { + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + var keyBytes = NativeUtf8.GetNullTerminatedBytes(key); + value.WithHandle(valuePtr => + { + UseHandle(handlePtr => + { + fixed (byte* keyPtr = keyBytes) + { + NativeResult.EnsureSuccess(Internal.API.regorus_value_object_insert((void*)handlePtr, keyPtr, (void*)valuePtr)); + } + }); + }); + } + + public void SetInsert(Value value) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + value.WithHandle(valuePtr => + { + UseHandle(handlePtr => + { + NativeResult.EnsureSuccess(Internal.API.regorus_value_set_insert((void*)handlePtr, (void*)valuePtr)); + }); + }); + } + + public Value ObjectGet(string key) + { + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + + var keyBytes = NativeUtf8.GetNullTerminatedBytes(key); + return UseHandle(handlePtr => + { + fixed (byte* keyPtr = keyBytes) + { + var result = Internal.API.regorus_value_object_get((void*)handlePtr, keyPtr); + var pointer = NativeResult.GetPointerAndDrop(result, RegorusPointerType.PointerValue); + return new Value(RegorusValueHandle.FromPointer(pointer)); + } + }); + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (Interlocked.CompareExchange(ref _isDisposed, 1, 0) == 0) + { + _handle?.Dispose(); + _handle = null; + } + } + + ~Value() + { + Dispose(disposing: false); + } + } +} diff --git a/bindings/csharp/TargetExampleApp/TargetExampleApp.csproj b/bindings/csharp/TargetExampleApp/TargetExampleApp.csproj index 6a96655e..eb8e29ec 100644 --- a/bindings/csharp/TargetExampleApp/TargetExampleApp.csproj +++ b/bindings/csharp/TargetExampleApp/TargetExampleApp.csproj @@ -14,7 +14,7 @@ - + diff --git a/bindings/csharp/TestApp/TestApp.csproj b/bindings/csharp/TestApp/TestApp.csproj index d3cf29f8..bcf32c58 100644 --- a/bindings/csharp/TestApp/TestApp.csproj +++ b/bindings/csharp/TestApp/TestApp.csproj @@ -11,6 +11,6 @@ - + diff --git a/bindings/ffi/Cargo.lock b/bindings/ffi/Cargo.lock index 0019dea0..e7a38488 100644 --- a/bindings/ffi/Cargo.lock +++ b/bindings/ffi/Cargo.lock @@ -18,9 +18,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -125,9 +125,9 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "borrow-or-share" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" +checksum = "dc0b364ead1874514c8c2855ab558056ebfeb775653e7ae45ff72f28f8f3166c" [[package]] name = "bstr" @@ -172,9 +172,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.43" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "shlex", @@ -211,18 +211,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -431,9 +431,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -444,9 +444,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -457,11 +457,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -472,42 +471,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -620,9 +615,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -814,9 +809,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -1146,9 +1141,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.108" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", @@ -1201,9 +1196,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -1252,9 +1247,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unsafe-libyaml" @@ -1534,17 +1529,16 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -1552,9 +1546,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -1605,9 +1599,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -1616,9 +1610,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -1627,9 +1621,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", diff --git a/bindings/ffi/src/common.rs b/bindings/ffi/src/common.rs index e48b3e86..2cb4c3b2 100644 --- a/bindings/ffi/src/common.rs +++ b/bindings/ffi/src/common.rs @@ -49,6 +49,18 @@ pub enum RegorusDataType { Pointer, } +/// Type of pointer stored in RegorusResult +#[repr(C)] +#[allow(unused, clippy::enum_variant_names)] +pub enum RegorusPointerType { + /// No pointer or unknown type + PointerNone, + /// Value pointer (Box) + PointerValue, + /// CompiledPolicy pointer (Box) + PointerCompiledPolicy, +} + /// Result of a call on `RegorusEngine`. /// /// Must be freed using `regorus_result_drop`. @@ -72,10 +84,18 @@ pub struct RegorusResult { /// Valid when data_type is Integer. pub(crate) int_value: c_longlong, + /// Unsigned 64-bit integer value. + /// Valid when data_type is Integer (used for u64 returns). + pub(crate) u64_value: u64, + /// Pointer value. /// Valid when data_type is Pointer. pub(crate) pointer_value: *mut std::os::raw::c_void, + /// Type of pointer stored in pointer_value. + /// Used for proper cleanup in regorus_result_drop. + pub(crate) pointer_type: RegorusPointerType, + /// Errors produced by the call. /// Owned by Rust. pub(crate) error_message: *mut c_char, @@ -90,7 +110,9 @@ impl RegorusResult { output: std::ptr::null_mut(), bool_value: false, int_value: 0, + u64_value: 0, pointer_value: std::ptr::null_mut(), + pointer_type: RegorusPointerType::PointerNone, error_message: std::ptr::null_mut(), } } @@ -103,7 +125,24 @@ impl RegorusResult { output: to_c_str(output), bool_value: false, int_value: 0, + u64_value: 0, + pointer_value: std::ptr::null_mut(), + pointer_type: RegorusPointerType::PointerNone, + error_message: std::ptr::null_mut(), + } + } + + /// Create a successful result with raw c_char string (takes ownership). + pub(crate) fn ok_string_raw(output: *mut c_char) -> Self { + Self { + status: RegorusStatus::Ok, + data_type: RegorusDataType::String, + output, + bool_value: false, + int_value: 0, + u64_value: 0, pointer_value: std::ptr::null_mut(), + pointer_type: RegorusPointerType::PointerNone, error_message: std::ptr::null_mut(), } } @@ -117,7 +156,9 @@ impl RegorusResult { output: std::ptr::null_mut(), bool_value: value, int_value: 0, + u64_value: 0, pointer_value: std::ptr::null_mut(), + pointer_type: RegorusPointerType::PointerNone, error_message: std::ptr::null_mut(), } } @@ -131,20 +172,43 @@ impl RegorusResult { output: std::ptr::null_mut(), bool_value: false, int_value: value as c_longlong, + u64_value: 0, pointer_value: std::ptr::null_mut(), + pointer_type: RegorusPointerType::PointerNone, + error_message: std::ptr::null_mut(), + } + } + + /// Create a successful result with unsigned 64-bit integer value. + #[allow(unused)] + pub(crate) fn ok_u64(value: u64) -> Self { + Self { + status: RegorusStatus::Ok, + data_type: RegorusDataType::Integer, + output: std::ptr::null_mut(), + bool_value: false, + int_value: 0, + u64_value: value, + pointer_value: std::ptr::null_mut(), + pointer_type: RegorusPointerType::PointerNone, error_message: std::ptr::null_mut(), } } /// Create a successful result with pointer value. - pub(crate) fn ok_pointer(pointer: *mut std::os::raw::c_void) -> Self { + pub(crate) fn ok_pointer( + pointer: *mut std::os::raw::c_void, + pointer_type: RegorusPointerType, + ) -> Self { Self { status: RegorusStatus::Ok, data_type: RegorusDataType::Pointer, output: std::ptr::null_mut(), bool_value: false, int_value: 0, + u64_value: 0, pointer_value: pointer, + pointer_type, error_message: std::ptr::null_mut(), } } @@ -157,7 +221,9 @@ impl RegorusResult { output: std::ptr::null_mut(), bool_value: false, int_value: 0, + u64_value: 0, pointer_value: std::ptr::null_mut(), + pointer_type: RegorusPointerType::PointerNone, error_message: std::ptr::null_mut(), } } @@ -170,7 +236,9 @@ impl RegorusResult { output: std::ptr::null_mut(), bool_value: false, int_value: 0, + u64_value: 0, pointer_value: std::ptr::null_mut(), + pointer_type: RegorusPointerType::PointerNone, error_message: to_c_str(message), } } @@ -215,7 +283,7 @@ pub(crate) fn to_regorus_string_result(r: Result) -> RegorusResult { /// Drop a `RegorusResult`. /// -/// `output` and `error_message` strings are not valid after drop. +/// `output`, `error_message` strings and `pointer_value` (if not transferred) are not valid after drop. #[no_mangle] pub extern "C" fn regorus_result_drop(r: RegorusResult) { unsafe { @@ -225,5 +293,25 @@ pub extern "C" fn regorus_result_drop(r: RegorusResult) { if !r.output.is_null() { let _ = CString::from_raw(r.output); } + + // Free the pointer if ownership wasn't transferred (pointer is still non-null) + if !r.pointer_value.is_null() { + match r.pointer_type { + RegorusPointerType::PointerValue => { + let _ = Box::from_raw(r.pointer_value as *mut regorus::Value); + } + RegorusPointerType::PointerCompiledPolicy => { + // Import the compiled policy type + #[cfg(feature = "azure_policy")] + { + use crate::compiled_policy::RegorusCompiledPolicy; + let _ = Box::from_raw(r.pointer_value as *mut RegorusCompiledPolicy); + } + } + RegorusPointerType::PointerNone => { + // No cleanup needed + } + } + } } } diff --git a/bindings/ffi/src/compile.rs b/bindings/ffi/src/compile.rs index 9d7f6720..f913b2b3 100644 --- a/bindings/ffi/src/compile.rs +++ b/bindings/ffi/src/compile.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -use crate::common::{from_c_str, RegorusResult, RegorusStatus}; +use crate::common::{from_c_str, RegorusPointerType, RegorusResult, RegorusStatus}; use crate::compiled_policy::RegorusCompiledPolicy; use regorus::{compile_policy_with_entrypoint, PolicyModule, Value}; @@ -83,7 +83,10 @@ pub extern "C" fn regorus_compile_policy_with_entrypoint( Ok(compiled_policy) => { let wrapped_policy = RegorusCompiledPolicy { compiled_policy }; let boxed_policy = Box::new(wrapped_policy); - RegorusResult::ok_pointer(Box::into_raw(boxed_policy) as *mut std::os::raw::c_void) + RegorusResult::ok_pointer( + Box::into_raw(boxed_policy) as *mut std::os::raw::c_void, + RegorusPointerType::PointerCompiledPolicy, + ) } Err(e) => RegorusResult::err_with_message( RegorusStatus::CompilationFailed, @@ -152,7 +155,10 @@ pub extern "C" fn regorus_compile_policy_for_target( Ok(compiled_policy) => { let wrapped_policy = RegorusCompiledPolicy { compiled_policy }; let boxed_policy = Box::new(wrapped_policy); - RegorusResult::ok_pointer(Box::into_raw(boxed_policy) as *mut std::os::raw::c_void) + RegorusResult::ok_pointer( + Box::into_raw(boxed_policy) as *mut std::os::raw::c_void, + RegorusPointerType::PointerCompiledPolicy, + ) } Err(e) => RegorusResult::err_with_message( RegorusStatus::CompilationFailed, diff --git a/bindings/ffi/src/effect_registry.rs b/bindings/ffi/src/effect_registry.rs index cdd348ae..9aa9c590 100644 --- a/bindings/ffi/src/effect_registry.rs +++ b/bindings/ffi/src/effect_registry.rs @@ -62,7 +62,7 @@ pub extern "C" fn regorus_effect_schema_register( // Register the schema match schemas::effect::register(schema_name, schema.into()) { - Ok(()) => RegorusResult::ok_pointer(std::ptr::null_mut()), + Ok(()) => RegorusResult::ok_void(), Err(e) => RegorusResult::err_with_message( RegorusStatus::Error, format!("Failed to register effect schema: {e}"), @@ -171,5 +171,5 @@ pub extern "C" fn regorus_effect_schema_remove(name: *const c_char) -> RegorusRe #[no_mangle] pub extern "C" fn regorus_effect_schema_clear() -> RegorusResult { schemas::effect::clear(); - RegorusResult::ok_pointer(std::ptr::null_mut()) + RegorusResult::ok_void() } diff --git a/bindings/ffi/src/engine.rs b/bindings/ffi/src/engine.rs index 864e75f9..5243b17c 100644 --- a/bindings/ffi/src/engine.rs +++ b/bindings/ffi/src/engine.rs @@ -2,7 +2,8 @@ // Licensed under the MIT License. use crate::common::{ - from_c_str, to_ref, to_regorus_result, to_regorus_string_result, RegorusResult, RegorusStatus, + from_c_str, to_ref, to_regorus_result, to_regorus_string_result, RegorusPointerType, + RegorusResult, RegorusStatus, }; use crate::compiled_policy::RegorusCompiledPolicy; use anyhow::Result; @@ -11,7 +12,7 @@ use std::os::raw::c_char; /// Wrapper for `regorus::Engine`. #[derive(Clone)] pub struct RegorusEngine { - engine: ::regorus::Engine, + pub(crate) engine: ::regorus::Engine, } #[no_mangle] @@ -409,7 +410,10 @@ pub extern "C" fn regorus_engine_compile_for_target(engine: *mut RegorusEngine) Ok(compiled_policy) => { let wrapped_policy = RegorusCompiledPolicy { compiled_policy }; let boxed_policy = Box::new(wrapped_policy); - RegorusResult::ok_pointer(Box::into_raw(boxed_policy) as *mut std::os::raw::c_void) + RegorusResult::ok_pointer( + Box::into_raw(boxed_policy) as *mut std::os::raw::c_void, + RegorusPointerType::PointerCompiledPolicy, + ) } Err(e) => RegorusResult::err_with_message( RegorusStatus::CompilationFailed, @@ -444,7 +448,10 @@ pub extern "C" fn regorus_engine_compile_with_entrypoint( match result { Ok(wrapped_policy) => { let boxed_policy = Box::new(wrapped_policy); - RegorusResult::ok_pointer(Box::into_raw(boxed_policy) as *mut std::os::raw::c_void) + RegorusResult::ok_pointer( + Box::into_raw(boxed_policy) as *mut std::os::raw::c_void, + RegorusPointerType::PointerCompiledPolicy, + ) } Err(e) => RegorusResult::err_with_message( RegorusStatus::CompilationFailed, diff --git a/bindings/ffi/src/lib.rs b/bindings/ffi/src/lib.rs index 62273926..19407a0d 100644 --- a/bindings/ffi/src/lib.rs +++ b/bindings/ffi/src/lib.rs @@ -9,3 +9,4 @@ mod effect_registry; mod engine; mod schema_registry; mod target_registry; +mod value; diff --git a/bindings/ffi/src/schema_registry.rs b/bindings/ffi/src/schema_registry.rs index a7bf50cd..37e233bf 100644 --- a/bindings/ffi/src/schema_registry.rs +++ b/bindings/ffi/src/schema_registry.rs @@ -65,7 +65,7 @@ pub extern "C" fn regorus_resource_schema_register( // Register the schema match schemas::resource::register(schema_name, schema.into()) { - Ok(()) => RegorusResult::ok_pointer(std::ptr::null_mut()), + Ok(()) => RegorusResult::ok_void(), Err(e) => RegorusResult::err_with_message( RegorusStatus::Error, format!("Failed to register schema: {e}"), @@ -174,5 +174,5 @@ pub extern "C" fn regorus_resource_schema_remove(name: *const c_char) -> Regorus #[no_mangle] pub extern "C" fn regorus_resource_schema_clear() -> RegorusResult { schemas::resource::clear(); - RegorusResult::ok_pointer(std::ptr::null_mut()) + RegorusResult::ok_void() } diff --git a/bindings/ffi/src/value.rs b/bindings/ffi/src/value.rs new file mode 100644 index 00000000..222ee96d --- /dev/null +++ b/bindings/ffi/src/value.rs @@ -0,0 +1,489 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use anyhow::{anyhow, Result}; +use regorus::Value; +use std::ffi::{c_char, c_void, CString}; + +use crate::common::{from_c_str, RegorusPointerType, RegorusResult, RegorusStatus}; +use crate::engine::RegorusEngine; + +// Helper to convert Value pointer +fn to_value_ref<'a>(ptr: *mut c_void) -> Result<&'a Value> { + if ptr.is_null() { + return Err(anyhow!("Null value pointer")); + } + Ok(unsafe { &*(ptr as *mut Value) }) +} + +fn to_value_mut<'a>(ptr: *mut c_void) -> Result<&'a mut Value> { + if ptr.is_null() { + return Err(anyhow!("Null value pointer")); + } + Ok(unsafe { &mut *(ptr as *mut Value) }) +} + +// Creation functions +#[no_mangle] +pub extern "C" fn regorus_value_create_null() -> RegorusResult { + let value = Box::new(Value::Null); + RegorusResult::ok_pointer( + Box::into_raw(value) as *mut c_void, + RegorusPointerType::PointerValue, + ) +} + +#[no_mangle] +pub extern "C" fn regorus_value_create_undefined() -> RegorusResult { + let value = Box::new(Value::Undefined); + RegorusResult::ok_pointer( + Box::into_raw(value) as *mut c_void, + RegorusPointerType::PointerValue, + ) +} + +#[no_mangle] +pub extern "C" fn regorus_value_create_bool(value: bool) -> RegorusResult { + let val = Box::new(Value::Bool(value)); + RegorusResult::ok_pointer( + Box::into_raw(val) as *mut c_void, + RegorusPointerType::PointerValue, + ) +} + +#[no_mangle] +pub extern "C" fn regorus_value_create_int(value: i64) -> RegorusResult { + let val = Box::new(Value::from(value)); + RegorusResult::ok_pointer( + Box::into_raw(val) as *mut c_void, + RegorusPointerType::PointerValue, + ) +} + +#[no_mangle] +pub extern "C" fn regorus_value_create_float(value: f64) -> RegorusResult { + let val = Box::new(Value::from(value)); + RegorusResult::ok_pointer( + Box::into_raw(val) as *mut c_void, + RegorusPointerType::PointerValue, + ) +} + +#[no_mangle] +pub extern "C" fn regorus_value_create_string(s: *const c_char) -> RegorusResult { + let result = || -> Result<*mut c_void> { + let s = from_c_str(s)?; + let val = Box::new(Value::from(s.as_str())); + Ok(Box::into_raw(val) as *mut c_void) + }(); + + match result { + Ok(ptr) => RegorusResult::ok_pointer(ptr, RegorusPointerType::PointerValue), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +#[no_mangle] +pub extern "C" fn regorus_value_create_array() -> RegorusResult { + let val = Box::new(Value::new_array()); + RegorusResult::ok_pointer( + Box::into_raw(val) as *mut c_void, + RegorusPointerType::PointerValue, + ) +} + +#[no_mangle] +pub extern "C" fn regorus_value_create_object() -> RegorusResult { + let val = Box::new(Value::new_object()); + RegorusResult::ok_pointer( + Box::into_raw(val) as *mut c_void, + RegorusPointerType::PointerValue, + ) +} + +#[no_mangle] +pub extern "C" fn regorus_value_create_set() -> RegorusResult { + let val = Box::new(Value::new_set()); + RegorusResult::ok_pointer( + Box::into_raw(val) as *mut c_void, + RegorusPointerType::PointerValue, + ) +} + +// JSON serialization +#[no_mangle] +pub extern "C" fn regorus_value_from_json(json: *const c_char) -> RegorusResult { + let result = || -> Result<*mut c_void> { + let json_str = from_c_str(json)?; + let val = Box::new(Value::from_json_str(&json_str)?); + Ok(Box::into_raw(val) as *mut c_void) + }(); + + match result { + Ok(ptr) => RegorusResult::ok_pointer(ptr, RegorusPointerType::PointerValue), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +#[no_mangle] +pub extern "C" fn regorus_value_to_json(value: *mut c_void) -> RegorusResult { + let result = || -> Result { + let val = to_value_ref(value)?; + val.to_json_str() + }(); + + match result { + Ok(s) => { + let c_str = CString::new(s).unwrap(); + RegorusResult::ok_string_raw(c_str.into_raw()) + } + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +// Type checking +#[no_mangle] +pub extern "C" fn regorus_value_is_null(value: *mut c_void) -> RegorusResult { + let result = || -> Result { + let val = to_value_ref(value)?; + Ok(matches!(val, Value::Null)) + }(); + + match result { + Ok(b) => RegorusResult::ok_bool(b), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +#[no_mangle] +pub extern "C" fn regorus_value_is_object(value: *mut c_void) -> RegorusResult { + let result = || -> Result { + let val = to_value_ref(value)?; + Ok(matches!(val, Value::Object(_))) + }(); + + match result { + Ok(b) => RegorusResult::ok_bool(b), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +#[no_mangle] +pub extern "C" fn regorus_value_is_string(value: *mut c_void) -> RegorusResult { + let result = || -> Result { + let val = to_value_ref(value)?; + Ok(matches!(val, Value::String(_))) + }(); + + match result { + Ok(b) => RegorusResult::ok_bool(b), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +// Typed value accessors +/// Get boolean value +#[no_mangle] +pub extern "C" fn regorus_value_as_bool(value: *mut c_void) -> RegorusResult { + let result = || -> Result { + let val = to_value_ref(value)?; + Ok(*val.as_bool()?) + }(); + + match result { + Ok(b) => RegorusResult::ok_bool(b), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +/// Get integer value +#[no_mangle] +pub extern "C" fn regorus_value_as_i64(value: *mut c_void) -> RegorusResult { + let result = || -> Result { + let val = to_value_ref(value)?; + val.as_i64() + }(); + + match result { + Ok(i) => RegorusResult::ok_int(i), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +/// Get string value (returns owned copy) +#[no_mangle] +pub extern "C" fn regorus_value_as_string(value: *mut c_void) -> RegorusResult { + let result = || -> Result { + let val = to_value_ref(value)?; + Ok(val.as_string()?.to_string()) + }(); + + match result { + Ok(s) => RegorusResult::ok_string(s), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +// Object operations +#[no_mangle] +pub extern "C" fn regorus_value_object_insert( + object: *mut c_void, + key: *const c_char, + value: *mut c_void, +) -> RegorusResult { + let result = || -> Result<()> { + let obj = to_value_mut(object)?; + let key_str = from_c_str(key)?; + let val = to_value_ref(value)?.clone(); + + obj.as_object_mut()? + .insert(Value::from(key_str.as_str()), val); + + Ok(()) + }(); + + match result { + Ok(_) => RegorusResult::ok_void(), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +#[no_mangle] +pub extern "C" fn regorus_value_object_get( + object: *mut c_void, + key: *const c_char, +) -> RegorusResult { + let result = || -> Result<*mut c_void> { + let obj = to_value_ref(object)?; + let key_str = from_c_str(key)?; + + let map = obj.as_object()?; + let key_val = Value::from(key_str.as_str()); + + if let Some(val) = map.get(&key_val) { + let cloned = Box::new(val.clone()); + Ok(Box::into_raw(cloned) as *mut c_void) + } else { + Err(anyhow!("Key not found: {}", key_str)) + } + }(); + + match result { + Ok(ptr) => RegorusResult::ok_pointer(ptr, RegorusPointerType::PointerValue), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +// Array operations +/// Get the length of an array +#[no_mangle] +pub extern "C" fn regorus_value_array_len(array: *mut c_void) -> RegorusResult { + let result = || -> Result { + let arr = to_value_ref(array)?; + let array_ref = arr.as_array()?; + Ok(array_ref.len() as i64) + }(); + + match result { + Ok(len) => RegorusResult::ok_int(len), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +/// Get an element from an array by index +#[no_mangle] +pub extern "C" fn regorus_value_array_get(array: *mut c_void, index: i64) -> RegorusResult { + let result = || -> Result<*mut c_void> { + let arr = to_value_ref(array)?; + let array_ref = arr.as_array()?; + + if index < 0 || index >= array_ref.len() as i64 { + return Err(anyhow!("Index out of bounds: {}", index)); + } + + let val = &array_ref[index as usize]; + let cloned = Box::new(val.clone()); + Ok(Box::into_raw(cloned) as *mut c_void) + }(); + + match result { + Ok(ptr) => RegorusResult::ok_pointer(ptr, RegorusPointerType::PointerValue), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +/// Append a value to an array +#[no_mangle] +pub extern "C" fn regorus_value_array_push( + array: *mut c_void, + value: *mut c_void, +) -> RegorusResult { + let result = || -> Result<()> { + let arr = to_value_mut(array)?; + let val = to_value_ref(value)?.clone(); + + arr.as_array_mut()?.push(val); + + Ok(()) + }(); + + match result { + Ok(_) => RegorusResult::ok_void(), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +/// Insert a value into a set +#[no_mangle] +pub extern "C" fn regorus_value_set_insert(set: *mut c_void, value: *mut c_void) -> RegorusResult { + let result = || -> Result<()> { + let set_value = to_value_mut(set)?; + let val = to_value_ref(value)?.clone(); + + set_value.as_set_mut()?.insert(val); + + Ok(()) + }(); + + match result { + Ok(_) => RegorusResult::ok_void(), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +// Memory management +#[no_mangle] +pub extern "C" fn regorus_value_drop(value: *mut c_void) { + if !value.is_null() { + unsafe { + let _ = Box::from_raw(value as *mut Value); + } + } +} + +/// Clone a Value +#[no_mangle] +pub extern "C" fn regorus_value_clone(value: *mut c_void) -> RegorusResult { + let result = || -> Result<*mut c_void> { + if value.is_null() { + return Err(anyhow!("Null value pointer")); + } + + let val_ref = unsafe { &*(value as *mut Value) }; + let cloned = Box::new(val_ref.clone()); + Ok(Box::into_raw(cloned) as *mut c_void) + }(); + + match result { + Ok(ptr) => RegorusResult::ok_pointer(ptr, RegorusPointerType::PointerValue), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +// Engine integration - Input/Data +#[no_mangle] +pub extern "C" fn regorus_engine_set_input_value( + engine: *mut RegorusEngine, + value: *mut c_void, +) -> RegorusResult { + let result = || -> Result<()> { + if engine.is_null() { + return Err(anyhow!("Null engine pointer")); + } + + let engine_ref = unsafe { &mut *engine }; + let val = to_value_ref(value)?.clone(); + + engine_ref.engine.set_input(val); + Ok(()) + }(); + + match result { + Ok(_) => RegorusResult::ok_void(), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +#[no_mangle] +pub extern "C" fn regorus_engine_add_data_value( + engine: *mut RegorusEngine, + value: *mut c_void, +) -> RegorusResult { + let result = || -> Result<()> { + if engine.is_null() { + return Err(anyhow!("Null engine pointer")); + } + + let engine_ref = unsafe { &mut *engine }; + let val = to_value_ref(value)?.clone(); + + engine_ref.engine.add_data(val)?; + Ok(()) + }(); + + match result { + Ok(_) => RegorusResult::ok_void(), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +// Engine integration - Eval (returns Value instead of JSON) +#[no_mangle] +pub extern "C" fn regorus_engine_eval_query_as_value( + engine: *mut RegorusEngine, + query: *const c_char, +) -> RegorusResult { + let result = || -> Result<*mut c_void> { + if engine.is_null() { + return Err(anyhow!("Null engine pointer")); + } + + let engine_ref = unsafe { &mut *engine }; + let query_str = from_c_str(query)?; + + // Convert QueryResults to Value by directly extracting values (no JSON conversion) + let results = engine_ref.engine.eval_query(query_str, false)?; + + // Create a Value array to hold all result expressions + let mut result_array = Vec::new(); + for result in results.result { + let mut expr_array = Vec::new(); + for expr in result.expressions { + expr_array.push(expr.value); + } + result_array.push(Value::from(expr_array)); + } + + let value = Box::new(Value::from(result_array)); + + Ok(Box::into_raw(value) as *mut c_void) + }(); + + match result { + Ok(ptr) => RegorusResult::ok_pointer(ptr, RegorusPointerType::PointerValue), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} + +#[no_mangle] +pub extern "C" fn regorus_engine_eval_rule_as_value( + engine: *mut RegorusEngine, + rule: *const c_char, +) -> RegorusResult { + let result = || -> Result<*mut c_void> { + if engine.is_null() { + return Err(anyhow!("Null engine pointer")); + } + + let engine_ref = unsafe { &mut *engine }; + let rule_str = from_c_str(rule)?; + + let value = Box::new(engine_ref.engine.eval_rule(rule_str)?); + Ok(Box::into_raw(value) as *mut c_void) + }(); + + match result { + Ok(ptr) => RegorusResult::ok_pointer(ptr, RegorusPointerType::PointerValue), + Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{}", e)), + } +} diff --git a/bindings/java/Cargo.lock b/bindings/java/Cargo.lock index c5041a3d..be0c0d01 100644 --- a/bindings/java/Cargo.lock +++ b/bindings/java/Cargo.lock @@ -18,9 +18,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -75,9 +75,9 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "borrow-or-share" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" +checksum = "dc0b364ead1874514c8c2855ab558056ebfeb775653e7ae45ff72f28f8f3166c" [[package]] name = "bstr" @@ -109,9 +109,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.43" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "shlex", @@ -303,9 +303,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -316,9 +316,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -329,11 +329,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -344,42 +343,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -502,9 +497,9 @@ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -690,9 +685,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -1002,9 +997,9 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" -version = "2.0.108" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", @@ -1064,9 +1059,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -1074,9 +1069,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unsafe-libyaml" @@ -1352,17 +1347,16 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -1370,9 +1364,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -1423,9 +1417,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -1434,9 +1428,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -1445,9 +1439,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", diff --git a/bindings/python/Cargo.lock b/bindings/python/Cargo.lock index 9e0314e9..7f7d4f0f 100644 --- a/bindings/python/Cargo.lock +++ b/bindings/python/Cargo.lock @@ -18,9 +18,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -75,9 +75,9 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "borrow-or-share" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" +checksum = "dc0b364ead1874514c8c2855ab558056ebfeb775653e7ae45ff72f28f8f3166c" [[package]] name = "bstr" @@ -103,9 +103,9 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "cc" -version = "1.2.43" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "shlex", @@ -287,9 +287,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -300,9 +300,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -313,11 +313,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -328,42 +327,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -473,9 +468,9 @@ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -685,9 +680,9 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -1053,9 +1048,9 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" -version = "2.0.108" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", @@ -1101,9 +1096,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -1111,9 +1106,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unindent" @@ -1301,17 +1296,16 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -1319,9 +1313,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -1372,9 +1366,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -1383,9 +1377,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -1394,9 +1388,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", diff --git a/bindings/wasm/Cargo.lock b/bindings/wasm/Cargo.lock index c0bb9652..6bf8693d 100644 --- a/bindings/wasm/Cargo.lock +++ b/bindings/wasm/Cargo.lock @@ -18,9 +18,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -75,9 +75,9 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "borrow-or-share" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" +checksum = "dc0b364ead1874514c8c2855ab558056ebfeb775653e7ae45ff72f28f8f3166c" [[package]] name = "bstr" @@ -103,9 +103,9 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "cc" -version = "1.2.43" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "shlex", @@ -296,9 +296,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -309,9 +309,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -322,11 +322,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -337,42 +336,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -473,9 +468,9 @@ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -671,9 +666,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -986,9 +981,9 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" -version = "2.0.108" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", @@ -1028,9 +1023,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -1038,9 +1033,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unsafe-libyaml" @@ -1303,17 +1298,16 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -1321,9 +1315,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -1374,9 +1368,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -1385,9 +1379,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -1396,9 +1390,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote",