yeptris 0.6.7.4 → 0.6.7.5
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/lib/yeptris/cbor.rb +114 -0
- data/lib/yeptris/ffi.rb +33 -5
- data/lib/yeptris/psych/visitors.rb +6 -0
- data/lib/yeptris.rb +2 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a084064bffdbce7ccb0461e1402e7a91331e530e71b9ad31967d82e6e5b751db
|
|
4
|
+
data.tar.gz: 0e8c5b97a1e09ef1f3bc4672806b777d68260075536370eedc8b628513f439f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9791fdedd1c2afc3588abb612a8b98bd8ae57f065aea74db052b49f46025dfa52c40acb60a2aebb12acb41a5d464a957185d4ee62e0a07b38e069fcc94d431b2
|
|
7
|
+
data.tar.gz: 6e3931a4cd862b8e8061d9b0c999f73113e0f62e11952ae630abbfd42cbfd76dd3f935a52990ee94a646c319e391b24f379398b940a3ca3fc101084fa31fda9c
|
data/lib/yeptris/cbor.rb
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yeptris
|
|
4
|
+
# CBOR (RFC 8949) over the same FFI document the rest of the
|
|
5
|
+
# binding rides (TODO.cbor/04). Decode materializes through the
|
|
6
|
+
# Psych-compatible path; encode builds the tree with YAMLTree and
|
|
7
|
+
# hands the document to the C encoder — plain data only (aliases
|
|
8
|
+
# and non-decimal tag text are unencodable by the C contract).
|
|
9
|
+
#
|
|
10
|
+
# Representation notes inherited from the decoder: integers beyond
|
|
11
|
+
# int64 and bignums materialize as their shortest-double text, byte
|
|
12
|
+
# strings as tag-chained text — CBOR's JSON-data-model mapping.
|
|
13
|
+
module CBOR
|
|
14
|
+
STRICT = (1 << 0) # decode: reject non-minimal arguments
|
|
15
|
+
CANONICAL = (1 << 1) # encode: s4.2.1 core deterministic profile
|
|
16
|
+
|
|
17
|
+
class Error < Yeptris::Error; end
|
|
18
|
+
class UnencodableError < Error; end
|
|
19
|
+
|
|
20
|
+
module_function
|
|
21
|
+
|
|
22
|
+
def available?
|
|
23
|
+
defined?(::Yeptris::FFI::CBOR_EX) && ::Yeptris::FFI::CBOR_EX
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def load(data, strict: false)
|
|
27
|
+
raise Error, "libyeptris has no CBOR support" unless available?
|
|
28
|
+
|
|
29
|
+
doc_ptr = ::Yeptris::FFI.yeptris_cbor_decode(data, data.bytesize, strict ? STRICT : 0, nil)
|
|
30
|
+
raise ParseError, ::Yeptris::FFI.last_error_message if doc_ptr.null?
|
|
31
|
+
|
|
32
|
+
# the wrapper's finalizer also frees — its idempotent #free is
|
|
33
|
+
# the ONLY release path (a raw double free corrupts the heap)
|
|
34
|
+
doc = ::Yeptris::Document.new(doc_ptr)
|
|
35
|
+
doc.root.to_ruby
|
|
36
|
+
ensure
|
|
37
|
+
doc&.free
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def load_sequence(data, strict: false)
|
|
41
|
+
raise Error, "libyeptris has no CBOR support" unless available?
|
|
42
|
+
|
|
43
|
+
items = []
|
|
44
|
+
receiver = ::FFI::Function.new(:int, %i[pointer pointer size_t]) do |_ctx, item, _index|
|
|
45
|
+
# the callback owns the item; materialize then free in place
|
|
46
|
+
# (through the wrapper — the finalizer frees too)
|
|
47
|
+
doc = ::Yeptris::Document.new(item)
|
|
48
|
+
items << doc.root&.to_ruby
|
|
49
|
+
doc.free
|
|
50
|
+
0
|
|
51
|
+
end
|
|
52
|
+
st = ::Yeptris::FFI.yeptris_cbor_decode_sequence(
|
|
53
|
+
data, data.bytesize, strict ? STRICT : 0, receiver, nil, nil
|
|
54
|
+
)
|
|
55
|
+
raise ParseError, ::Yeptris::FFI.last_error_message if st.zero? && !data.empty?
|
|
56
|
+
|
|
57
|
+
items
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def dump(obj, canonical: true)
|
|
61
|
+
docs = build_documents([obj])
|
|
62
|
+
begin
|
|
63
|
+
encode_one(docs[0], canonical)
|
|
64
|
+
ensure
|
|
65
|
+
docs.each(&:free)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def dump_sequence(objects, canonical: true)
|
|
70
|
+
docs = build_documents(objects)
|
|
71
|
+
begin
|
|
72
|
+
opts = canonical ? CANONICAL : 0
|
|
73
|
+
arr = ::FFI::MemoryPointer.new(:pointer, docs.size)
|
|
74
|
+
arr.write_array_of_pointer(docs.map(&:c_ptr))
|
|
75
|
+
len_ptr = ::FFI::MemoryPointer.new(:size_t)
|
|
76
|
+
take_buffer(
|
|
77
|
+
::Yeptris::FFI.yeptris_cbor_encode_sequence(arr, docs.size, opts, len_ptr),
|
|
78
|
+
len_ptr
|
|
79
|
+
)
|
|
80
|
+
ensure
|
|
81
|
+
docs.each(&:free)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# -- internals ----------------------------------------------------
|
|
86
|
+
|
|
87
|
+
def build_documents(objects)
|
|
88
|
+
# ONE document per object: a visitor's tree is a single
|
|
89
|
+
# document and push sets its root — reuse would overwrite
|
|
90
|
+
objects.map do |obj|
|
|
91
|
+
visitor = ::Yeptris::Psych::Visitors::YAMLTree.new
|
|
92
|
+
visitor.push(obj)
|
|
93
|
+
visitor.document
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def encode_one(doc, canonical)
|
|
98
|
+
opts = canonical ? CANONICAL : 0
|
|
99
|
+
len_ptr = ::FFI::MemoryPointer.new(:size_t)
|
|
100
|
+
take_buffer(::Yeptris::FFI.yeptris_cbor_encode(doc.c_ptr, opts, len_ptr), len_ptr)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# The encode convenience contract: a malloc'd buffer plus its
|
|
104
|
+
# byte length — binary data, freed through the library's own free.
|
|
105
|
+
def take_buffer(ptr, len_ptr)
|
|
106
|
+
raise UnencodableError, ::Yeptris::FFI.last_error_message if ptr.null?
|
|
107
|
+
|
|
108
|
+
len = len_ptr.read_uint64
|
|
109
|
+
ptr.read_bytes(len).force_encoding(Encoding::BINARY)
|
|
110
|
+
ensure
|
|
111
|
+
::Yeptris::FFI.yeptris_free(ptr) if ptr && !ptr.null?
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
data/lib/yeptris/ffi.rb
CHANGED
|
@@ -230,17 +230,45 @@ module Yeptris
|
|
|
230
230
|
false
|
|
231
231
|
end
|
|
232
232
|
|
|
233
|
+
# CBOR (RFC 8949, TODO.cbor): absent on libraries before the
|
|
234
|
+
# codec's release — the CBOR module feature-detects
|
|
235
|
+
CBOR_EX = begin
|
|
236
|
+
attach_function :yeptris_cbor_decode, %i[pointer size_t uint32 yeptris_status_out],
|
|
237
|
+
:yeptris_document
|
|
238
|
+
callback :cbor_item_cb, %i[pointer yeptris_document size_t], :int
|
|
239
|
+
attach_function :yeptris_cbor_decode_sequence,
|
|
240
|
+
%i[pointer size_t uint32 cbor_item_cb pointer yeptris_status_out], :size_t
|
|
241
|
+
attach_function :yeptris_cbor_encode, %i[yeptris_document uint32 pointer], :pointer
|
|
242
|
+
attach_function :yeptris_cbor_encode_sequence,
|
|
243
|
+
%i[pointer size_t uint32 pointer], :pointer
|
|
244
|
+
true
|
|
245
|
+
rescue ::FFI::NotFoundError
|
|
246
|
+
false
|
|
247
|
+
end
|
|
248
|
+
|
|
233
249
|
# Owned char* results (serialize*): one reader, freed exactly once.
|
|
234
250
|
# The release goes through yeptris_free (libyeptris's own
|
|
235
251
|
# allocator-matching free) because ffi's :free attach has no
|
|
236
252
|
# Windows process-symbol fallback — libyeptris.dll doesn't export
|
|
237
253
|
# libc free, so resolving :free against it fails on Windows.
|
|
238
|
-
|
|
254
|
+
# A raised attach ABORTS this file mid-evaluation — everything
|
|
255
|
+
# after it (NODE_SCALAR and the kind constants below) never
|
|
256
|
+
# defines, and a lazily autoloaded node.rb then dies with
|
|
257
|
+
# 'uninitialized constant' (#138). Every fallback attaches too.
|
|
258
|
+
YEPTRIS_FREE = begin
|
|
239
259
|
attach_function :yeptris_free, [:pointer], :void
|
|
260
|
+
:direct
|
|
240
261
|
rescue ::FFI::NotFoundError
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
262
|
+
begin
|
|
263
|
+
# libyeptris < v0.6.6: POSIX resolves :free through the
|
|
264
|
+
# process symbol table, so the libc attach still works there.
|
|
265
|
+
attach_function :yeptris_free, :free, [:pointer], :void
|
|
266
|
+
:libc
|
|
267
|
+
rescue ::FFI::NotFoundError
|
|
268
|
+
# no owned-buffer release on this lib+platform combination;
|
|
269
|
+
# Owned.string leaks instead of killing the whole file
|
|
270
|
+
:none
|
|
271
|
+
end
|
|
244
272
|
end
|
|
245
273
|
|
|
246
274
|
module Owned
|
|
@@ -258,7 +286,7 @@ module Yeptris
|
|
|
258
286
|
else
|
|
259
287
|
ptr.read_string.force_encoding(Encoding::UTF_8)
|
|
260
288
|
end
|
|
261
|
-
::Yeptris::FFI.yeptris_free(ptr)
|
|
289
|
+
::Yeptris::FFI.yeptris_free(ptr) if ::Yeptris::FFI::YEPTRIS_FREE != :none
|
|
262
290
|
s
|
|
263
291
|
end
|
|
264
292
|
end
|
|
@@ -41,6 +41,12 @@ module Yeptris
|
|
|
41
41
|
BuiltDocument.new(@tree)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# The raw document (the CBOR encoder consumes the tree
|
|
45
|
+
# directly; #tree wraps it for stdlib's yaml face)
|
|
46
|
+
def document
|
|
47
|
+
@tree
|
|
48
|
+
end
|
|
49
|
+
|
|
44
50
|
def finish
|
|
45
51
|
@tree.serialize(explicit_doc_start: true)
|
|
46
52
|
end
|
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.6.7.
|
|
6
|
+
VERSION = "0.6.7.5".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
|
|
@@ -44,6 +44,7 @@ module Yeptris
|
|
|
44
44
|
autoload :ValueML, "yeptris/valueml"
|
|
45
45
|
autoload :Psych, "yeptris/psych"
|
|
46
46
|
autoload :Schema, "yeptris/schema"
|
|
47
|
+
autoload :CBOR, "yeptris/cbor"
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
# NOTE (the #318 poisoned-process class): the Psych error-name aliases
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yeptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.7.
|
|
4
|
+
version: 0.6.7.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -41,6 +41,7 @@ files:
|
|
|
41
41
|
- ext/yeptris_native/json_ruby.c
|
|
42
42
|
- ext/yeptris_native/yeptris_native.c
|
|
43
43
|
- lib/yeptris.rb
|
|
44
|
+
- lib/yeptris/cbor.rb
|
|
44
45
|
- lib/yeptris/document.rb
|
|
45
46
|
- lib/yeptris/ffi.rb
|
|
46
47
|
- lib/yeptris/json.rb
|