diff --git a/.Rbuildignore b/.Rbuildignore index c784cbd..3a65ed9 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -3,3 +3,5 @@ ^src/\.cargo$ ^README\.Rmd$ ^LICENSE\.md$ +^src/rust/vendor$ +^\.github$ diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000..2d19fc7 --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml new file mode 100644 index 0000000..a3ac618 --- /dev/null +++ b/.github/workflows/R-CMD-check.yaml @@ -0,0 +1,49 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +name: R-CMD-check + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: macos-latest, r: 'release'} + - {os: windows-latest, r: 'release'} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v3 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::rcmdcheck + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true diff --git a/.gitignore b/.gitignore index cd67eac..dd01e11 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .Rproj.user +src/rust/vendor diff --git a/NAMESPACE b/NAMESPACE index 79fcb03..60ccb03 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -10,6 +10,7 @@ export(decode_file) export(encode) export(encode_file) export(engine) +export(new_alphabet) export(new_config) export(new_engine) importFrom(blob,blob) diff --git a/R/alphabet.R b/R/alphabet.R index 34a624e..c46ff1a 100644 --- a/R/alphabet.R +++ b/R/alphabet.R @@ -37,6 +37,7 @@ alphabet <- function(which = "standard") { structure(alphabet_(which), class = "alphabet") } +#' @export #' @rdname alphabet new_alphabet <- function(chars) { n <- nchar(chars) diff --git a/R/config.R b/R/config.R index a2725ee..a3bcfaf 100644 --- a/R/config.R +++ b/R/config.R @@ -18,6 +18,9 @@ #' @param decode_padding_mode default `"canonical"`. Other values are `"indifferent"` and `"none"`. See details for more. #' @export #' @return an object of class `engine_config` +#' @examples +#' # create a new nonsensicle config +#' new_config(FALSE, TRUE, "none") new_config <- function( encode_padding = TRUE, decode_padding_trailing_bits = FALSE, @@ -38,14 +41,10 @@ new_config <- function( structure(res, class = "engine_config") } -# shoddy print method for the time being - #' @export print.engine_config <- function(x, ...) { y <- print_config_(x) - # z <- trimws(strsplit(y, "\n")[[1]][2:4]) cat("\n") - # cat(gsub(",", "", z), sep = "\n") invisible(x) } diff --git a/R/encode.R b/R/encode.R index 8a49bae..1fb3aac 100644 --- a/R/encode.R +++ b/R/encode.R @@ -9,6 +9,17 @@ #' and blob vector the same length as `what`, respectively. #' @export #' @name encode +#' @examples +#' # encode hello world +#' encoded <- encode("Hello world") +#' encoded +#' +#' # decode to a blob +#' decoded <- decode(encoded) +#' decoded +#' +#' # convert back to a character +#' rawToChar(decoded[[1]]) encode <- function(what, eng = engine()) { n <- length(what) if (inherits(what, "raw") || (n == 1 & inherits(what, "character"))) { diff --git a/R/engine.R b/R/engine.R index 383b35a..4da4ba1 100644 --- a/R/engine.R +++ b/R/engine.R @@ -2,7 +2,10 @@ #' #' @param which default `"standard"`. The base64 encoding engine to be used. #' See details for more. -#' @param .alphabet an object of class `alphabet` as created with [`alphabet()`] or [`new_alphabet()`] +#' @param .alphabet an object of class `alphabet` as created with +#' [`alphabet()`] or [`new_alphabet()`] +#' @param .config an object of class `engine_config` as created with +#' [new_config()] #' @details #' #' ## Engines diff --git a/README.Rmd b/README.Rmd index 359bec1..9eb343d 100644 --- a/README.Rmd +++ b/README.Rmd @@ -16,6 +16,7 @@ knitr::opts_chunk$set( # b64 +[![R-CMD-check](https://github.com/extendr/b64/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/extendr/b64/actions/workflows/R-CMD-check.yaml) The goal of b64 is to provide a very fast, lightweight, and vectorized base64 encoder and decoder. diff --git a/configure b/configure new file mode 100755 index 0000000..d656e00 --- /dev/null +++ b/configure @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + +# https://github.com/eitsupi/prqlr/blob/main/configure +export PATH="$PATH:$HOME/.cargo/bin" + +if [ ! "$(command -v cargo)" ]; then + echo "----------------------- [RUST NOT FOUND]---------------------------" + echo "The 'cargo' command was not found on the PATH. Please install rustc" + echo "from: https://www.rust-lang.org/tools/install" + echo "" + echo "Alternatively, you may install cargo from your OS package manager:" + echo " - Debian/Ubuntu: apt-get install cargo" + echo " - Fedora/CentOS: dnf install cargo" + echo " - macOS: brew install rustc" + echo "-------------------------------------------------------------------" + echo "" + exit 1 +fi + +exit 0 diff --git a/configure.win b/configure.win new file mode 100644 index 0000000..d9b66ed --- /dev/null +++ b/configure.win @@ -0,0 +1,15 @@ +#!/bin/sh + +# https://github.com/eitsupi/prqlr/blob/main/configure.win +export PATH="$PATH:$HOME/.cargo/bin" + +if [ ! "$(command -v cargo)" ]; then + echo "----------------------- [RUST NOT FOUND]---------------------------" + echo "The 'cargo' command was not found on the PATH. Please install rustc" + echo "from: https://www.rust-lang.org/tools/install" + echo "-------------------------------------------------------------------" + echo "" + exit 1 +fi + +exit 0 diff --git a/man/encode.Rd b/man/encode.Rd index efcfb6c..17a435e 100644 --- a/man/encode.Rd +++ b/man/encode.Rd @@ -29,3 +29,15 @@ and blob vector the same length as \code{what}, respectively. \description{ Encode and decode using base64 } +\examples{ +# encode hello world +encoded <- encode("Hello world") +encoded + +# decode to a blob +decoded <- decode(encoded) +decoded + +# convert back to a character +rawToChar(decoded[[1]]) +} diff --git a/man/engine.Rd b/man/engine.Rd index 552749b..8f556d6 100644 --- a/man/engine.Rd +++ b/man/engine.Rd @@ -13,7 +13,11 @@ new_engine(.alphabet = alphabet(), .config = new_config()) \item{which}{default \code{"standard"}. The base64 encoding engine to be used. See details for more.} -\item{.alphabet}{an object of class \code{alphabet} as created with \code{\link[=alphabet]{alphabet()}} or \code{\link[=new_alphabet]{new_alphabet()}}} +\item{.alphabet}{an object of class \code{alphabet} as created with +\code{\link[=alphabet]{alphabet()}} or \code{\link[=new_alphabet]{new_alphabet()}}} + +\item{.config}{an object of class \code{engine_config} as created with +\code{\link[=new_config]{new_config()}}} } \description{ Create an encoding engine diff --git a/man/new_config.Rd b/man/new_config.Rd index a1b980a..561c8c0 100644 --- a/man/new_config.Rd +++ b/man/new_config.Rd @@ -36,3 +36,7 @@ characters are also permitted } } } +\examples{ +# create a new nonsensicle config +new_config(FALSE, TRUE, "none") +} diff --git a/src/Makevars b/src/Makevars index ab33d0c..34bac1b 100644 --- a/src/Makevars +++ b/src/Makevars @@ -7,9 +7,17 @@ all: C_clean $(SHLIB): $(STATLIB) +CRAN_FLAGS=-j 2 --offline CARGOTMP = $(CURDIR)/.cargo +VENDOR_DIR = $(CURDIR)/vendor $(STATLIB): + if [ -f ./rust/vendor.tar.xz ]; then \ + tar xf rust/vendor.tar.xz && \ + mkdir -p $(CARGOTMP) && \ + cp rust/vendor-config.toml $(CARGOTMP)/config.toml; \ + fi + # In some environments, ~/.cargo/bin might not be included in PATH, so we need # to set it here to ensure cargo can be invoked. It is appended to PATH and # therefore is only used if cargo is absent from the user's PATH. @@ -17,14 +25,12 @@ $(STATLIB): export CARGO_HOME=$(CARGOTMP); \ fi && \ export PATH="$(PATH):$(HOME)/.cargo/bin" && \ - cargo build --lib --release --manifest-path=./rust/Cargo.toml --target-dir $(TARGET_DIR) - if [ "$(NOT_CRAN)" != "true" ]; then \ - rm -Rf $(CARGOTMP) && \ - rm -Rf $(LIBDIR)/build; \ - fi + cargo build $(CRAN_FLAGS) --lib --release --manifest-path=./rust/Cargo.toml --target-dir $(TARGET_DIR) && \ + echo `cargo --version` && echo `rustc --version`; + rm -Rf $(CARGOTMP) $(VENDOR_DIR) $(LIBDIR)/build; \ C_clean: - rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) + rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) $(CARGOTMP) $(VENDOR_DIR) clean: - rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) rust/target + rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) $(CARGOTMP) $(VENDOR_DIR) $(TARGET_DIR) diff --git a/src/Makevars.win b/src/Makevars.win index d55cab5..3f07c56 100644 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -9,14 +9,29 @@ all: C_clean $(SHLIB): $(STATLIB) +CRAN_FLAGS=-j 2 --offline +CARGOTMP = $(CURDIR)/.cargo +VENDOR_DIR = $(CURDIR)/vendor + +all: C_clean + +$(SHLIB): $(STATLIB) + +CRAN_FLAGS=-j 2 --offline CARGOTMP = $(CURDIR)/.cargo $(STATLIB): + # uncompress vendored deps + if [ -f ./rust/vendor.tar.xz ]; then \ + tar xf rust/vendor.tar.xz && \ + mkdir -p $(CARGOTMP) && \ + cp rust/vendor-config.toml $(CARGOTMP)/config.toml; \ + fi + mkdir -p $(TARGET_DIR)/libgcc_mock # `rustc` adds `-lgcc_eh` flags to the compiler, but Rtools' GCC doesn't have # `libgcc_eh` due to the compilation settings. So, in order to please the # compiler, we need to add empty `libgcc_eh` to the library search paths. - # # For more details, please refer to # https://github.com/r-windows/rtools-packages/blob/2407b23f1e0925bbb20a4162c963600105236318/mingw-w64-gcc/PKGBUILD#L313-L316 touch $(TARGET_DIR)/libgcc_mock/libgcc_eh.a @@ -26,15 +41,15 @@ $(STATLIB): export CARGO_HOME=$(CARGOTMP); \ fi && \ export CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER="$(CARGO_LINKER)" && \ - export LIBRARY_PATH="$${LIBRARY_PATH};$(CURDIR)/$(TARGET_DIR)/libgcc_mock" && \ - cargo build --target=$(TARGET) --lib --release --manifest-path=./rust/Cargo.toml --target-dir $(TARGET_DIR) + export LIBRARY_PATH="$${LIBRARY_PATH};$(CURDIR)/$(TARGET_DIR)/libgcc_mock"; \ + cargo build $(CRAN_FLAGS) --target=$(TARGET) --lib --release --manifest-path=./rust/Cargo.toml --target-dir $(TARGET_DIR) && \ + echo `cargo --version` && echo `rustc --version`; if [ "$(NOT_CRAN)" != "true" ]; then \ - rm -Rf $(CARGOTMP) && \ - rm -Rf $(LIBDIR)/build; \ + rm -Rf $(CARGOTMP) $(VENDOR_DIR) $(LIBDIR)/build; \ fi C_clean: - rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) + rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) $(CARGOTMP) $(VENDOR_DIR) clean: - rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) $(TARGET_DIR) + rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) $(CARGOTMP) $(VENDOR_DIR) $(TARGET_DIR) diff --git a/src/rust/vendor-config.toml b/src/rust/vendor-config.toml new file mode 100644 index 0000000..0236928 --- /dev/null +++ b/src/rust/vendor-config.toml @@ -0,0 +1,5 @@ +[source.crates-io] +replace-with = "vendored-sources" + +[source.vendored-sources] +directory = "vendor" diff --git a/src/rust/vendor.tar.xz b/src/rust/vendor.tar.xz new file mode 100644 index 0000000..ac628b4 Binary files /dev/null and b/src/rust/vendor.tar.xz differ