yeptris 0.2.5.3-aarch64-linux → 0.3.0.1-aarch64-linux

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53ba5f8ec2b0bce5440f6c728f78af3703a0ea3656b8c752a6bcacaf3362528f
4
- data.tar.gz: e6ac1792bbf42a5bec4fbe2bcebdd060b22a21a0be62decfeea59216301c70a6
3
+ metadata.gz: 4639faf83e98440ebb4973f881db719fb6629ccbf7949f8bed6052e5be53184a
4
+ data.tar.gz: a0b7ed9983184783e89a590cc317b147c6eb41e39ab6801c41dd744391573020
5
5
  SHA512:
6
- metadata.gz: eeb00725be0541b489ace917c0e45480f0bf17056adaadb39835c9cdcce0bb44885fcf899624bc8d3d4331547b16c351ded8122783141b9acff641c6f126e701
7
- data.tar.gz: add571ff504fd8ae8e5b1ee899ac8029762ee138277cd6ccd0830cdd9fd7a18126f5f3a8d13fd24736fe7f7e88ae551bfc989598ce071b34c087d1a93f174c89
6
+ metadata.gz: 775dd41728fd5171efb2a0e895498a7c2f98dc6cba9c68c0593c476d3b320c0a17e0f9d83efe69bae90b5cadcce53ab8c516d54eb0478065095aa6a2f37f802c
7
+ data.tar.gz: e11d2650357819532da00d1749b1fcfda1d948886f9d445b106b9eba22dab88ec4d688daab5bb0ca921500d9ca1eadf1fdec8ae8511a4287506c74822f53ba28
data/lib/yeptris/json.rb CHANGED
@@ -54,6 +54,55 @@ module Yeptris
54
54
  T_MAP_OPEN = 7
55
55
  T_CLOSE = 8
56
56
 
57
+ # The tape keeps RAW string spans (escapes untouched — the C
58
+ # contract); the walk decodes them here. The hot path (no
59
+ # backslash) returns the slice untouched.
60
+ SIMPLE_ESCAPES = {
61
+ '"' => '"'.b, "\\" => "\\".b, "/" => "/".b, "b" => "\b".b, "f" => "\f".b,
62
+ "n" => "\n".b, "r" => "\r".b, "t" => "\t".b
63
+ }.freeze
64
+
65
+ def decode_span(src, off, len)
66
+ s = src.byteslice(off, len)
67
+ s.force_encoding(Encoding::UTF_8)
68
+ return s unless s.include?("\\")
69
+
70
+ b = s.b
71
+ out = +"".b
72
+ i = 0
73
+ n = b.bytesize
74
+ while i < n
75
+ c = b.getbyte(i)
76
+ if c != 0x5C || i + 1 >= n
77
+ out << c
78
+ i += 1
79
+ next
80
+ end
81
+ e = b.getbyte(i + 1)
82
+ if e != 0x75 # simple escape
83
+ ch = e.chr
84
+ out << (SIMPLE_ESCAPES[ch] || ch)
85
+ i += 2
86
+ next
87
+ end
88
+ cp = b.byteslice(i + 2, 4).to_i(16)
89
+ if cp >= 0xD800 && cp <= 0xDBFF && i + 12 <= n &&
90
+ b.getbyte(i + 6) == 0x5C && b.getbyte(i + 7) == 0x75
91
+ lo = b.byteslice(i + 8, 4).to_i(16)
92
+ if lo >= 0xDC00 && lo <= 0xDFFF
93
+ cp = 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00)
94
+ i += 12
95
+ else
96
+ i += 6
97
+ end
98
+ else
99
+ i += 6
100
+ end
101
+ out << [cp].pack("U").b
102
+ end
103
+ out.force_encoding(Encoding::UTF_8)
104
+ end
105
+
57
106
  def tape_engine(source)
58
107
  tape = ::Yeptris::FFI::JsonTape.new
59
108
  rc = ::Yeptris::FFI.yeptris_parse_json_tape(source, source.bytesize, tape)
@@ -97,8 +146,7 @@ module Yeptris
97
146
  stack.pop
98
147
  key_sets&.pop
99
148
  when T_STR
100
- text = src.byteslice(offs[i], lens[i])
101
- text.force_encoding(Encoding::UTF_8) unless utf8
149
+ text = lens[i] == 0 ? +"".force_encoding(Encoding::UTF_8) : decode_span(src, offs[i], lens[i])
102
150
  if pending_key.nil? && !stack.empty? && stack.last.is_a?(Hash)
103
151
  if key_sets && key_sets.last.key?(text)
104
152
  raise ParseError, %(duplicate key "#{text}" in JSON object)
@@ -249,26 +297,15 @@ module Yeptris
249
297
  # and null stay plain), Symbols become their name.
250
298
  class DumpError < Error; end
251
299
 
252
- ENTRY_BYTES = 12
253
- MAP_ENTRY = [::Yeptris::FFI::BUILD_MAP, 0, 0, 0].pack("CCx2VV").freeze
254
- SEQ_ENTRY = [::Yeptris::FFI::BUILD_SEQ, 0, 0, 0].pack("CCx2VV").freeze
255
- END_ENTRY = [::Yeptris::FFI::BUILD_END, 0, 0, 0].pack("CCx2VV").freeze
256
- CONT_ENTRY = { ::Yeptris::FFI::BUILD_MAP => MAP_ENTRY, ::Yeptris::FFI::BUILD_SEQ => SEQ_ENTRY,
257
- ::Yeptris::FFI::BUILD_END => END_ENTRY }.freeze
258
-
259
300
  def dump(obj)
260
- parts = []
301
+ parts = String.new(encoding: Encoding::BINARY,
302
+ capacity: 12 * 16) # 12-byte entries, appended in place
261
303
  blob = String.new(encoding: Encoding::BINARY)
262
304
  off = [0]
263
- emit = lambda do |op, style, o, len|
264
- parts << (o.zero? && len.zero? && style.zero? ? CONT_ENTRY[op] :
265
- [op, style, o, len].pack("CCx2VV"))
266
- end
267
- place_obj(obj, emit, blob, off)
305
+ place_obj(obj, parts, blob, off)
268
306
  doc = ::Yeptris::Document.create
269
- buf = ::FFI::MemoryPointer.from_string(parts.join)
270
- bblob = ::FFI::MemoryPointer.from_string(blob)
271
- rc = doc.build_entries(buf, parts.length, bblob, blob.bytesize)
307
+ # FFI passes String args BY REFERENCE — no MemoryPointer copies
308
+ rc = doc.build_entries(parts, parts.bytesize / 12, blob, blob.bytesize)
272
309
  raise DumpError, "document_build failed: #{rc}" unless rc == ::Yeptris::FFI::OK
273
310
  out = ::Yeptris::FFI::JSON_EX ? doc.serialize_json_compact : doc.serialize_json
274
311
  # JSON.generate emits no trailing newline (the document writer does)
@@ -277,37 +314,51 @@ module Yeptris
277
314
  doc&.free
278
315
  end
279
316
 
280
- def place_obj(obj, emit, blob, off)
317
+ F = ::Yeptris::FFI
318
+ MAP_E = [F::BUILD_MAP, 0, 0, 0].pack("CCx2VV").freeze
319
+ SEQ_E = [F::BUILD_SEQ, 0, 0, 0].pack("CCx2VV").freeze
320
+ END_E = [F::BUILD_END, 0, 0, 0].pack("CCx2VV").freeze
321
+ DQ = F::STYLE_DOUBLE_QUOTED
322
+ PL = F::STYLE_PLAIN
323
+ SC_DQ = [F::BUILD_SCALAR, DQ].pack("CCx2").freeze
324
+ SC_PL = [F::BUILD_SCALAR, PL].pack("CCx2").freeze
325
+
326
+ def place_obj(obj, parts, blob, off)
281
327
  case obj
282
328
  when Hash
283
- emit.call(::Yeptris::FFI::BUILD_MAP, 0, 0, 0)
329
+ parts << MAP_E
284
330
  obj.each do |k, v|
285
331
  key = k.is_a?(String) ? k : k.is_a?(Symbol) ? k.name : k.to_s
286
- scalar_json(key, ::Yeptris::FFI::STYLE_DOUBLE_QUOTED, emit, blob, off)
287
- place_obj(v, emit, blob, off)
332
+ scalar_json(key, SC_DQ, parts, blob, off)
333
+ place_obj(v, parts, blob, off)
288
334
  end
289
- emit.call(::Yeptris::FFI::BUILD_END, 0, 0, 0)
335
+ parts << END_E
290
336
  when Array
291
- emit.call(::Yeptris::FFI::BUILD_SEQ, 0, 0, 0)
292
- obj.each { |e| place_obj(e, emit, blob, off) }
293
- emit.call(::Yeptris::FFI::BUILD_END, 0, 0, 0)
337
+ parts << SEQ_E
338
+ obj.each { |e| place_obj(e, parts, blob, off) }
339
+ parts << END_E
294
340
  when String
295
- scalar_json(obj, ::Yeptris::FFI::STYLE_DOUBLE_QUOTED, emit, blob, off)
341
+ scalar_json(obj, SC_DQ, parts, blob, off)
296
342
  when Symbol
297
- scalar_json(obj.name, ::Yeptris::FFI::STYLE_DOUBLE_QUOTED, emit, blob, off)
298
- when Integer, Float, true, false, nil
299
- text = obj.nil? ? "null" : obj.to_s
300
- scalar_json(text, ::Yeptris::FFI::STYLE_PLAIN, emit, blob, off)
343
+ scalar_json(obj.name, SC_DQ, parts, blob, off)
344
+ when Integer, Float
345
+ scalar_json(obj.to_s, SC_PL, parts, blob, off)
346
+ when true
347
+ scalar_json("true", SC_PL, parts, blob, off)
348
+ when false
349
+ scalar_json("false", SC_PL, parts, blob, off)
350
+ when nil
351
+ scalar_json("null", SC_PL, parts, blob, off)
301
352
  when Date, Time
302
- scalar_json(obj.iso8601, ::Yeptris::FFI::STYLE_DOUBLE_QUOTED, emit, blob, off)
353
+ scalar_json(obj.iso8601, SC_DQ, parts, blob, off)
303
354
  else
304
355
  raise DumpError, "cannot dump #{obj.class}: unsupported object " \
305
356
  "(JSON.generate calls to_json on custom types)"
306
357
  end
307
358
  end
308
359
 
309
- def scalar_json(text, style, emit, blob, off)
310
- emit.call(::Yeptris::FFI::BUILD_SCALAR, style, off[0], text.bytesize)
360
+ def scalar_json(text, prefix, parts, blob, off)
361
+ parts << (prefix + [off[0], text.bytesize].pack("VV"))
311
362
  blob << text
312
363
  off[0] += text.bytesize
313
364
  end
Binary file
data/lib/yeptris.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Yeptris
4
4
  # The gem's version lives in the parent namespace's file — the last
5
5
  # internal require (yeptris/version) retired with it.
6
- VERSION = "0.2.5.3".freeze
6
+ VERSION = "0.3.0.1".freeze
7
7
  # The error hierarchy lives in THIS file (the parent namespace's
8
8
  # own file): nested constants do not trigger a parent-constant
9
9
  # autoload, and the law forbids internal requires — defining the
data/libyeptris.so CHANGED
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yeptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5.3
4
+ version: 0.3.0.1
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-14 00:00:00.000000000 Z
11
+ date: 2026-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi