Skip to content

Commit 10144c7

Browse files
committed
Add documentation for private event loop functions
1 parent dd8deb6 commit 10144c7

File tree

6 files changed

+136
-14
lines changed

6 files changed

+136
-14
lines changed

R/later.R

+61-13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,44 @@
1111

1212
.globals <- new.env(parent = emptyenv())
1313

14+
#' Private event loops
15+
#'
16+
#' Normally, later uses a global event loop for scheduling and running
17+
#' functions. However, in some cases, it is useful to create a \emph{private}
18+
#' event loop to schedule and execute tasks without disturbing the global event
19+
#' loop. For example, you might have asynchronous code that queries a remote
20+
#' data source, but want to wait for a full back-and-forth communication to
21+
#' complete before continuing in your code -- from the caller's perspective, it
22+
#' should behave like synchronous code, and not do anything with the global
23+
#' event loop (which could run code unrelated to your operation). To do this,
24+
#' you would run your asynchronous code using a private event loop.
25+
#'
26+
#' \code{create_loop} creates and returns a handle to a private event loop,
27+
#' which is useful when for scheduling tasks when you do not want to interfere
28+
#' with the global event loop.
29+
#'
30+
#' \code{destory_loop} destroys a private event loop.
31+
#'
32+
#' \code{exists_loop} reports whether an event loop exists -- that is, that it
33+
#' has not been destroyed.
34+
#'
35+
#' \code{current_loop} returns the currently-active event loop. Any calls to
36+
#' \code{\link{later}()} or \code{\link{run_now}()} will use the current loop by
37+
#' default.
38+
#'
39+
#' \code{with_loop} evaluates an expression with a given event loop as the
40+
#' currently-active loop.
41+
#'
42+
#' \code{with_temp_loop} creates an event loop, makes it the current loop, then
43+
#' evaluates the given expression. Afterwards, the new event loop is destroyed.
44+
#'
45+
#' \code{global_loop} returns a handle to the global event loop.
46+
#'
47+
#'
48+
#' @param loop A handle to an event loop.
49+
#' @param expr An expression to evaluate.
50+
#' @rdname create_loop
51+
#'
1452
#' @export
1553
create_loop <- function() {
1654
id <- .globals$next_id
@@ -28,6 +66,7 @@ create_loop <- function() {
2866
loop
2967
}
3068

69+
#' @rdname create_loop
3170
#' @export
3271
destroy_loop <- function(loop) {
3372
if (identical(loop, global_loop())) {
@@ -39,16 +78,19 @@ destroy_loop <- function(loop) {
3978
}
4079
}
4180

81+
#' @rdname create_loop
4282
#' @export
4383
exists_loop <- function(loop) {
4484
existsCallbackRegistry(loop$id)
4585
}
4686

87+
#' @rdname create_loop
4788
#' @export
4889
current_loop <- function() {
4990
.globals$current_loop
5091
}
5192

93+
#' @rdname create_loop
5294
#' @export
5395
with_temp_loop <- function(expr) {
5496
loop <- create_loop()
@@ -57,6 +99,7 @@ with_temp_loop <- function(expr) {
5799
with_loop(loop, expr)
58100
}
59101

102+
#' @rdname create_loop
60103
#' @export
61104
with_loop <- function(loop, expr) {
62105
if (!identical(loop, current_loop())) {
@@ -68,6 +111,7 @@ with_loop <- function(loop, expr) {
68111
force(expr)
69112
}
70113

114+
#' @rdname create_loop
71115
#' @export
72116
global_loop <- function() {
73117
.globals$global_loop
@@ -86,42 +130,43 @@ print.event_loop <- function(x, ...) {
86130

87131

88132
#' Executes a function later
89-
#'
133+
#'
90134
#' Schedule an R function or formula to run after a specified period of time.
91135
#' Similar to JavaScript's `setTimeout` function. Like JavaScript, R is
92136
#' single-threaded so there's no guarantee that the operation will run exactly
93137
#' at the requested time, only that at least that much time will elapse.
94-
#'
138+
#'
95139
#' The mechanism used by this package is inspired by Simon Urbanek's
96140
#' [background](https://github.com/s-u/background) package and similar code in
97141
#' Rhttpd.
98-
#'
142+
#'
99143
#' @note
100144
#' To avoid bugs due to reentrancy, by default, scheduled operations only run
101145
#' when there is no other R code present on the execution stack; i.e., when R is
102146
#' sitting at the top-level prompt. You can force past-due operations to run at
103147
#' a time of your choosing by calling [run_now()].
104-
#'
148+
#'
105149
#' Error handling is not particularly well-defined and may change in the future.
106150
#' options(error=browser) should work and errors in `func` should generally not
107151
#' crash the R process, but not much else can be said about it at this point.
108152
#' If you must have specific behavior occur in the face of errors, put error
109153
#' handling logic inside of `func`.
110-
#'
154+
#'
111155
#' @param func A function or formula (see [rlang::as_function()]).
112-
#' @param delay Number of seconds in the future to delay execution. There is no
113-
#' guarantee that the function will be executed at the desired time, but it
156+
#' @param delay Number of seconds in the future to delay execution. There is no
157+
#' guarantee that the function will be executed at the desired time, but it
114158
#' should not execute earlier.
159+
#' @param loop A handle to an event loop. Defaults to the currently-active loop.
115160
#'
116161
#' @examples
117162
#' # Example of formula style
118163
#' later(~cat("Hello from the past\n"), 3)
119-
#'
164+
#'
120165
#' # Example of function style
121166
#' later(function() {
122167
#' print(summary(cars))
123168
#' }, 2)
124-
#'
169+
#'
125170
#' @export
126171
later <- function(func, delay = 0, loop = current_loop()) {
127172
f <- rlang::as_function(func)
@@ -148,15 +193,16 @@ later <- function(func, delay = 0, loop = current_loop()) {
148193
#' @param all If `FALSE`, `run_now()` will execute at most one scheduled
149194
#' operation (instead of all eligible operations). This can be useful in cases
150195
#' where you want to interleave scheduled operations with your own logic.
151-
#'
196+
#' @param loop A handle to an event loop. Defaults to the currently-active loop.
197+
#'
152198
#' @return A logical indicating whether any callbacks were actually run.
153199
#'
154200
#' @export
155201
run_now <- function(timeoutSecs = 0L, all = TRUE, loop = current_loop()) {
156202
if (timeoutSecs == Inf) {
157203
timeoutSecs <- -1
158204
}
159-
205+
160206
if (!is.numeric(timeoutSecs))
161207
stop("timeoutSecs must be numeric")
162208

@@ -166,10 +212,11 @@ run_now <- function(timeoutSecs = 0L, all = TRUE, loop = current_loop()) {
166212
}
167213

168214
#' Check if later loop is empty
169-
#'
215+
#'
170216
#' Returns true if there are currently no callbacks that are scheduled to
171217
#' execute in the present or future.
172-
#'
218+
#'
219+
#' @inheritParams create_loop
173220
#' @keywords internal
174221
#' @export
175222
loop_empty <- function(loop = current_loop()) {
@@ -182,6 +229,7 @@ loop_empty <- function(loop = current_loop()) {
182229
#' scheduled, in seconds. If the operation is in the past, the value will be
183230
#' negative. If no operation is currently scheduled, the value will be `Inf`.
184231
#'
232+
#' @inheritParams create_loop
185233
#' @export
186234
next_op_secs <- function(loop = current_loop()) {
187235
nextOpSecs(loop$id)

man/create_loop.Rd

+64
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/later.Rd

+3-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/loop_empty.Rd

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/next_op_secs.Rd

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/run_now.Rd

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)