Net-Async-Redis-XS
view release on metacpan or search on metacpan
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <math.h>
/* Back-compatibility */
#ifndef G_LIST
#define G_LIST G_ARRAY
#endif
#ifndef PERL_ARGS_ASSERT_AV_COUNT
/* Taken from inline.h, was added in 5.33.something */
#define PERL_ARGS_ASSERT_AV_COUNT \
assert(av)
#endif
#ifndef av_count
/* Taken from inline.h, was added in 5.33.something */
PERL_STATIC_INLINE Size_t
Perl_av_count(pTHX_ AV *av)
{
PERL_ARGS_ASSERT_AV_COUNT;
assert(SvTYPE(av) == SVt_PVAV);
return AvFILL(av) + 1;
}
#define av_count(a) Perl_av_count(aTHX_ a)
#endif
/* Types of data structures that can nest */
enum PendingStackType {
array, map, set, attribute, push
};
/* Container representation - basic stack of nested lists */
struct pending_stack {
AV *data;
struct pending_stack *prev;
long expected;
enum PendingStackType type;
};
void
add_value(pTHX_ struct pending_stack *target, SV *v)
{
if(!target)
return;
av_push(
target->data,
v
);
}
MODULE = Net::Async::Redis::XS PACKAGE = Net::Async::Redis::XS
PROTOTYPES: DISABLE
AV *
decode_buffer(SV *this, SV *p)
PPCODE:
/* Plain bytestring required: no magic, no UTF-8, no nonsense */
if(!SvPOK(p))
croak("expected a string");
if(SvUTF8(p))
sv_utf8_downgrade(p, true);
STRLEN len;
const char *in = SvPVbyte(p, len);
const char *ptr = in;
const char *end = in + len;
struct pending_stack *ps = NULL;
AV *results = (AV *) sv_2mortal((SV *) newAV());
bool extracted_item = false;
SV *extracted = &PL_sv_undef;
/* Perl strings _should_ guarantee this, so perhaps better as an assert? */
if(*end != '\0') {
croak("no trailing null?");
}
/* The shortest command is a single-character null, which has the
* type `_` followed by CRLF terminator, so that's at least 3
* characters for a valid command.
*/
if(len >= 3) { // && *(end - 1) == '\x0A' && *(end - 2) == '\x0D') {
while(*ptr && ptr < end) {
/* First step is to check the data type and extract it if we can */
switch(*ptr++) {
case '~': /* set */
case '*': { /* array */
int n = 0;
/* We effectively want grok_atoUV behaviour, but without having a full UV */
while(*ptr >= '0' && *ptr <= '9') {
n = (n * 10) + (*ptr - '0');
++ptr;
}
if(ptr + 2 > end) {
goto end_parsing;
}
if(ptr[0] != '\x0D' || ptr[1] != '\x0A') {
croak("protocol violation - array length not followed by CRLF");
}
ptr += 2;
AV *x = (AV *) sv_2mortal((SV *)newAV());
if(n > 0) {
av_extend(x, n);
}
struct pending_stack *pn = Newx(pn, 1, struct pending_stack);
*pn = (struct pending_stack) {
.data = x,
.prev = ps,
.expected = n,
.type = array
};
ps = pn;
break;
}
case '>': { /* push (pubsub) */
int n = 0;
while(*ptr >= '0' && *ptr <= '9') {
( run in 1.660 second using v1.01-cache-2.11-cpan-5511b514fd6 )