Skip to content

Commit 6c7ec3f

Browse files
committed
RC6; stability of return types for aios
1 parent a94c91d commit 6c7ec3f

File tree

7 files changed

+80
-43
lines changed

7 files changed

+80
-43
lines changed

NEWS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
* `nano_init()` is deprecated due to the above change in behaviour.
1414
* `send()` no longer has a '...' argument. This has had no effect since 0.6.0, but will now error if additional arguments are provided (please check and remove previous uses of the argument 'echo'). Also no longer returns invisibly for consistency with `recv()`.
1515
* `recv()` and `recv_aio()` now return an integer 'errorValue' at each of `$raw` and `$data` when 'keep.raw' is set to TRUE, ensuring stability of return types.
16-
* `ncurl()` now returns an integer 'errorValue' at each of `$status`, `$headers`, `$raw` and `$data` for both sync and async, ensuring stability of return types. Where 'follow' is set to FALSE, or for all async requests, the redirect address is now returned as a character string at `$data`.
17-
* `nano()` now creates a nano object with method `$context_open()` for applicable protocols. Opening a context will attach a context at `$context` and a `$context_close()` method. When a context is active, all object methods use the context instead of the socket. Method `$socket_setopt()` renamed to `$setopt()` as it can be used on the socket or active context as applicable.
16+
* `ncurl()` now returns an integer 'errorValue' at each of `$status`, `$headers`, `$raw` and `$data` for both sync and async, ensuring stability of return types. Where 'follow' is set to FALSE, or for all async requests, redirect addresses are now returned as a character string at `$data`.
17+
* `nano()` now creates a nano object with method `$context_open()` for applicable protocols. Opening a context will attach a context at `$context` and a `$context_close()` method. When a context is active, all object methods apply to the context instead of the socket. Method `$socket_setopt()` renamed to `$setopt()` as it can be used on the socket or active context as applicable.
1818
* `listen()` and `dial()` now only take a socket as argument; for nano objects, the `$listen()` and `$dial()` methods must be used instead.
19-
* Non-logical values supplied to logical arguments will now error across the package. This is documented for each function where this is applicable.
19+
* Non-logical values supplied to logical arguments will now error: this is documented for each function where this is applicable.
2020

2121
*Other changes:*
2222

R/nano.R

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,24 @@
1818

1919
#' Create Nano Object
2020
#'
21-
#' Create a nano object, encapsulating a Socket along with an associated
22-
#' Dialer/Listener.
21+
#' Create a nano object, encapsulating a Socket, Dialers/Listeners and
22+
#' associated methods.
2323
#'
2424
#' @inheritParams socket
2525
#'
2626
#' @return A nano object of class 'nanoObject'.
2727
#'
28-
#' @details This function encapsulates a Socket and a single Dialer and/or Listener.
28+
#' @details This function encapsulates a Socket, Dialer and/or Listener, and its
29+
#' associated methods.
2930
#'
3031
#' The Socket may be accessed by \code{$socket}, and the Dialer or
3132
#' Listener by \code{$dialer[[1]]} or \code{$listener[[1]]} respectively.
3233
#'
3334
#' The object's methods may be accessed by \code{$} e.g. \code{$send()} or
3435
#' \code{$recv()}. These methods mirror their functional equivalents, with
3536
#' the same arguments and defaults, apart from that the first argument of the
36-
#' functional equivalent is mapped to the object's encapsulated socket and
37-
#' does not need to be supplied.
37+
#' functional equivalent is mapped to the object's encapsulated socket (or
38+
#' context, if active) and does not need to be supplied.
3839
#'
3940
#' More complex network topologies may be created by binding further
4041
#' dialers or listeners using the object's \code{$dial()} and \code{$listen()}
@@ -47,10 +48,15 @@
4748
#' apply settings to individual dialers/listeners, access them directly
4849
#' via \code{$dialer[[2]]} or \code{$listener[[2]]} etc.
4950
#'
51+
#' For Dialers or Listeners not automatically started, the
52+
#' \code{$dialer_start()} or \code{$listener_start()} methods will be
53+
#' available. These act on the most recently created Dialer or Listener
54+
#' respectively.
55+
#'
5056
#' For applicable protocols, new contexts may be created by using the
5157
#' \code{$context_open()} method. This will attach a new context at
5258
#' \code{$context} as well as a \code{$context_close()} method. While a
53-
#' context is active, all object methods use the context instead of the
59+
#' context is active, all object methods use the context rather than the
5460
#' socket. A new context may be created by calling \code{$context_open()},
5561
#' which will replace any existing context. It is only necessary to use
5662
#' \code{$context_close()} to close the existing context and revert to using

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ aio
365365
#> < recvAio >
366366
#> - $data for message data
367367
aio$data |> str()
368-
#> num [1:100000000] -1.208 2.406 0.478 0.909 0.572 ...
368+
#> num [1:100000000] 0.2809 0.3156 0.6802 0.0214 -0.428 ...
369369
```
370370

371371
As `call_aio()` is blocking and will wait for completion, an alternative
@@ -526,11 +526,11 @@ ncurl("https://httpbin.org/headers")
526526
#> [1] 7b 0a 20 20 22 68 65 61 64 65 72 73 22 3a 20 7b 0a 20 20 20 20 22 48 6f 73
527527
#> [26] 74 22 3a 20 22 68 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22
528528
#> [51] 58 2d 41 6d 7a 6e 2d 54 72 61 63 65 2d 49 64 22 3a 20 22 52 6f 6f 74 3d 31
529-
#> [76] 2d 36 33 36 33 38 31 31 38 2d 37 35 66 32 37 63 61 37 35 36 61 64 31 62 63
530-
#> [101] 65 37 64 66 35 64 66 32 36 22 0a 20 20 7d 0a 7d 0a
529+
#> [76] 2d 36 33 36 33 65 32 33 64 2d 36 61 35 64 33 64 39 37 31 66 64 35 32 35 31
530+
#> [101] 61 37 61 39 37 36 31 36 30 22 0a 20 20 7d 0a 7d 0a
531531
#>
532532
#> $data
533-
#> [1] "{\n \"headers\": {\n \"Host\": \"httpbin.org\", \n \"X-Amzn-Trace-Id\": \"Root=1-63638118-75f27ca756ad1bce7df5df26\"\n }\n}\n"
533+
#> [1] "{\n \"headers\": {\n \"Host\": \"httpbin.org\", \n \"X-Amzn-Trace-Id\": \"Root=1-6363e23d-6a5d3d971fd5251a7a976160\"\n }\n}\n"
534534
```
535535

536536
For advanced use, supports additional HTTP methods such as POST or PUT.
@@ -551,13 +551,13 @@ res
551551

552552
call_aio(res)$headers
553553
#> $Date
554-
#> [1] "Thu, 03 Nov 2022 08:51:36 GMT"
554+
#> [1] "Thu, 03 Nov 2022 15:46:05 GMT"
555555
#>
556556
#> $Server
557557
#> [1] "gunicorn/19.9.0"
558558

559559
res$data
560-
#> [1] "{\n \"args\": {}, \n \"data\": \"{\\\"key\\\": \\\"value\\\"}\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Authorization\": \"Bearer APIKEY\", \n \"Content-Length\": \"16\", \n \"Content-Type\": \"application/json\", \n \"Host\": \"httpbin.org\", \n \"X-Amzn-Trace-Id\": \"Root=1-63638118-15a922066ddbf19c49979633\"\n }, \n \"json\": {\n \"key\": \"value\"\n }, \n \"origin\": \"82.163.196.114\", \n \"url\": \"http://httpbin.org/post\"\n}\n"
560+
#> [1] "{\n \"args\": {}, \n \"data\": \"{\\\"key\\\": \\\"value\\\"}\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Authorization\": \"Bearer APIKEY\", \n \"Content-Length\": \"16\", \n \"Content-Type\": \"application/json\", \n \"Host\": \"httpbin.org\", \n \"X-Amzn-Trace-Id\": \"Root=1-6363e23d-4639d32e5648c7015c23491a\"\n }, \n \"json\": {\n \"key\": \"value\"\n }, \n \"origin\": \"80.169.103.218\", \n \"url\": \"http://httpbin.org/post\"\n}\n"
561561
```
562562

563563
In this respect, it may be used as a performant and lightweight method
@@ -599,10 +599,10 @@ s |> send('{"action": "subscribe", "symbols": "EURUSD"}')
599599
#> [1] 0
600600

601601
s |> recv()
602-
#> [1] "{\"s\":\"EURUSD\",\"a\":0.97694,\"b\":0.97687,\"dc\":\"-0.4494\",\"dd\":\"-0.0044\",\"ppms\":false,\"t\":1667465497000}"
602+
#> [1] "{\"s\":\"EURUSD\",\"a\":0.9766,\"b\":0.97658,\"dd\":\"-0.0047\",\"dc\":\"-0.4843\",\"ppms\":false,\"t\":1667490367000}"
603603

604604
s |> recv()
605-
#> [1] "{\"s\":\"EURUSD\",\"a\":0.97693,\"b\":0.97686,\"dc\":\"-0.4504\",\"dd\":\"-0.0044\",\"ppms\":false,\"t\":1667465497000}"
605+
#> [1] "{\"s\":\"EURUSD\",\"a\":0.97657,\"b\":0.97655,\"dc\":\"-0.4874\",\"dd\":\"-0.0048\",\"ppms\":false,\"t\":1667490367000}"
606606

607607
close(s)
608608
```

man/nano.Rd

Lines changed: 12 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/aio.c

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,32 @@ static SEXP mk_error_haio(const int xc, SEXP env) {
184184

185185
}
186186

187+
static SEXP mk_error_data(const int xc) {
188+
189+
SEXP out, err;
190+
const char *names[] = {"data", ""};
191+
PROTECT(out = Rf_mkNamed(VECSXP, names));
192+
err = Rf_ScalarInteger(xc);
193+
Rf_classgets(err, nano_error);
194+
SET_VECTOR_ELT(out, 0, err);
195+
UNPROTECT(1);
196+
return out;
197+
198+
}
199+
200+
static SEXP mk_error_result(const int xc) {
201+
202+
SEXP out, err;
203+
const char *names[] = {"result", ""};
204+
PROTECT(out = Rf_mkNamed(VECSXP, names));
205+
err = Rf_ScalarInteger(xc);
206+
Rf_classgets(err, nano_error);
207+
SET_VECTOR_ELT(out, 0, err);
208+
UNPROTECT(1);
209+
return out;
210+
211+
}
212+
187213
// core aio --------------------------------------------------------------------
188214

189215
SEXP rnng_aio_result(SEXP env) {
@@ -414,13 +440,13 @@ SEXP rnng_send_aio(SEXP con, SEXP data, SEXP mode, SEXP timeout, SEXP clo) {
414440

415441
if ((xc = nng_msg_alloc(&msg, 0))) {
416442
R_Free(saio);
417-
return mk_error(xc);
443+
return mk_error_result(xc);
418444
}
419445
if ((xc = nng_msg_append(msg, dp, xlen)) ||
420446
(xc = nng_aio_alloc(&saio->aio, saio_complete, saio))) {
421447
nng_msg_free(msg);
422448
R_Free(saio);
423-
return mk_error(xc);
449+
return mk_error_result(xc);
424450
}
425451

426452
nng_aio_set_msg(saio->aio, msg);
@@ -446,14 +472,14 @@ SEXP rnng_send_aio(SEXP con, SEXP data, SEXP mode, SEXP timeout, SEXP clo) {
446472

447473
if ((xc = nng_msg_alloc(&msg, 0))) {
448474
R_Free(saio);
449-
return mk_error(xc);
475+
return mk_error_result(xc);
450476
}
451477

452478
if ((xc = nng_msg_append(msg, dp, xlen)) ||
453479
(xc = nng_aio_alloc(&saio->aio, saio_complete, saio))) {
454480
nng_msg_free(msg);
455481
R_Free(saio);
456-
return mk_error(xc);
482+
return mk_error_result(xc);
457483
}
458484

459485
nng_aio_set_msg(saio->aio, msg);
@@ -483,14 +509,14 @@ SEXP rnng_send_aio(SEXP con, SEXP data, SEXP mode, SEXP timeout, SEXP clo) {
483509
if ((xc = nng_aio_alloc(&iaio->aio, iaio_complete, iaio))) {
484510
R_Free(iov);
485511
R_Free(iaio);
486-
return mk_error(xc);
512+
return mk_error_result(xc);
487513
}
488514

489515
if ((xc = nng_aio_set_iov(iaio->aio, 1u, iov))) {
490516
nng_aio_free(iaio->aio);
491517
R_Free(iov);
492518
R_Free(iaio);
493-
return mk_error(xc);
519+
return mk_error_result(xc);
494520
}
495521

496522
nng_aio_set_timeout(iaio->aio, dur);
@@ -545,7 +571,7 @@ SEXP rnng_recv_aio(SEXP con, SEXP mode, SEXP timeout, SEXP keep, SEXP bytes, SEX
545571

546572
if ((xc = nng_aio_alloc(&raio->aio, raio_complete, raio))) {
547573
R_Free(raio);
548-
return kpr ? mk_error_recv(xc) : mk_error(xc);
574+
return kpr ? mk_error_recv(xc) : mk_error_data(xc);
549575
}
550576

551577
nng_aio_set_timeout(raio->aio, dur);
@@ -566,7 +592,7 @@ SEXP rnng_recv_aio(SEXP con, SEXP mode, SEXP timeout, SEXP keep, SEXP bytes, SEX
566592

567593
if ((xc = nng_aio_alloc(&raio->aio, raio_complete, raio))) {
568594
R_Free(raio);
569-
return kpr ? mk_error_recv(xc) : mk_error(xc);
595+
return kpr ? mk_error_recv(xc) : mk_error_data(xc);
570596
}
571597

572598
nng_aio_set_timeout(raio->aio, dur);
@@ -593,15 +619,15 @@ SEXP rnng_recv_aio(SEXP con, SEXP mode, SEXP timeout, SEXP keep, SEXP bytes, SEX
593619
R_Free(iov->iov_buf);
594620
R_Free(iov);
595621
R_Free(iaio);
596-
return kpr ? mk_error_recv(xc) : mk_error(xc);
622+
return kpr ? mk_error_recv(xc) : mk_error_data(xc);
597623
}
598624

599625
if ((xc = nng_aio_set_iov(iaio->aio, 1u, iov))) {
600626
nng_aio_free(iaio->aio);
601627
R_Free(iov->iov_buf);
602628
R_Free(iov);
603629
R_Free(iaio);
604-
return kpr ? mk_error_recv(xc) : mk_error(xc);
630+
return kpr ? mk_error_recv(xc) : mk_error_data(xc);
605631
}
606632

607633
nng_aio_set_timeout(iaio->aio, dur);
@@ -880,6 +906,7 @@ SEXP rnng_request(SEXP con, SEXP data, SEXP sendmode, SEXP recvmode, SEXP timeou
880906

881907
nng_ctx *ctxp = (nng_ctx *) R_ExternalPtrAddr(con);
882908
const nng_duration dur = timeout == R_NilValue ? NNG_DURATION_DEFAULT : (nng_duration) Rf_asInteger(timeout);
909+
const int kpr = LOGICAL(keep)[0];
883910
nano_aio *saio = R_Calloc(1, nano_aio);
884911
nng_msg *msg;
885912

@@ -891,14 +918,14 @@ SEXP rnng_request(SEXP con, SEXP data, SEXP sendmode, SEXP recvmode, SEXP timeou
891918

892919
if ((xc = nng_msg_alloc(&msg, 0))) {
893920
R_Free(saio);
894-
return mk_error(xc);
921+
return kpr ? mk_error_recv(xc) : mk_error_data(xc);
895922
}
896923

897924
if ((xc = nng_msg_append(msg, dp, xlen)) ||
898925
(xc = nng_aio_alloc(&saio->aio, saio_complete, saio))) {
899926
nng_msg_free(msg);
900927
R_Free(saio);
901-
return mk_error(xc);
928+
return kpr ? mk_error_recv(xc) : mk_error_data(xc);
902929
}
903930

904931
nng_aio_set_msg(saio->aio, msg);
@@ -915,7 +942,7 @@ SEXP rnng_request(SEXP con, SEXP data, SEXP sendmode, SEXP recvmode, SEXP timeou
915942

916943
if ((xc = nng_aio_alloc(&raio->aio, raio_complete, raio))) {
917944
R_Free(raio);
918-
return mk_error(xc);
945+
return kpr ? mk_error_recv(xc) : mk_error_data(xc);
919946
}
920947

921948
nng_aio_set_timeout(raio->aio, dur);
@@ -937,7 +964,6 @@ SEXP rnng_request(SEXP con, SEXP data, SEXP sendmode, SEXP recvmode, SEXP timeou
937964
R_RegisterCFinalizerEx(sendaio, saio_finalizer, TRUE);
938965
R_MakeWeakRef(aio, sendaio, R_NilValue, TRUE);
939966

940-
const int kpr = LOGICAL(keep)[0];
941967
Rf_defineVar(nano_StateSymbol, Rf_ScalarLogical(kpr), env);
942968

943969
PROTECT(datafun = Rf_allocSExp(CLOSXP));

src/core.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
// internals -------------------------------------------------------------------
2323

24-
SEXP mk_error(const int xc) {
24+
static SEXP mk_error(const int xc) {
2525

2626
SEXP err = Rf_ScalarInteger(xc);
2727
Rf_classgets(err, nano_error);
@@ -73,7 +73,7 @@ SEXP nano_encode(SEXP object) {
7373
SEXP out;
7474

7575
if (!Rf_isVectorAtomic(object))
76-
Rf_error("'data' is not an atomic vector type");
76+
Rf_error("'data' must be an atomic vector type to send in mode 'raw'");
7777
if (TYPEOF(object) == STRSXP) {
7878
const char *s;
7979
unsigned char *buf;
@@ -127,7 +127,7 @@ SEXP nano_encodes(SEXP data, SEXP mode) {
127127

128128
int xc;
129129
if (TYPEOF(mode) == INTSXP) {
130-
xc = INTEGER(mode)[0] == 1 ? 1 : 0;
130+
xc = INTEGER(mode)[0];
131131
} else {
132132
const char *mod = CHAR(STRING_ELT(mode, 0));
133133
size_t slen = strlen(mod);
@@ -137,7 +137,7 @@ SEXP nano_encodes(SEXP data, SEXP mode) {
137137
case 1:
138138
case 2:
139139
case 3:
140-
if (!strncmp(r, mod, slen)) { xc = 0; break; }
140+
if (!strncmp(r, mod, slen)) { xc = 2; break; }
141141
case 4:
142142
case 5:
143143
case 6:
@@ -148,7 +148,7 @@ SEXP nano_encodes(SEXP data, SEXP mode) {
148148
}
149149
}
150150

151-
if (xc == 0)
151+
if (xc != 1)
152152
return nano_encode(data);
153153

154154
SEXP out;

src/nanonext.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363

6464
#ifdef NANONEXT_INTERNALS
6565
#define ERROR_OUT(xc) Rf_error("%d | %s", xc, nng_strerror(xc))
66-
extern SEXP mk_error(const int);
6766
extern SEXP mk_werror(const int);
6867
extern SEXP mk_error_recv(const int);
6968
extern SEXP mk_error_ncurl(const int);

0 commit comments

Comments
 (0)