Skip to content
Merged
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
16 changes: 13 additions & 3 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,22 @@ jobs:
fail-fast: false
matrix:
config:
- { os: "ubuntu-latest", R: "latest" }
- { os: "macOS-latest", R: "latest" }

# Check latest R versions
- { os: "ubuntu-latest", R: "latest" }
- { os: "macOS-latest", R: "latest" }
- { os: "windows-latest", R: "latest" }
- { os: "ubuntu-latest", R: "devel" }
- { os: "ubuntu-latest", R: "devel" }
- { os: "windows-latest", R: "devel" }

# Check older versions of R
- { os: "ubuntu-latest", R: 'oldrel-1'}
- { os: "ubuntu-latest", R: 'oldrel-2'}
- { os: "ubuntu-latest", R: 'oldrel-3'}
- { os: "ubuntu-latest", R: 'oldrel-4'}

- { os: "windows-latest", R: "oldrel-4" }

env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
Expand Down
3 changes: 2 additions & 1 deletion paws.common/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: paws.common
Type: Package
Title: Paws Low-Level Amazon Web Services API
Version: 0.8.7
Version: 0.8.8
Authors@R: c(
person("David", "Kretch", email = "david.kretch@gmail.com", role = "aut"),
person("Adam", "Banker", email = "adam.banker39@gmail.com", role = "aut"),
Expand All @@ -14,6 +14,7 @@ Description: Functions for making low-level API requests to Amazon Web Services
higher-level interfaces to individual services, such as Simple Storage
Service (S3).
License: Apache License (>= 2.0)
Depends: R (>= 4.1.0)
URL: https://github.com/paws-r/paws, https://paws-r.r-universe.dev/paws.common, https://www.paws-r-sdk.com
BugReports: https://github.com/paws-r/paws/issues
Encoding: UTF-8
Expand Down
3 changes: 3 additions & 0 deletions paws.common/NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# paws.common 0.8.8
* fix C++ compilation issues on older R versions by refactoring code to use C++11 standard and requiring R >= 4.1.0 (#957). Thanks to @detule for raising the issue.

# paws.common 0.8.7
* fix timezone handling in bearer token tests (#955). Thanks to @kyleam for raising issue.

Expand Down
2 changes: 1 addition & 1 deletion paws.common/src/RcppExports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ BEGIN_RCPP
END_RCPP
}
// json_build_any
std::string json_build_any(SEXP values);
CharacterVector json_build_any(SEXP values);
RcppExport SEXP _paws_common_json_build_any(SEXP valuesSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Expand Down
58 changes: 33 additions & 25 deletions paws.common/src/json_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ inline std::string tag_get(SEXP object, const char *tag)
case STRSXP:
if (Rf_length(val) > 0)
{
return std::string(CHAR(STRING_ELT(val, 0)));
return std::string(Rf_translateCharUTF8(STRING_ELT(val, 0)));
}
break;
case LGLSXP:
Expand Down Expand Up @@ -135,8 +135,8 @@ std::string type(SEXP object)
}

// -------------------- Forward declaration --------------------
// This function will be defined later and called recursively
std::string json_build_any(SEXP values);
// Internal function that builds JSON and returns std::string (used internally)
std::string json_build_internal(SEXP values);

// -------------------- Helper function to safely convert to string --------------------
// This function converts an SEXP to a string representation, handling various R types.
Expand All @@ -151,17 +151,17 @@ std::string safe_as_string(SEXP x)
switch (type)
{
case STRSXP:
// Directly return string for character SEXPs
return std::string(CHAR(STRING_ELT(x, 0)));
// Directly return string for character SEXPs, ensuring UTF-8 encoding
return std::string(Rf_translateCharUTF8(STRING_ELT(x, 0)));
case INTSXP:
case REALSXP:
case LGLSXP:
case RAWSXP:
// Coerce to character and then return string for numeric, logical, raw
return std::string(CHAR(STRING_ELT(Rf_coerceVector(x, STRSXP), 0)));
return std::string(Rf_translateCharUTF8(STRING_ELT(Rf_coerceVector(x, STRSXP), 0)));
default:
// Coerce any other type to character as a fallback
return std::string(CHAR(STRING_ELT(Rf_coerceVector(x, STRSXP), 0)));
return std::string(Rf_translateCharUTF8(STRING_ELT(Rf_coerceVector(x, STRSXP), 0)));
}
}

Expand Down Expand Up @@ -255,7 +255,7 @@ std::string json_build_list(SEXP values)
for (R_xlen_t i = 0; i < n; i++)
{
// Recursively build JSON for each element
std::string elem_json = json_build_any(VECTOR_ELT(values, i));
std::string elem_json = json_build_internal(VECTOR_ELT(values, i));
// Only add non-empty elements, excluding "empty" JSON array/object strings
if (!elem_json.empty() && elem_json != "[]" && elem_json != "{}")
{
Expand Down Expand Up @@ -325,7 +325,7 @@ std::string json_build_structure(SEXP values)
}

// Recursively build JSON for the payload's value
return json_build_any(payload_val);
return json_build_internal(payload_val);
}

SEXP names = Rf_getAttrib(values, symbol_cache.names_sym);
Expand Down Expand Up @@ -360,11 +360,11 @@ std::string json_build_structure(SEXP values)
val = uuid_val; // Use the newly created UUID SEXP
}

std::string key = CHAR(STRING_ELT(names, i)); // Get the field name
std::string key = Rf_translateCharUTF8(STRING_ELT(names, i)); // Get the field name
std::string loc_name = tag_get(val, "locationName"); // Check for locationName tag
std::string name = loc_name.empty() ? key : loc_name; // Use locationName if present

std::string json_val = json_build_any(val); // Recursively build JSON for field value
std::string json_val = json_build_internal(val); // Recursively build JSON for field value
// Only add non-empty fields, excluding "empty" JSON array/object strings
if (!json_val.empty() && json_val != "[]" && json_val != "{}")
{
Expand Down Expand Up @@ -420,14 +420,14 @@ inline std::string json_build_map(SEXP values)
// Populate the vector with key-value pairs from the R object
for (R_xlen_t i = 0; i < n; ++i)
{
std::string key = CHAR(STRING_ELT(names_sexp, i));
std::string key = Rf_translateCharUTF8(STRING_ELT(names_sexp, i));
SEXP val = VECTOR_ELT(values, i);
named_elements.push_back({key, val});
}

// Sort the vector based on the string key in each pair
std::sort(named_elements.begin(), named_elements.end(),
[](const auto &a, const auto &b)
[](const std::pair<std::string, SEXP> &a, const std::pair<std::string, SEXP> &b)
{
return a.first < b.first;
});
Expand All @@ -442,7 +442,7 @@ inline std::string json_build_map(SEXP values)
SEXP val = element.second;

// Recursively build JSON for the value
std::string json_val = json_build_any(val);
std::string json_val = json_build_internal(val);

// Only add non-empty pairs to the final JSON string
if (!json_val.empty() && json_val != "[]" && json_val != "{}")
Expand All @@ -469,17 +469,8 @@ inline std::string json_build_map(SEXP values)
return result;
}

/**
* @brief Build Json Strings Using AWS Attributes for JSON Template
*
* @param object A list to be parsed into JSON string
*
* @return a JSON String
*/
//' @useDynLib paws.common _paws_common_json_build_any
//' @importFrom Rcpp evalCpp
// [[Rcpp::export]]
std::string json_build_any(SEXP values)
// Internal implementation that returns std::string (used by recursive calls)
std::string json_build_internal(SEXP values)
{
// Determine the effective type of the R object for JSON building
std::string t = type(values);
Expand All @@ -494,3 +485,20 @@ std::string json_build_any(SEXP values)
// Default to scalar if none of the above, or if `type` returns "scalar"
return json_build_scalar(values);
}

/**
* @brief Build Json Strings Using AWS Attributes for JSON Template
*
* @param object A list to be parsed into JSON string
*
* @return a JSON String
*/
//' @useDynLib paws.common _paws_common_json_build_any
//' @importFrom Rcpp evalCpp
// [[Rcpp::export]]
CharacterVector json_build_any(SEXP values)
{
// Call internal implementation and UTF-8 encode result
std::string result = json_build_internal(values);
return CharacterVector::create(String(result, CE_UTF8));
}
1 change: 1 addition & 0 deletions paws.common/src/json_escape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ CharacterVector json_convert_string(CharacterVector x)
for (int i = 0; i < n; ++i)
{
String cur = x[i];
cur.set_encoding(CE_UTF8); // Ensure UTF-8 encoding
out[i] = json_escape(cur);
}
return out;
Expand Down
Loading