teptris 0.1.0 → 0.2.35

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/ext/teptris_ext/engine/LICENSE.md +21 -0
  3. data/ext/teptris_ext/engine/src/include/teptris/plan.h +123 -0
  4. data/ext/teptris_ext/engine/src/include/teptris/teptris.h +208 -0
  5. data/ext/teptris_ext/engine/src/include/teptris/version.h +9 -0
  6. data/ext/teptris_ext/engine/src/teptris/api.c +362 -0
  7. data/ext/teptris_ext/engine/src/teptris/build.c +355 -0
  8. data/ext/teptris_ext/engine/src/teptris/common/chartype.c +70 -0
  9. data/ext/teptris_ext/engine/src/teptris/common/chartype.h +41 -0
  10. data/ext/teptris_ext/engine/src/teptris/common/ryu/common.h +114 -0
  11. data/ext/teptris_ext/engine/src/teptris/common/ryu/d2s.c +496 -0
  12. data/ext/teptris_ext/engine/src/teptris/common/ryu/d2s_full_table.h +367 -0
  13. data/ext/teptris_ext/engine/src/teptris/common/ryu/d2s_intrinsics.h +357 -0
  14. data/ext/teptris_ext/engine/src/teptris/common/ryu/digit_table.h +35 -0
  15. data/ext/teptris_ext/engine/src/teptris/common/ryu/ryu_d2s.h +39 -0
  16. data/ext/teptris_ext/engine/src/teptris/common/ryu/ryu_parse.h +45 -0
  17. data/ext/teptris_ext/engine/src/teptris/common/ryu/s2d.c +259 -0
  18. data/ext/teptris_ext/engine/src/teptris/common/simd.h +119 -0
  19. data/ext/teptris_ext/engine/src/teptris/dom/dom.c +192 -0
  20. data/ext/teptris_ext/engine/src/teptris/dom/dom.h +122 -0
  21. data/ext/teptris_ext/engine/src/teptris/emit/emitter.c +718 -0
  22. data/ext/teptris_ext/engine/src/teptris/emit/emitter.h +11 -0
  23. data/ext/teptris_ext/engine/src/teptris/memory/arena.c +104 -0
  24. data/ext/teptris_ext/engine/src/teptris/memory/arena.h +53 -0
  25. data/ext/teptris_ext/engine/src/teptris/parse/datetime.c +218 -0
  26. data/ext/teptris_ext/engine/src/teptris/parse/keys.c +121 -0
  27. data/ext/teptris_ext/engine/src/teptris/parse/parse.h +76 -0
  28. data/ext/teptris_ext/engine/src/teptris/parse/parser.c +931 -0
  29. data/ext/teptris_ext/engine/src/teptris/parse/scalars.c +940 -0
  30. data/ext/teptris_ext/engine/src/teptris/plan/plan.c +472 -0
  31. data/ext/teptris_ext/engine/src/teptris/version.c +6 -0
  32. data/ext/teptris_ext/extconf.rb +61 -0
  33. data/ext/teptris_ext/materialize.c +608 -0
  34. data/lib/teptris/descriptor.rb +70 -0
  35. data/lib/teptris/toml.rb +24 -271
  36. data/lib/teptris/version.rb +1 -1
  37. data/lib/teptris.rb +18 -2
  38. metadata +41 -22
  39. data/lib/teptris/lib.rb +0 -81
data/lib/teptris/toml.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require "date"
2
2
 
3
3
  require_relative "error"
4
- require_relative "lib"
4
+
5
5
  require_relative "version"
6
6
 
7
7
  module Teptris
@@ -12,7 +12,9 @@ module Teptris
12
12
  module TOML
13
13
  class << self
14
14
  def load(toml)
15
- parse_and_materialize(toml, 0, nil)
15
+ raise ArgumentError, "input must be a String" unless toml.is_a?(String)
16
+
17
+ TeptrisExt.load(toml)
16
18
  end
17
19
 
18
20
  # Safe-load shaped entry point for frameworks: permitted_classes
@@ -23,46 +25,31 @@ module Teptris
23
25
  unless %i[native string].include?(datetime_policy)
24
26
  raise ArgumentError, "datetime_policy must be :native or :string"
25
27
  end
26
- mode = datetime_policy == :string ? 1 : 0
27
- permitted = permitted_classes && Set.new(permitted_classes)
28
- if permitted && mode.zero?
29
- permitted << String # TOML scalars are always materialized
28
+ opts = {}
29
+ opts[:string_datetimes] = true if datetime_policy == :string
30
+ if permitted_classes && datetime_policy == :native
31
+ permitted = permitted_classes + [:__scalar]
32
+ opts[:forbid_time] = true unless permitted.include?(Time)
33
+ opts[:forbid_date] = true unless permitted.include?(Date)
30
34
  end
31
- parse_and_materialize(toml, mode, permitted)
35
+ load(toml) if opts.empty?
36
+ TeptrisExt.load(toml, opts)
32
37
  end
33
38
 
34
- # Reserved: fused descriptor materialization, the same descriptor
35
- # shape as leptris/yeptris#238 — see docs/DESCRIPTOR_ABI.md. The
36
- # entry point exists so frameworks can code against it today; the
37
- # fused native pass lands with the co-designed ABI.
39
+ # One-pass schema materialization over a compiled
40
+ # Teptris::Descriptor: unplanned keys are never materialized
41
+ # (teptris#46).
38
42
  def load_schema(toml, descriptor)
39
- raise Error,
40
- "descriptor materialization lands with the co-designed " \
41
- "ABI (leptris/yeptris#238); entry point is reserved — " \
42
- "see docs/DESCRIPTOR_ABI.md (descriptor #{descriptor.class})"
43
+ unless descriptor.is_a?(Teptris::Descriptor)
44
+ raise ArgumentError,
45
+ "descriptor must be a Teptris::Descriptor (use " \
46
+ "Teptris::Descriptor.build), got #{descriptor.class}"
47
+ end
48
+ descriptor.walk(toml)
43
49
  end
44
50
 
45
- private
46
-
47
- def parse_and_materialize(toml, mode, permitted)
48
- raise ArgumentError, "input must be a String" unless toml.is_a?(String)
49
-
50
- data = FFI::MemoryPointer.from_string(toml)
51
- docp = FFI::MemoryPointer.new(:pointer)
52
- st = Lib.teptris_parse(data, toml.bytesize, nil, docp)
53
- handle = docp.read_pointer
54
- if st != Teptris::TEPTRIS_OK
55
- raise build_parse_error(handle)
56
- end
57
- begin
58
- @mode = mode
59
- @permitted = permitted
60
- load_flat(handle)
61
- ensure
62
- @mode = nil
63
- @permitted = nil
64
- Lib.teptris_document_free(handle)
65
- end
51
+ def engine_version
52
+ TeptrisExt.engine_version
66
53
  end
67
54
 
68
55
  public
@@ -72,241 +59,7 @@ module Teptris
72
59
  end
73
60
 
74
61
  def dump(obj)
75
- raise ArgumentError, "cannot dump #{obj.class}" unless obj.is_a?(Hash)
76
-
77
- out = +""
78
- emit_table(obj, out, nil)
79
- out
80
- end
81
-
82
- private
83
-
84
- def build_parse_error(handle)
85
- line = 0
86
- column = 0
87
- msg = "parse failed"
88
- unless handle.null?
89
- es = Lib::ErrorStruct.new(Lib.teptris_document_error(handle))
90
- line = es[:line]
91
- column = es[:column]
92
- msg = es[:message]
93
- end
94
- ParseError.new(msg, line, column)
95
- end
96
-
97
- # One-bulk-drain load: the C side flattens the whole tree in a
98
- # single crossing; this decoder walks the typed flat buffer.
99
- FLAT_TABLE = 0x01
100
- FLAT_ARRAY = 0x02
101
- FLAT_STRING = 0x03
102
- FLAT_INT = 0x04
103
- FLAT_FLOAT = 0x05
104
- FLAT_FALSE = 0x06
105
- FLAT_TRUE = 0x07
106
- FLAT_DT = 0x08 # ..0x0B: offset, local-datetime, date, local-time
107
-
108
- def load_flat(handle)
109
- bufp = FFI::MemoryPointer.new(:pointer)
110
- lenp = FFI::MemoryPointer.new(:size_t)
111
- st = Lib.teptris_document_flatten(handle, bufp, lenp)
112
- raise Error, "flatten failed" unless st == Teptris::TEPTRIS_OK
113
-
114
- buf = bufp.read_pointer
115
- begin
116
- data = buf.get_bytes(0, lenp.read_uint64)
117
- value, = decode_flat(data, 0)
118
- value
119
- ensure
120
- Lib.teptris_flatten_free(buf)
121
- end
122
- end
123
-
124
- def decode_flat(d, pos)
125
- case d.getbyte(pos)
126
- when FLAT_TABLE
127
- n = d.unpack1("L<", offset: pos + 1)
128
- pos += 5
129
- h = {}
130
- n.times do
131
- kl = d.unpack1("L<", offset: pos)
132
- pos += 4
133
- k = d.byteslice(pos, kl).force_encoding(Encoding::UTF_8)
134
- pos += kl
135
- v, pos = decode_flat(d, pos)
136
- h[k] = v
137
- end
138
- [h, pos]
139
- when FLAT_ARRAY
140
- n = d.unpack1("L<", offset: pos + 1)
141
- pos += 5
142
- a = Array.new(n)
143
- n.times do |i|
144
- a[i], pos = decode_flat(d, pos)
145
- end
146
- [a, pos]
147
- when FLAT_STRING
148
- l = d.unpack1("L<", offset: pos + 1)
149
- pos += 5
150
- [d.byteslice(pos, l).force_encoding(Encoding::UTF_8), pos + l]
151
- when FLAT_INT
152
- [d.unpack1("q<", offset: pos + 1), pos + 9]
153
- when FLAT_FLOAT
154
- [d.unpack1("E", offset: pos + 1), pos + 9]
155
- when FLAT_FALSE then [false, pos + 1]
156
- when FLAT_TRUE then [true, pos + 1]
157
- when FLAT_DT, FLAT_DT + 1, FLAT_DT + 2, FLAT_DT + 3
158
- kind = d.getbyte(pos)
159
- year = d.unpack1("q<", offset: pos + 1)
160
- mon = d.getbyte(pos + 9)
161
- day = d.getbyte(pos + 10)
162
- hour = d.getbyte(pos + 11)
163
- min = d.getbyte(pos + 12)
164
- sec = d.getbyte(pos + 13)
165
- nsec = d.unpack1("L<", offset: pos + 14)
166
- off = d.unpack1("q<", offset: pos + 18)
167
- [flat_datetime(kind, year, mon, day, hour, min, sec, nsec, off),
168
- pos + 26]
169
- else
170
- raise Error, "corrupt flat buffer at #{pos}"
171
- end
172
- end
173
-
174
- def flat_datetime(kind, y, mon, day, hour, min, sec, nsec, off)
175
- return flat_datetime_string(kind, y, mon, day, hour, min, sec, nsec, off) if @mode == 1
176
-
177
- rational = Rational(sec * 1_000_000_000 + nsec, 1_000_000_000)
178
- case kind
179
- when FLAT_DT
180
- check_permitted!(Time)
181
- Time.new(y, mon, day, hour, min, rational, off)
182
- when FLAT_DT + 1
183
- check_permitted!(Time)
184
- Time.local(y, mon, day, hour, min, rational)
185
- when FLAT_DT + 2
186
- check_permitted!(Date)
187
- Date.new(y, mon, day)
188
- else
189
- s = format("%02d:%02d:%02d", hour, min, sec)
190
- s << "." << format("%09d", nsec).sub(/0+\z/, "") if nsec.positive?
191
- s
192
- end
193
- end
194
-
195
- def check_permitted!(klass)
196
- permitted = @permitted
197
- return if permitted.nil? || permitted.include?(klass)
198
-
199
- raise Error,
200
- "value materializes #{klass}, which is not in " \
201
- "permitted_classes (use datetime_policy: :string to keep " \
202
- "datetimes as strings)"
203
- end
204
-
205
- def flat_datetime_string(kind, y, mon, day, hour, min, sec, nsec, off)
206
- case kind
207
- when FLAT_DT + 2 then return format("%04d-%02d-%02d", y, mon, day)
208
- when FLAT_DT + 3 then s = +""
209
- else s = +(format("%04d-%02d-%02dT", y, mon, day))
210
- end
211
- s << format("%02d:%02d:%02d", hour, min, sec)
212
- if nsec.positive?
213
- s << "." << format("%09d", nsec).sub(/0+\z/, "")
214
- end
215
- case kind
216
- when FLAT_DT
217
- off.zero? ? s << "Z" : s << format("%+03d:%02d", off / 3600, (off % 3600).abs / 60)
218
- end
219
- s
220
- end
221
-
222
- # ---- dump -----------------------------------------------------------
223
-
224
- def emit_table(hash, out, prefix)
225
- hash.each do |k, v|
226
- next if table?(v) || aot?(v)
227
-
228
- out << emit_key(k) << " = " << emit_value(v) << "\n"
229
- end
230
- hash.each do |k, v|
231
- next unless table?(v) || aot?(v)
232
-
233
- path = prefix ? "#{prefix}.#{emit_key(k)}" : emit_key(k)
234
- if aot?(v)
235
- v.each do |item|
236
- out << "[[" << path << "]]\n"
237
- emit_table(item, out, path)
238
- end
239
- else
240
- out << "[" << path << "]\n"
241
- emit_table(v, out, path)
242
- end
243
- end
244
- end
245
-
246
- def table?(v)
247
- v.is_a?(Hash)
248
- end
249
-
250
- def aot?(v)
251
- v.is_a?(Array) && !v.empty? && v.all? { |e| e.is_a?(Hash) }
252
- end
253
-
254
- def emit_key(k)
255
- k = k.to_s
256
- if /\A[A-Za-z0-9_-]+\z/.match?(k)
257
- k
258
- elsif !k.include?("'") && !k.each_char.any? { |c| c.ord < 0x20 }
259
- "'#{k}'"
260
- else
261
- "\"#{escape_basic(k)}\""
262
- end
263
- end
264
-
265
- BASIC_ESCAPES = {
266
- "\\" => "\\\\\\\\", # \ -> \\
267
- "\"" => "\\\"", "\b" => "\\b", "\f" => "\\f",
268
- "\n" => "\\n", "\r" => "\\r", "\t" => "\\t"
269
- }.freeze
270
-
271
- def escape_basic(s)
272
- s.gsub(/[\\\"\b\f\n\r\t]/) { |c| BASIC_ESCAPES[c] }
273
- end
274
-
275
- def emit_value(v)
276
- case v
277
- when String
278
- if !v.include?("'") && !v.each_char.any? { |c| c.ord < 0x20 }
279
- "'#{v}'"
280
- else
281
- "\"#{escape_basic(v)}\""
282
- end
283
- when Integer then v.to_s
284
- when Float
285
- return v.to_s if v.finite?
286
-
287
- v.nan? ? "nan" : (v.positive? ? "inf" : "-inf")
288
- when TrueClass then "true"
289
- when FalseClass then "false"
290
- when Time
291
- base = v.strftime("%Y-%m-%dT%H:%M:%S")
292
- frac = v.strftime("%N").sub(/0+\z/, "")
293
- base << "." << frac unless frac.empty?
294
- base << tz(v)
295
- when Date then v.iso8601
296
- when Array then "[#{v.map { |e| emit_value(e) }.join(', ')}]"
297
- when Hash
298
- "{#{v.map { |k, e| "#{emit_key(k)} = #{emit_value(e)}" }.join(', ')}}"
299
- else raise Error, "cannot dump #{v.class}"
300
- end
301
- end
302
-
303
- def tz(time)
304
- off = time.utc_offset
305
- return "Z" if off.zero?
306
-
307
- sign = off.negative? ? "-" : "+"
308
- off = -off if off.negative?
309
- format("%s%02d:%02d", sign, off / 3600, (off % 3600) / 60)
62
+ TeptrisExt.dump(obj)
310
63
  end
311
64
  end
312
65
  end
@@ -1,3 +1,3 @@
1
1
  module Teptris
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.35"
3
3
  end
data/lib/teptris.rb CHANGED
@@ -1,10 +1,26 @@
1
- require "set"
1
+ require "date"
2
2
 
3
3
  require_relative "teptris/version"
4
4
  require_relative "teptris/error"
5
- require_relative "teptris/lib"
5
+ require_relative "teptris/descriptor"
6
6
  require_relative "teptris/toml"
7
7
 
8
+ # Windows ucrt rubies name their DLL per minor (x64-ucrt-ruby330.dll), so
9
+ # the mingw gems ship one extension per ruby minor beside a shared
10
+ # libteptris.dll (nokogiri's fat-gem layout). The native extension IS the
11
+ # binding — no fallback, ever.
12
+ begin
13
+ if RUBY_PLATFORM =~ /mingw/
14
+ require "teptris/#{RUBY_VERSION[/\A\d+\.\d+/]}/teptris_ext"
15
+ else
16
+ require "teptris_ext"
17
+ end
18
+ rescue LoadError
19
+ raise LoadError,
20
+ "teptris native extension not available for #{RUBY_PLATFORM} " \
21
+ "ruby #{RUBY_VERSION} (no fallback by design)"
22
+ end
23
+
8
24
  module Teptris
9
25
  TEPTRIS_OK = 0
10
26
  end
metadata CHANGED
@@ -1,39 +1,58 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.35
5
5
  platform: ruby
6
6
  authors:
7
7
  - teptris contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-13 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: ffi
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.15'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.15'
27
- description: An FFI binding over libteptris, a C11 TOML 1.0 parser/emitter. API shape
28
- mirrors the tomlib gem.
11
+ date: 2026-09-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A native C extension over libteptris, a C11 TOML 1.1 parser/emitter.
14
+ API shape mirrors the tomlib gem.
29
15
  email:
30
16
  executables: []
31
- extensions: []
17
+ extensions:
18
+ - ext/teptris_ext/extconf.rb
32
19
  extra_rdoc_files: []
33
20
  files:
21
+ - ext/teptris_ext/engine/LICENSE.md
22
+ - ext/teptris_ext/engine/src/include/teptris/plan.h
23
+ - ext/teptris_ext/engine/src/include/teptris/teptris.h
24
+ - ext/teptris_ext/engine/src/include/teptris/version.h
25
+ - ext/teptris_ext/engine/src/teptris/api.c
26
+ - ext/teptris_ext/engine/src/teptris/build.c
27
+ - ext/teptris_ext/engine/src/teptris/common/chartype.c
28
+ - ext/teptris_ext/engine/src/teptris/common/chartype.h
29
+ - ext/teptris_ext/engine/src/teptris/common/ryu/common.h
30
+ - ext/teptris_ext/engine/src/teptris/common/ryu/d2s.c
31
+ - ext/teptris_ext/engine/src/teptris/common/ryu/d2s_full_table.h
32
+ - ext/teptris_ext/engine/src/teptris/common/ryu/d2s_intrinsics.h
33
+ - ext/teptris_ext/engine/src/teptris/common/ryu/digit_table.h
34
+ - ext/teptris_ext/engine/src/teptris/common/ryu/ryu_d2s.h
35
+ - ext/teptris_ext/engine/src/teptris/common/ryu/ryu_parse.h
36
+ - ext/teptris_ext/engine/src/teptris/common/ryu/s2d.c
37
+ - ext/teptris_ext/engine/src/teptris/common/simd.h
38
+ - ext/teptris_ext/engine/src/teptris/dom/dom.c
39
+ - ext/teptris_ext/engine/src/teptris/dom/dom.h
40
+ - ext/teptris_ext/engine/src/teptris/emit/emitter.c
41
+ - ext/teptris_ext/engine/src/teptris/emit/emitter.h
42
+ - ext/teptris_ext/engine/src/teptris/memory/arena.c
43
+ - ext/teptris_ext/engine/src/teptris/memory/arena.h
44
+ - ext/teptris_ext/engine/src/teptris/parse/datetime.c
45
+ - ext/teptris_ext/engine/src/teptris/parse/keys.c
46
+ - ext/teptris_ext/engine/src/teptris/parse/parse.h
47
+ - ext/teptris_ext/engine/src/teptris/parse/parser.c
48
+ - ext/teptris_ext/engine/src/teptris/parse/scalars.c
49
+ - ext/teptris_ext/engine/src/teptris/plan/plan.c
50
+ - ext/teptris_ext/engine/src/teptris/version.c
51
+ - ext/teptris_ext/extconf.rb
52
+ - ext/teptris_ext/materialize.c
34
53
  - lib/teptris.rb
54
+ - lib/teptris/descriptor.rb
35
55
  - lib/teptris/error.rb
36
- - lib/teptris/lib.rb
37
56
  - lib/teptris/toml.rb
38
57
  - lib/teptris/version.rb
39
58
  homepage: https://github.com/leptris/teptris-ruby
@@ -58,5 +77,5 @@ requirements: []
58
77
  rubygems_version: 3.5.22
59
78
  signing_key:
60
79
  specification_version: 4
61
- summary: TOML for Ruby at libleptris speed (FFI, no C extension)
80
+ summary: TOML for Ruby at libteptris speed (native C extension)
62
81
  test_files: []
data/lib/teptris/lib.rb DELETED
@@ -1,81 +0,0 @@
1
- require "ffi"
2
-
3
- module Teptris
4
- # Loads the shared libteptris: TEPTRIS_LIB_PATH env, vendored
5
- # lib/platform/<tag>/, the sibling C checkout's build tree, then the
6
- # system paths (yeptris-ruby resolution chain).
7
- module Lib
8
- extend FFI::Library
9
-
10
- NAMES = %w[libteptris.dylib libteptris.so libteptris.dll].freeze
11
-
12
- def self.candidates
13
- out = []
14
- out << ENV["TEPTRIS_LIB_PATH"] if ENV["TEPTRIS_LIB_PATH"]
15
- out.concat(Dir[File.expand_path("../libteptris.*", __dir__)])
16
- NAMES.each do |n|
17
- %w[build build-release build-shared build-bench].each do |b|
18
- out << File.expand_path("../../teptris/#{b}/src/#{n}", __dir__)
19
- end
20
- out << n
21
- end
22
- out.compact
23
- end
24
-
25
- loaded = nil
26
- candidates.each do |c|
27
- begin
28
- ffi_lib c
29
- loaded = c
30
- break
31
- rescue LoadError
32
- next
33
- end
34
- end
35
- raise Error, "libteptris not found (set TEPTRIS_LIB_PATH)" unless loaded
36
- LIBRARY_PATH = loaded
37
-
38
- typedef :pointer, :doc
39
- typedef :pointer, :node
40
-
41
- attach_function :teptris_parse, [:pointer, :size_t, :pointer, :pointer], :int
42
- attach_function :teptris_document_free, [:doc], :void
43
- attach_function :teptris_document_error, [:doc], :pointer
44
- attach_function :teptris_document_root, [:doc], :node
45
- attach_function :teptris_document_emit, [:doc, :pointer, :pointer], :int
46
- attach_function :teptris_node_kind, [:node], :int
47
- attach_function :teptris_node_string, [:node, :pointer], :int
48
- attach_function :teptris_node_integer, [:node, :pointer], :int
49
- attach_function :teptris_node_float, [:node, :pointer], :int
50
- attach_function :teptris_node_boolean, [:node, :pointer], :int
51
- attach_function :teptris_node_datetime, [:node, :pointer], :int
52
- attach_function :teptris_node_array_length, [:node], :size_t
53
- attach_function :teptris_node_array_at, [:node, :size_t], :node
54
- attach_function :teptris_node_table_length, [:node], :size_t
55
- attach_function :teptris_node_table_at, [:node, :size_t, :pointer], :node
56
- attach_function :teptris_document_flatten, [:doc, :pointer, :pointer], :int
57
- attach_function :teptris_flatten_free, [:pointer], :void
58
-
59
- class ErrorStruct < FFI::Struct
60
- layout :status, :int, :line, :size_t, :column, :size_t, :message, :string
61
- end
62
-
63
- class ViewStruct < FFI::Struct
64
- layout :ptr, :pointer, :len, :size_t
65
- end
66
-
67
- class DateTimeStruct < FFI::Struct
68
- layout :year, :int32,
69
- :month, :uint8, :day, :uint8,
70
- :hour, :uint8, :minute, :uint8, :second, :uint8,
71
- :_pad, [:uint8, 3],
72
- :nanosecond, :uint32, :offset_seconds, :int32
73
- end
74
- end
75
-
76
- KIND = {
77
- string: 0, integer: 1, float: 2, boolean: 3,
78
- datetime: 4, datetime_local: 5, date_local: 6, time_local: 7,
79
- array: 8, table: 9
80
- }.freeze
81
- end