yeptris 0.6.5.4 → 0.6.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/libyeptris/extconf.rb +57 -0
- data/lib/yeptris/ffi.rb +12 -15
- data/lib/yeptris/json.rb +5 -2
- data/lib/yeptris/psych.rb +76 -3
- data/lib/yeptris.rb +36 -14
- data/vendor/libyeptris/CMakeLists.txt +254 -0
- data/vendor/libyeptris/cmake/yeptris-config.cmake.in +5 -0
- data/vendor/libyeptris/cmake/yeptris.pc.in +11 -0
- data/vendor/libyeptris/src/CMakeLists.txt +167 -0
- data/vendor/libyeptris/src/include/yeptris/api.h +32 -0
- data/vendor/libyeptris/src/include/yeptris/cbor.h +101 -0
- data/vendor/libyeptris/src/include/yeptris/dom.h +181 -0
- data/vendor/libyeptris/src/include/yeptris/emit.h +81 -0
- data/vendor/libyeptris/src/include/yeptris/error.h +41 -0
- data/vendor/libyeptris/src/include/yeptris/events.h +157 -0
- data/vendor/libyeptris/src/include/yeptris/json.h +45 -0
- data/vendor/libyeptris/src/include/yeptris/json.hpp +258 -0
- data/vendor/libyeptris/src/include/yeptris/jsonc_compat.h +115 -0
- data/vendor/libyeptris/src/include/yeptris/marshal.h +52 -0
- data/vendor/libyeptris/src/include/yeptris/parse.h +48 -0
- data/vendor/libyeptris/src/include/yeptris/plan.h +100 -0
- data/vendor/libyeptris/src/include/yeptris/resolve.h +71 -0
- data/vendor/libyeptris/src/include/yeptris/schema.h +119 -0
- data/vendor/libyeptris/src/include/yeptris/tape.h +99 -0
- data/vendor/libyeptris/src/include/yeptris/types.h +38 -0
- data/vendor/libyeptris/src/include/yeptris/values.h +102 -0
- data/vendor/libyeptris/src/include/yeptris/version.h.in +29 -0
- data/vendor/libyeptris/src/include/yeptris/visit.h +77 -0
- data/vendor/libyeptris/src/include/yeptris/yajl_compat.h +135 -0
- data/vendor/libyeptris/src/include/yeptris.h +23 -0
- data/vendor/libyeptris/src/yeptris/build.c +371 -0
- data/vendor/libyeptris/src/yeptris/cbor/cbor.h +25 -0
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +846 -0
- data/vendor/libyeptris/src/yeptris/cbor/encode.c +824 -0
- data/vendor/libyeptris/src/yeptris/common/chartype.c +41 -0
- data/vendor/libyeptris/src/yeptris/common/chartype.h +77 -0
- data/vendor/libyeptris/src/yeptris/common/cpu.c +81 -0
- data/vendor/libyeptris/src/yeptris/common/cpu.h +40 -0
- data/vendor/libyeptris/src/yeptris/common/error.c +65 -0
- data/vendor/libyeptris/src/yeptris/common/error.h +79 -0
- data/vendor/libyeptris/src/yeptris/common/mutex.h +45 -0
- data/vendor/libyeptris/src/yeptris/common/nametab.c +275 -0
- data/vendor/libyeptris/src/yeptris/common/nametab.h +68 -0
- data/vendor/libyeptris/src/yeptris/common/port.h +74 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text.c +49 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text.h +295 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_avx2.c +534 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_neon.c +662 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_scalar.c +298 -0
- data/vendor/libyeptris/src/yeptris/common/string_view.c +34 -0
- data/vendor/libyeptris/src/yeptris/common/string_view.h +93 -0
- data/vendor/libyeptris/src/yeptris/doc.h +37 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.c +973 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.h +290 -0
- data/vendor/libyeptris/src/yeptris/dom/hpool.c +107 -0
- data/vendor/libyeptris/src/yeptris/dom/mapindex.c +173 -0
- data/vendor/libyeptris/src/yeptris/dom/mapindex.h +61 -0
- data/vendor/libyeptris/src/yeptris/dom/mutate.c +429 -0
- data/vendor/libyeptris/src/yeptris/emit/emit.c +349 -0
- data/vendor/libyeptris/src/yeptris/emit/float/api.h +38 -0
- data/vendor/libyeptris/src/yeptris/emit/float/dragon.c +405 -0
- data/vendor/libyeptris/src/yeptris/emit/float/floatint.h +203 -0
- data/vendor/libyeptris/src/yeptris/emit/float/print.c +396 -0
- data/vendor/libyeptris/src/yeptris/emit/style.c +81 -0
- data/vendor/libyeptris/src/yeptris/emit/style.h +24 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.c +746 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.h +61 -0
- data/vendor/libyeptris/src/yeptris/encoding/bom.c +31 -0
- data/vendor/libyeptris/src/yeptris/encoding/encoding.h +63 -0
- data/vendor/libyeptris/src/yeptris/encoding/transcode.c +148 -0
- data/vendor/libyeptris/src/yeptris/encoding/utf8_validate.c +178 -0
- data/vendor/libyeptris/src/yeptris/events/capture.c +150 -0
- data/vendor/libyeptris/src/yeptris/events/capture.h +39 -0
- data/vendor/libyeptris/src/yeptris/events/iterparse.c +208 -0
- data/vendor/libyeptris/src/yeptris/events/pull.c +97 -0
- data/vendor/libyeptris/src/yeptris/events/push.c +104 -0
- data/vendor/libyeptris/src/yeptris/events/recorder.c +107 -0
- data/vendor/libyeptris/src/yeptris/events/values.c +527 -0
- data/vendor/libyeptris/src/yeptris/events/values_priv.h +51 -0
- data/vendor/libyeptris/src/yeptris/events/yaml_compat.c +86 -0
- data/vendor/libyeptris/src/yeptris/events/yaml_compat.h +90 -0
- data/vendor/libyeptris/src/yeptris/jsonapi/jsonc_compat.c +687 -0
- data/vendor/libyeptris/src/yeptris/jsonapi/yajl_compat.c +728 -0
- data/vendor/libyeptris/src/yeptris/marshal.c +744 -0
- data/vendor/libyeptris/src/yeptris/memory/allocator.c +20 -0
- data/vendor/libyeptris/src/yeptris/memory/allocator.h +43 -0
- data/vendor/libyeptris/src/yeptris/memory/arena.c +134 -0
- data/vendor/libyeptris/src/yeptris/memory/arena.h +52 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.c +115 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.h +36 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.c +3689 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.h +65 -0
- data/vendor/libyeptris/src/yeptris/parse/events.h +124 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.c +349 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.h +33 -0
- data/vendor/libyeptris/src/yeptris/parse/scalars.c +416 -0
- data/vendor/libyeptris/src/yeptris/parse/scalars.h +75 -0
- data/vendor/libyeptris/src/yeptris/parse.c +650 -0
- data/vendor/libyeptris/src/yeptris/plan.c +817 -0
- data/vendor/libyeptris/src/yeptris/resolve/compat11.c +334 -0
- data/vendor/libyeptris/src/yeptris/resolve/core12.c +143 -0
- data/vendor/libyeptris/src/yeptris/resolve/resolver.h +56 -0
- data/vendor/libyeptris/src/yeptris/resolve/tags.c +58 -0
- data/vendor/libyeptris/src/yeptris/scan/json.c +792 -0
- data/vendor/libyeptris/src/yeptris/scan/json.h +109 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.c +463 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.h +150 -0
- data/vendor/libyeptris/src/yeptris/schema.c +238 -0
- data/vendor/libyeptris/src/yeptris/tape.c +1292 -0
- data/vendor/libyeptris/src/yeptris/version.c +7 -0
- data/vendor/libyeptris/src/yeptris/visit/dom_visit.c +115 -0
- data/vendor/libyeptris/src/yeptris/visit/json_visit.c +293 -0
- data/vendor/libyeptris/src/yeptris/visit/yaml_visit.c +127 -0
- metadata +112 -2
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/* events.h — the four consumption models over one engine (TODO.impl/12).
|
|
2
|
+
*
|
|
3
|
+
* push: one callback per event (C users; ~1 µs/event through FFI —
|
|
4
|
+
* bindings prefer the recorder's bulk drain).
|
|
5
|
+
* pull: StAX-style cursor; zero C->host dispatch; event strings are
|
|
6
|
+
* owned by the puller and valid UNTIL THE NEXT CALL.
|
|
7
|
+
* recorder: fixed-size records + one string arena; bulk drain, O(chunks)
|
|
8
|
+
* host crossings. v1 buffers input until the final chunk; the
|
|
9
|
+
* streaming feed (mid-document resumption) lands with
|
|
10
|
+
* parse/feed.c and keeps this shape.
|
|
11
|
+
* iterparse: document-at-a-time over multi-document streams; one
|
|
12
|
+
* document's events per call, memory bounded by the largest
|
|
13
|
+
* document. Events valid UNTIL THE NEXT CALL.
|
|
14
|
+
*
|
|
15
|
+
* All four are sinks over the single parse engine: identical event
|
|
16
|
+
* streams, proven by the cross-model corpus check (test_events_cross).
|
|
17
|
+
*/
|
|
18
|
+
#ifndef YEPTRIS_EVENTS_H
|
|
19
|
+
#define YEPTRIS_EVENTS_H
|
|
20
|
+
|
|
21
|
+
#include <stddef.h>
|
|
22
|
+
#include <stdint.h>
|
|
23
|
+
|
|
24
|
+
#include <yeptris/api.h>
|
|
25
|
+
#include <yeptris/error.h> /* YeptrisStatus */
|
|
26
|
+
#include <yeptris/resolve.h> /* YeptrisSchema */
|
|
27
|
+
#include <yeptris/types.h>
|
|
28
|
+
|
|
29
|
+
#ifdef __cplusplus
|
|
30
|
+
extern "C" {
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
/* Event types (ABI-pinned order; mirrors the internal engine 1:1). */
|
|
34
|
+
typedef enum {
|
|
35
|
+
YEPTRIS_EV_STREAM_START = 1,
|
|
36
|
+
YEPTRIS_EV_STREAM_END,
|
|
37
|
+
YEPTRIS_EV_DOCUMENT_START,
|
|
38
|
+
YEPTRIS_EV_DOCUMENT_END,
|
|
39
|
+
YEPTRIS_EV_SEQUENCE_START,
|
|
40
|
+
YEPTRIS_EV_SEQUENCE_END,
|
|
41
|
+
YEPTRIS_EV_MAPPING_START,
|
|
42
|
+
YEPTRIS_EV_MAPPING_END,
|
|
43
|
+
YEPTRIS_EV_SCALAR,
|
|
44
|
+
YEPTRIS_EV_ALIAS,
|
|
45
|
+
} YeptrisEventType;
|
|
46
|
+
|
|
47
|
+
/* Flag bits in YeptrisEventRecord.flags. */
|
|
48
|
+
enum {
|
|
49
|
+
YEPTRIS_EF_FLOW = 1u << 0, /* collection in flow style */
|
|
50
|
+
YEPTRIS_EF_EXPLICIT = 1u << 1, /* document with --- / ... marker */
|
|
51
|
+
YEPTRIS_EF_IMPLICIT = 1u << 2, /* plain scalar, no tag */
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/* One event, string fields pointing into the owning model's storage. */
|
|
55
|
+
typedef struct {
|
|
56
|
+
YeptrisEventType type;
|
|
57
|
+
int style; /* YeptrisScalarStyle (dom.h) for scalars */
|
|
58
|
+
int flow; /* collection: flow style */
|
|
59
|
+
int explicit_marker; /* document: --- / ... seen */
|
|
60
|
+
int implicit; /* scalar: plain and untagged */
|
|
61
|
+
const char* value; /* scalar content or alias name; NULL if empty */
|
|
62
|
+
size_t value_len;
|
|
63
|
+
const char* anchor; /* node property; NULL when absent */
|
|
64
|
+
size_t anchor_len;
|
|
65
|
+
const char* tag; /* resolved tag; NULL when absent */
|
|
66
|
+
size_t tag_len;
|
|
67
|
+
uint32_t line; /* 1-based node start */
|
|
68
|
+
uint32_t col;
|
|
69
|
+
} YeptrisEvent;
|
|
70
|
+
|
|
71
|
+
/* ---- push ------------------------------------------------------------- */
|
|
72
|
+
|
|
73
|
+
/* Returns nonzero from the callback to abort the parse (surfaced as
|
|
74
|
+
* YEPTRIS_ERROR_PARSE with the last-error channel set). Event strings
|
|
75
|
+
* are valid only during the call. */
|
|
76
|
+
typedef int (*yeptris_event_fn)(void* ctx, const YeptrisEvent* ev);
|
|
77
|
+
|
|
78
|
+
YEPTRIS_API YeptrisStatus yeptris_push_parse(const char* buf, size_t len, yeptris_event_fn on_event,
|
|
79
|
+
void* ctx);
|
|
80
|
+
|
|
81
|
+
/* ---- pull ------------------------------------------------------------- */
|
|
82
|
+
|
|
83
|
+
YEPTRIS_API YeptrisPullParser yeptris_pull_new(const char* buf, size_t len);
|
|
84
|
+
|
|
85
|
+
/* Next event (owned by the puller, valid until the next call), or
|
|
86
|
+
* NULL at stream end or on error — distinguish with yeptris_pull_status. */
|
|
87
|
+
YEPTRIS_API const YeptrisEvent* yeptris_pull_next(YeptrisPullParser pull);
|
|
88
|
+
|
|
89
|
+
/* Bulk cursor (the FFI shape): up to max events per call, strings in
|
|
90
|
+
* the puller's arena valid until the next pull call. Returns count. */
|
|
91
|
+
YEPTRIS_API size_t yeptris_pull_next_batch(YeptrisPullParser pull, YeptrisEvent* out, size_t max);
|
|
92
|
+
|
|
93
|
+
YEPTRIS_API YeptrisStatus yeptris_pull_status(const YeptrisPullParser pull, uint32_t* line,
|
|
94
|
+
uint32_t* col);
|
|
95
|
+
YEPTRIS_API void yeptris_pull_free(YeptrisPullParser pull);
|
|
96
|
+
|
|
97
|
+
/* ---- recorder --------------------------------------------------------- */
|
|
98
|
+
|
|
99
|
+
/* Fixed-size record; strings slice the arena by offset+length. */
|
|
100
|
+
typedef struct {
|
|
101
|
+
uint8_t type; /* YeptrisEventType */
|
|
102
|
+
uint8_t style;
|
|
103
|
+
uint8_t flags; /* YEPTRIS_EF_* */
|
|
104
|
+
uint8_t tag_id; /* resolved implicit tag (YeptrisTagId, resolve.h) —
|
|
105
|
+
* the typing SSOT, so hosts never re-scan. Uses the
|
|
106
|
+
* struct's pad byte: sizeof stays 36 (ABI-pinned) */
|
|
107
|
+
uint32_t line;
|
|
108
|
+
uint32_t col;
|
|
109
|
+
uint32_t value_off;
|
|
110
|
+
uint32_t value_len;
|
|
111
|
+
uint32_t anchor_off;
|
|
112
|
+
uint32_t anchor_len;
|
|
113
|
+
uint32_t tag_off;
|
|
114
|
+
uint32_t tag_len;
|
|
115
|
+
} YeptrisEventRecord;
|
|
116
|
+
|
|
117
|
+
YEPTRIS_API YeptrisRecorder yeptris_recorder_new(void);
|
|
118
|
+
|
|
119
|
+
/* Same, with the implicit-typing schema for the parse (bindings pass
|
|
120
|
+
* compat_11 to reproduce Psych's typing). */
|
|
121
|
+
YEPTRIS_API YeptrisRecorder yeptris_recorder_new_ex(YeptrisSchema schema);
|
|
122
|
+
|
|
123
|
+
/* Accumulates input; the parse advances whenever a complete document
|
|
124
|
+
* has arrived (its closing --- / ... marker line), and final != 0
|
|
125
|
+
* flushes the trailing document. Each feed's records — fixed-size
|
|
126
|
+
* array plus the arena — hold the documents closed by that chunk and
|
|
127
|
+
* are valid until the next feed: drain per chunk. Returns
|
|
128
|
+
* YEPTRIS_OK, YEPTRIS_ERROR_PARSE (terminal; drain what this feed
|
|
129
|
+
* recorded) or YEPTRIS_ERROR_ARG. */
|
|
130
|
+
YEPTRIS_API YeptrisStatus yeptris_recorder_feed(YeptrisRecorder rec, const char* chunk, size_t len,
|
|
131
|
+
int final);
|
|
132
|
+
|
|
133
|
+
/* Bulk accessors: the record array and the string arena. Valid until
|
|
134
|
+
* the next feed; reset at every feed entry (drain per chunk). */
|
|
135
|
+
YEPTRIS_API const YeptrisEventRecord* yeptris_recorder_records(YeptrisRecorder rec, size_t* count);
|
|
136
|
+
YEPTRIS_API const char* yeptris_recorder_arena(YeptrisRecorder rec, size_t* len);
|
|
137
|
+
YEPTRIS_API void yeptris_recorder_free(YeptrisRecorder rec);
|
|
138
|
+
|
|
139
|
+
/* ---- iterparse -------------------------------------------------------- */
|
|
140
|
+
|
|
141
|
+
YEPTRIS_API YeptrisIterparse yeptris_iterparse_new(const char* buf, size_t len);
|
|
142
|
+
|
|
143
|
+
/* The next document's events (owned by the iterator, valid until the
|
|
144
|
+
* next call): *count events, or NULL when the stream is exhausted.
|
|
145
|
+
* STREAM_START / STREAM_END frame the stream exactly once each; the
|
|
146
|
+
* DOCUMENT_* pair frames each yielded slice. */
|
|
147
|
+
YEPTRIS_API const YeptrisEvent* yeptris_iterparse_next(YeptrisIterparse it, size_t* count);
|
|
148
|
+
|
|
149
|
+
YEPTRIS_API YeptrisStatus yeptris_iterparse_status(const YeptrisIterparse it, uint32_t* line,
|
|
150
|
+
uint32_t* col);
|
|
151
|
+
YEPTRIS_API void yeptris_iterparse_free(YeptrisIterparse it);
|
|
152
|
+
|
|
153
|
+
#ifdef __cplusplus
|
|
154
|
+
}
|
|
155
|
+
#endif
|
|
156
|
+
|
|
157
|
+
#endif /* YEPTRIS_EVENTS_H */
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* json.h — strict JSON mode (TODO.impl/08C/21).
|
|
2
|
+
*
|
|
3
|
+
* YAML 1.2 strictly contains JSON, but users of json-c-shaped APIs
|
|
4
|
+
* want RFC 8259 semantics exactly: this entry validates the whole
|
|
5
|
+
* input against the strict grammar (scan/json.c is the one truth)
|
|
6
|
+
* before the engine runs, so an accepted input is guaranteed to be
|
|
7
|
+
* pure JSON and every invalid one fails with the violation offset.
|
|
8
|
+
* Charset note: JSON strings allow DEL and forbid raw C0 — the
|
|
9
|
+
* opposite corner of YAML c-printable — so this path validates
|
|
10
|
+
* UTF-8 well-formedness only, never the printable set.
|
|
11
|
+
*/
|
|
12
|
+
#ifndef YEPTRIS_JSON_H
|
|
13
|
+
#define YEPTRIS_JSON_H
|
|
14
|
+
|
|
15
|
+
#include <stddef.h>
|
|
16
|
+
|
|
17
|
+
#include <yeptris/api.h>
|
|
18
|
+
#include <yeptris/parse.h>
|
|
19
|
+
#include <yeptris/types.h>
|
|
20
|
+
|
|
21
|
+
#ifdef __cplusplus
|
|
22
|
+
extern "C" {
|
|
23
|
+
#endif
|
|
24
|
+
|
|
25
|
+
/* Parses one strict-JSON document. Same contract as yeptris_parse:
|
|
26
|
+
* a YeptrisDocument handle (queries via the DOM API) or NULL with
|
|
27
|
+
* *st set; violations carry the byte offset via yeptris_last_error. */
|
|
28
|
+
YEPTRIS_API YeptrisDocument yeptris_parse_json(const char* data, size_t len, YeptrisStatus* st);
|
|
29
|
+
|
|
30
|
+
/* Serializes the document's FIRST document as strict JSON (flow
|
|
31
|
+
* collections, JSON escapes, shortest floats, null/true/false words).
|
|
32
|
+
* Returns a malloc'd NUL-terminated buffer (caller frees) with *len
|
|
33
|
+
* (may be NULL) set, or NULL on a NULL document / allocation
|
|
34
|
+
* failure / zero documents. */
|
|
35
|
+
YEPTRIS_API char* yeptris_serialize_json(YeptrisDocument doc, size_t* len);
|
|
36
|
+
|
|
37
|
+
/* The compact variant: no padding spaces (JSON.generate's shape);
|
|
38
|
+
* compact == 0 is byte-identical to yeptris_serialize_json. */
|
|
39
|
+
YEPTRIS_API char* yeptris_serialize_json_ex(YeptrisDocument doc, size_t* len, int compact);
|
|
40
|
+
|
|
41
|
+
#ifdef __cplusplus
|
|
42
|
+
}
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
#endif /* YEPTRIS_JSON_H */
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// json.hpp — the nlohmann-flavored C++17 wrapper (TODO.impl/21).
|
|
2
|
+
//
|
|
3
|
+
// Value semantics over the C ABI: yeptris::json owns its document
|
|
4
|
+
// (RAII), children are views into it. JSON in, JSON out — strict
|
|
5
|
+
// parsing via yeptris_parse_json, output via the JSON writer.
|
|
6
|
+
// Errors throw (nlohmann discipline); no exceptions in the C core.
|
|
7
|
+
//
|
|
8
|
+
// Deliberately a view, not a copy: j["k"] returns a child that stays
|
|
9
|
+
// valid while the parent json lives (the nlohmann ergonomics without
|
|
10
|
+
// the deep-template machinery).
|
|
11
|
+
|
|
12
|
+
#ifndef YEPTRIS_JSON_HPP
|
|
13
|
+
#define YEPTRIS_JSON_HPP
|
|
14
|
+
|
|
15
|
+
#include <cstdint>
|
|
16
|
+
#include <stdexcept>
|
|
17
|
+
#include <string>
|
|
18
|
+
#include <string_view>
|
|
19
|
+
#include <type_traits>
|
|
20
|
+
|
|
21
|
+
#include <yeptris/dom.h>
|
|
22
|
+
#include <yeptris/json.h>
|
|
23
|
+
|
|
24
|
+
namespace yeptris {
|
|
25
|
+
|
|
26
|
+
class parse_error : public std::runtime_error {
|
|
27
|
+
public:
|
|
28
|
+
explicit parse_error(const char* msg) : std::runtime_error(msg) {}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
class type_error : public std::logic_error {
|
|
32
|
+
public:
|
|
33
|
+
explicit type_error(const char* msg) : std::logic_error(msg) {}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
class json {
|
|
37
|
+
public:
|
|
38
|
+
json() = default;
|
|
39
|
+
|
|
40
|
+
json(const json&) = delete;
|
|
41
|
+
json& operator=(const json&) = delete;
|
|
42
|
+
|
|
43
|
+
json(json&& other) noexcept : doc_(other.doc_), node_(other.node_), owns_(other.owns_) {
|
|
44
|
+
other.doc_ = nullptr;
|
|
45
|
+
other.node_ = nullptr;
|
|
46
|
+
other.owns_ = false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
json& operator=(json&& other) noexcept {
|
|
50
|
+
if (this != &other) {
|
|
51
|
+
destroy();
|
|
52
|
+
doc_ = other.doc_;
|
|
53
|
+
node_ = other.node_;
|
|
54
|
+
owns_ = other.owns_;
|
|
55
|
+
other.doc_ = nullptr;
|
|
56
|
+
other.node_ = nullptr;
|
|
57
|
+
other.owns_ = false;
|
|
58
|
+
}
|
|
59
|
+
return *this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
~json() {
|
|
63
|
+
destroy();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static json parse(std::string_view text) {
|
|
67
|
+
YeptrisStatus st = YEPTRIS_OK;
|
|
68
|
+
YeptrisDocument d = yeptris_parse_json(text.data(), text.size(), &st);
|
|
69
|
+
if (d == nullptr) {
|
|
70
|
+
uint32_t line = 0, col = 0;
|
|
71
|
+
const char* msg = yeptris_last_error(&line, &col);
|
|
72
|
+
throw parse_error(msg ? msg : "not valid JSON");
|
|
73
|
+
}
|
|
74
|
+
json j;
|
|
75
|
+
j.doc_ = d;
|
|
76
|
+
j.node_ = yeptris_document_root(d, 0);
|
|
77
|
+
j.owns_ = true;
|
|
78
|
+
return j;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
std::string dump() const {
|
|
82
|
+
check_root();
|
|
83
|
+
size_t len = 0;
|
|
84
|
+
char* out = yeptris_serialize_json(doc_, &len);
|
|
85
|
+
if (out == nullptr) {
|
|
86
|
+
throw std::runtime_error("serialization failed");
|
|
87
|
+
}
|
|
88
|
+
std::string s(out, len);
|
|
89
|
+
free(out);
|
|
90
|
+
return s;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ---- type queries (nlohmann names) ----
|
|
94
|
+
bool is_object() const {
|
|
95
|
+
return kind() == YEPTRIS_NODE_MAPPING;
|
|
96
|
+
}
|
|
97
|
+
bool is_array() const {
|
|
98
|
+
return kind() == YEPTRIS_NODE_SEQUENCE;
|
|
99
|
+
}
|
|
100
|
+
bool is_string() const {
|
|
101
|
+
return kind() == YEPTRIS_NODE_SCALAR && !is_number() && !is_boolean() && !is_null();
|
|
102
|
+
}
|
|
103
|
+
bool is_number() const {
|
|
104
|
+
return is_number_integer() || is_number_float();
|
|
105
|
+
}
|
|
106
|
+
bool is_number_integer() const {
|
|
107
|
+
return typed_ok<int64_t>();
|
|
108
|
+
}
|
|
109
|
+
bool is_number_float() const {
|
|
110
|
+
return typed_ok<double>();
|
|
111
|
+
}
|
|
112
|
+
bool is_boolean() const {
|
|
113
|
+
return typed_ok<bool>();
|
|
114
|
+
}
|
|
115
|
+
bool is_null() const;
|
|
116
|
+
|
|
117
|
+
// ---- object access ----
|
|
118
|
+
json operator[](std::string_view key) const {
|
|
119
|
+
require(YEPTRIS_NODE_MAPPING, "object");
|
|
120
|
+
YeptrisNode n = yeptris_node_map_get(node_, key.data(), key.size());
|
|
121
|
+
if (n == nullptr) {
|
|
122
|
+
throw std::out_of_range("key not found");
|
|
123
|
+
}
|
|
124
|
+
return child(n);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
json at(std::string_view key) const {
|
|
128
|
+
return (*this)[key];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
bool contains(std::string_view key) const {
|
|
132
|
+
return kind() == YEPTRIS_NODE_MAPPING &&
|
|
133
|
+
yeptris_node_map_get(node_, key.data(), key.size()) != nullptr;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
size_t size() const {
|
|
137
|
+
if (kind() == YEPTRIS_NODE_MAPPING) {
|
|
138
|
+
return yeptris_node_map_count(node_);
|
|
139
|
+
}
|
|
140
|
+
if (kind() == YEPTRIS_NODE_SEQUENCE) {
|
|
141
|
+
return yeptris_node_seq_count(node_);
|
|
142
|
+
}
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ---- array access ----
|
|
147
|
+
json operator[](size_t index) const {
|
|
148
|
+
require(YEPTRIS_NODE_SEQUENCE, "array");
|
|
149
|
+
if (index >= yeptris_node_seq_count(node_)) {
|
|
150
|
+
throw std::out_of_range("index out of range");
|
|
151
|
+
}
|
|
152
|
+
return child(yeptris_node_seq_at(node_, index));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
json at(size_t index) const {
|
|
156
|
+
return (*this)[index];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ---- typed getters ----
|
|
160
|
+
std::string get_string() const {
|
|
161
|
+
if (kind() != YEPTRIS_NODE_SCALAR) {
|
|
162
|
+
throw type_error("not a scalar");
|
|
163
|
+
}
|
|
164
|
+
size_t len = 0;
|
|
165
|
+
const char* v = yeptris_node_value(node_, &len);
|
|
166
|
+
return std::string(v ? v : "", len); /* json-c semantics: the
|
|
167
|
+
raw text — "1" for numbers, "true" for booleans */
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
int64_t get_int() const {
|
|
171
|
+
int64_t v = 0;
|
|
172
|
+
if (yeptris_node_int(node_, &v) != YEPTRIS_OK) {
|
|
173
|
+
throw type_error("not an integer");
|
|
174
|
+
}
|
|
175
|
+
return v;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
double get_double() const {
|
|
179
|
+
double v = 0;
|
|
180
|
+
if (yeptris_node_float(node_, &v) != YEPTRIS_OK) {
|
|
181
|
+
throw type_error("not a float");
|
|
182
|
+
}
|
|
183
|
+
return v;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
bool get_bool() const {
|
|
187
|
+
int v = 0;
|
|
188
|
+
if (yeptris_node_bool(node_, &v) != YEPTRIS_OK) {
|
|
189
|
+
throw type_error("not a boolean");
|
|
190
|
+
}
|
|
191
|
+
return v != 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private:
|
|
195
|
+
json(YeptrisDocument doc, YeptrisNode node) : doc_(doc), node_(node), owns_(false) {}
|
|
196
|
+
|
|
197
|
+
json child(YeptrisNode n) const {
|
|
198
|
+
return json(doc_, n);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
void destroy() {
|
|
202
|
+
if (owns_ && doc_ != nullptr) {
|
|
203
|
+
yeptris_document_free(doc_);
|
|
204
|
+
}
|
|
205
|
+
doc_ = nullptr;
|
|
206
|
+
node_ = nullptr;
|
|
207
|
+
owns_ = false;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
void check_root() const {
|
|
211
|
+
if (doc_ == nullptr) {
|
|
212
|
+
throw std::logic_error("empty json");
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
int kind() const {
|
|
217
|
+
return node_ != nullptr ? (int)yeptris_node_kind(node_) : -1;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
void require(int k, const char* what) const {
|
|
221
|
+
if (kind() != k) {
|
|
222
|
+
throw type_error(what);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
template <typename T> bool typed_ok() const {
|
|
227
|
+
if (node_ == nullptr || kind() != YEPTRIS_NODE_SCALAR) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
if constexpr (std::is_same_v<T, int64_t>) {
|
|
231
|
+
int64_t v;
|
|
232
|
+
return yeptris_node_int(node_, &v) == YEPTRIS_OK;
|
|
233
|
+
} else if constexpr (std::is_same_v<T, double>) {
|
|
234
|
+
double v;
|
|
235
|
+
return yeptris_node_float(node_, &v) == YEPTRIS_OK;
|
|
236
|
+
} else {
|
|
237
|
+
int v;
|
|
238
|
+
return yeptris_node_bool(node_, &v) == YEPTRIS_OK;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
YeptrisDocument doc_ = nullptr;
|
|
243
|
+
YeptrisNode node_ = nullptr;
|
|
244
|
+
bool owns_ = false;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
inline bool json::is_null() const {
|
|
248
|
+
if (kind() != YEPTRIS_NODE_SCALAR) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
size_t len = 0;
|
|
252
|
+
const char* v = yeptris_node_value(node_, &len);
|
|
253
|
+
return len == 4 && v != nullptr && std::string_view(v, len) == "null";
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
} // namespace yeptris
|
|
257
|
+
|
|
258
|
+
#endif // YEPTRIS_JSON_HPP
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/* jsonc_compat.h — the json-c migration layer (TODO.impl/21).
|
|
2
|
+
*
|
|
3
|
+
* REAL json-c symbol names over the yeptris core: users link
|
|
4
|
+
* -lyeptris-jsonc instead of -ljson-c and change nothing else.
|
|
5
|
+
*
|
|
6
|
+
* Scope (v1, the read path): parsing, type queries, value getters,
|
|
7
|
+
* object/array access, and JSON output. The building API
|
|
8
|
+
* (json_object_new_ etc.) landed with DOM mutation
|
|
9
|
+
* (TODO.impl/11 phase 3): the new_object family, object_add,
|
|
10
|
+
* array_add, and the delete entry points.
|
|
11
|
+
*
|
|
12
|
+
* Lifetime: the object returned by json_tokener_parse owns the
|
|
13
|
+
* document; json_object_put frees it. Objects obtained by reference
|
|
14
|
+
* (children) are owned by their document — put on them is a no-op
|
|
15
|
+
* returning 1 (json-c children outlive callers the same way).
|
|
16
|
+
*/
|
|
17
|
+
#ifndef YEPTRIS_JSONC_COMPAT_H
|
|
18
|
+
#define YEPTRIS_JSONC_COMPAT_H
|
|
19
|
+
|
|
20
|
+
#include <stddef.h>
|
|
21
|
+
|
|
22
|
+
#ifdef __cplusplus
|
|
23
|
+
extern "C" {
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
/* Values mirror json-c's json_type. */
|
|
27
|
+
typedef enum {
|
|
28
|
+
json_type_null = 0,
|
|
29
|
+
json_type_boolean,
|
|
30
|
+
json_type_double,
|
|
31
|
+
json_type_int,
|
|
32
|
+
json_type_object,
|
|
33
|
+
json_type_array,
|
|
34
|
+
json_type_string
|
|
35
|
+
} json_type;
|
|
36
|
+
|
|
37
|
+
typedef struct json_object json_object;
|
|
38
|
+
|
|
39
|
+
/* json-c's string flags for to_json_string_ext */
|
|
40
|
+
#define JSON_C_TO_STRING_PLAIN 0
|
|
41
|
+
#define JSON_C_TO_STRING_SPACED (1 << 0)
|
|
42
|
+
#define JSON_C_TO_STRING_PRETTY (1 << 1)
|
|
43
|
+
#define JSON_C_TO_STRING_PRETTY_TAB (1 << 2)
|
|
44
|
+
#define JSON_C_TO_STRING_NOZERO (1 << 3)
|
|
45
|
+
|
|
46
|
+
/* Parses one JSON document (strict; trailing whitespace allowed).
|
|
47
|
+
* Returns NULL on invalid input. The result owns its document —
|
|
48
|
+
* release with json_object_put. */
|
|
49
|
+
json_object* json_tokener_parse(const char* str);
|
|
50
|
+
json_object* json_tokener_parse_ex(const char* buf, int len);
|
|
51
|
+
void json_tokener_free(json_object* obj);
|
|
52
|
+
|
|
53
|
+
/* Lifetime: put on the ROOT frees the document (once); on a child it
|
|
54
|
+
* is a no-op returning 1. get returns the object unchanged. */
|
|
55
|
+
int json_object_put(json_object* obj);
|
|
56
|
+
json_object* json_object_get(json_object* obj);
|
|
57
|
+
|
|
58
|
+
/* Type queries. */
|
|
59
|
+
json_type json_object_get_type(const json_object* obj);
|
|
60
|
+
int json_object_is_type(const json_object* obj, json_type type);
|
|
61
|
+
|
|
62
|
+
/* Value getters (0 when the type does not match, like json-c). */
|
|
63
|
+
const char* json_object_get_string(json_object* obj);
|
|
64
|
+
int32_t json_object_get_int(const json_object* obj);
|
|
65
|
+
int64_t json_object_get_int64(const json_object* obj);
|
|
66
|
+
double json_object_get_double(const json_object* obj);
|
|
67
|
+
int json_object_get_boolean(const json_object* obj);
|
|
68
|
+
|
|
69
|
+
/* Object access: *value receives the field (a borrowed reference). */
|
|
70
|
+
int json_object_object_get_ex(const json_object* obj, const char* key, json_object** value);
|
|
71
|
+
size_t json_object_object_length(const json_object* obj);
|
|
72
|
+
|
|
73
|
+
/* Array access (borrowed references). */
|
|
74
|
+
size_t json_object_array_length(const json_object* obj);
|
|
75
|
+
json_object* json_object_array_get_idx(const json_object* obj, size_t idx);
|
|
76
|
+
|
|
77
|
+
/* Output: strict JSON. The returned pointer is owned by the object
|
|
78
|
+
* (freed with it) — json-c's contract. Roots only in v1: serializing
|
|
79
|
+
* an attached child returns NULL (subtree output arrives with the
|
|
80
|
+
* pretty printer). */
|
|
81
|
+
const char* json_object_to_json_string(json_object* obj);
|
|
82
|
+
const char* json_object_to_json_string_ext(json_object* obj, int flags);
|
|
83
|
+
|
|
84
|
+
/* ---- Building (TODO.impl/21 v2, over DOM mutation 11/3) ----
|
|
85
|
+
*
|
|
86
|
+
* json-c semantics: new_* returns an unowned object; adding it to a
|
|
87
|
+
* parent transfers ownership (a put on it afterwards is a no-op); the
|
|
88
|
+
* caller's pointer stays valid until the ROOT is put. Values are
|
|
89
|
+
* copied. Duplicate keys replace in place (position kept). NULL val
|
|
90
|
+
* to object_add deletes the key (legacy json-c behavior). */
|
|
91
|
+
json_object* json_object_new_object(void);
|
|
92
|
+
json_object* json_object_new_array(void);
|
|
93
|
+
json_object* json_object_new_string(const char* s);
|
|
94
|
+
json_object* json_object_new_string_len(const char* s, int len);
|
|
95
|
+
json_object* json_object_new_int(int32_t i);
|
|
96
|
+
json_object* json_object_new_int64(int64_t i);
|
|
97
|
+
json_object* json_object_new_double(double d);
|
|
98
|
+
json_object* json_object_new_boolean(int b);
|
|
99
|
+
|
|
100
|
+
/* 0 added, 1 replaced, -1 error (obj not an object, or OOM). */
|
|
101
|
+
int json_object_object_add(json_object* obj, const char* key, json_object* val);
|
|
102
|
+
int json_object_object_del(json_object* obj, const char* key);
|
|
103
|
+
|
|
104
|
+
/* 0 ok, -1 error (obj not an array, or OOM). */
|
|
105
|
+
int json_object_array_add(json_object* obj, json_object* val);
|
|
106
|
+
int json_object_array_del_idx(json_object* obj, size_t idx, size_t count);
|
|
107
|
+
|
|
108
|
+
/* index < len replaces in place; index == len appends. */
|
|
109
|
+
int json_object_array_put_idx(json_object* obj, size_t idx, json_object* val);
|
|
110
|
+
|
|
111
|
+
#ifdef __cplusplus
|
|
112
|
+
}
|
|
113
|
+
#endif
|
|
114
|
+
|
|
115
|
+
#endif /* YEPTRIS_JSONC_COMPAT_H */
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* marshal.h — Ruby Marshal 4.8 emission (TODO.restructure/21).
|
|
2
|
+
*
|
|
3
|
+
* The binding materialization fast path: the C side converts the
|
|
4
|
+
* value records directly into Ruby's Marshal wire format, so the host
|
|
5
|
+
* materializes the whole object graph with ONE core-C call
|
|
6
|
+
* (Marshal.load) instead of walking per-value records in Ruby.
|
|
7
|
+
*
|
|
8
|
+
* Semantics are pinned to the binding walks (the ':sym' plain scan,
|
|
9
|
+
* Psych's single-char y/n and dot-required floats, alias identity
|
|
10
|
+
* via object links). Constructs the format cannot express return
|
|
11
|
+
* YEPTRIS_ERROR_UNSUPPORTED — the host falls back to the record walk.
|
|
12
|
+
*
|
|
13
|
+
* Memory: *out is a single malloc'd buffer; free with
|
|
14
|
+
* yeptris_marshal_free exactly once. */
|
|
15
|
+
#ifndef YEPTRIS_MARSHAL_H
|
|
16
|
+
#define YEPTRIS_MARSHAL_H
|
|
17
|
+
|
|
18
|
+
#include <stddef.h>
|
|
19
|
+
|
|
20
|
+
#include <yeptris/api.h>
|
|
21
|
+
#include <yeptris/dom.h>
|
|
22
|
+
#include <yeptris/resolve.h>
|
|
23
|
+
|
|
24
|
+
#ifdef __cplusplus
|
|
25
|
+
extern "C" {
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
typedef enum {
|
|
29
|
+
/* the whole stream as one Ruby Array of documents (load_all) */
|
|
30
|
+
YEPTRIS_MARSHAL_ALL_DOCS = 0,
|
|
31
|
+
/* just the first document's root (load) */
|
|
32
|
+
YEPTRIS_MARSHAL_FIRST_DOC = 1,
|
|
33
|
+
} YeptrisMarshalMode;
|
|
34
|
+
|
|
35
|
+
/* Parses `data` and emits Marshal 4.8 bytes of the object graph the
|
|
36
|
+
* value stream describes. Returns YEPTRIS_OK, YEPTRIS_ERROR_PARSE /
|
|
37
|
+
* _MEMORY / _ARG, or YEPTRIS_ERROR_UNSUPPORTED (merge keys or
|
|
38
|
+
* timestamps: materialize those through the record walk). */
|
|
39
|
+
YEPTRIS_API YeptrisStatus yeptris_marshal(const char* data, size_t len, YeptrisSchema schema,
|
|
40
|
+
YeptrisMarshalMode mode, char** out, size_t* out_len);
|
|
41
|
+
|
|
42
|
+
/* The same emission for one node subtree of a built document — the
|
|
43
|
+
* bulk path behind Node#to_ruby (one call, not one per node). */
|
|
44
|
+
YEPTRIS_API YeptrisStatus yeptris_marshal_node(YeptrisNode node, char** out, size_t* out_len);
|
|
45
|
+
|
|
46
|
+
YEPTRIS_API void yeptris_marshal_free(char* out);
|
|
47
|
+
|
|
48
|
+
#ifdef __cplusplus
|
|
49
|
+
}
|
|
50
|
+
#endif
|
|
51
|
+
|
|
52
|
+
#endif /* YEPTRIS_MARSHAL_H */
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* parse.h — the parse entry points (TODO.impl/07/11 public surface). */
|
|
2
|
+
|
|
3
|
+
#ifndef YEPTRIS_PARSE_H
|
|
4
|
+
#define YEPTRIS_PARSE_H
|
|
5
|
+
|
|
6
|
+
#include <stddef.h>
|
|
7
|
+
|
|
8
|
+
#include <yeptris/api.h>
|
|
9
|
+
#include <yeptris/error.h>
|
|
10
|
+
#include <yeptris/resolve.h>
|
|
11
|
+
#include <yeptris/types.h>
|
|
12
|
+
|
|
13
|
+
#ifdef __cplusplus
|
|
14
|
+
extern "C" {
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
/* Parses a YAML document set. buf must remain valid for the lifetime of
|
|
18
|
+
* the returned document (scalar values are borrowed zero-copy views).
|
|
19
|
+
* On failure returns NULL; *status (may be NULL) receives the code and
|
|
20
|
+
* yeptris_last_error() carries the message with line/column.
|
|
21
|
+
*
|
|
22
|
+
* Memory: the caller owns the document; free it with
|
|
23
|
+
* yeptris_document_free — one call releases everything. */
|
|
24
|
+
YEPTRIS_API YeptrisDocument yeptris_parse(const char* buf, size_t len, YeptrisStatus* status);
|
|
25
|
+
|
|
26
|
+
/* Per-parse options (TODO.impl/10): schema selects the implicit-typing
|
|
27
|
+
* resolver (default YEPTRIS_SCHEMA_12_CORE), max_depth caps nesting
|
|
28
|
+
* (0: the library default), strict/tab_policy/recover are reserved
|
|
29
|
+
* pins of the option shape (the strict grammar is the default today;
|
|
30
|
+
* lenient modes land with the recover work). Zero-initialized = the
|
|
31
|
+
* yeptris_parse defaults. */
|
|
32
|
+
typedef struct YeptrisParseOptions {
|
|
33
|
+
YeptrisSchema schema;
|
|
34
|
+
int max_depth;
|
|
35
|
+
int strict;
|
|
36
|
+
int tab_policy;
|
|
37
|
+
int recover;
|
|
38
|
+
} YeptrisParseOptions;
|
|
39
|
+
|
|
40
|
+
YEPTRIS_API YeptrisDocument yeptris_parse_ex(const char* buf, size_t len,
|
|
41
|
+
const YeptrisParseOptions* opts,
|
|
42
|
+
YeptrisStatus* status);
|
|
43
|
+
|
|
44
|
+
#ifdef __cplusplus
|
|
45
|
+
}
|
|
46
|
+
#endif
|
|
47
|
+
|
|
48
|
+
#endif /* YEPTRIS_PARSE_H */
|