From bf22465a8574a29b94fe51646bd71e2fd3803ca0 Mon Sep 17 00:00:00 2001
From: Etienne Bacher <52219252+etiennebacher@users.noreply.github.com>
Date: Tue, 16 Jan 2024 16:59:46 +0100
Subject: [PATCH 1/7] remove cli and rlang
---
DESCRIPTION | 4 +---
R/alphabet.R | 11 +++++------
R/config.R | 4 ++--
R/encode.R | 4 ++--
R/engine.R | 22 +++++++++++-----------
5 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/DESCRIPTION b/DESCRIPTION
index fba95ed..286d217 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -18,9 +18,7 @@ RoxygenNote: 7.2.3
Config/rextendr/version: 0.3.1.9000
SystemRequirements: Cargo (Rust's package manager), rustc
Imports:
- blob,
- cli,
- rlang
+ blob
Suggests:
testthat (>= 3.0.0)
Config/testthat/edition: 3
diff --git a/R/alphabet.R b/R/alphabet.R
index c46ff1a..756055b 100644
--- a/R/alphabet.R
+++ b/R/alphabet.R
@@ -30,9 +30,9 @@
#' new_alphabet("qwertyuiop[]asdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890")
#' @returns an object of class `alphabet`
alphabet <- function(which = "standard") {
- rlang::arg_match(
+ match.arg(
which,
- values = c("standard", "bcrypt", "bin_hex", "crypt", "imap_mutf7", "url_safe")
+ choices = c("standard", "bcrypt", "bin_hex", "crypt", "imap_mutf7", "url_safe")
)
structure(alphabet_(which), class = "alphabet")
}
@@ -42,10 +42,9 @@ alphabet <- function(which = "standard") {
new_alphabet <- function(chars) {
n <- nchar(chars)
if (nchar(chars) != 64) {
- cli::cli_abort(
- c(
- "{.arg chars} must be 64 unique characters",
- "i" = "{n} characters provided"
+ stop(
+ paste(
+ "`chars` must contain 64 unique characters. Only", n, "characters were provided."
)
)
}
diff --git a/R/config.R b/R/config.R
index a3bcfaf..78ee9e2 100644
--- a/R/config.R
+++ b/R/config.R
@@ -27,9 +27,9 @@ new_config <- function(
decode_padding_mode = c("canonical", "indifferent", "none")
) {
- padding_mode <- rlang::arg_match0(
+ padding_mode <- match.arg(
decode_padding_mode,
- values = c("canonical", "indifferent", "none")
+ choices = c("canonical", "indifferent", "none")
)
res <- new_config_(
diff --git a/R/encode.R b/R/encode.R
index 1fb3aac..f7975c8 100644
--- a/R/encode.R
+++ b/R/encode.R
@@ -45,7 +45,7 @@ decode <- function(what, eng = engine()) {
#' @name encode
encode_file <- function(path, eng = engine()) {
if (!file.exists(path)) {
- cli::cli_abort("{.arg path} does not exist")
+ stop(paste0("`", path, "` does not exist"))
}
encode_file_(path, eng)
@@ -56,7 +56,7 @@ encode_file <- function(path, eng = engine()) {
#' @rdname encode
decode_file <- function(path, eng = engine()) {
if (!file.exists(path)) {
- cli::cli_abort("{.arg path} does not exist")
+ stop(paste0("`", path, "` does not exist"))
}
decode_file_(path, eng)
diff --git a/R/engine.R b/R/engine.R
index 64a0987..26b0ed2 100644
--- a/R/engine.R
+++ b/R/engine.R
@@ -28,7 +28,7 @@
#' new_engine(alphabet("bcrypt"), new_config())
engine <- function(which = "standard") {
provided <- c("standard", "standard_no_pad", "url_safe", "url_safe_no_pad")
- rlang::arg_match0(which, provided)
+ match.arg(which, choices = provided)
structure(engine_(which), class = "engine")
}
@@ -36,18 +36,18 @@ engine <- function(which = "standard") {
#' @rdname engine
new_engine <- function(.alphabet = alphabet(), .config = new_config()) {
- if (!rlang::inherits_only(.alphabet, "alphabet")) {
- cli::cli_abort(
- c(
- "{.arg .alphabet} is not an object of class {.cls alphabet}",
- "*" = "use {.fn alphabet} for a standard base64 alphabet"
+ if (!inherits(.alphabet, "alphabet")) {
+ stop(
+ paste(
+ "`.alphabet` is not an object of class 'alphabet'.\n" ,
+ "Use `alphabet()` for a standard base64 alphabet."
)
)
- } else if (!rlang::inherits_only(.config, "engine_config")) {
- cli::cli_abort(
- c(
- "{.arg config} is not a {.cls engine_config} object",
- "*" = "create one with {.fn new_config}"
+ } else if (!inherits(.config, "engine_config")) {
+ stop(
+ paste(
+ "`.config` is not an object of class 'engine_config'.\n" ,
+ "Create one with `new_config()`."
)
)
}
From 272c819c793d2e581cc31c344e3acbad2f8ec59c Mon Sep 17 00:00:00 2001
From: Etienne Bacher <52219252+etiennebacher@users.noreply.github.com>
Date: Tue, 16 Jan 2024 18:14:24 +0100
Subject: [PATCH 2/7] remove blob dependency
---
.gitignore | 1 +
DESCRIPTION | 7 ++---
NAMESPACE | 1 -
NEWS.md | 4 +++
R/b64-package.R | 1 -
R/extendr-wrappers.R | 2 --
README.md | 66 ++++++++++++++++++++++++++++++--------------
man/b64-package.Rd | 5 ++--
man/utils.Rd | 2 --
src/rust/src/lib.rs | 13 +++------
10 files changed, 61 insertions(+), 41 deletions(-)
diff --git a/.gitignore b/.gitignore
index eb4a11b..9be5147 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
.Rproj.user
src/rust/vendor
+src/vendor
docs
diff --git a/DESCRIPTION b/DESCRIPTION
index 286d217..91967fa 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,6 +1,6 @@
Package: b64
Title: Fast and Vectorized Base 64 Engine
-Version: 0.1.0
+Version: 0.1.0.9000
Authors@R:
person("Josiah", "Parry", , "josiah.parry@gmail.com", role = c("aut", "cre"),
comment = c(ORCID = "0000-0001-9910-865X"))
@@ -14,11 +14,10 @@ License: MIT + file LICENSE
Encoding: UTF-8
Language: en
Roxygen: list(markdown = TRUE)
-RoxygenNote: 7.2.3
+RoxygenNote: 7.3.0
Config/rextendr/version: 0.3.1.9000
SystemRequirements: Cargo (Rust's package manager), rustc
-Imports:
- blob
Suggests:
+ blob,
testthat (>= 3.0.0)
Config/testthat/edition: 3
diff --git a/NAMESPACE b/NAMESPACE
index 822940c..652530e 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -15,5 +15,4 @@ export(engine)
export(new_alphabet)
export(new_config)
export(new_engine)
-importFrom(blob,blob)
useDynLib(b64, .registration = TRUE)
diff --git a/NEWS.md b/NEWS.md
index a69ec04..b94aabf 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,7 @@
+# b64 (development version)
+
+* All hard dependencies were removed (#2, @etiennebacher).
+
# b64 0.1.0
* Initial CRAN submission.
diff --git a/R/b64-package.R b/R/b64-package.R
index 5481d76..a65cf64 100644
--- a/R/b64-package.R
+++ b/R/b64-package.R
@@ -1,5 +1,4 @@
#' @keywords internal
-#' @importFrom blob blob
"_PACKAGE"
## usethis namespace: start
diff --git a/R/extendr-wrappers.R b/R/extendr-wrappers.R
index 7c5048a..04a1c6c 100644
--- a/R/extendr-wrappers.R
+++ b/R/extendr-wrappers.R
@@ -61,8 +61,6 @@ print_config_ <- function(config) .Call(wrap__print_config_, config)
#' chunked
#'
#' b64_wrap(chunked, "\n")
-#'
-#'
#' @param width a numeric scalar defining the width of the chunks. Must be divisible by 4.
#' @param encoded a character vector of base64 encoded strings.
#' @export
diff --git a/README.md b/README.md
index bfa3db3..3dad52a 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-# b64
+# b64
@@ -36,8 +36,11 @@ Decode using `decode()`
``` r
decoded <- decode(hello)
decoded
-#>
-#> [1] blob[19 B]
+#> [[1]]
+#> [1] 48 65 6c 6c 6f 2c 20 66 72 6f 6d 20 65 78 74 65 6e 64 72
+#>
+#> attr(,"class")
+#> [1] "blob" "vctrs_list_of" "vctrs_vctr" "list"
```
We can convert the decoded base64 to characters and see how it worked.
@@ -54,19 +57,19 @@ Both `encode()` and `decode()` are vectorized.
``` r
lorem <- unlist(lorem::ipsum(5, 1, 5))
lorem
-#> [1] "Sit ligula senectus litora viverra consequat."
-#> [2] "Consectetur vulputate vivamus sapien a ridiculus porta."
-#> [3] "Ipsum orci cras posuere lacus."
-#> [4] "Lorem nostra hendrerit nascetur vel duis consequat."
-#> [5] "Adipiscing dui blandit vestibulum bibendum?"
+#> [1] "Dolor malesuada cursus faucibus facilisi accumsan viverra?"
+#> [2] "Sit penatibus lobortis at aptent pellentesque!"
+#> [3] "Sit euismod accumsan semper ante cubilia nam velit himenaeos!"
+#> [4] "Lorem pulvinar augue aliquam!"
+#> [5] "Dolor nullam facilisi senectus penatibus."
encoded <- encode(lorem)
encoded
-#> [1] "U2l0IGxpZ3VsYSBzZW5lY3R1cyBsaXRvcmEgdml2ZXJyYSBjb25zZXF1YXQu"
-#> [2] "Q29uc2VjdGV0dXIgdnVscHV0YXRlIHZpdmFtdXMgc2FwaWVuIGEgcmlkaWN1bHVzIHBvcnRhLg=="
-#> [3] "SXBzdW0gb3JjaSBjcmFzIHBvc3VlcmUgbGFjdXMu"
-#> [4] "TG9yZW0gbm9zdHJhIGhlbmRyZXJpdCBuYXNjZXR1ciB2ZWwgZHVpcyBjb25zZXF1YXQu"
-#> [5] "QWRpcGlzY2luZyBkdWkgYmxhbmRpdCB2ZXN0aWJ1bHVtIGJpYmVuZHVtPw=="
+#> [1] "RG9sb3IgbWFsZXN1YWRhIGN1cnN1cyBmYXVjaWJ1cyBmYWNpbGlzaSBhY2N1bXNhbiB2aXZlcnJhPw=="
+#> [2] "U2l0IHBlbmF0aWJ1cyBsb2JvcnRpcyBhdCBhcHRlbnQgcGVsbGVudGVzcXVlIQ=="
+#> [3] "U2l0IGV1aXNtb2QgYWNjdW1zYW4gc2VtcGVyIGFudGUgY3ViaWxpYSBuYW0gdmVsaXQgaGltZW5hZW9zIQ=="
+#> [4] "TG9yZW0gcHVsdmluYXIgYXVndWUgYWxpcXVhbSE="
+#> [5] "RG9sb3IgbnVsbGFtIGZhY2lsaXNpIHNlbmVjdHVzIHBlbmF0aWJ1cy4="
```
We can decode all of these using `decode()` as well. This will always
@@ -74,8 +77,30 @@ return a `blob` object.
``` r
decode(encoded)
-#>
-#> [1] blob[45 B] blob[55 B] blob[30 B] blob[51 B] blob[43 B]
+#> [[1]]
+#> [1] 44 6f 6c 6f 72 20 6d 61 6c 65 73 75 61 64 61 20 63 75 72 73 75 73 20 66 61
+#> [26] 75 63 69 62 75 73 20 66 61 63 69 6c 69 73 69 20 61 63 63 75 6d 73 61 6e 20
+#> [51] 76 69 76 65 72 72 61 3f
+#>
+#> [[2]]
+#> [1] 53 69 74 20 70 65 6e 61 74 69 62 75 73 20 6c 6f 62 6f 72 74 69 73 20 61 74
+#> [26] 20 61 70 74 65 6e 74 20 70 65 6c 6c 65 6e 74 65 73 71 75 65 21
+#>
+#> [[3]]
+#> [1] 53 69 74 20 65 75 69 73 6d 6f 64 20 61 63 63 75 6d 73 61 6e 20 73 65 6d 70
+#> [26] 65 72 20 61 6e 74 65 20 63 75 62 69 6c 69 61 20 6e 61 6d 20 76 65 6c 69 74
+#> [51] 20 68 69 6d 65 6e 61 65 6f 73 21
+#>
+#> [[4]]
+#> [1] 4c 6f 72 65 6d 20 70 75 6c 76 69 6e 61 72 20 61 75 67 75 65 20 61 6c 69 71
+#> [26] 75 61 6d 21
+#>
+#> [[5]]
+#> [1] 44 6f 6c 6f 72 20 6e 75 6c 6c 61 6d 20 66 61 63 69 6c 69 73 69 20 73 65 6e
+#> [26] 65 63 74 75 73 20 70 65 6e 61 74 69 62 75 73 2e
+#>
+#> attr(,"class")
+#> [1] "blob" "vctrs_list_of" "vctrs_vctr" "list"
```
## Encoding and decoding files
@@ -99,8 +124,8 @@ bench::mark(
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#>
-#> 1 b64 39.8ms 41.3ms 24.0 24MB 0
-#> 2 base64enc 112.1ms 115.2ms 8.56 66.5MB 17.1
+#> 1 b64 76.9ms 79.8ms 12.6 24.1MB 0
+#> 2 base64enc 189ms 199.7ms 5.07 66.9MB 10.1
```
While the encoding is very impressive, better yet is the decoding
@@ -122,8 +147,8 @@ bench::mark(
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#>
-#> 1 b64 16.1ms 16.8ms 56.1 18MB 9.34
-#> 2 base64enc 209.1ms 210.7ms 4.75 18MB 0
+#> 1 b64 46ms 47.1ms 21.2 18.1MB 5.30
+#> 2 base64enc 308ms 314.1ms 3.18 18.1MB 0
```
## Alternative engines
@@ -153,7 +178,8 @@ We can use our new engine to decode it.
``` r
decode(url_safe_encoded, url_engine)
#>
-#> [1] blob[4 B]
+#> [[1]]
+#> [1] fa ec 20 55
```
### Custom Engines
diff --git a/man/b64-package.Rd b/man/b64-package.Rd
index 18ddd4e..106496b 100644
--- a/man/b64-package.Rd
+++ b/man/b64-package.Rd
@@ -1,11 +1,12 @@
% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/b64-package.R
+% Please edit documentation in R/b64-package.R, R/extendr-wrappers.R
\docType{package}
\name{b64-package}
-\alias{b64}
\alias{b64-package}
\title{b64: Fast and Vectorized Base 64 Engine}
\description{
+Provides a fast, lightweight, and vectorized base 64 engine to encode and decode character and raw vectors as well as files stored on disk. Common base 64 alphabets are supported out of the box including the standard, URL-safe, bcrypt, crypt, 'BinHex', and IMAP-modified UTF-7 alphabets. Custom engines can be created to support unique base 64 encoding and decoding needs.
+
Provides a fast, lightweight, and vectorized base 64 engine to encode and decode character and raw vectors as well as files stored on disk. Common base 64 alphabets are supported out of the box including the standard, URL-safe, bcrypt, crypt, 'BinHex', and IMAP-modified UTF-7 alphabets. Custom engines can be created to support unique base 64 encoding and decoding needs.
}
\author{
diff --git a/man/utils.Rd b/man/utils.Rd
index a13cd5e..8d06b05 100644
--- a/man/utils.Rd
+++ b/man/utils.Rd
@@ -39,6 +39,4 @@ chunked <- b64_chunk(encoded, 4)
chunked
b64_wrap(chunked, "\n")
-
-
}
diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs
index 22e0257..50b9fc6 100644
--- a/src/rust/src/lib.rs
+++ b/src/rust/src/lib.rs
@@ -34,13 +34,9 @@ fn encode_vectorized_(what: Either, engine: Robj) -> Strings {
})
.collect::(),
Either::Right(r) => {
- if !r.inherits("blob") {
- throw_r_error("Expected a character vector or an object of class `blob`")
- }
-
r.into_iter()
.map(|(_, b)| {
- if b.is_null() {
+ if !b.inherits("raw") | b.is_null() {
Rstr::na()
} else {
let raw: Raw = b.try_into().unwrap();
@@ -195,12 +191,11 @@ fn decode_vectorized_(what: Either, engine: Robj) -> Robj {
.set_class(&["blob", "vctrs_list_of", "vctrs_vctr", "list"])
.unwrap(),
Either::Right(r) => {
- if !r.inherits("blob") {
- throw_r_error("Expected a character vector or an object of class `blob`")
- }
r.into_iter()
.map(|(_, b)| {
- if b.is_null() {
+ if !b.inherits("raw") {
+ Rstr::na().into_robj()
+ } else if b.is_null() {
().into_robj()
} else {
let raw: Raw = b.try_into().unwrap();
From 15a30c0c5e68969a19477b3c77a37d7fb5cf1fd5 Mon Sep 17 00:00:00 2001
From: Etienne Bacher <52219252+etiennebacher@users.noreply.github.com>
Date: Sat, 20 Jan 2024 14:26:22 +0100
Subject: [PATCH 3/7] add myself as ctb
---
DESCRIPTION | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/DESCRIPTION b/DESCRIPTION
index 91967fa..c39129d 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,9 +1,11 @@
Package: b64
Title: Fast and Vectorized Base 64 Engine
Version: 0.1.0.9000
-Authors@R:
+Authors@R: c(
person("Josiah", "Parry", , "josiah.parry@gmail.com", role = c("aut", "cre"),
- comment = c(ORCID = "0000-0001-9910-865X"))
+ comment = c(ORCID = "0000-0001-9910-865X")),
+ person("Etienne", "Bacher", email = "etienne.bacher@protonmail.com", role = "ctb",
+ comment = c(ORCID = "0000-0002-9271-5075")))
Description: Provides a fast, lightweight, and vectorized base 64 engine
to encode and decode character and raw vectors as well as files stored
on disk. Common base 64 alphabets are supported out of the box
From abb5b0e8e906d8fe5d76443d6884af8a0700c653 Mon Sep 17 00:00:00 2001
From: Etienne Bacher <52219252+etiennebacher@users.noreply.github.com>
Date: Sat, 20 Jan 2024 14:26:41 +0100
Subject: [PATCH 4/7] load blob in readme for pretty printing
---
README.Rmd | 5 ++--
README.md | 73 +++++++++++++++++++-----------------------------------
2 files changed, 28 insertions(+), 50 deletions(-)
diff --git a/README.Rmd b/README.Rmd
index 12b9fc4..e16e1cc 100644
--- a/README.Rmd
+++ b/README.Rmd
@@ -40,9 +40,10 @@ hello <- encode("Hello, from extendr")
hello
```
-Decode using `decode()`
+Decode using `decode()`. Note that the returned object will always have the `"blob"` class. To achieve 0 dependencies, the `blob` package is only listed as a suggested dependency but if you attach it, its print method will be used.
```{r}
+library(blob)
decoded <- decode(hello)
decoded
```
@@ -66,7 +67,7 @@ encoded <- encode(lorem)
encoded
```
-We can decode all of these using `decode()` as well. This will always return a `blob` object.
+We can decode all of these using `decode()` as well.
```{r}
decode(encoded)
diff --git a/README.md b/README.md
index 3dad52a..16d00f3 100644
--- a/README.md
+++ b/README.md
@@ -31,16 +31,17 @@ hello
#> [1] "SGVsbG8sIGZyb20gZXh0ZW5kcg=="
```
-Decode using `decode()`
+Decode using `decode()`. Note that the returned object will always have
+the `"blob"` class. To achieve 0 dependencies, the `blob` package is
+only listed as a suggested dependency but if you attach it, its print
+method will be used.
``` r
+library(blob)
decoded <- decode(hello)
decoded
-#> [[1]]
-#> [1] 48 65 6c 6c 6f 2c 20 66 72 6f 6d 20 65 78 74 65 6e 64 72
-#>
-#> attr(,"class")
-#> [1] "blob" "vctrs_list_of" "vctrs_vctr" "list"
+#>
+#> [1] blob[19 B]
```
We can convert the decoded base64 to characters and see how it worked.
@@ -57,50 +58,27 @@ Both `encode()` and `decode()` are vectorized.
``` r
lorem <- unlist(lorem::ipsum(5, 1, 5))
lorem
-#> [1] "Dolor malesuada cursus faucibus facilisi accumsan viverra?"
-#> [2] "Sit penatibus lobortis at aptent pellentesque!"
-#> [3] "Sit euismod accumsan semper ante cubilia nam velit himenaeos!"
-#> [4] "Lorem pulvinar augue aliquam!"
-#> [5] "Dolor nullam facilisi senectus penatibus."
+#> [1] "Elit porttitor litora phasellus primis."
+#> [2] "Sit vel natoque eu quisque."
+#> [3] "Sit accumsan elementum pharetra aliquet parturient ullamcorper."
+#> [4] "Consectetur iaculis nunc elementum."
+#> [5] "Dolor donec iaculis sem."
encoded <- encode(lorem)
encoded
-#> [1] "RG9sb3IgbWFsZXN1YWRhIGN1cnN1cyBmYXVjaWJ1cyBmYWNpbGlzaSBhY2N1bXNhbiB2aXZlcnJhPw=="
-#> [2] "U2l0IHBlbmF0aWJ1cyBsb2JvcnRpcyBhdCBhcHRlbnQgcGVsbGVudGVzcXVlIQ=="
-#> [3] "U2l0IGV1aXNtb2QgYWNjdW1zYW4gc2VtcGVyIGFudGUgY3ViaWxpYSBuYW0gdmVsaXQgaGltZW5hZW9zIQ=="
-#> [4] "TG9yZW0gcHVsdmluYXIgYXVndWUgYWxpcXVhbSE="
-#> [5] "RG9sb3IgbnVsbGFtIGZhY2lsaXNpIHNlbmVjdHVzIHBlbmF0aWJ1cy4="
+#> [1] "RWxpdCBwb3J0dGl0b3IgbGl0b3JhIHBoYXNlbGx1cyBwcmltaXMu"
+#> [2] "U2l0IHZlbCBuYXRvcXVlIGV1IHF1aXNxdWUu"
+#> [3] "U2l0IGFjY3Vtc2FuIGVsZW1lbnR1bSBwaGFyZXRyYSBhbGlxdWV0IHBhcnR1cmllbnQgdWxsYW1jb3JwZXIu"
+#> [4] "Q29uc2VjdGV0dXIgaWFjdWxpcyBudW5jIGVsZW1lbnR1bS4="
+#> [5] "RG9sb3IgZG9uZWMgaWFjdWxpcyBzZW0u"
```
-We can decode all of these using `decode()` as well. This will always
-return a `blob` object.
+We can decode all of these using `decode()` as well.
``` r
decode(encoded)
-#> [[1]]
-#> [1] 44 6f 6c 6f 72 20 6d 61 6c 65 73 75 61 64 61 20 63 75 72 73 75 73 20 66 61
-#> [26] 75 63 69 62 75 73 20 66 61 63 69 6c 69 73 69 20 61 63 63 75 6d 73 61 6e 20
-#> [51] 76 69 76 65 72 72 61 3f
-#>
-#> [[2]]
-#> [1] 53 69 74 20 70 65 6e 61 74 69 62 75 73 20 6c 6f 62 6f 72 74 69 73 20 61 74
-#> [26] 20 61 70 74 65 6e 74 20 70 65 6c 6c 65 6e 74 65 73 71 75 65 21
-#>
-#> [[3]]
-#> [1] 53 69 74 20 65 75 69 73 6d 6f 64 20 61 63 63 75 6d 73 61 6e 20 73 65 6d 70
-#> [26] 65 72 20 61 6e 74 65 20 63 75 62 69 6c 69 61 20 6e 61 6d 20 76 65 6c 69 74
-#> [51] 20 68 69 6d 65 6e 61 65 6f 73 21
-#>
-#> [[4]]
-#> [1] 4c 6f 72 65 6d 20 70 75 6c 76 69 6e 61 72 20 61 75 67 75 65 20 61 6c 69 71
-#> [26] 75 61 6d 21
-#>
-#> [[5]]
-#> [1] 44 6f 6c 6f 72 20 6e 75 6c 6c 61 6d 20 66 61 63 69 6c 69 73 69 20 73 65 6e
-#> [26] 65 63 74 75 73 20 70 65 6e 61 74 69 62 75 73 2e
-#>
-#> attr(,"class")
-#> [1] "blob" "vctrs_list_of" "vctrs_vctr" "list"
+#>
+#> [1] blob[39 B] blob[27 B] blob[63 B] blob[35 B] blob[24 B]
```
## Encoding and decoding files
@@ -124,8 +102,8 @@ bench::mark(
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#>
-#> 1 b64 76.9ms 79.8ms 12.6 24.1MB 0
-#> 2 base64enc 189ms 199.7ms 5.07 66.9MB 10.1
+#> 1 b64 67.5ms 74.2ms 13.7 24.1MB 1.96
+#> 2 base64enc 177.9ms 183.3ms 5.50 66.9MB 11.0
```
While the encoding is very impressive, better yet is the decoding
@@ -147,8 +125,8 @@ bench::mark(
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#>
-#> 1 b64 46ms 47.1ms 21.2 18.1MB 5.30
-#> 2 base64enc 308ms 314.1ms 3.18 18.1MB 0
+#> 1 b64 43.4ms 51.7ms 19.7 18.1MB 5.63
+#> 2 base64enc 356.7ms 373.3ms 2.68 18.1MB 0
```
## Alternative engines
@@ -178,8 +156,7 @@ We can use our new engine to decode it.
``` r
decode(url_safe_encoded, url_engine)
#>
-#> [[1]]
-#> [1] fa ec 20 55
+#> [1] blob[4 B]
```
### Custom Engines
From f0776f489af9f799ea82095cebc9c9bac92fe9ee Mon Sep 17 00:00:00 2001
From: Etienne Bacher <52219252+etiennebacher@users.noreply.github.com>
Date: Sat, 20 Jan 2024 15:10:39 +0100
Subject: [PATCH 5/7] use match instead of inherit("raw")
---
R/extendr-wrappers.R | 20 +++++-----
man/b64-package.Rd | 5 +++
src/rust/src/lib.rs | 89 +++++++++++++++++++-------------------------
3 files changed, 54 insertions(+), 60 deletions(-)
diff --git a/R/extendr-wrappers.R b/R/extendr-wrappers.R
index 04a1c6c..a03ed18 100644
--- a/R/extendr-wrappers.R
+++ b/R/extendr-wrappers.R
@@ -39,27 +39,27 @@ new_config_ <- function(encode_padding, decode_padding_trailing_bits, decode_pad
print_config_ <- function(config) .Call(wrap__print_config_, config)
-#' Utility Functions
-#'
+#' Utility Functions
+#'
#' Functions to perform common tasks when working with base64 encoded strings.
-#'
+#'
#' @details
-#'
-#' `b64_chunk()` splits a character vector of base64 encoded strings into chunks of a
+#'
+#' `b64_chunk()` splits a character vector of base64 encoded strings into chunks of a
#' specified width.
-#'
+#'
#' `b64_wrap()` wraps a character vector of base64 encoded strings with a newline character.
-#'
+#'
#' @returns
-#'
+#'
#' - `b64_chunk()` returns a list of character vectors.
#' - `b64_wrap()` returns a scalar character vector.
-#'
+#'
#' @examples
#' encoded <- encode("Hello, world!")
#' chunked <- b64_chunk(encoded, 4)
#' chunked
-#'
+#'
#' b64_wrap(chunked, "\n")
#' @param width a numeric scalar defining the width of the chunks. Must be divisible by 4.
#' @param encoded a character vector of base64 encoded strings.
diff --git a/man/b64-package.Rd b/man/b64-package.Rd
index 106496b..583c06c 100644
--- a/man/b64-package.Rd
+++ b/man/b64-package.Rd
@@ -12,5 +12,10 @@ Provides a fast, lightweight, and vectorized base 64 engine to encode and decode
\author{
\strong{Maintainer}: Josiah Parry \email{josiah.parry@gmail.com} (\href{https://orcid.org/0000-0001-9910-865X}{ORCID})
+Other contributors:
+\itemize{
+ \item Etienne Bacher \email{etienne.bacher@protonmail.com} (\href{https://orcid.org/0000-0002-9271-5075}{ORCID}) [contributor]
+}
+
}
\keyword{internal}
diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs
index 50b9fc6..7d6e6d0 100644
--- a/src/rust/src/lib.rs
+++ b/src/rust/src/lib.rs
@@ -33,18 +33,17 @@ fn encode_vectorized_(what: Either, engine: Robj) -> Strings {
}
})
.collect::(),
- Either::Right(r) => {
- r.into_iter()
- .map(|(_, b)| {
- if !b.inherits("raw") | b.is_null() {
- Rstr::na()
- } else {
- let raw: Raw = b.try_into().unwrap();
- Rstr::from(eng.encode(raw.as_slice()))
- }
- })
- .collect::()
- }
+ Either::Right(r) => r
+ .into_iter()
+ .map(|(_, b)| {
+ if b.is_null() {
+ Rstr::na()
+ } else {
+ let raw: Raw = b.try_into().unwrap();
+ Rstr::from(eng.encode(raw.as_slice()))
+ }
+ })
+ .collect::(),
}
}
@@ -59,28 +58,27 @@ fn encode_file_(path: &str, engine: Robj) -> String {
encoder.into_inner()
}
-
-/// Utility Functions
-///
+/// Utility Functions
+///
/// Functions to perform common tasks when working with base64 encoded strings.
-///
+///
/// @details
-///
-/// `b64_chunk()` splits a character vector of base64 encoded strings into chunks of a
+///
+/// `b64_chunk()` splits a character vector of base64 encoded strings into chunks of a
/// specified width.
-///
+///
/// `b64_wrap()` wraps a character vector of base64 encoded strings with a newline character.
-///
+///
/// @returns
-///
+///
/// - `b64_chunk()` returns a list of character vectors.
/// - `b64_wrap()` returns a scalar character vector.
-///
+///
/// @examples
/// encoded <- encode("Hello, world!")
/// chunked <- b64_chunk(encoded, 4)
/// chunked
-///
+///
/// b64_wrap(chunked, "\n")
/// @param width a numeric scalar defining the width of the chunks. Must be divisible by 4.
/// @param encoded a character vector of base64 encoded strings.
@@ -88,7 +86,6 @@ fn encode_file_(path: &str, engine: Robj) -> String {
/// @rdname utils
#[extendr(use_try_from = true)]
fn b64_chunk(encoded: Strings, width: Either) -> List {
-
let width = match width {
Left(l) => l,
Right(r) => r as i32,
@@ -113,7 +110,6 @@ fn b64_chunk(encoded: Strings, width: Either) -> List {
.collect::()
}
-
/// @param chunks a character vector of base64 encoded strings.
/// @param newline a character scalar defining the newline character.
/// @export
@@ -132,9 +128,7 @@ fn b64_wrap(chunks: Either, newline: &str) -> Strings {
}
})
.collect::(),
- Right(r) => {
- b64_wrap_(r, newline).into()
- }
+ Right(r) => b64_wrap_(r, newline).into(),
}
}
@@ -152,12 +146,10 @@ fn decode_(input: Either, engine: Robj) -> Robj {
Ok(d) => d,
Err(e) => throw_r_error(e.to_string().as_str()),
}
- },
- Either::Right(r) => {
- match eng.decode(r.as_slice()) {
- Ok(d) => d,
- Err(e) => throw_r_error(e.to_string().as_str()),
- }
+ }
+ Either::Right(r) => match eng.decode(r.as_slice()) {
+ Ok(d) => d,
+ Err(e) => throw_r_error(e.to_string().as_str()),
},
};
@@ -190,26 +182,24 @@ fn decode_vectorized_(what: Either, engine: Robj) -> Robj {
.collect::()
.set_class(&["blob", "vctrs_list_of", "vctrs_vctr", "list"])
.unwrap(),
- Either::Right(r) => {
- r.into_iter()
- .map(|(_, b)| {
- if !b.inherits("raw") {
- Rstr::na().into_robj()
- } else if b.is_null() {
- ().into_robj()
- } else {
- let raw: Raw = b.try_into().unwrap();
- let decoded = eng.decode(raw.as_slice());
+ Either::Right(r) => r
+ .into_iter()
+ .map(|(_, b)| {
+ let raw = Raw::try_from(b);
+ match raw {
+ Ok(r) => {
+ let decoded = eng.decode(r.as_slice());
match decoded {
Ok(d) => Raw::from_bytes(&d).into_robj(),
Err(_) => ().into_robj(),
}
}
- })
- .collect::()
- .set_class(&["blob", "vctrs_list_of", "vctrs_vctr", "list"])
- .unwrap()
- }
+ Err(_) => ().into_robj(),
+ }
+ })
+ .collect::()
+ .set_class(&["blob", "vctrs_list_of", "vctrs_vctr", "list"])
+ .unwrap(),
}
}
@@ -248,7 +238,6 @@ fn new_alphabet_(chars: &str) -> ExternalPtr {
Ok(r) => ExternalPtr::new(r),
Err(e) => extendr_api::throw_r_error(&format!("Error creating alphabet: {}", e)),
}
-
}
// get alphabet as a string for printing
From 634ac3e8b251a8bb792360db41da0bd405eb999e Mon Sep 17 00:00:00 2001
From: Etienne Bacher <52219252+etiennebacher@users.noreply.github.com>
Date: Sat, 20 Jan 2024 15:19:27 +0100
Subject: [PATCH 6/7] cargo clippy --fix
---
src/rust/src/lib.rs | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs
index 7d6e6d0..b44beee 100644
--- a/src/rust/src/lib.rs
+++ b/src/rust/src/lib.rs
@@ -23,7 +23,7 @@ fn encode_vectorized_(what: Either, engine: Robj) -> Strings {
let eng: ExternalPtr = engine.try_into().unwrap();
match what {
Either::Left(s) => s
- .into_iter()
+ .iter()
.map(|s| {
if s.is_na() {
Rstr::na()
@@ -95,7 +95,7 @@ fn b64_chunk(encoded: Strings, width: Either) -> List {
extendr_api::throw_r_error("Chunk size must be a multiple of 4.");
}
encoded
- .into_iter()
+ .iter()
.map(|s| {
if s.is_na() {
Strings::new(0)
@@ -133,7 +133,7 @@ fn b64_wrap(chunks: Either, newline: &str) -> Strings {
}
fn b64_wrap_(chunks: Strings, newline: &str) -> String {
- chunks.into_iter().join(newline)
+ chunks.iter().join(newline)
}
#[extendr(use_try_from = true)]
@@ -163,7 +163,7 @@ fn decode_vectorized_(what: Either, engine: Robj) -> Robj {
let eng: ExternalPtr = engine.try_into().unwrap();
match what {
Either::Left(s) => s
- .into_iter()
+ .iter()
.map(|s| {
if s.is_na() {
().into_robj()
@@ -225,7 +225,7 @@ fn alphabet_(which: &str) -> ExternalPtr {
"imap_mutf7" => ExternalPtr::new(alphabet::IMAP_MUTF7),
"standard" => ExternalPtr::new(alphabet::STANDARD),
"url_safe" => ExternalPtr::new(alphabet::URL_SAFE),
- _ => extendr_api::throw_r_error(&format!("Unknown alphabet: {}", which)),
+ _ => extendr_api::throw_r_error(format!("Unknown alphabet: {}", which)),
}
}
@@ -236,7 +236,7 @@ fn new_alphabet_(chars: &str) -> ExternalPtr {
match res {
Ok(r) => ExternalPtr::new(r),
- Err(e) => extendr_api::throw_r_error(&format!("Error creating alphabet: {}", e)),
+ Err(e) => extendr_api::throw_r_error(format!("Error creating alphabet: {}", e)),
}
}
@@ -261,7 +261,7 @@ fn new_config_(
"indifferent" => DecodePaddingMode::Indifferent,
"canonical" => DecodePaddingMode::RequireCanonical,
"none" => DecodePaddingMode::RequireNone,
- _ => extendr_api::throw_r_error(&format!("Unknown padding mode: {}", decode_padding_mode)),
+ _ => extendr_api::throw_r_error(format!("Unknown padding mode: {}", decode_padding_mode)),
};
let config = GeneralPurposeConfig::new()
@@ -285,7 +285,7 @@ fn engine_(which: &str) -> ExternalPtr {
"standard_no_pad" => ExternalPtr::new(general_purpose::STANDARD_NO_PAD),
"url_safe" => ExternalPtr::new(general_purpose::URL_SAFE),
"url_safe_no_pad" => ExternalPtr::new(general_purpose::URL_SAFE_NO_PAD),
- _ => extendr_api::throw_r_error(&format!("Unknown engine: {}", which)),
+ _ => extendr_api::throw_r_error(format!("Unknown engine: {}", which)),
}
}
From aaf79a1815f8e778643bc1ecfee522b436053ee1 Mon Sep 17 00:00:00 2001
From: Etienne Bacher <52219252+etiennebacher@users.noreply.github.com>
Date: Sat, 20 Jan 2024 16:41:22 +0100
Subject: [PATCH 7/7] iter -> into_iter
---
src/rust/src/lib.rs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs
index b44beee..c95ed35 100644
--- a/src/rust/src/lib.rs
+++ b/src/rust/src/lib.rs
@@ -23,7 +23,7 @@ fn encode_vectorized_(what: Either, engine: Robj) -> Strings {
let eng: ExternalPtr = engine.try_into().unwrap();
match what {
Either::Left(s) => s
- .iter()
+ .into_iter()
.map(|s| {
if s.is_na() {
Rstr::na()
@@ -95,7 +95,7 @@ fn b64_chunk(encoded: Strings, width: Either) -> List {
extendr_api::throw_r_error("Chunk size must be a multiple of 4.");
}
encoded
- .iter()
+ .into_iter()
.map(|s| {
if s.is_na() {
Strings::new(0)
@@ -133,7 +133,7 @@ fn b64_wrap(chunks: Either, newline: &str) -> Strings {
}
fn b64_wrap_(chunks: Strings, newline: &str) -> String {
- chunks.iter().join(newline)
+ chunks.into_iter().join(newline)
}
#[extendr(use_try_from = true)]
@@ -163,7 +163,7 @@ fn decode_vectorized_(what: Either, engine: Robj) -> Robj {
let eng: ExternalPtr = engine.try_into().unwrap();
match what {
Either::Left(s) => s
- .iter()
+ .into_iter()
.map(|s| {
if s.is_na() {
().into_robj()