File-Raw-JSON
view release on metacpan or search on metacpan
SV *die_msg = s->die_msg;
STRLEN dlen;
SV *m = die_msg ? newSVsv(die_msg) : NULL;
jsonl_stream_state_free(aTHX_ s);
ctx->call_state = NULL;
ctx->cancel = 1;
if (m) {
const char *dpv = SvPV(m, dlen);
sv_2mortal(m);
croak("%.*s", (int)dlen, dpv);
}
croak("File::Raw::JSON: stream cancelled");
}
if (eof) {
jsonl_stream_state_free(aTHX_ s);
ctx->call_state = NULL;
}
return 0;
}
/* ============================================================
* Plugin descriptors. Statics so the registry's non-owning pointer
* stays valid for the life of the process.
* ============================================================ */
static FilePlugin json_plugin;
static FilePlugin jsonl_plugin;
/* ============================================================ */
MODULE = File::Raw::JSON PACKAGE = File::Raw::JSON
PROTOTYPES: DISABLE
# ---- direct in-memory codec entry points ------------------------
#
# file_json_decode($bytes, ?key => value, ...) -> parsed value
# file_json_encode($value, ?key => value, ...) -> JSON bytes
#
# These bypass File::Raw's plugin pipeline entirely - no path, no
# syscalls, just bytes <-> Perl structure. Same options grammar as
# the plugin tail (mode, pretty, indent, sort_keys, canonical,
# ordered, relaxed, allow_nonref, allow_nan_inf, max_depth, eol,
# boolean_class, utf8); odd-count tails croak. See build_opts_hv
# above the first MODULE block for the option-collection helper.
# File::Raw::JSON->import(...) - selective installer. Mirrors
# File::Raw's pattern (file.c XS_file_import). `use File::Raw::JSON`
# with no arg list = no-op; with a list of names, each requested
# function CV is aliased into the caller's package via newXS, sharing
# the underlying XSUB pointer with the source CV.
#
# Recognised: file_json_decode, file_json_encode, :codec (= both),
# :all (= same). Unknown names warn but don't die, matching File::Raw.
void
import(...)
PREINIT:
const char *pkg;
I32 i;
PPCODE:
pkg = CopSTASHPV(PL_curcop);
if (items <= 1) XSRETURN_EMPTY;
for (i = 1; i < items; i++) {
STRLEN len;
const char *arg = SvPV(ST(i), len);
if ((len == 6 && strEQ(arg, ":codec")) ||
(len == 4 && strEQ(arg, ":all")))
{
fjson_install_alias(aTHX_ pkg, "file_json_decode");
fjson_install_alias(aTHX_ pkg, "file_json_encode");
continue;
}
if ((len == 16 && strEQ(arg, "file_json_decode")) ||
(len == 16 && strEQ(arg, "file_json_encode")))
{
fjson_install_alias(aTHX_ pkg, arg);
continue;
}
warn("File::Raw::JSON: '%.*s' is not exported", (int)len, arg);
}
XSRETURN_EMPTY;
SV *
file_json_decode(bytes, ...)
SV *bytes
PREINIT:
json_options_t o;
HV *opts_hv;
const char *boolean_class;
HV *bool_stash;
STRLEN len;
const char *pv;
CODE:
json_options_defaults(&o);
o.mode = JSON_MODE_DOCUMENT;
opts_hv = build_opts_hv(aTHX_ ax, items, 1, "file_json_decode");
boolean_class = decode_opts(aTHX_ opts_hv, &o);
bool_stash = resolve_boolean_stash(aTHX_ boolean_class);
if (!bytes || !SvOK(bytes)) XSRETURN_UNDEF;
pv = SvPV(bytes, len);
if (o.mode == JSON_MODE_LINES) {
AV *av = json_decode_lines(aTHX_ pv, len, &o, bool_stash);
RETVAL = newRV_noinc((SV *)av);
} else {
SV *out = json_decode_document(aTHX_ pv, len, &o, bool_stash);
RETVAL = out ? out : &PL_sv_undef;
if (RETVAL == &PL_sv_undef) SvREFCNT_inc(RETVAL);
}
OUTPUT:
RETVAL
SV *
file_json_encode(value, ...)
SV *value
PREINIT:
json_options_t o;
opts_hv = build_opts_hv(aTHX_ ax, items, 1, "file_json_encode");
(void)decode_opts(aTHX_ opts_hv, &o);
if (o.mode == JSON_MODE_LINES) {
RETVAL = json_encode_lines(aTHX_ value, &o);
} else {
RETVAL = json_encode_document(aTHX_ value, &o);
}
if (!RETVAL) {
RETVAL = &PL_sv_undef;
SvREFCNT_inc(RETVAL);
}
OUTPUT:
RETVAL
BOOT:
{
init_boolean_singletons(aTHX);
json_plugin.name = "json";
json_plugin.read_fn = json_read;
json_plugin.write_fn = json_write;
json_plugin.record_fn = NULL;
json_plugin.stream_fn = json_stream_reject;
json_plugin.state = &MODE_DOCUMENT_TAG;
if (file_register_plugin(aTHX_ &json_plugin) <= 0)
warn("File::Raw::JSON: failed to register 'json' plugin");
jsonl_plugin.name = "jsonl";
jsonl_plugin.read_fn = json_read; /* mode tag selects MODE_LINES */
jsonl_plugin.write_fn = json_write;
jsonl_plugin.record_fn = NULL;
jsonl_plugin.stream_fn = jsonl_stream;
jsonl_plugin.state = &MODE_LINES_TAG;
if (file_register_plugin(aTHX_ &jsonl_plugin) <= 0)
warn("File::Raw::JSON: failed to register 'jsonl' plugin");
}
# ============================================================
# File::Raw::JSON::Boolean - XSUB constructors + overload bodies
# ============================================================
#
# All four overload entry points (bool / numify / stringify / not)
# run as XSUBs rather than Perl subs, ~3x faster than the pure-Perl
# overload that was here before. The overload table itself is still
# wired up by `use overload ...` in Boolean.pm - that's the cheapest
# way to register, and the dispatch cost is identical regardless of
# whether the body is a Perl sub or an XSUB.
#
# Calling convention: overload invokes our handlers with three args
# (self, other, swap). We only need self; ignore the rest. Returning
# the static PL_sv_yes / PL_sv_no avoids per-call SV allocation.
MODULE = File::Raw::JSON PACKAGE = File::Raw::JSON::Boolean
PROTOTYPES: DISABLE
void
TRUE(...)
PPCODE:
PERL_UNUSED_VAR(items);
if (!g_frj_true_sv) init_boolean_singletons(aTHX);
SvREFCNT_inc_simple_void(g_frj_true_sv);
XPUSHs(sv_2mortal(g_frj_true_sv));
XSRETURN(1);
void
FALSE(...)
PPCODE:
PERL_UNUSED_VAR(items);
if (!g_frj_false_sv) init_boolean_singletons(aTHX);
SvREFCNT_inc_simple_void(g_frj_false_sv);
XPUSHs(sv_2mortal(g_frj_false_sv));
XSRETURN(1);
SV *
overload_bool(self, other, swap)
SV *self
SV *other
SV *swap
OVERLOAD: bool
CODE:
PERL_UNUSED_VAR(other);
PERL_UNUSED_VAR(swap);
RETVAL = (SvROK(self) && SvTRUE(SvRV(self)))
? &PL_sv_yes : &PL_sv_no;
SvREFCNT_inc_simple_void(RETVAL); /* OUTPUT typemap will mortalise */
OUTPUT:
RETVAL
SV *
overload_numify(self, other, swap)
SV *self
SV *other
SV *swap
OVERLOAD: 0+
CODE:
PERL_UNUSED_VAR(other);
PERL_UNUSED_VAR(swap);
RETVAL = newSViv(
(SvROK(self) && SvTRUE(SvRV(self))) ? 1 : 0
);
OUTPUT:
RETVAL
SV *
overload_stringify(self, other, swap)
SV *self
SV *other
SV *swap
OVERLOAD: \"\"
CODE:
PERL_UNUSED_VAR(other);
PERL_UNUSED_VAR(swap);
RETVAL = newSVpvn(
(SvROK(self) && SvTRUE(SvRV(self))) ? "1" : "0", 1
);
OUTPUT:
RETVAL
SV *
overload_not(self, other, swap)
SV *self
SV *other
SV *swap
OVERLOAD: !
CODE:
PERL_UNUSED_VAR(other);
PERL_UNUSED_VAR(swap);
( run in 0.580 second using v1.01-cache-2.11-cpan-5511b514fd6 )