From c0bef21983e8615322dee32fa5b8b17e8f262dca Mon Sep 17 00:00:00 2001 From: Constantinos Giachalis Date: Wed, 2 Apr 2025 11:46:49 +0300 Subject: [PATCH] Extend jsonString R6 class to support ordered json type * Added new R6 class ojsonString --- NAMESPACE | 1 + R/RcppExports.R | 8 ++ R/jsonStrings.R | 135 +++++++++++++++-------- R/ojsonStrings.R | 27 +++++ inst/include/jsonStrings.h | 3 + man/jsonString.Rd | 39 ++++++- man/ojsonString.Rd | 82 ++++++++++++++ src/JsonString.h | 219 +++++++++++++++++++++++++++++++++++++ src/RcppExports.cpp | 26 +++++ src/jsonStrings.cpp | 47 ++++++++ 10 files changed, 537 insertions(+), 50 deletions(-) create mode 100644 R/ojsonStrings.R create mode 100644 man/ojsonString.Rd diff --git a/NAMESPACE b/NAMESPACE index 9bb5319..fabad34 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export(jsonString) +export(ojsonString) importFrom(R6,R6Class) importFrom(Rcpp,evalCpp) importFrom(Rcpp,setRcppClass) diff --git a/R/RcppExports.R b/R/RcppExports.R index 52c9b7f..590d041 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -9,3 +9,11 @@ read_json <- function(filename) { .Call(`_jsonStrings_read_json`, filename) } +toOJSONXptr <- function(string) { + .Call(`_jsonStrings_toOJSONXptr`, string) +} + +read_ojson <- function(filename) { + .Call(`_jsonStrings_read_ojson`, filename) +} + diff --git a/R/jsonStrings.R b/R/jsonStrings.R index 6648d45..a269f18 100644 --- a/R/jsonStrings.R +++ b/R/jsonStrings.R @@ -4,6 +4,7 @@ NULL JsonString <- setRcppClass("JsonString") +oJsonString <- setRcppClass("oJsonString") Xptr <- function(jstring){ jstring[[".__enclos_env__"]][["private"]][[".jsonString"]][["ptr"]] @@ -23,11 +24,26 @@ jsonString <- R6Class( private = list( .prettyPrint = TRUE, - .jsonString = NULL + .jsonString = NULL, + .is_ordered_json = NULL, + getPtr = function(x) { + if (isJsonString(x)) { + if (private$.is_ordered_json != x$is_ordered_json) { + stop(sprintf("Json type mismatch: input json string should be of type '%s' not '%s'", + self$json_type, x$json_type), call. = FALSE) + } + ptr <- Xptr(x) + } else if(isString(x)) { + ptr <- if(private$.is_ordered_json) toOJSONXptr(x) else toJSONXptr(x) + } else { + stop(sprintf("Invalid %s argument.", sQuote(deparse(substitute(x)))), call. = FALSE) + } + ptr + } ), active = list( - #' @field prettyPrint get or set the value of \code{prettyPrint} + #' @field prettyPrint Get or set the value of \code{prettyPrint} #' @examples #' jstring <- jsonString$new( #' "[1, [\"a\", 99], {\"x\": [2,3,4], \"y\": 42}]" @@ -45,6 +61,37 @@ jsonString <- R6Class( ) private[[".prettyPrint"]] <- value } + }, + #' @field json_type Get the json type: either \code{json} or \code{ordered_json} + #' @examples + #' jstring <- jsonString$new( + #' "[1, [\"a\", 99], {\"x\": [2,3,4], \"y\": 42}]" + #' ) + #' jstring$json_type + #' # "json" + json_type = function(value) { + if (!missing(value)) { + stop("'json_type' is read only field.", call. = FALSE) + } + if (private$.is_ordered_json) { + json_type <- "ordered_json" + } else { + json_type <- "json" + } + json_type + }, + #' @field is_ordered_json Check if object is of type \code{ordered_json} + #' @examples + #' jstring <- jsonString$new( + #' "[1, [\"a\", 99], {\"x\": [2,3,4], \"y\": 42}]" + #' ) + #' jstring$is_ordered_json + #' # FALSE + is_ordered_json = function(value) { + if (!missing(value)) { + stop("'is_ordered_json' is read only field.", call. = FALSE) + } + private$.is_ordered_json } ), @@ -54,24 +101,36 @@ jsonString <- R6Class( #' #' @param string a string representing a JSON object, or the path to a #' JSON file - #' + #' @param ordered_json Should the \code{jsonString} object be of type + #' \code{json} (default) or \code{ordered_json}. + #' #' @return A \code{jsonString} object. #' #' @examples #' jstring <- "[1, [\"a\", 99], {\"x\": [2,3,4], \"y\": 42}]" #' jsonString$new(jstring) - initialize = function(string) { + initialize = function(string, ordered_json = FALSE) { + + stopifnot(isBoolean(ordered_json)) + private[[".is_ordered_json"]] <- ordered_json + # initialization from a pointer is hidden to the user if(inherits(string, "externalptr")) { - private[[".jsonString"]] <- JsonString$new(string, 0L) + private[[".jsonString"]] <- if (ordered_json) oJsonString$new(string, 0L) else JsonString$new(string, 0L) return(invisible(self)) } stopifnot(isString(string)) if(file.exists(string)) { - ptr <- read_json(path.expand(string)) - private[[".jsonString"]] <- JsonString$new(ptr, 0L) + + private[[".jsonString"]] <- if (ordered_json) { + ptr <- read_ojson(path.expand(string)) + oJsonString$new(ptr, 0L) + } else { + ptr <- read_json(path.expand(string)) + JsonString$new(ptr, 0L) + } } else { - private[[".jsonString"]] <- JsonString$new(string) + private[[".jsonString"]] <- if (ordered_json) oJsonString$new(string) else JsonString$new(string) } invisible(self) }, @@ -117,7 +176,7 @@ jsonString <- R6Class( #' jstring$at(2, "x") at = function(...) { ptr <- private[[".jsonString"]]$at(list(...)) - jsonString$new(ptr) + jsonString$new(ptr, private$.is_ordered_json) }, #' @description Checks whether a key exists in the reference JSON string. @@ -170,14 +229,10 @@ jsonString <- R6Class( #' jstring addProperty = function(key, value) { stopifnot(isString(key)) - if(isJsonString(value)) { - ptr <- Xptr(value) - } else if(isString(value)) { - ptr <- toJSONXptr(value) - } else { - stop("Invalid `value` argument.") - } + + ptr <- private$getPtr(value) private[[".jsonString"]]$addProperty(key, ptr) + invisible(self) }, @@ -239,14 +294,10 @@ jsonString <- R6Class( #' jstring$update(jstring2) #' jstring update = function(jstring) { - if(isJsonString(jstring)) { - ptr <- Xptr(jstring) - } else if(isString(jstring)) { - ptr <- toJSONXptr(jstring) - } else { - stop("Invalid `jstring` argument.") - } + + ptr <- private$getPtr(jstring) private[[".jsonString"]]$update(ptr) + invisible(self) }, @@ -266,14 +317,10 @@ jsonString <- R6Class( #' jstring$merge(jstring2) #' jstring merge = function(jstring) { - if(isJsonString(jstring)) { - ptr <- Xptr(jstring) - } else if(isString(jstring)) { - ptr <- toJSONXptr(jstring) - } else { - stop("Invalid `jstring` argument.") - } + + ptr <- private$getPtr(jstring) private[[".jsonString"]]$merge(ptr) + invisible(self) }, @@ -299,15 +346,11 @@ jsonString <- R6Class( #' ]" #' jstring$patch(jspatch) patch = function(jspatch) { - if(isJsonString(jspatch)) { - ptrpatch <- Xptr(jspatch) - } else if(isString(jspatch)) { - ptrpatch <- toJSONXptr(jspatch) - } else { - stop("Invalid `jspatch` argument.") - } + + ptrpatch <- private$getPtr(jspatch) ptr <- private[[".jsonString"]]$patch(ptrpatch) - jsonString$new(ptr) + + jsonString$new(ptr, private$.is_ordered_json) }, #' @description Append an element to the reference JSON string (if it @@ -326,14 +369,10 @@ jsonString <- R6Class( #' jstring$push(jstring2) #' jstring push = function(jstring) { - if(isJsonString(jstring)) { - ptr <- Xptr(jstring) - } else if(isString(jstring)) { - ptr <- toJSONXptr(jstring) - } else { - stop("Invalid `jstring` argument.") - } + + ptr <- private$getPtr(jstring) private[[".jsonString"]]$push(ptr) + invisible(self) }, @@ -395,7 +434,7 @@ jsonString <- R6Class( #' jstring$flatten() flatten = function() { ptr <- private[[".jsonString"]]$flatten() - jsonString$new(ptr) + jsonString$new(ptr, private$.is_ordered_json) }, #' @description Unflatten the reference JSON string (if it is flattened). @@ -412,7 +451,7 @@ jsonString <- R6Class( #' jstring$unflatten() unflatten = function() { ptr <- private[[".jsonString"]]$unflatten() - jsonString$new(ptr) + jsonString$new(ptr, private$.is_ordered_json) }, #' @description Write the reference JSON string to a file. @@ -449,7 +488,7 @@ jsonString <- R6Class( #' naive_copy$erase("b") #' jstring copy = function() { - jsonString$new(Xptr(self)) + jsonString$new(Xptr(self), private$.is_ordered_json) } ) diff --git a/R/ojsonStrings.R b/R/ojsonStrings.R new file mode 100644 index 0000000..5d9c6a4 --- /dev/null +++ b/R/ojsonStrings.R @@ -0,0 +1,27 @@ +#' @title R6 class to represent an ordered JSON string +#' @description R6 class to represent a JSON string that +#' preserves the insertion order of object keys. +#' +#' @export +ojsonString <- R6Class( + + lock_class = TRUE, + cloneable = FALSE, + classname = "ojsonString", + inherit = jsonString, + public = list( + #' @description Creates a new \code{ojsonString} object. + #' + #' @param string a string representing an JSON object, or the path to a + #' JSON file + #' + #' @return A \code{ojsonString} object. + #' + #' @examples + #' jstring <- "[1, [\"a\", 99], {\"y\": [2,3,4], \"x\": 42}]" + #' ojsonString$new(jstring) + initialize = function(string) { + super$initialize(string = string, ordered_json = TRUE) + } + ) +) \ No newline at end of file diff --git a/inst/include/jsonStrings.h b/inst/include/jsonStrings.h index 9a63e22..cc6b329 100644 --- a/inst/include/jsonStrings.h +++ b/inst/include/jsonStrings.h @@ -3,9 +3,12 @@ #include "nlohmann/json_cran.h" using json = nlohmann::json; +using ordered_json = nlohmann::ordered_json; + #include #include typedef Rcpp::XPtr jsonXptr; +typedef Rcpp::XPtr ojsonXptr; #endif diff --git a/man/jsonString.Rd b/man/jsonString.Rd index 2b26cbc..ec281b0 100644 --- a/man/jsonString.Rd +++ b/man/jsonString.Rd @@ -19,6 +19,16 @@ jstring$prettyPrint jstring jstring$prettyPrint <- FALSE jstring +jstring <- jsonString$new( + "[1, [\"a\", 99], {\"x\": [2,3,4], \"y\": 42}]" +) +jstring$json_type +# "json" +jstring <- jsonString$new( + "[1, [\"a\", 99], {\"x\": [2,3,4], \"y\": 42}]" +) +jstring$is_ordered_json +# FALSE jstring <- "[1, [\"a\", 99], {\"x\": [2,3,4], \"y\": 42}]" jsonString$new(jstring) @@ -231,7 +241,11 @@ jstring \section{Active bindings}{ \if{html}{\out{
}} \describe{ -\item{\code{prettyPrint}}{get or set the value of \code{prettyPrint}} +\item{\code{prettyPrint}}{Get or set the value of \code{prettyPrint}} + +\item{\code{json_type}}{Get the json type: either \code{json} or \code{ordered_json}} + +\item{\code{is_ordered_json}}{Check if object is of type \code{ordered_json}} } \if{html}{\out{
}} } @@ -265,7 +279,7 @@ jstring \subsection{Method \code{new()}}{ Creates a new \code{jsonString} object. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{jsonString$new(string)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{jsonString$new(string, ordered_json = FALSE)}\if{html}{\out{
}} } \subsection{Arguments}{ @@ -273,6 +287,9 @@ Creates a new \code{jsonString} object. \describe{ \item{\code{string}}{a string representing a JSON object, or the path to a JSON file} + +\item{\code{ordered_json}}{Should the \code{jsonString} object be of type +\code{json} (default) or \code{ordered_json}.} } \if{html}{\out{}} } @@ -291,6 +308,24 @@ jstring } \if{html}{\out{}} +\if{html}{\out{
}} +\preformatted{jstring <- jsonString$new( + "[1, [\"a\", 99], {\"x\": [2,3,4], \"y\": 42}]" +) +jstring$json_type +# "json" +} +\if{html}{\out{
}} + +\if{html}{\out{
}} +\preformatted{jstring <- jsonString$new( + "[1, [\"a\", 99], {\"x\": [2,3,4], \"y\": 42}]" +) +jstring$is_ordered_json +# FALSE +} +\if{html}{\out{
}} + \if{html}{\out{
}} \preformatted{jstring <- "[1, [\"a\", 99], {\"x\": [2,3,4], \"y\": 42}]" jsonString$new(jstring) diff --git a/man/ojsonString.Rd b/man/ojsonString.Rd new file mode 100644 index 0000000..14a18ee --- /dev/null +++ b/man/ojsonString.Rd @@ -0,0 +1,82 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ojsonStrings.R +\name{ojsonString} +\alias{ojsonString} +\title{R6 class to represent an ordered JSON string} +\description{ +R6 class to represent a JSON string that +preserves the insertion order of object keys. +} +\examples{ + +## ------------------------------------------------ +## Method `ojsonString$new` +## ------------------------------------------------ + +jstring <- "[1, [\"a\", 99], {\"y\": [2,3,4], \"x\": 42}]" +ojsonString$new(jstring) +} +\section{Super class}{ +\code{\link[jsonStrings:jsonString]{jsonStrings::jsonString}} -> \code{ojsonString} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-ojsonString-new}{\code{ojsonString$new()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-ojsonString-new}{}}} +\subsection{Method \code{new()}}{ +Creates a new \code{ojsonString} object. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{ojsonString$new(string)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{string}}{a string representing an JSON object, or the path to a +JSON file} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A \code{ojsonString} object. +} +\subsection{Examples}{ +\if{html}{\out{
}} +\preformatted{jstring <- "[1, [\"a\", 99], {\"y\": [2,3,4], \"x\": 42}]" +ojsonString$new(jstring) +} +\if{html}{\out{
}} + +} + +} +} diff --git a/src/JsonString.h b/src/JsonString.h index 990c189..e74914f 100644 --- a/src/JsonString.h +++ b/src/JsonString.h @@ -214,4 +214,223 @@ class JsonString { return jsonXptr(new json(junflat), false); } +}; + +ordered_json toOJSONstring(std::string); + +class oJsonString { +public: + ordered_json jsonString; + ojsonXptr ptr; + explicit oJsonString(const std::string& string_) + : jsonString(toOJSONstring(string_)), ptr(ojsonXptr(&jsonString, false)) {} + oJsonString(Rcpp::XPtr ptr_, int xxx) + : jsonString(*(ptr_.get())), ptr(ojsonXptr(&jsonString, false)) {} + + void writeFile(std::string filename) { + std::ofstream jsonfile; + jsonfile.open(filename); + jsonfile << std::setw(4) << jsonString << std::endl; + jsonfile.close(); + } + + ojsonXptr at(Rcpp::List path) { + ordered_json js = jsonString; + for(R_xlen_t i = 0; i < path.size(); i++) { + Rcpp::RObject robj = path(i); + int obj_type = robj.sexp_type(); + if(obj_type == 13 || obj_type == 14) { + if(!js.is_array()) { + Rcpp::stop("Not an array."); + } + int index; + if(obj_type == 13) { + Rcpp::IntegerVector vindex = Rcpp::wrap(robj); + if(vindex.length() != 1) { + Rcpp::stop("Invalid path."); + } + index = vindex[0]; + } else { + Rcpp::NumericVector vindex = Rcpp::wrap(robj); + if(vindex.length() != 1) { + Rcpp::stop("Invalid path."); + } + index = (int)(vindex[0]); + } + if(index < 0) { + Rcpp::stop("Negative indices make no sense."); + } + if(index >= (int)(js.size())) { + Rcpp::stop("Too large index."); + } + js = js.at(index); + } else if(obj_type == 16) { + if(!js.is_object()) { + Rcpp::stop("Not an object."); + } + Rcpp::StringVector vkey = Rcpp::wrap(robj); + if(vkey.length() != 1) { + Rcpp::stop("Invalid path."); + } + Rcpp::String key = vkey[0]; + js = js[key]; + } else { + Rcpp::stop("Invalid path."); + } + } + return ojsonXptr(new ordered_json(js), false); + } + + bool hasKey(std::string key) { return jsonString.contains(key); } + + Rcpp::StringVector keys() { + if(!jsonString.is_object()) { + Rcpp::stop("The reference JSON string is not an object."); + } + size_t s = jsonString.size(); + Rcpp::StringVector out(s); + unsigned i = 0; + for(auto item : jsonString.items()) { + out(i) = item.key(); + i++; + } + return out; + } + + void addProperty(std::string key, ojsonXptr pptyXptr) { + if(!jsonString.is_object()) { + Rcpp::stop("The reference JSON string is not an object."); + } + if(jsonString.contains(key)) { + Rcpp::stop("New key already present."); + }; + ordered_json ppty = *(pptyXptr.get()); + //jsonString[key] = ppty; + jsonString[key].emplace_back(ppty); + } + + void eraseProperty(std::string key) { + if(!jsonString.is_object()) { + Rcpp::stop("The reference JSON string is not an object."); + } + jsonString.erase(key); + } + + void eraseElement(size_t idx) { + if(!jsonString.is_array()) { + Rcpp::stop("The reference JSON string is not an array."); + } + if(idx >= jsonString.size()) { + Rcpp::stop("Too large index."); + } + jsonString.erase(idx); + } + + size_t size() { return jsonString.size(); } + + void update(ojsonXptr obj) { + if(!jsonString.is_object()) { + Rcpp::stop("The reference JSON string is not an object."); + } + ordered_json js2 = *(obj.get()); + if(!js2.is_object()) { + Rcpp::stop("The other JSON string is not an object."); + } + jsonString.update(js2); + } + + void push(ojsonXptr elem) { + if(!(jsonString.is_array() || jsonString.is_null())) { + Rcpp::stop("The reference JSON string is not an array."); + } + ordered_json js2 = *(elem.get()); + jsonString.push_back(js2); + } + + ojsonXptr patch(ojsonXptr jspatchptr) { + if(!(jsonString.is_object() || jsonString.is_array())) { + Rcpp::stop("The reference JSON string must be an object or an array."); + } + ordered_json jspatch = *(jspatchptr.get()); + if(!jspatch.is_array()) { + Rcpp::stop("The `patch` JSON string is not an array."); + } + try { + ordered_json jsresult = jsonString.patch(jspatch); + return ojsonXptr(new ordered_json(jsresult), false); + } catch(ordered_json::exception& e) { + Rcpp::stop(e.what()); + } + } + + void merge(ojsonXptr jspatchptr) { + ordered_json jspatch = *(jspatchptr.get()); + jsonString.merge_patch(jspatch); + } + + bool is(std::string type) { + std::array types = {"array", "object", "number", + "integer", "string", "null", + "boolean", "float"}; + auto it = std::find(types.begin(), types.end(), type); + if(it == types.end()) { + Rcpp::stop("Unknown type."); + } + int index = it - types.begin() + 1; + bool result = false; + switch(index) { + case 1: + result = jsonString.is_array(); + break; + case 2: + result = jsonString.is_object(); + break; + case 3: + result = jsonString.is_number(); + break; + case 4: + result = jsonString.is_number_integer(); + break; + case 5: + result = jsonString.is_string(); + break; + case 6: + result = jsonString.is_null(); + break; + case 7: + result = jsonString.is_boolean(); + break; + case 8: + result = jsonString.is_number_float(); + break; + } + return result; + } + + std::string type() { return jsonString.type_name(); } + + std::string asString(bool pretty = false) { + std::string string; + if(pretty) { + string = jsonString.dump(4); + } else { + string = jsonString.dump(); + } + return string; + } + + void print(bool pretty = true) { + Rcpp::Rcout << this->asString(pretty) << "\n"; + } + + ojsonXptr flatten(){ + ordered_json jflat = jsonString.flatten(); + return ojsonXptr(new ordered_json(jflat), false); + } + + ojsonXptr unflatten(){ + ordered_json junflat = jsonString.unflatten(); + return ojsonXptr(new ordered_json(junflat), false); + } + }; \ No newline at end of file diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 0b452c6..ac19324 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -33,13 +33,39 @@ BEGIN_RCPP return rcpp_result_gen; END_RCPP } +// toOJSONXptr +ojsonXptr toOJSONXptr(const std::string& string); +RcppExport SEXP _jsonStrings_toOJSONXptr(SEXP stringSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< const std::string& >::type string(stringSEXP); + rcpp_result_gen = Rcpp::wrap(toOJSONXptr(string)); + return rcpp_result_gen; +END_RCPP +} +// read_ojson +ojsonXptr read_ojson(std::string filename); +RcppExport SEXP _jsonStrings_read_ojson(SEXP filenameSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< std::string >::type filename(filenameSEXP); + rcpp_result_gen = Rcpp::wrap(read_ojson(filename)); + return rcpp_result_gen; +END_RCPP +} RcppExport SEXP _rcpp_module_boot_class_JsonString(); +RcppExport SEXP _rcpp_module_boot_class_oJsonString(); static const R_CallMethodDef CallEntries[] = { {"_jsonStrings_toJSONXptr", (DL_FUNC) &_jsonStrings_toJSONXptr, 1}, {"_jsonStrings_read_json", (DL_FUNC) &_jsonStrings_read_json, 1}, + {"_jsonStrings_toOJSONXptr", (DL_FUNC) &_jsonStrings_toOJSONXptr, 1}, + {"_jsonStrings_read_ojson", (DL_FUNC) &_jsonStrings_read_ojson, 1}, {"_rcpp_module_boot_class_JsonString", (DL_FUNC) &_rcpp_module_boot_class_JsonString, 0}, + {"_rcpp_module_boot_class_oJsonString", (DL_FUNC) &_rcpp_module_boot_class_oJsonString, 0}, {NULL, NULL, 0} }; diff --git a/src/jsonStrings.cpp b/src/jsonStrings.cpp index a0fc312..afb230c 100644 --- a/src/jsonStrings.cpp +++ b/src/jsonStrings.cpp @@ -21,6 +21,27 @@ jsonXptr read_json(std::string filename){ return jsonXptr(new json(jstring), false); } +ordered_json toOJSONstring(std::string string) { + if(!ordered_json::accept(string)) { + Rcpp::stop("Invalid JSON string."); + } + return ordered_json::parse(string); +} + +// [[Rcpp::export]] +ojsonXptr toOJSONXptr(const std::string& string){ + ordered_json jstring = toOJSONstring(string); + return ojsonXptr(new ordered_json(jstring), false); +} + +// [[Rcpp::export]] +ojsonXptr read_ojson(std::string filename){ + std::ifstream i(filename); + json jstring; + i >> jstring; + return ojsonXptr(new ordered_json(jstring), false); +} + #include "JsonString.h" RCPP_MODULE(class_JsonString) { @@ -47,4 +68,30 @@ RCPP_MODULE(class_JsonString) { .method("flatten", &JsonString::flatten) .method("unflatten", &JsonString::unflatten) .method("writeFile", &JsonString::writeFile); +} + +RCPP_MODULE(class_oJsonString) { + using namespace Rcpp; + class_("oJsonString") + .constructor() + .constructor, int>() + .field("ptr", &oJsonString::ptr) + .method("asString", &oJsonString::asString) + .method("print", &oJsonString::print) + .method("at", &oJsonString::at) + .method("hasKey", &oJsonString::hasKey) + .method("keys", &oJsonString::keys) + .method("addProperty", &oJsonString::addProperty) + .method("eraseProperty", &oJsonString::eraseProperty) + .method("eraseElement", &oJsonString::eraseElement) + .method("update", &oJsonString::update) + .method("is", &oJsonString::is) + .method("type", &oJsonString::type) + .method("push", &oJsonString::push) + .method("size", &oJsonString::size) + .method("patch", &oJsonString::patch) + .method("merge", &oJsonString::merge) + .method("flatten", &oJsonString::flatten) + .method("unflatten", &oJsonString::unflatten) + .method("writeFile", &oJsonString::writeFile); } \ No newline at end of file