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.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/ext/libyeptris/extconf.rb +57 -0
  3. data/lib/yeptris/ffi.rb +12 -15
  4. data/lib/yeptris/json.rb +5 -2
  5. data/lib/yeptris/psych.rb +76 -3
  6. data/lib/yeptris.rb +36 -14
  7. data/vendor/libyeptris/CMakeLists.txt +254 -0
  8. data/vendor/libyeptris/cmake/yeptris-config.cmake.in +5 -0
  9. data/vendor/libyeptris/cmake/yeptris.pc.in +11 -0
  10. data/vendor/libyeptris/src/CMakeLists.txt +167 -0
  11. data/vendor/libyeptris/src/include/yeptris/api.h +32 -0
  12. data/vendor/libyeptris/src/include/yeptris/cbor.h +101 -0
  13. data/vendor/libyeptris/src/include/yeptris/dom.h +181 -0
  14. data/vendor/libyeptris/src/include/yeptris/emit.h +81 -0
  15. data/vendor/libyeptris/src/include/yeptris/error.h +41 -0
  16. data/vendor/libyeptris/src/include/yeptris/events.h +157 -0
  17. data/vendor/libyeptris/src/include/yeptris/json.h +45 -0
  18. data/vendor/libyeptris/src/include/yeptris/json.hpp +258 -0
  19. data/vendor/libyeptris/src/include/yeptris/jsonc_compat.h +115 -0
  20. data/vendor/libyeptris/src/include/yeptris/marshal.h +52 -0
  21. data/vendor/libyeptris/src/include/yeptris/parse.h +48 -0
  22. data/vendor/libyeptris/src/include/yeptris/plan.h +100 -0
  23. data/vendor/libyeptris/src/include/yeptris/resolve.h +71 -0
  24. data/vendor/libyeptris/src/include/yeptris/schema.h +119 -0
  25. data/vendor/libyeptris/src/include/yeptris/tape.h +99 -0
  26. data/vendor/libyeptris/src/include/yeptris/types.h +38 -0
  27. data/vendor/libyeptris/src/include/yeptris/values.h +102 -0
  28. data/vendor/libyeptris/src/include/yeptris/version.h.in +29 -0
  29. data/vendor/libyeptris/src/include/yeptris/visit.h +77 -0
  30. data/vendor/libyeptris/src/include/yeptris/yajl_compat.h +135 -0
  31. data/vendor/libyeptris/src/include/yeptris.h +23 -0
  32. data/vendor/libyeptris/src/yeptris/build.c +371 -0
  33. data/vendor/libyeptris/src/yeptris/cbor/cbor.h +25 -0
  34. data/vendor/libyeptris/src/yeptris/cbor/decode.c +846 -0
  35. data/vendor/libyeptris/src/yeptris/cbor/encode.c +824 -0
  36. data/vendor/libyeptris/src/yeptris/common/chartype.c +41 -0
  37. data/vendor/libyeptris/src/yeptris/common/chartype.h +77 -0
  38. data/vendor/libyeptris/src/yeptris/common/cpu.c +81 -0
  39. data/vendor/libyeptris/src/yeptris/common/cpu.h +40 -0
  40. data/vendor/libyeptris/src/yeptris/common/error.c +65 -0
  41. data/vendor/libyeptris/src/yeptris/common/error.h +79 -0
  42. data/vendor/libyeptris/src/yeptris/common/mutex.h +45 -0
  43. data/vendor/libyeptris/src/yeptris/common/nametab.c +275 -0
  44. data/vendor/libyeptris/src/yeptris/common/nametab.h +68 -0
  45. data/vendor/libyeptris/src/yeptris/common/port.h +74 -0
  46. data/vendor/libyeptris/src/yeptris/common/simd_text.c +49 -0
  47. data/vendor/libyeptris/src/yeptris/common/simd_text.h +295 -0
  48. data/vendor/libyeptris/src/yeptris/common/simd_text_avx2.c +534 -0
  49. data/vendor/libyeptris/src/yeptris/common/simd_text_neon.c +662 -0
  50. data/vendor/libyeptris/src/yeptris/common/simd_text_scalar.c +298 -0
  51. data/vendor/libyeptris/src/yeptris/common/string_view.c +34 -0
  52. data/vendor/libyeptris/src/yeptris/common/string_view.h +93 -0
  53. data/vendor/libyeptris/src/yeptris/doc.h +37 -0
  54. data/vendor/libyeptris/src/yeptris/dom/dom.c +973 -0
  55. data/vendor/libyeptris/src/yeptris/dom/dom.h +290 -0
  56. data/vendor/libyeptris/src/yeptris/dom/hpool.c +107 -0
  57. data/vendor/libyeptris/src/yeptris/dom/mapindex.c +173 -0
  58. data/vendor/libyeptris/src/yeptris/dom/mapindex.h +61 -0
  59. data/vendor/libyeptris/src/yeptris/dom/mutate.c +429 -0
  60. data/vendor/libyeptris/src/yeptris/emit/emit.c +349 -0
  61. data/vendor/libyeptris/src/yeptris/emit/float/api.h +38 -0
  62. data/vendor/libyeptris/src/yeptris/emit/float/dragon.c +405 -0
  63. data/vendor/libyeptris/src/yeptris/emit/float/floatint.h +203 -0
  64. data/vendor/libyeptris/src/yeptris/emit/float/print.c +396 -0
  65. data/vendor/libyeptris/src/yeptris/emit/style.c +81 -0
  66. data/vendor/libyeptris/src/yeptris/emit/style.h +24 -0
  67. data/vendor/libyeptris/src/yeptris/emit/writer.c +746 -0
  68. data/vendor/libyeptris/src/yeptris/emit/writer.h +61 -0
  69. data/vendor/libyeptris/src/yeptris/encoding/bom.c +31 -0
  70. data/vendor/libyeptris/src/yeptris/encoding/encoding.h +63 -0
  71. data/vendor/libyeptris/src/yeptris/encoding/transcode.c +148 -0
  72. data/vendor/libyeptris/src/yeptris/encoding/utf8_validate.c +178 -0
  73. data/vendor/libyeptris/src/yeptris/events/capture.c +150 -0
  74. data/vendor/libyeptris/src/yeptris/events/capture.h +39 -0
  75. data/vendor/libyeptris/src/yeptris/events/iterparse.c +208 -0
  76. data/vendor/libyeptris/src/yeptris/events/pull.c +97 -0
  77. data/vendor/libyeptris/src/yeptris/events/push.c +104 -0
  78. data/vendor/libyeptris/src/yeptris/events/recorder.c +107 -0
  79. data/vendor/libyeptris/src/yeptris/events/values.c +527 -0
  80. data/vendor/libyeptris/src/yeptris/events/values_priv.h +51 -0
  81. data/vendor/libyeptris/src/yeptris/events/yaml_compat.c +86 -0
  82. data/vendor/libyeptris/src/yeptris/events/yaml_compat.h +90 -0
  83. data/vendor/libyeptris/src/yeptris/jsonapi/jsonc_compat.c +687 -0
  84. data/vendor/libyeptris/src/yeptris/jsonapi/yajl_compat.c +728 -0
  85. data/vendor/libyeptris/src/yeptris/marshal.c +744 -0
  86. data/vendor/libyeptris/src/yeptris/memory/allocator.c +20 -0
  87. data/vendor/libyeptris/src/yeptris/memory/allocator.h +43 -0
  88. data/vendor/libyeptris/src/yeptris/memory/arena.c +134 -0
  89. data/vendor/libyeptris/src/yeptris/memory/arena.h +52 -0
  90. data/vendor/libyeptris/src/yeptris/memory/pool.c +115 -0
  91. data/vendor/libyeptris/src/yeptris/memory/pool.h +36 -0
  92. data/vendor/libyeptris/src/yeptris/parse/engine.c +3689 -0
  93. data/vendor/libyeptris/src/yeptris/parse/engine.h +65 -0
  94. data/vendor/libyeptris/src/yeptris/parse/events.h +124 -0
  95. data/vendor/libyeptris/src/yeptris/parse/numbers.c +349 -0
  96. data/vendor/libyeptris/src/yeptris/parse/numbers.h +33 -0
  97. data/vendor/libyeptris/src/yeptris/parse/scalars.c +416 -0
  98. data/vendor/libyeptris/src/yeptris/parse/scalars.h +75 -0
  99. data/vendor/libyeptris/src/yeptris/parse.c +650 -0
  100. data/vendor/libyeptris/src/yeptris/plan.c +817 -0
  101. data/vendor/libyeptris/src/yeptris/resolve/compat11.c +334 -0
  102. data/vendor/libyeptris/src/yeptris/resolve/core12.c +143 -0
  103. data/vendor/libyeptris/src/yeptris/resolve/resolver.h +56 -0
  104. data/vendor/libyeptris/src/yeptris/resolve/tags.c +58 -0
  105. data/vendor/libyeptris/src/yeptris/scan/json.c +792 -0
  106. data/vendor/libyeptris/src/yeptris/scan/json.h +109 -0
  107. data/vendor/libyeptris/src/yeptris/scan/scan.c +463 -0
  108. data/vendor/libyeptris/src/yeptris/scan/scan.h +150 -0
  109. data/vendor/libyeptris/src/yeptris/schema.c +238 -0
  110. data/vendor/libyeptris/src/yeptris/tape.c +1292 -0
  111. data/vendor/libyeptris/src/yeptris/version.c +7 -0
  112. data/vendor/libyeptris/src/yeptris/visit/dom_visit.c +115 -0
  113. data/vendor/libyeptris/src/yeptris/visit/json_visit.c +293 -0
  114. data/vendor/libyeptris/src/yeptris/visit/yaml_visit.c +127 -0
  115. 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 */