Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle non-first AsIs; add unit tests #80

Open
wants to merge 2 commits into
base: issue75
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"files.associations": {
"map": "cpp",
"set": "cpp",
"string": "cpp",
"string_view": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp"
}
}
10 changes: 6 additions & 4 deletions R/to_json.R
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@
#'
#' @export
to_json <- function( x, unbox = FALSE, digits = NULL, numeric_dates = TRUE,
factors_as_string = TRUE, by = "row" ) {
factors_as_string = TRUE, by = "row",
json_verbatim = FALSE ) {
if( "col" %in% by ) by <- "column"
by <- match.arg( by, choices = c("row", "column") )
digits <- handle_digits( digits )
rcpp_to_json( x, unbox, digits, numeric_dates, factors_as_string, by )
rcpp_to_json( x, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim )
}

#' To ndjson
Expand Down Expand Up @@ -107,11 +108,12 @@ to_json <- function( x, unbox = FALSE, digits = NULL, numeric_dates = TRUE,
#'
#' @export
to_ndjson <- function( x, unbox = FALSE, digits = NULL, numeric_dates = TRUE,
factors_as_string = TRUE, by = "row" ) {
factors_as_string = TRUE, by = "row",
json_verbatim = FALSE ) {
if( "col" %in% by ) by <- "column"
by <- match.arg( by, choices = c("row", "column") )
digits <- handle_digits( digits )
rcpp_to_ndjson( x, unbox, digits, numeric_dates, factors_as_string, by )
rcpp_to_ndjson( x, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim )
}

handle_digits <- function( digits ) {
Expand Down
11 changes: 7 additions & 4 deletions inst/include/jsonify/to_json/api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ namespace api {
int digits = -1,
bool numeric_dates = true,
bool factors_as_string = true,
std::string by = "row"
std::string by = "row",
bool json_verbatim = false
) {
rapidjson::StringBuffer sb;
rapidjson::Writer < rapidjson::StringBuffer > writer( sb );
jsonify::writers::complex::write_value( writer, lst, unbox, digits, numeric_dates, factors_as_string, by );
jsonify::writers::complex::write_value( writer, lst, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim );
return jsonify::utils::finalise_json( sb );
}

Expand All @@ -28,7 +29,8 @@ namespace api {
// int digits = -1,
// bool numeric_dates = true,
// bool factors_as_string = true,
// std::string by = "row"
// std::string by = "row",
// bool json_verbatim = false
// ) {
// // loop over rows or columns,
// }
Expand Down Expand Up @@ -373,7 +375,8 @@ namespace api {
int digits = -1,
bool numeric_dates = true,
bool factors_as_string = true,
std::string by = "row"
std::string by = "row",
bool json_verbatim = false
) {

std::ostringstream os; // for storing the final string of ndjson
Expand Down
19 changes: 17 additions & 2 deletions inst/include/jsonify/to_json/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@
namespace jsonify {
namespace utils {

// true if `vec` contains `target`; else false
inline bool contains(const Rcpp::CharacterVector& vec, const std::string& target) {
for (int i = 0; i < vec.size(); ++i) {
if (Rcpp::as<std::string>(vec[i]) == target) {
return true;
}
}
return false;
}

// true if `sv` is length-one and has class "json"
inline bool is_raw_json(Rcpp::StringVector sv) {
return contains(rClass(sv), "json");
}

template < int RTYPE >
inline Rcpp::CharacterVector rClass( Rcpp::Vector< RTYPE > v ) {
if( Rf_isNull( v.attr("class")) ) {
Expand Down Expand Up @@ -51,8 +66,8 @@ namespace utils {

template< typename RTYPE >
inline bool should_unbox( RTYPE x, int n, bool unbox ) {
Rcpp::CharacterVector attr = rClass( x );
return ( unbox && n == 1 && strcmp(attr[0], "AsIs") != 0 );
Rcpp::CharacterVector klasses = rClass( x );
return ( unbox && n == 1 && !contains(klasses, "AsIs") );
}

template< typename Writer >
Expand Down
33 changes: 19 additions & 14 deletions inst/include/jsonify/to_json/writers/complex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ namespace jsonify {
namespace writers {
namespace complex {

// MT: I'm not sure this `switch_vector()` function is ever called.
// I can't find any usage that doesn't also pass an additional `row` arg.
// (I.e. all usages seem to call the other overloaded `switch_vector()` func.
template < typename Writer >
inline void switch_vector(
Writer& writer,
Expand Down Expand Up @@ -75,7 +78,8 @@ namespace complex {
bool& unbox,
int& digits,
bool& numeric_dates,
bool& factors_as_string,
bool& factors_as_string,
bool& json_verbatim,
R_xlen_t& row
) {

Expand Down Expand Up @@ -117,10 +121,10 @@ namespace complex {
default: {
if( Rf_isMatrix( this_vec ) ) {
Rcpp::StringMatrix sm = Rcpp::as< Rcpp::StringMatrix >( this_vec );
jsonify::writers::simple::write_value( writer, sm, row, unbox );
jsonify::writers::simple::write_value( writer, sm, row, unbox, json_verbatim );
} else {
Rcpp::StringVector sv = Rcpp::as< Rcpp::StringVector >( this_vec );
jsonify::writers::simple::write_value( writer, sv, row );
jsonify::writers::simple::write_value( writer, sv, row, json_verbatim );
}
break;
}
Expand All @@ -135,7 +139,8 @@ namespace complex {
int digits = -1,
bool numeric_dates = true,
bool factors_as_string = true,
std::string by = "row",
std::string by = "row",
bool json_verbatim = false,
R_xlen_t row = -1, // for when we are recursing into a row of a data.frame
bool in_data_frame = false // for keeping track of when we're in a column of a data.frame
) {
Expand Down Expand Up @@ -168,7 +173,7 @@ namespace complex {
}
default :{
Rcpp::StringMatrix sm = Rcpp::as< Rcpp::StringMatrix >( list_element );
return jsonify::writers::simple::write_value( writer, sm, unbox, by );
return jsonify::writers::simple::write_value( writer, sm, unbox, by, json_verbatim );
break;
}
}
Expand Down Expand Up @@ -222,7 +227,7 @@ namespace complex {
const char *h = column_names[ df_col ];
writer.String( h );
SEXP this_vec = df[ h ];
write_value( writer, this_vec, unbox, digits, numeric_dates, factors_as_string, by, -1, in_data_frame );
write_value( writer, this_vec, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim, -1, in_data_frame ); // recurse

}
writer.EndObject();
Expand All @@ -243,11 +248,11 @@ namespace complex {

case VECSXP: {
Rcpp::List lst = Rcpp::as< Rcpp::List >( this_vec );
write_value( writer, lst, unbox, digits, numeric_dates, factors_as_string, by, row, in_data_frame );
write_value( writer, lst, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim, row, in_data_frame ); // recurse
break;
}
default: {
switch_vector( writer, this_vec, unbox, digits, numeric_dates, factors_as_string, row );
switch_vector( writer, this_vec, unbox, digits, numeric_dates, factors_as_string, json_verbatim, row );
}
} // end switch

Expand All @@ -270,11 +275,11 @@ namespace complex {
switch( TYPEOF( this_vec ) ) {
case VECSXP: {
Rcpp::List lst = Rcpp::as< Rcpp::List >( this_vec );
write_value( writer, lst, unbox, digits, numeric_dates, factors_as_string, by, df_row, in_data_frame );
write_value( writer, lst, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim, df_row, in_data_frame ); // recurse
break;
}
default: {
switch_vector( writer, this_vec, unbox, digits, numeric_dates, factors_as_string, df_row );
switch_vector( writer, this_vec, unbox, digits, numeric_dates, factors_as_string, json_verbatim, df_row );
}
}
}
Expand Down Expand Up @@ -308,7 +313,7 @@ namespace complex {
lst.names() = this_name;
}

write_value( writer, lst, unbox, digits, numeric_dates, factors_as_string, by, -1, in_data_frame );
write_value( writer, lst, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim, -1, in_data_frame );

} else {
lst = temp_lst;
Expand Down Expand Up @@ -346,7 +351,7 @@ namespace complex {
writer.String( s );
}
// setting in_data_frame to false because we're no longer at the data.frame top-level
write_value( writer, recursive_list, unbox, digits, numeric_dates, factors_as_string, by, -1, false );
write_value( writer, recursive_list, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim, -1, false );
}

jsonify::utils::writer_ender( writer, has_names, in_data_frame );
Expand Down Expand Up @@ -374,7 +379,7 @@ namespace complex {
case LANGSXP: { // language constructs (special lists)
Rcpp::Pairlist s = Rcpp::as< Rcpp::Pairlist >( list_element );
Rcpp::List l = Rcpp::as< Rcpp::List >( s );
write_value( writer, l, unbox, digits, numeric_dates, factors_as_string, by );
write_value( writer, l, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim );
break;
}
case CLOSXP: {} // closures
Expand All @@ -383,7 +388,7 @@ namespace complex {
case ENVSXP: {}
case FUNSXP: {
Rcpp::List l = Rcpp::as< Rcpp::List >( list_element );
write_value( writer, l, unbox, digits, numeric_dates, factors_as_string, by );
write_value( writer, l, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim );
break;
}
default: {
Expand Down
6 changes: 6 additions & 0 deletions inst/include/jsonify/to_json/writers/scalars.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef JSONIFY_WRITERS_SCALARS_H
#define JSONIFY_WRITERS_SCALARS_H

#include <cstring>

namespace jsonify {
namespace writers {
Expand All @@ -9,6 +10,11 @@ namespace scalars {
// ---------------------------------------------------------------------------
// scalar values
// ---------------------------------------------------------------------------
template <typename Writer>
inline void write_raw_json( Writer& writer, const char* value ) {
writer.RawValue( value, strlen(length), rapidjson::kTypeNull );
}

template <typename Writer>
inline void write_value( Writer& writer, const char* value ) {
writer.String( value );
Expand Down
32 changes: 22 additions & 10 deletions inst/include/jsonify/to_json/writers/simple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,22 @@ namespace simple {
inline void write_value(
Writer& writer,
Rcpp::StringVector sv,
bool unbox
bool unbox,
bool json_verbatim
) {

R_xlen_t n = sv.size();
bool will_unbox = jsonify::utils::should_unbox( sv, n, unbox );
bool is_raw_json = jsonify::utils::is_raw_json(sv);
jsonify::utils::start_array( writer, will_unbox );
R_xlen_t i;

for ( i = 0; i < n; ++i ) {
if (Rcpp::StringVector::is_na( sv[i] ) ) {
writer.Null();
} else{
} else if (is_raw_json && json_verbatim) {
jsonify::writers::scalars::write_raw_json( writer, sv[i] );
} else {
jsonify::writers::scalars::write_value( writer, sv[i] );
}
}
Expand All @@ -44,11 +48,14 @@ namespace simple {
inline void write_value(
Writer& writer,
Rcpp::StringVector& sv,
int row
int row,
bool json_verbatim
) {

if ( Rcpp::StringVector::is_na( sv[ row ] ) ) {
writer.Null();
} else if (jsonify::utils::is_raw_json(sv) && json_verbatim) {
jsonify::writers::scalars::write_raw_json( writer, sv[row] );
} else {
const char *s = sv[ row ];
jsonify::writers::scalars::write_value( writer, s );
Expand All @@ -63,11 +70,14 @@ namespace simple {
inline void write_value(
Writer& writer,
Rcpp::StringVector sv,
R_xlen_t& row
R_xlen_t& row,
bool json_verbatim
) {

if ( Rcpp::StringVector::is_na( sv[ row ] ) ) {
writer.Null();
} else if (jsonify::utils::is_raw_json(sv) && json_verbatim) {
jsonify::writers::scalars::write_raw_json( writer, sv[row] );
} else {
const char *s = sv[ row ];
jsonify::writers::scalars::write_value( writer, s );
Expand Down Expand Up @@ -630,19 +640,21 @@ namespace simple {
Writer& writer,
Rcpp::StringMatrix& mat,
int& row,
bool unbox = false
bool unbox = false,
bool json_verbatim = false
) {

Rcpp::StringVector this_row = mat(row, Rcpp::_);
write_value( writer, this_row, unbox );
write_value( writer, this_row, unbox, json_verbatim );
}

template < typename Writer >
inline void write_value(
Writer& writer,
Rcpp::CharacterMatrix mat,
Rcpp::StringMatrix mat,
bool unbox = false,
std::string by = "row"
std::string by = "row",
bool json_verbatim = false
) {

bool will_unbox = false;
Expand All @@ -653,13 +665,13 @@ namespace simple {
n = mat.nrow();
for ( i = 0; i < n; ++i ) {
Rcpp::StringVector this_row = mat( i, Rcpp::_ );
write_value( writer, this_row, unbox );
write_value( writer, this_row, unbox, json_verbatim );
}
} else { // by == column
n = mat.ncol();
for ( i = 0; i < n; ++i ) {
Rcpp::StringVector this_col = mat( Rcpp::_, i );
write_value( writer, this_col, unbox );
write_value( writer, this_col, unbox, json_verbatim );
}
}
jsonify::utils::end_array( writer, will_unbox );
Expand Down
16 changes: 11 additions & 5 deletions src/to_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@ Rcpp::StringVector rcpp_to_json(
int digits = -1,
bool numeric_dates = true,
bool factors_as_string = true,
std::string by = "row"
std::string by = "row",
bool json_verbatim = false
) {

SEXP lst2 = Rcpp::clone( lst );
return jsonify::api::to_json( lst2, unbox, digits, numeric_dates, factors_as_string, by );
return jsonify::api::to_json( lst2, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim );
}

// [[Rcpp::export]]
Rcpp::StringVector rcpp_to_ndjson(
SEXP lst, bool unbox = false, int digits = -1, bool numeric_dates = true,
bool factors_as_string = true, std::string by = "row"
SEXP lst,
bool unbox = false,
int digits = -1,
bool numeric_dates = true,
bool factors_as_string = true,
std::string by = "row",
bool json_verbatim = false
) {
return jsonify::api::to_ndjson(lst, unbox, digits, numeric_dates, factors_as_string, by );
return jsonify::api::to_ndjson(lst, unbox, digits, numeric_dates, factors_as_string, by, json_verbatim );
}
Loading