diff --git a/NEWS.md b/NEWS.md index 829eb29c..b28aa36b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,5 @@ # cpp11 (development version) +* Allow cpp11 decorators of the form `cpp11::linking_to` (@sbearrows, #193) # cpp11 0.3.1 diff --git a/R/register.R b/R/register.R index f0056af9..ffcf5dba 100644 --- a/R/register.R +++ b/R/register.R @@ -279,7 +279,8 @@ get_cpp_register_needs <- function() { check_valid_attributes <- function(decorations) { - bad_decor <- !decorations$decoration %in% c("cpp11::register", "cpp11::init") + bad_decor <- startsWith(decorations$decoration, "cpp11::") & + (!decorations$decoration %in% c("cpp11::register", "cpp11::init", "cpp11::linking_to")) if(any(bad_decor)) { lines <- decorations$line[bad_decor] @@ -288,7 +289,7 @@ check_valid_attributes <- function(decorations) { bad_lines <- glue::glue_collapse(glue::glue("- Invalid attribute `{names}` on line {lines} in file '{file}'."), "\n") - msg <- glue::glue("cpp11 attributes must be either `cpp11::register` or `cpp11::init`: + msg <- glue::glue("cpp11 attributes must be one of `cpp11::register`, `cpp11::init` or `cpp11::linking_to`: {bad_lines} ") stop(msg, call. = FALSE) diff --git a/R/source.R b/R/source.R index 3fefeb44..e9eb9c82 100644 --- a/R/source.R +++ b/R/source.R @@ -22,7 +22,7 @@ #' [dyn.load()] (invisibly). For `[cpp_eval()]` the results of the evaluated #' expression. #' @examples -#' \dontrun{ +#' #' cpp_source( #' code = '#include "cpp11/integers.hpp" #' @@ -51,7 +51,7 @@ #' #' [[cpp11::register]] void #' show_progress() { -#' RProgress::RProgress pb("Downloading [:bar] ETA: :eta"); +#' RProgress::RProgress pb("Processing [:bar] ETA: :eta"); #' #' pb.tick(0); #' for (int i = 0; i < 100; i++) { @@ -63,7 +63,7 @@ #' #' show_progress() #' } -#' } +#' #' @export cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), dir = tempfile()) { stop_unless_installed(c("brio", "callr", "cli", "decor", "desc", "glue", "tibble", "vctrs")) diff --git a/man/cpp11-package.Rd b/man/cpp11-package.Rd index d7931614..4a4f147d 100644 --- a/man/cpp11-package.Rd +++ b/man/cpp11-package.Rd @@ -15,6 +15,7 @@ Provides a header only, C++11 interface to R's C \seealso{ Useful links: \itemize{ + \item \url{https://cpp11.r-lib.org} \item \url{https://github.com/r-lib/cpp11} \item Report bugs at \url{https://github.com/r-lib/cpp11/issues} } diff --git a/tests/testthat/linking_to_incorrect_registers.cpp b/tests/testthat/linking_to_incorrect_registers.cpp new file mode 100644 index 00000000..6a84700a --- /dev/null +++ b/tests/testthat/linking_to_incorrect_registers.cpp @@ -0,0 +1,12 @@ +[[cpp11::link_to("progress")]] + +[[cpp11::register]] void +show_progress() { + RProgress::RProgress pb("Processing [:bar] ETA: :eta"); + + pb.tick(0); + for (int i = 0; i < 100; i++) { + usleep(2.0 / 100 * 1000000); + pb.tick(); + } +} diff --git a/tests/testthat/linking_to_registers.cpp b/tests/testthat/linking_to_registers.cpp new file mode 100644 index 00000000..7872413a --- /dev/null +++ b/tests/testthat/linking_to_registers.cpp @@ -0,0 +1,12 @@ +[[cpp11::linking_to("progress")]] + +[[cpp11::register]] void +show_progress() { + RProgress::RProgress pb("Processing [:bar] ETA: :eta"); + + pb.tick(0); + for (int i = 0; i < 100; i++) { + usleep(2.0 / 100 * 1000000); + pb.tick(); + } +} diff --git a/tests/testthat/multiple_incorrect.cpp b/tests/testthat/multiple_incorrect.cpp index caa100d9..394f9407 100644 --- a/tests/testthat/multiple_incorrect.cpp +++ b/tests/testthat/multiple_incorrect.cpp @@ -1,5 +1,5 @@ -[[cpp11:register]] int foo() { return 1; } +[[cpp11::registe]] int foo() { return 1; } -[[cpp11:register]] double bar(bool run) { return 1.0; } +[[cpp11::register]] double bar(bool run) { return 1.0; } -[[cpp11::register]] bool baz(bool run, int value = 0) { return true; } +[[cpp11::reg]] bool baz(bool run, int value = 0) { return true; } diff --git a/tests/testthat/single_incorrect.cpp b/tests/testthat/single_incorrect.cpp index 7867d53b..0fe22b16 100644 --- a/tests/testthat/single_incorrect.cpp +++ b/tests/testthat/single_incorrect.cpp @@ -1 +1 @@ -[[cpp11:register]] int foo() { return 1; } +[[cpp11::registe]] int foo() { return 1; } diff --git a/tests/testthat/test-register.R b/tests/testthat/test-register.R index 582d346a..7224c561 100644 --- a/tests/testthat/test-register.R +++ b/tests/testthat/test-register.R @@ -718,6 +718,13 @@ test_that("check_valid_attributes does not return an error if all registers are file.copy(test_path("multiple.cpp"), file.path(p, "src", "multiple.cpp")) expect_error_free(cpp_register(p)) + + pkg <- local_package() + p <- pkg_path(pkg) + dir.create(file.path(p, "src")) + file.copy(test_path("linking_to_registers.cpp"), file.path(p, "src", "linking_to_registers.cpp")) + + expect_error_free(cpp_register(p)) }) @@ -735,4 +742,11 @@ test_that("check_valid_attributes returns an error if one or more registers is i file.copy(test_path("multiple_incorrect.cpp"), file.path(p, "src", "multiple_incorrect.cpp")) expect_error(cpp_register(p)) + + pkg <- local_package() + p <- pkg_path(pkg) + dir.create(file.path(p, "src")) + file.copy(test_path("linking_to_incorrect_registers.cpp"), file.path(p, "src", "linking_to_incorrect_registers.cpp")) + + expect_error(cpp_register(p)) }) diff --git a/tests/testthat/test-source.R b/tests/testthat/test-source.R index 8d708be3..68f67141 100644 --- a/tests/testthat/test-source.R +++ b/tests/testthat/test-source.R @@ -118,13 +118,31 @@ test_that("check_valid_attributes does not return an error if all registers are x.push_back({"foo"_nm = 1}); return x; }')) + expect_error_free( + cpp11::cpp_source( + code = '#include + #include + + [[cpp11::linking_to("progress")]] + + [[cpp11::register]] void show_progress() { + RProgress::RProgress pb("Processing [:bar] ETA: :eta"); + + pb.tick(0); + for (int i = 0; i < 100; i++) { + usleep(2.0 / 100 * 1000000); + pb.tick(); + } + } + ') + ) }) test_that("check_valid_attributes returns an error if one or more registers is incorrect", { expect_error( cpp11::cpp_source(code = '#include using namespace cpp11::literals; - [[cpp11:register]] + [[cpp11::reg]] cpp11::list fn() { cpp11::writable::list x; x.push_back({"foo"_nm = 1}); @@ -140,7 +158,17 @@ test_that("check_valid_attributes returns an error if one or more registers is i expect_error( cpp11::cpp_source(code = '#include using namespace cpp11::literals; - [[cpp11:register]] + [[cpp11::reg]] + cpp11::list fn() { + cpp11::writable::list x; + x.push_back({"foo"_nm = 1}); + return x; + }')) + + expect_error( + cpp11::cpp_source(code = '#include + using namespace cpp11::literals; + [[cpp11::reg]] cpp11::list fn() { cpp11::writable::list x; x.push_back({"foo"_nm = 1}); @@ -152,4 +180,21 @@ test_that("check_valid_attributes returns an error if one or more registers is i x.push_back({"foo"_nm = 1}); return x; }')) -}) \ No newline at end of file + + expect_error( + cpp11::cpp_source( + code = ' + #include + #include + [[cpp11::link_to("progress")]] + [[cpp11::register]] void show_progress() { + RProgress::RProgress pb("Processing [:bar] ETA: :eta"); + pb.tick(0); + for (int i = 0; i < 100; i++) { + usleep(2.0 / 100 * 1000000); + pb.tick(); + } + } +') + ) +})