tigerbeetle 0.0.40 → 0.17.8

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 (293) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +0 -25
  3. data/README.md +670 -80
  4. data/docs/migration.md +201 -0
  5. data/sig/tigerbeetle.rbs +271 -0
  6. data/src/ext/tigerbeetle/extconf.rb +47 -0
  7. data/src/ext/tigerbeetle/lib/aarch64-linux-gnu.2.27/libtb_client.so +0 -0
  8. data/src/ext/tigerbeetle/lib/aarch64-linux-musl/libtb_client.so +0 -0
  9. data/src/ext/tigerbeetle/lib/aarch64-macos/libtb_client.dylib +0 -0
  10. data/src/ext/tigerbeetle/lib/x86_64-linux-gnu.2.27/libtb_client.so +0 -0
  11. data/src/ext/tigerbeetle/lib/x86_64-linux-musl/libtb_client.so +0 -0
  12. data/src/ext/tigerbeetle/lib/x86_64-macos/libtb_client.dylib +0 -0
  13. data/src/ext/tigerbeetle/lib/x86_64-windows/tb_client.dll +0 -0
  14. data/src/ext/tigerbeetle/rb_tb_gen.h +458 -0
  15. data/{ext/tb_client/tigerbeetle/src/clients/rust/assets → src/ext/tigerbeetle}/tb_client.h +18 -16
  16. data/src/ext/tigerbeetle/tigerbeetle.c +310 -0
  17. data/src/tigerbeetle/bindings.rb +347 -0
  18. data/src/tigerbeetle/client.rb +129 -0
  19. data/src/tigerbeetle/completion_dispatcher.rb +108 -0
  20. data/src/tigerbeetle/id.rb +40 -0
  21. data/src/tigerbeetle/tb.rb +3 -0
  22. data/src/tigerbeetle/version.rb +3 -0
  23. data/src/tigerbeetle.rb +39 -0
  24. metadata +33 -350
  25. data/CHANGELOG.md +0 -162
  26. data/ext/tb_client/extconf.rb +0 -41
  27. data/ext/tb_client/tigerbeetle/LICENSE +0 -177
  28. data/ext/tb_client/tigerbeetle/build.zig +0 -2296
  29. data/ext/tb_client/tigerbeetle/src/aof.zig +0 -1000
  30. data/ext/tb_client/tigerbeetle/src/build/fetch.zig +0 -112
  31. data/ext/tb_client/tigerbeetle/src/build_multiversion.zig +0 -808
  32. data/ext/tb_client/tigerbeetle/src/cdc/amqp/protocol.zig +0 -1283
  33. data/ext/tb_client/tigerbeetle/src/cdc/amqp/spec.zig +0 -1704
  34. data/ext/tb_client/tigerbeetle/src/cdc/amqp/types.zig +0 -341
  35. data/ext/tb_client/tigerbeetle/src/cdc/amqp.zig +0 -1450
  36. data/ext/tb_client/tigerbeetle/src/cdc/runner.zig +0 -1659
  37. data/ext/tb_client/tigerbeetle/src/clients/c/samples/main.c +0 -406
  38. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/context.zig +0 -1092
  39. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/echo_client.zig +0 -286
  40. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/packet.zig +0 -158
  41. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal.zig +0 -229
  42. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal_fuzz.zig +0 -110
  43. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.h +0 -386
  44. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.zig +0 -34
  45. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_exports.zig +0 -281
  46. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header.zig +0 -312
  47. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header_test.zig +0 -138
  48. data/ext/tb_client/tigerbeetle/src/clients/c/test.zig +0 -466
  49. data/ext/tb_client/tigerbeetle/src/clients/docs_samples.zig +0 -157
  50. data/ext/tb_client/tigerbeetle/src/clients/docs_types.zig +0 -90
  51. data/ext/tb_client/tigerbeetle/src/clients/dotnet/ci.zig +0 -203
  52. data/ext/tb_client/tigerbeetle/src/clients/dotnet/docs.zig +0 -79
  53. data/ext/tb_client/tigerbeetle/src/clients/dotnet/dotnet_bindings.zig +0 -542
  54. data/ext/tb_client/tigerbeetle/src/clients/go/ci.zig +0 -109
  55. data/ext/tb_client/tigerbeetle/src/clients/go/docs.zig +0 -86
  56. data/ext/tb_client/tigerbeetle/src/clients/go/go_bindings.zig +0 -370
  57. data/ext/tb_client/tigerbeetle/src/clients/go/pkg/native/tb_client.h +0 -386
  58. data/ext/tb_client/tigerbeetle/src/clients/java/ci.zig +0 -167
  59. data/ext/tb_client/tigerbeetle/src/clients/java/docs.zig +0 -126
  60. data/ext/tb_client/tigerbeetle/src/clients/java/java_bindings.zig +0 -996
  61. data/ext/tb_client/tigerbeetle/src/clients/java/src/client.zig +0 -748
  62. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni.zig +0 -3238
  63. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_tests.zig +0 -1718
  64. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_thread_cleaner.zig +0 -190
  65. data/ext/tb_client/tigerbeetle/src/clients/node/ci.zig +0 -104
  66. data/ext/tb_client/tigerbeetle/src/clients/node/docs.zig +0 -75
  67. data/ext/tb_client/tigerbeetle/src/clients/node/node.zig +0 -522
  68. data/ext/tb_client/tigerbeetle/src/clients/node/node_bindings.zig +0 -267
  69. data/ext/tb_client/tigerbeetle/src/clients/node/src/c.zig +0 -3
  70. data/ext/tb_client/tigerbeetle/src/clients/node/src/translate.zig +0 -379
  71. data/ext/tb_client/tigerbeetle/src/clients/python/ci.zig +0 -131
  72. data/ext/tb_client/tigerbeetle/src/clients/python/docs.zig +0 -63
  73. data/ext/tb_client/tigerbeetle/src/clients/python/python_bindings.zig +0 -588
  74. data/ext/tb_client/tigerbeetle/src/clients/rust/ci.zig +0 -73
  75. data/ext/tb_client/tigerbeetle/src/clients/rust/docs.zig +0 -106
  76. data/ext/tb_client/tigerbeetle/src/clients/rust/rust_bindings.zig +0 -305
  77. data/ext/tb_client/tigerbeetle/src/config.zig +0 -296
  78. data/ext/tb_client/tigerbeetle/src/constants.zig +0 -790
  79. data/ext/tb_client/tigerbeetle/src/copyhound.zig +0 -202
  80. data/ext/tb_client/tigerbeetle/src/counting_allocator.zig +0 -72
  81. data/ext/tb_client/tigerbeetle/src/direction.zig +0 -120
  82. data/ext/tb_client/tigerbeetle/src/docs_website/build.zig +0 -158
  83. data/ext/tb_client/tigerbeetle/src/docs_website/src/content.zig +0 -156
  84. data/ext/tb_client/tigerbeetle/src/docs_website/src/docs.zig +0 -252
  85. data/ext/tb_client/tigerbeetle/src/docs_website/src/file_checker.zig +0 -313
  86. data/ext/tb_client/tigerbeetle/src/docs_website/src/html.zig +0 -87
  87. data/ext/tb_client/tigerbeetle/src/docs_website/src/page_writer.zig +0 -63
  88. data/ext/tb_client/tigerbeetle/src/docs_website/src/redirects.zig +0 -47
  89. data/ext/tb_client/tigerbeetle/src/docs_website/src/search_index_writer.zig +0 -28
  90. data/ext/tb_client/tigerbeetle/src/docs_website/src/service_worker_writer.zig +0 -61
  91. data/ext/tb_client/tigerbeetle/src/docs_website/src/single_page_writer.zig +0 -169
  92. data/ext/tb_client/tigerbeetle/src/docs_website/src/website.zig +0 -46
  93. data/ext/tb_client/tigerbeetle/src/ewah.zig +0 -445
  94. data/ext/tb_client/tigerbeetle/src/ewah_benchmark.zig +0 -128
  95. data/ext/tb_client/tigerbeetle/src/ewah_fuzz.zig +0 -171
  96. data/ext/tb_client/tigerbeetle/src/fuzz_tests.zig +0 -179
  97. data/ext/tb_client/tigerbeetle/src/integration_tests.zig +0 -662
  98. data/ext/tb_client/tigerbeetle/src/io/common.zig +0 -155
  99. data/ext/tb_client/tigerbeetle/src/io/darwin.zig +0 -1093
  100. data/ext/tb_client/tigerbeetle/src/io/linux.zig +0 -1880
  101. data/ext/tb_client/tigerbeetle/src/io/test.zig +0 -1005
  102. data/ext/tb_client/tigerbeetle/src/io/windows.zig +0 -1598
  103. data/ext/tb_client/tigerbeetle/src/io.zig +0 -34
  104. data/ext/tb_client/tigerbeetle/src/iops.zig +0 -134
  105. data/ext/tb_client/tigerbeetle/src/list.zig +0 -236
  106. data/ext/tb_client/tigerbeetle/src/lsm/binary_search.zig +0 -848
  107. data/ext/tb_client/tigerbeetle/src/lsm/binary_search_benchmark.zig +0 -179
  108. data/ext/tb_client/tigerbeetle/src/lsm/cache_map.zig +0 -424
  109. data/ext/tb_client/tigerbeetle/src/lsm/cache_map_fuzz.zig +0 -420
  110. data/ext/tb_client/tigerbeetle/src/lsm/compaction.zig +0 -2114
  111. data/ext/tb_client/tigerbeetle/src/lsm/composite_key.zig +0 -185
  112. data/ext/tb_client/tigerbeetle/src/lsm/forest.zig +0 -1146
  113. data/ext/tb_client/tigerbeetle/src/lsm/forest_fuzz.zig +0 -1102
  114. data/ext/tb_client/tigerbeetle/src/lsm/forest_table_iterator.zig +0 -200
  115. data/ext/tb_client/tigerbeetle/src/lsm/groove.zig +0 -1495
  116. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge.zig +0 -739
  117. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge_benchmark.zig +0 -166
  118. data/ext/tb_client/tigerbeetle/src/lsm/manifest.zig +0 -754
  119. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level.zig +0 -1294
  120. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level_fuzz.zig +0 -510
  121. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log.zig +0 -1241
  122. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log_fuzz.zig +0 -628
  123. data/ext/tb_client/tigerbeetle/src/lsm/node_pool.zig +0 -247
  124. data/ext/tb_client/tigerbeetle/src/lsm/scan_buffer.zig +0 -116
  125. data/ext/tb_client/tigerbeetle/src/lsm/scan_builder.zig +0 -543
  126. data/ext/tb_client/tigerbeetle/src/lsm/scan_fuzz.zig +0 -938
  127. data/ext/tb_client/tigerbeetle/src/lsm/scan_lookup.zig +0 -293
  128. data/ext/tb_client/tigerbeetle/src/lsm/scan_merge.zig +0 -359
  129. data/ext/tb_client/tigerbeetle/src/lsm/scan_range.zig +0 -99
  130. data/ext/tb_client/tigerbeetle/src/lsm/scan_state.zig +0 -17
  131. data/ext/tb_client/tigerbeetle/src/lsm/scan_tree.zig +0 -962
  132. data/ext/tb_client/tigerbeetle/src/lsm/schema.zig +0 -617
  133. data/ext/tb_client/tigerbeetle/src/lsm/scratch_memory.zig +0 -84
  134. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array.zig +0 -1500
  135. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_benchmark.zig +0 -149
  136. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_fuzz.zig +0 -7
  137. data/ext/tb_client/tigerbeetle/src/lsm/set_associative_cache.zig +0 -865
  138. data/ext/tb_client/tigerbeetle/src/lsm/table.zig +0 -607
  139. data/ext/tb_client/tigerbeetle/src/lsm/table_memory.zig +0 -843
  140. data/ext/tb_client/tigerbeetle/src/lsm/table_value_iterator.zig +0 -90
  141. data/ext/tb_client/tigerbeetle/src/lsm/timestamp_range.zig +0 -40
  142. data/ext/tb_client/tigerbeetle/src/lsm/tree.zig +0 -629
  143. data/ext/tb_client/tigerbeetle/src/lsm/tree_fuzz.zig +0 -933
  144. data/ext/tb_client/tigerbeetle/src/lsm/zig_zag_merge.zig +0 -534
  145. data/ext/tb_client/tigerbeetle/src/message_buffer.zig +0 -469
  146. data/ext/tb_client/tigerbeetle/src/message_bus.zig +0 -1219
  147. data/ext/tb_client/tigerbeetle/src/message_bus_fuzz.zig +0 -936
  148. data/ext/tb_client/tigerbeetle/src/message_pool.zig +0 -343
  149. data/ext/tb_client/tigerbeetle/src/multiversion.zig +0 -2195
  150. data/ext/tb_client/tigerbeetle/src/queue.zig +0 -390
  151. data/ext/tb_client/tigerbeetle/src/repl/completion.zig +0 -201
  152. data/ext/tb_client/tigerbeetle/src/repl/parser.zig +0 -1356
  153. data/ext/tb_client/tigerbeetle/src/repl/terminal.zig +0 -496
  154. data/ext/tb_client/tigerbeetle/src/repl.zig +0 -1034
  155. data/ext/tb_client/tigerbeetle/src/scripts/amqp.zig +0 -973
  156. data/ext/tb_client/tigerbeetle/src/scripts/cfo.zig +0 -1866
  157. data/ext/tb_client/tigerbeetle/src/scripts/changelog.zig +0 -304
  158. data/ext/tb_client/tigerbeetle/src/scripts/ci.zig +0 -227
  159. data/ext/tb_client/tigerbeetle/src/scripts/client_readmes.zig +0 -658
  160. data/ext/tb_client/tigerbeetle/src/scripts/devhub.zig +0 -466
  161. data/ext/tb_client/tigerbeetle/src/scripts/release.zig +0 -1058
  162. data/ext/tb_client/tigerbeetle/src/scripts.zig +0 -105
  163. data/ext/tb_client/tigerbeetle/src/shell.zig +0 -1195
  164. data/ext/tb_client/tigerbeetle/src/stack.zig +0 -260
  165. data/ext/tb_client/tigerbeetle/src/state_machine/auditor.zig +0 -911
  166. data/ext/tb_client/tigerbeetle/src/state_machine/workload.zig +0 -2079
  167. data/ext/tb_client/tigerbeetle/src/state_machine.zig +0 -4872
  168. data/ext/tb_client/tigerbeetle/src/state_machine_fuzz.zig +0 -288
  169. data/ext/tb_client/tigerbeetle/src/state_machine_tests.zig +0 -3128
  170. data/ext/tb_client/tigerbeetle/src/static_allocator.zig +0 -82
  171. data/ext/tb_client/tigerbeetle/src/stdx/bit_set.zig +0 -157
  172. data/ext/tb_client/tigerbeetle/src/stdx/bounded_array.zig +0 -292
  173. data/ext/tb_client/tigerbeetle/src/stdx/debug.zig +0 -65
  174. data/ext/tb_client/tigerbeetle/src/stdx/flags.zig +0 -1414
  175. data/ext/tb_client/tigerbeetle/src/stdx/huge_page_allocator.zig +0 -115
  176. data/ext/tb_client/tigerbeetle/src/stdx/mlock.zig +0 -92
  177. data/ext/tb_client/tigerbeetle/src/stdx/prng.zig +0 -677
  178. data/ext/tb_client/tigerbeetle/src/stdx/radix.zig +0 -336
  179. data/ext/tb_client/tigerbeetle/src/stdx/ring_buffer.zig +0 -511
  180. data/ext/tb_client/tigerbeetle/src/stdx/sort_test.zig +0 -112
  181. data/ext/tb_client/tigerbeetle/src/stdx/stdx.zig +0 -1163
  182. data/ext/tb_client/tigerbeetle/src/stdx/testing/low_level_hash_vectors.zig +0 -142
  183. data/ext/tb_client/tigerbeetle/src/stdx/testing/snaptest.zig +0 -361
  184. data/ext/tb_client/tigerbeetle/src/stdx/time_units.zig +0 -275
  185. data/ext/tb_client/tigerbeetle/src/stdx/unshare.zig +0 -295
  186. data/ext/tb_client/tigerbeetle/src/stdx/vendored/aegis.zig +0 -436
  187. data/ext/tb_client/tigerbeetle/src/stdx/windows.zig +0 -48
  188. data/ext/tb_client/tigerbeetle/src/stdx/zipfian.zig +0 -402
  189. data/ext/tb_client/tigerbeetle/src/storage.zig +0 -489
  190. data/ext/tb_client/tigerbeetle/src/storage_fuzz.zig +0 -180
  191. data/ext/tb_client/tigerbeetle/src/testing/bench.zig +0 -146
  192. data/ext/tb_client/tigerbeetle/src/testing/cluster/grid_checker.zig +0 -53
  193. data/ext/tb_client/tigerbeetle/src/testing/cluster/journal_checker.zig +0 -61
  194. data/ext/tb_client/tigerbeetle/src/testing/cluster/manifest_checker.zig +0 -76
  195. data/ext/tb_client/tigerbeetle/src/testing/cluster/message_bus.zig +0 -110
  196. data/ext/tb_client/tigerbeetle/src/testing/cluster/network.zig +0 -412
  197. data/ext/tb_client/tigerbeetle/src/testing/cluster/state_checker.zig +0 -331
  198. data/ext/tb_client/tigerbeetle/src/testing/cluster/storage_checker.zig +0 -458
  199. data/ext/tb_client/tigerbeetle/src/testing/cluster.zig +0 -1198
  200. data/ext/tb_client/tigerbeetle/src/testing/exhaustigen.zig +0 -128
  201. data/ext/tb_client/tigerbeetle/src/testing/fixtures.zig +0 -181
  202. data/ext/tb_client/tigerbeetle/src/testing/fuzz.zig +0 -144
  203. data/ext/tb_client/tigerbeetle/src/testing/id.zig +0 -97
  204. data/ext/tb_client/tigerbeetle/src/testing/io.zig +0 -317
  205. data/ext/tb_client/tigerbeetle/src/testing/marks.zig +0 -126
  206. data/ext/tb_client/tigerbeetle/src/testing/packet_simulator.zig +0 -533
  207. data/ext/tb_client/tigerbeetle/src/testing/reply_sequence.zig +0 -154
  208. data/ext/tb_client/tigerbeetle/src/testing/state_machine.zig +0 -389
  209. data/ext/tb_client/tigerbeetle/src/testing/storage.zig +0 -1247
  210. data/ext/tb_client/tigerbeetle/src/testing/table.zig +0 -249
  211. data/ext/tb_client/tigerbeetle/src/testing/time.zig +0 -98
  212. data/ext/tb_client/tigerbeetle/src/testing/tmp_tigerbeetle.zig +0 -212
  213. data/ext/tb_client/tigerbeetle/src/testing/vortex/constants.zig +0 -26
  214. data/ext/tb_client/tigerbeetle/src/testing/vortex/faulty_network.zig +0 -579
  215. data/ext/tb_client/tigerbeetle/src/testing/vortex/java_driver/ci.zig +0 -39
  216. data/ext/tb_client/tigerbeetle/src/testing/vortex/logged_process.zig +0 -214
  217. data/ext/tb_client/tigerbeetle/src/testing/vortex/rust_driver/ci.zig +0 -34
  218. data/ext/tb_client/tigerbeetle/src/testing/vortex/supervisor.zig +0 -785
  219. data/ext/tb_client/tigerbeetle/src/testing/vortex/workload.zig +0 -543
  220. data/ext/tb_client/tigerbeetle/src/testing/vortex/zig_driver.zig +0 -181
  221. data/ext/tb_client/tigerbeetle/src/tidy.zig +0 -1449
  222. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_driver.zig +0 -227
  223. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_load.zig +0 -1069
  224. data/ext/tb_client/tigerbeetle/src/tigerbeetle/cli.zig +0 -1422
  225. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect.zig +0 -1658
  226. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect_integrity.zig +0 -518
  227. data/ext/tb_client/tigerbeetle/src/tigerbeetle/libtb_client.zig +0 -36
  228. data/ext/tb_client/tigerbeetle/src/tigerbeetle/main.zig +0 -646
  229. data/ext/tb_client/tigerbeetle/src/tigerbeetle.zig +0 -958
  230. data/ext/tb_client/tigerbeetle/src/time.zig +0 -236
  231. data/ext/tb_client/tigerbeetle/src/trace/event.zig +0 -745
  232. data/ext/tb_client/tigerbeetle/src/trace/statsd.zig +0 -462
  233. data/ext/tb_client/tigerbeetle/src/trace.zig +0 -556
  234. data/ext/tb_client/tigerbeetle/src/unit_tests.zig +0 -321
  235. data/ext/tb_client/tigerbeetle/src/vopr.zig +0 -1785
  236. data/ext/tb_client/tigerbeetle/src/vortex.zig +0 -101
  237. data/ext/tb_client/tigerbeetle/src/vsr/checkpoint_trailer.zig +0 -473
  238. data/ext/tb_client/tigerbeetle/src/vsr/checksum.zig +0 -208
  239. data/ext/tb_client/tigerbeetle/src/vsr/checksum_benchmark.zig +0 -43
  240. data/ext/tb_client/tigerbeetle/src/vsr/client.zig +0 -768
  241. data/ext/tb_client/tigerbeetle/src/vsr/client_replies.zig +0 -532
  242. data/ext/tb_client/tigerbeetle/src/vsr/client_sessions.zig +0 -338
  243. data/ext/tb_client/tigerbeetle/src/vsr/clock.zig +0 -1019
  244. data/ext/tb_client/tigerbeetle/src/vsr/fault_detector.zig +0 -279
  245. data/ext/tb_client/tigerbeetle/src/vsr/free_set.zig +0 -1381
  246. data/ext/tb_client/tigerbeetle/src/vsr/free_set_fuzz.zig +0 -315
  247. data/ext/tb_client/tigerbeetle/src/vsr/grid.zig +0 -1460
  248. data/ext/tb_client/tigerbeetle/src/vsr/grid_blocks_missing.zig +0 -757
  249. data/ext/tb_client/tigerbeetle/src/vsr/grid_scrubber.zig +0 -797
  250. data/ext/tb_client/tigerbeetle/src/vsr/journal.zig +0 -2586
  251. data/ext/tb_client/tigerbeetle/src/vsr/marzullo.zig +0 -308
  252. data/ext/tb_client/tigerbeetle/src/vsr/message_header.zig +0 -1777
  253. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch.zig +0 -715
  254. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch_fuzz.zig +0 -185
  255. data/ext/tb_client/tigerbeetle/src/vsr/repair_budget.zig +0 -333
  256. data/ext/tb_client/tigerbeetle/src/vsr/replica.zig +0 -12356
  257. data/ext/tb_client/tigerbeetle/src/vsr/replica_format.zig +0 -416
  258. data/ext/tb_client/tigerbeetle/src/vsr/replica_reformat.zig +0 -165
  259. data/ext/tb_client/tigerbeetle/src/vsr/replica_test.zig +0 -2928
  260. data/ext/tb_client/tigerbeetle/src/vsr/routing.zig +0 -1075
  261. data/ext/tb_client/tigerbeetle/src/vsr/superblock.zig +0 -1603
  262. data/ext/tb_client/tigerbeetle/src/vsr/superblock_fuzz.zig +0 -484
  263. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums.zig +0 -405
  264. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +0 -355
  265. data/ext/tb_client/tigerbeetle/src/vsr/sync.zig +0 -29
  266. data/ext/tb_client/tigerbeetle/src/vsr.zig +0 -1727
  267. data/lib/tb_client/shared_lib.rb +0 -66
  268. data/lib/tb_client.rb +0 -282
  269. data/lib/tigerbeetle/account.rb +0 -38
  270. data/lib/tigerbeetle/account_balance.rb +0 -23
  271. data/lib/tigerbeetle/account_filter.rb +0 -31
  272. data/lib/tigerbeetle/atomic_counter.rb +0 -14
  273. data/lib/tigerbeetle/client.rb +0 -214
  274. data/lib/tigerbeetle/converters/account.rb +0 -63
  275. data/lib/tigerbeetle/converters/account_balance.rb +0 -31
  276. data/lib/tigerbeetle/converters/account_filter.rb +0 -32
  277. data/lib/tigerbeetle/converters/base.rb +0 -35
  278. data/lib/tigerbeetle/converters/create_accounts_result.rb +0 -21
  279. data/lib/tigerbeetle/converters/create_transfers_result.rb +0 -21
  280. data/lib/tigerbeetle/converters/query_filter.rb +0 -33
  281. data/lib/tigerbeetle/converters/time.rb +0 -23
  282. data/lib/tigerbeetle/converters/transfer.rb +0 -64
  283. data/lib/tigerbeetle/converters/uint_128.rb +0 -24
  284. data/lib/tigerbeetle/converters.rb +0 -12
  285. data/lib/tigerbeetle/error.rb +0 -4
  286. data/lib/tigerbeetle/id.rb +0 -30
  287. data/lib/tigerbeetle/platforms.rb +0 -9
  288. data/lib/tigerbeetle/query_filter.rb +0 -31
  289. data/lib/tigerbeetle/request.rb +0 -7
  290. data/lib/tigerbeetle/transfer.rb +0 -40
  291. data/lib/tigerbeetle/version.rb +0 -4
  292. data/lib/tigerbeetle.rb +0 -13
  293. data/tigerbeetle.gemspec +0 -60
@@ -1,1283 +0,0 @@
1
- ///! Implements the AMQP (Advanced Message Queuing Protocol) 0.9.1 wire protocol.
2
- ///! https://www.amqp.org/sites/amqp.org/files/amqp0-9-1.zip
3
- ///!
4
- ///! The `Frame` is the basic unit of the AMQP protocol. Its minimum size is
5
- ///! 8 bytes, and the maximum size can be negotiated between the client and server.
6
- ///!
7
- ///! # Frame layout:
8
- ///! ┌────────┬──────────┬────────┐ ┌───────────────┐ ┌───────┐
9
- ///! │ type │ channel │ size │ │ payload │ │ 0xCE │
10
- ///! │ u8 │ u16 │ u32 │ │ variable size │ │ u8 │
11
- ///! └────────┴──────────┴────────┘ └───────────────┘ └───────┘
12
- ///! There are four frame types: "method", "header", "body", and "heartbeat".
13
- ///! Each frame type (except by heartbeat) has different types of payloads.
14
- ///!
15
- ///! # Method payload:
16
- ///! ┌──────────┬───────────┬─────────────────┐
17
- ///! │ class_id │ method_id │ arguments │
18
- ///! │ u16 │ u16 │ variable size │
19
- ///! └──────────┴───────────┴─────────────────┘
20
- ///! The `spec.zig` file contains declarations for all methods defined by the
21
- ///! specification and their expected arguments.
22
- ///!
23
- ///! # Header payload:
24
- ///! ┌──────────┬────────┬────────────┬────────────────┬─────────────────┐
25
- ///! │ class_id │ weight │ body_size │ property_flags │ properties │
26
- ///! │ u16 │ u16 │ u64 │ u16 │ variable size │
27
- ///! └──────────┴────────┴────────────┴────────────────┴─────────────────┘
28
- ///! Certain "method" frames are followed by a "header" frame. For example, in the `basic-publish`
29
- ///! method, the content header contains metadata about the message being published. The frame with
30
- ///! `type == header` always follows its corresponding `type == method` frame.
31
- ///! See `BasicProperties` for parsing the `property_flags` and `properties`.
32
- ///!
33
- ///! # Body payload:
34
- ///! ┌───────────────┐
35
- ///! │ content │
36
- ///! │ variable size │
37
- ///! └───────────────┘
38
- ///! The body frame contains the application-specific content of the message.
39
- ///! The body can be split across multiple frames if `body_size` exceeds the frame size, however we
40
- ///! only support single-frame bodies.
41
- ///!
42
- ///! # Endianness:
43
- ///! Integers are encoded in network byte order (big endian).
44
- ///!
45
- const std = @import("std");
46
- const stdx = @import("stdx");
47
- const assert = std.debug.assert;
48
- const maybe = stdx.maybe;
49
- const KiB = stdx.KiB;
50
-
51
- const spec = @import("spec.zig");
52
-
53
- pub const frame_min_size = spec.FRAME_MIN_SIZE;
54
- pub const tcp_port_default = 5672;
55
-
56
- /// The major, minor, and revision numbers can take any value from 0 to 99 for official
57
- /// specifications.
58
- /// Major, minor, and revision numbers of 100 and above are reserved for internal testing
59
- /// and development purposes.
60
- pub const version = .{
61
- .major = 0,
62
- .minor = 9,
63
- .revision = 1,
64
- };
65
-
66
- /// The protocol header consists of the upper case letters "AMQP"
67
- /// followed by the constant 0 and the AMQP version number.
68
- pub const protocol_header: *const [8]u8 = "AMQP" ++ [_]u8{
69
- 0,
70
- version.major,
71
- version.minor,
72
- version.revision,
73
- };
74
-
75
- pub const DeliveryMode = enum(u8) {
76
- transient = 1,
77
- persistent = 2,
78
- };
79
-
80
- pub const FrameEnd = enum(u8) {
81
- value = spec.FRAME_END,
82
- };
83
-
84
- pub const FrameType = enum(u8) {
85
- method = spec.FRAME_METHOD,
86
- header = spec.FRAME_HEADER,
87
- body = spec.FRAME_BODY,
88
- heartbeat = spec.FRAME_HEARTBEAT,
89
- };
90
-
91
- pub const MethodHeader = packed struct(u32) {
92
- class: u16,
93
- method: u16,
94
- };
95
-
96
- pub const Channel = enum(u16) {
97
- /// The channel number is 0 for all frames which are global to the connection.
98
- global = 0,
99
- /// Id of the current channel.
100
- /// Supporting multiple channels is unnecessary, as messages are submitted in batches
101
- /// through io_uring without concurrency.
102
- current = 1,
103
- };
104
-
105
- pub const ErrorCodes = enum(u16) {
106
- /// The client attempted to transfer content larger than the server could accept
107
- /// at the present time. The client may retry at a later time.
108
- ContentTooLarge = spec.SOFT_ERROR_CONTENT_TOO_LARGE,
109
- /// Returned when RabbitMQ sends back with 'basic.return' when a
110
- /// 'mandatory' message cannot be delivered to any queue.
111
- NoRoute = spec.SOFT_ERROR_NO_ROUTE,
112
- /// When the exchange cannot deliver to a consumer when the immediate flag is
113
- /// set. As a result of pending data on the queue or the absence of any
114
- /// consumers of the queue.
115
- NoConsumers = spec.SOFT_ERROR_NO_CONSUMERS,
116
- /// The client attempted to work with a server entity to which it has no
117
- /// access due to security settings.
118
- AccessRefused = spec.SOFT_ERROR_ACCESS_REFUSED,
119
- /// The client attempted to work with a server entity that does not exist.
120
- NotFound = spec.SOFT_ERROR_NOT_FOUND,
121
- /// The client attempted to work with a server entity to which it has no
122
- /// access because another client is working with it.
123
- ResourceLocked = spec.SOFT_ERROR_RESOURCE_LOCKED,
124
- /// The client requested a method that was not allowed because some precondition
125
- /// failed.
126
- PreconditionFailed = spec.SOFT_ERROR_PRECONDITION_FAILED,
127
- /// An operator intervened to close the connection for some reason. The client
128
- /// may retry at some later date.
129
- ConnectionForced = spec.HARD_ERROR_CONNECTION_FORCED,
130
- /// The client tried to work with an unknown virtual host.
131
- InvalidPath = spec.HARD_ERROR_INVALID_PATH,
132
- /// The sender sent a malformed frame that the recipient could not decode.
133
- /// This strongly implies a programming error in the sending peer.
134
- FrameError = spec.HARD_ERROR_FRAME_ERROR,
135
- /// The sender sent a frame that contained illegal values for one or more
136
- /// fields. This strongly implies a programming error in the sending peer.
137
- SyntaxError = spec.HARD_ERROR_SYNTAX_ERROR,
138
- /// The client sent an invalid sequence of frames, attempting to perform an
139
- /// operation that was considered invalid by the server. This usually implies
140
- /// a programming error in the client.
141
- CommandInvalid = spec.HARD_ERROR_COMMAND_INVALID,
142
- /// The client attempted to work with a channel that had not been correctly
143
- /// opened. This most likely indicates a fault in the client layer.
144
- ChannelError = spec.HARD_ERROR_CHANNEL_ERROR,
145
- /// The peer sent a frame that was not expected, usually in the context of
146
- /// a content header and body. This strongly indicates a fault in the peer's
147
- /// content processing.
148
- UnexpectedFrame = spec.HARD_ERROR_UNEXPECTED_FRAME,
149
- /// The server could not complete the method because it lacked sufficient
150
- /// resources. This may be due to the client creating too many of some type
151
- /// of entity.
152
- ResourceError = spec.HARD_ERROR_RESOURCE_ERROR,
153
- /// The client tried to work with some entity in a manner that is prohibited
154
- /// by the server, due to security settings or by some other criteria.
155
- NotAllowed = spec.HARD_ERROR_NOT_ALLOWED,
156
- /// The client tried to use functionality that is not implemented in the
157
- /// server.
158
- NotImplemented = spec.HARD_ERROR_NOT_IMPLEMENTED,
159
- /// The server could not complete the method because of an internal error.
160
- /// The server may require intervention by an operator in order to resume
161
- /// normal operations.
162
- InternalError = spec.HARD_ERROR_INTERNAL_ERROR,
163
-
164
- _,
165
- };
166
-
167
- pub const FieldValueTag = enum(u8) {
168
- boolean = 't',
169
- uint8 = 'B',
170
- int8 = 'b',
171
- uint16 = 'u',
172
- int16 = 's',
173
- uint32 = 'i',
174
- int32 = 'I',
175
- // Both `l` and `L` are decoded as signed integers by RabbitMQ:
176
- // https://www.rabbitmq.com/amqp-0-9-1-errata#section_3
177
- // https://github.com/rabbitmq/rabbitmq-server/issues/1093#issuecomment-276351183
178
- int64 = 'l',
179
- string = 'S',
180
- timestamp = 'T',
181
- field_table = 'F',
182
- void = 'V',
183
-
184
- // We don't send or expect to receive these types from the AMQP server.
185
- // Only user-defined tables would use them.
186
- not_implemented_uint64 = 'L',
187
- not_implemented_field_array = 'A',
188
- not_implemented_float = 'f',
189
- not_implemented_double = 'd',
190
- not_implemented_decimal = 'D',
191
- not_implemented_byte_array = 'x',
192
- };
193
-
194
- pub const Decoder = struct {
195
- pub const Error = error{
196
- BufferExhausted,
197
- Unexpected,
198
- };
199
-
200
- pub const FrameHeader = extern struct {
201
- type: FrameType,
202
- channel: Channel,
203
- size: u32,
204
- };
205
-
206
- pub const Header = struct {
207
- class: u16,
208
- weight: u16,
209
- body_size: u64,
210
- property_flags: u16,
211
- properties: []const u8,
212
- };
213
-
214
- pub const BasicProperties = BasicPropertiesType(.decode);
215
-
216
- /// `FieldValue` represents a `tag` + `value` pair as specified by the AMQP spec.
217
- pub const FieldValue = FieldValueType(.decode);
218
-
219
- /// Allows iteration over the contents of an AMQP table read from the receive buffer.
220
- pub const Table = struct {
221
- pub const Iterator = struct {
222
- decoder: Decoder,
223
-
224
- pub fn reset(self: *Iterator) void {
225
- self.decoder.reset();
226
- }
227
-
228
- pub fn next(self: *Iterator) Decoder.Error!?struct {
229
- key: []const u8,
230
- value: FieldValue,
231
- } {
232
- if (self.decoder.empty()) return null;
233
- return .{
234
- .key = try self.decoder.read_short_string(),
235
- .value = try self.decoder.read_field(),
236
- };
237
- }
238
- };
239
-
240
- length: u32,
241
- pointer: [*]const u8,
242
-
243
- pub fn init(value: []const u8) Table {
244
- assert(value.len <= std.math.maxInt(u32));
245
- return .{
246
- .length = @intCast(value.len),
247
- .pointer = value.ptr,
248
- };
249
- }
250
-
251
- pub fn slice(self: Table) []const u8 {
252
- return self.pointer[0..self.length];
253
- }
254
-
255
- pub fn iterator(self: Table) Iterator {
256
- return .{
257
- .decoder = Decoder.init(self.slice()),
258
- };
259
- }
260
- };
261
-
262
- buffer: []const u8,
263
- /// Invariants: index <= buffer.len
264
- index: usize,
265
-
266
- pub fn init(buffer: []const u8) Decoder {
267
- return .{
268
- .buffer = buffer,
269
- .index = 0,
270
- };
271
- }
272
-
273
- pub fn empty(self: *const Decoder) bool {
274
- return self.index == self.buffer.len;
275
- }
276
-
277
- pub fn read_int(self: *Decoder, comptime T: type) Error!T {
278
- comptime assert(@typeInfo(T) == .int);
279
- comptime assert(@typeInfo(T).int.signedness == .unsigned);
280
- comptime assert(@sizeOf(T) == 1 or @sizeOf(T) == 2 or @sizeOf(T) == 4 or @sizeOf(T) == 8);
281
- if (self.index + @sizeOf(T) > self.buffer.len) return error.BufferExhausted;
282
- defer {
283
- self.index += @sizeOf(T);
284
- assert(self.index <= self.buffer.len);
285
- }
286
-
287
- return std.mem.readInt(T, self.buffer[self.index..][0..@sizeOf(T)], .big);
288
- }
289
-
290
- pub fn read_enum(self: *Decoder, comptime Enum: type) Error!Enum {
291
- comptime assert(@typeInfo(Enum) == .@"enum");
292
- const Int = std.meta.Tag(Enum);
293
- const value = try self.read_int(Int);
294
- return std.meta.intToEnum(
295
- Enum,
296
- value,
297
- ) catch |err| switch (err) {
298
- error.InvalidEnumTag => return error.Unexpected,
299
- };
300
- }
301
-
302
- pub fn read_bool(self: *Decoder) Error!bool {
303
- const value = try self.read_int(u8);
304
- return value != 0;
305
- }
306
-
307
- pub fn read_short_string(self: *Decoder) Error![]const u8 {
308
- const length: u8 = try self.read_int(u8);
309
- return try self.read_bytes(length);
310
- }
311
-
312
- pub fn read_long_string(self: *Decoder) Error![]const u8 {
313
- const length: u32 = try self.read_int(u32);
314
- return try self.read_bytes(length);
315
- }
316
-
317
- pub fn read_table(self: *Decoder) Error!Table {
318
- const length: u32 = try self.read_int(u32);
319
- const bytes = try self.read_bytes(length);
320
- return Table.init(bytes);
321
- }
322
-
323
- fn read_bytes(self: *Decoder, length: u32) Error![]const u8 {
324
- assert(self.index <= self.buffer.len);
325
- if (self.index + length > self.buffer.len) return error.BufferExhausted;
326
- defer {
327
- self.index += length;
328
- assert(self.index <= self.buffer.len);
329
- }
330
-
331
- return self.buffer[self.index..][0..length];
332
- }
333
-
334
- pub fn read_field(self: *Decoder) Error!FieldValue {
335
- const tag = try self.read_enum(FieldValueTag);
336
- const value: FieldValue = switch (tag) {
337
- .boolean => .{ .boolean = try self.read_bool() },
338
- .uint8 => .{ .uint8 = try self.read_int(u8) },
339
- .int8 => .{ .int8 = @bitCast(try self.read_int(u8)) },
340
- .uint16 => .{ .uint16 = try self.read_int(u16) },
341
- .int16 => .{ .int16 = @bitCast(try self.read_int(u16)) },
342
- .uint32 => .{ .uint32 = try self.read_int(u32) },
343
- .int32 => .{ .int32 = @bitCast(try self.read_int(u32)) },
344
- .int64 => .{ .int64 = @bitCast(try self.read_int(u64)) },
345
- .string => .{ .string = try self.read_long_string() },
346
- .timestamp => .{ .timestamp = try self.read_int(u64) },
347
- .field_table => .{ .field_table = try self.read_table() },
348
- .void => .void,
349
-
350
- .not_implemented_uint64,
351
- .not_implemented_field_array,
352
- .not_implemented_float,
353
- .not_implemented_double,
354
- .not_implemented_decimal,
355
- .not_implemented_byte_array,
356
- => fatal("AMQP type '{c}' not supported.", .{@intFromEnum(tag)}),
357
- };
358
- assert(value == tag);
359
- return value;
360
- }
361
-
362
- pub fn read_frame_header(self: *Decoder) Error!FrameHeader {
363
- return .{
364
- .type = try self.read_enum(FrameType),
365
- .channel = try self.read_enum(Channel),
366
- .size = try self.read_int(u32),
367
- };
368
- }
369
-
370
- pub fn read_frame_end(self: *Decoder) Error!void {
371
- _ = try self.read_enum(FrameEnd);
372
- }
373
-
374
- pub fn read_method_header(self: *Decoder) Error!MethodHeader {
375
- return .{
376
- .class = try self.read_int(u16),
377
- .method = try self.read_int(u16),
378
- };
379
- }
380
-
381
- pub fn read_header(self: *Decoder, frame_size: usize) Error!Header {
382
- const initial_index = self.index;
383
-
384
- const class = try self.read_int(u16);
385
- const weight = try self.read_int(u16);
386
- const body_size = try self.read_int(u64);
387
- const property_flags = try self.read_int(u16);
388
-
389
- if (initial_index + frame_size > self.buffer.len) return error.BufferExhausted;
390
- const properties = self.buffer[self.index .. initial_index + frame_size];
391
- self.index += properties.len;
392
-
393
- try self.read_frame_end();
394
-
395
- return .{
396
- .class = class,
397
- .weight = weight,
398
- .body_size = body_size,
399
- .property_flags = @bitCast(property_flags),
400
- .properties = properties,
401
- };
402
- }
403
-
404
- pub fn read_body(self: *Decoder, frame_size: usize) Error![]const u8 {
405
- if (self.index + frame_size > self.buffer.len) return error.BufferExhausted;
406
- const body = self.buffer[self.index..][0..frame_size];
407
- self.index += frame_size;
408
- assert(self.index <= self.buffer.len);
409
- try self.read_frame_end();
410
- return body;
411
- }
412
- };
413
-
414
- pub const Encoder = struct {
415
- pub const FrameHeader = struct {
416
- /// Total size in bytes including the `size` field.
417
- pub const size_total = @sizeOf(@FieldType(Decoder.FrameHeader, "type")) +
418
- @sizeOf(@FieldType(Decoder.FrameHeader, "channel")) +
419
- @sizeOf(@FieldType(Decoder.FrameHeader, "size"));
420
-
421
- type: FrameType,
422
- channel: Channel,
423
- };
424
-
425
- pub const Header = struct {
426
- /// Total size in bytes including the `body_size` field.
427
- pub const size_total = @sizeOf(@FieldType(Decoder.Header, "class")) +
428
- @sizeOf(@FieldType(Decoder.Header, "weight")) +
429
- @sizeOf(@FieldType(Decoder.Header, "body_size"));
430
-
431
- class: u16,
432
- weight: u16,
433
- };
434
-
435
- pub const BasicProperties = BasicPropertiesType(.encode);
436
-
437
- /// `FieldValue` represents a `tag` + `value` pair as specified by the AMQP spec.
438
- pub const FieldValue = FieldValueType(.encode);
439
-
440
- /// Interface for a user-defined set of values to be encoded as an AMQP table
441
- /// directly into the send buffer without copying.
442
- pub const Table = struct {
443
- pub const VTable = struct {
444
- write: *const fn (*const anyopaque, *TableEncoder) void,
445
- };
446
-
447
- context: *const anyopaque,
448
- vtable: *const VTable,
449
-
450
- pub fn write(self: Table, encoder: *TableEncoder) void {
451
- self.vtable.write(self.context, encoder);
452
- }
453
- };
454
-
455
- /// Interface for user-defined content to be written directly
456
- /// into the send buffer without copying.
457
- pub const Body = struct {
458
- pub const VTable = struct {
459
- write: *const fn (*const anyopaque, []u8) usize,
460
- };
461
-
462
- context: *const anyopaque,
463
- vtable: *const VTable,
464
-
465
- pub fn write(self: Body, buffer: []u8) usize {
466
- return self.vtable.write(self.context, buffer);
467
- }
468
- };
469
-
470
- pub const TableEncoder = struct {
471
- encoder: *Encoder,
472
-
473
- pub fn put(self: *TableEncoder, key: []const u8, value: FieldValue) void {
474
- self.encoder.write_short_string(key);
475
- self.encoder.write_field(value);
476
- }
477
- };
478
-
479
- buffer: []u8,
480
- index: usize,
481
-
482
- frame_reference: ?struct {
483
- index: usize,
484
- frame_header: FrameHeader,
485
- },
486
- header_reference: ?struct {
487
- index: usize,
488
- header: Header,
489
- },
490
-
491
- pub fn init(buffer: []u8) Encoder {
492
- return .{
493
- .buffer = buffer,
494
- .index = 0,
495
- .frame_reference = null,
496
- .header_reference = null,
497
- };
498
- }
499
-
500
- pub fn write_int(self: *Encoder, comptime T: type, value: T) void {
501
- comptime assert(@typeInfo(T) == .int);
502
- comptime assert(@sizeOf(T) == 1 or @sizeOf(T) == 2 or @sizeOf(T) == 4 or @sizeOf(T) == 8);
503
- assert(self.index + @sizeOf(T) <= self.buffer.len);
504
- std.mem.writeInt(T, self.buffer[self.index..][0..@sizeOf(T)], value, .big);
505
- self.index += @sizeOf(T);
506
- assert(self.index <= self.buffer.len);
507
- }
508
-
509
- pub fn write_bool(self: *Encoder, value: bool) void {
510
- self.write_int(u8, @intFromBool(value));
511
- }
512
-
513
- pub fn write_short_string(self: *Encoder, value: []const u8) void {
514
- assert(value.len <= std.math.maxInt(u8));
515
- self.write_int(u8, @intCast(value.len));
516
- assert(self.index + value.len <= self.buffer.len);
517
- stdx.copy_left(.inexact, u8, self.buffer[self.index..], value);
518
- self.index += value.len;
519
- }
520
-
521
- pub fn write_long_string(self: *Encoder, value: []const u8) void {
522
- assert(value.len <= std.math.maxInt(u32));
523
- self.write_int(u32, @intCast(value.len));
524
- assert(self.index + value.len <= self.buffer.len);
525
- stdx.copy_left(.inexact, u8, self.buffer[self.index..], value);
526
- self.index += value.len;
527
- }
528
-
529
- pub fn write_long_string_body(self: *Encoder, body: ?Body) void {
530
- if (body == null) {
531
- self.write_int(u32, 0); // Zero sized string.
532
- return;
533
- }
534
-
535
- const start_index = self.index;
536
- self.index += @sizeOf(u32);
537
- assert(self.index <= self.buffer.len);
538
-
539
- self.index += body.?.write(self.buffer[self.index..]);
540
- assert(self.index <= self.buffer.len);
541
- const end_index = self.index;
542
-
543
- const size: u32 = @intCast(end_index - start_index - @sizeOf(u32));
544
- self.index = start_index;
545
- self.write_int(u32, size);
546
- self.index = end_index;
547
- }
548
-
549
- pub fn write_table(self: *Encoder, table: ?Table) void {
550
- if (table == null) {
551
- self.write_int(u32, 0); // Zero sized table.
552
- return;
553
- }
554
-
555
- const start_index = self.index;
556
- self.index += @sizeOf(u32);
557
- assert(self.index <= self.buffer.len);
558
-
559
- var table_encoder: TableEncoder = .{ .encoder = self };
560
- table.?.write(&table_encoder);
561
- const end_index = self.index;
562
-
563
- const size: u32 = @intCast(end_index - start_index - @sizeOf(u32));
564
- self.index = start_index;
565
- self.write_int(u32, size);
566
- self.index = end_index;
567
- }
568
-
569
- pub fn write_field(self: *Encoder, field: FieldValue) void {
570
- const tag: FieldValueTag = field;
571
- self.write_int(u8, @intFromEnum(tag));
572
- switch (field) {
573
- .boolean => |value| self.write_bool(value),
574
- .uint8 => |value| self.write_int(u8, value),
575
- .int8 => |value| self.write_int(u8, @bitCast(value)),
576
- .uint16 => |value| self.write_int(u16, value),
577
- .int16 => |value| self.write_int(u16, @bitCast(value)),
578
- .uint32 => |value| self.write_int(u32, value),
579
- .int32 => |value| self.write_int(u32, @bitCast(value)),
580
- .int64 => |value| self.write_int(u64, @bitCast(value)),
581
- .string => |value| self.write_long_string(value),
582
- .timestamp => |value| self.write_int(u64, value),
583
- .field_table => |value| self.write_table(value),
584
- .void => {},
585
-
586
- .not_implemented_uint64,
587
- .not_implemented_field_array,
588
- .not_implemented_float,
589
- .not_implemented_double,
590
- .not_implemented_decimal,
591
- .not_implemented_byte_array,
592
- => fatal("AMQP type '{c}' not supported.", .{@intFromEnum(tag)}),
593
- }
594
- }
595
-
596
- pub fn write_bytes(self: *Encoder, bytes: []const u8) void {
597
- assert(bytes.len > 0);
598
- assert(self.index + bytes.len <= self.buffer.len);
599
- stdx.copy_disjoint(.inexact, u8, self.buffer[self.index..], bytes);
600
- self.index += bytes.len;
601
- assert(self.index <= self.buffer.len);
602
- }
603
-
604
- pub fn begin_frame(self: *Encoder, frame_header: FrameHeader) void {
605
- assert(self.frame_reference == null);
606
- assert(self.header_reference == null or frame_header.type == .body);
607
- // Reserve the frame header bytes to be updated by `finish_frame()`.
608
- assert(self.index + FrameHeader.size_total <= self.buffer.len);
609
- const frame_header_index = self.index;
610
- self.index += FrameHeader.size_total;
611
- self.frame_reference = .{
612
- .index = frame_header_index,
613
- .frame_header = frame_header,
614
- };
615
- }
616
-
617
- pub fn finish_frame(self: *Encoder, frame_type: FrameType) void {
618
- assert(self.frame_reference != null);
619
- assert(self.frame_reference.?.frame_header.type == frame_type);
620
- maybe(self.header_reference == null);
621
-
622
- const reference = self.frame_reference.?;
623
- self.frame_reference = null;
624
- assert(reference.index + FrameHeader.size_total <= self.index);
625
- const restore_index = self.index;
626
- // The frame size field in the FrameHeader must be updated.
627
- // It represents the payload size, excluding the FrameHeader
628
- // and the frame end byte.
629
- const size: u32 = @intCast(restore_index - reference.index - FrameHeader.size_total);
630
- self.index = reference.index;
631
- self.write_int(u8, @intFromEnum(reference.frame_header.type));
632
- self.write_int(u16, @intFromEnum(reference.frame_header.channel));
633
- self.write_int(u32, size);
634
-
635
- self.index = restore_index;
636
- self.write_int(u8, spec.FRAME_END);
637
- }
638
-
639
- pub fn begin_header(self: *Encoder, header: Header) void {
640
- // Reserve the frame header bytes to be updated by `finish_header()`.
641
- assert(self.frame_reference != null);
642
- assert(self.frame_reference.?.frame_header.type == .header);
643
- assert(self.header_reference == null);
644
- const header_index = self.index;
645
- self.index += Header.size_total;
646
- self.header_reference = .{
647
- .header = header,
648
- .index = header_index,
649
- };
650
- }
651
-
652
- pub fn finish_header(self: *Encoder, body_size: u64) void {
653
- assert((body_size == 0) == (self.frame_reference == null));
654
- assert(body_size == 0 or self.frame_reference.?.frame_header.type == .body);
655
- assert(self.header_reference != null);
656
-
657
- const reference = self.header_reference.?;
658
- self.header_reference = null;
659
- assert(reference.index + Header.size_total <= self.index);
660
- const restore_index = self.index;
661
- self.index = reference.index;
662
- self.write_int(u16, reference.header.class);
663
- self.write_int(u16, reference.header.weight);
664
- self.write_int(u64, body_size);
665
- self.index = restore_index;
666
- }
667
-
668
- pub fn write_method_header(self: *Encoder, method_header: MethodHeader) void {
669
- assert(self.frame_reference != null);
670
- assert(self.frame_reference.?.frame_header.type == .method);
671
- assert(self.header_reference == null);
672
- self.write_int(u16, method_header.class);
673
- self.write_int(u16, method_header.method);
674
- }
675
- };
676
-
677
- fn FieldValueType(comptime target: enum { encode, decode }) type {
678
- return union(FieldValueTag) {
679
- boolean: bool,
680
- uint8: u8,
681
- int8: i8,
682
- uint16: u16,
683
- int16: i16,
684
- uint32: u32,
685
- int32: i32,
686
- int64: i64,
687
- string: []const u8,
688
- timestamp: u64,
689
- field_table: switch (target) {
690
- .encode => Encoder.Table,
691
- .decode => Decoder.Table,
692
- },
693
- void,
694
-
695
- not_implemented_uint64,
696
- not_implemented_field_array,
697
- not_implemented_float,
698
- not_implemented_double,
699
- not_implemented_decimal,
700
- not_implemented_byte_array,
701
- };
702
- }
703
-
704
- fn BasicPropertiesType(comptime target: enum { encode, decode }) type {
705
- return struct {
706
- const BasicProperties = @This();
707
-
708
- /// MIME content type of the message payload.
709
- content_type: ?[]const u8 = null,
710
- /// MIME content encoding of the message payload.
711
- content_encoding: ?[]const u8 = null,
712
- /// Application-defined custom headers.
713
- headers: ?switch (target) {
714
- .encode => Encoder.Table,
715
- .decode => Decoder.Table,
716
- } = null,
717
- /// For queues that implement persistence,
718
- /// whether the message will be logged to disk and survive a broker restart.
719
- delivery_mode: ?DeliveryMode = null,
720
- /// Message priority, 0 to 9.
721
- priority: ?u8 = null,
722
- /// Application-defined correlation identifier.
723
- correlation_id: ?[]const u8 = null,
724
- /// Address to reply to.
725
- reply_to: ?[]const u8 = null,
726
- /// Message expiration specification.
727
- expiration: ?[]const u8 = null,
728
- /// Application-defined message identifier.
729
- message_id: ?[]const u8 = null,
730
- /// Message timestamp (UNIX epoch in seconds).
731
- timestamp: ?u64 = null,
732
- /// Application-defined message type name.
733
- type: ?[]const u8 = null,
734
- /// Application-defined creating user id
735
- user_id: ?[]const u8 = null,
736
- /// Application-defined creating application id.
737
- app_id: ?[]const u8 = null,
738
- cluster_id: ?[]const u8 = null,
739
-
740
- fn property_flags(self: *const BasicProperties) u16 {
741
- var bitset: stdx.BitSetType(16) = .{};
742
- inline for (std.meta.fields(BasicProperties), 0..) |field, index| {
743
- bitset.set_value(index, @field(self, field.name) != null);
744
- }
745
- return @bitReverse(bitset.bits);
746
- }
747
-
748
- pub fn decode(flags: u16, content: []const u8) Decoder.Error!BasicProperties {
749
- comptime assert(target == .decode);
750
-
751
- var reader = Decoder.init(content);
752
- var bitset: stdx.BitSetType(16) = .{ .bits = @bitReverse(flags) };
753
- var properties: BasicProperties = .{};
754
- inline for (std.meta.fields(BasicProperties), 0..) |field, index| {
755
- if (bitset.is_set(index)) {
756
- const FieldType = std.meta.Child(field.type);
757
- @field(properties, field.name) = try switch (FieldType) {
758
- []const u8 => reader.read_short_string(),
759
- Decoder.Table => reader.read_table(),
760
- DeliveryMode => reader.read_enum(DeliveryMode),
761
- u64 => reader.read_int(u64),
762
- u8 => reader.read_int(u8),
763
- else => comptime unreachable,
764
- };
765
- }
766
- }
767
- assert(reader.index == content.len);
768
- return properties;
769
- }
770
-
771
- pub fn encode(self: *const BasicProperties, encoder: *Encoder) void {
772
- comptime assert(target == .encode);
773
-
774
- encoder.write_int(u16, self.property_flags());
775
- inline for (std.meta.fields(BasicProperties)) |field| {
776
- if (@field(self, field.name)) |value| {
777
- switch (@TypeOf(value)) {
778
- []const u8 => encoder.write_short_string(value),
779
- Encoder.Table => encoder.write_table(value),
780
- DeliveryMode => encoder.write_int(u8, @intFromEnum(value)),
781
- u64 => encoder.write_int(u64, value),
782
- u8 => encoder.write_int(u8, value),
783
- else => unreachable,
784
- }
785
- }
786
- }
787
- }
788
- };
789
- }
790
-
791
- /// Terminates the process with non-zero exit code.
792
- /// Use fatal when encountering an environmental error.
793
- /// Similar to `vsr.fatal`, but not logged in the `vsr` scope.
794
- pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
795
- const log = std.log.scoped(.amqp);
796
- log.err(format, args);
797
-
798
- const vsr = @import("../../vsr.zig");
799
- const status = vsr.FatalReason.cli.exit_status();
800
- assert(status != 0);
801
- std.process.exit(status);
802
- }
803
-
804
- const testing = std.testing;
805
-
806
- test "amqp: Encoder/Decoder primitives" {
807
- var buffer = try testing.allocator.alloc(u8, frame_min_size);
808
- defer testing.allocator.free(buffer);
809
-
810
- const Primitives = enum {
811
- bool,
812
- uint64,
813
- uint32,
814
- uint16,
815
- uint8,
816
- short_string,
817
- long_string,
818
- };
819
-
820
- var prng = stdx.PRNG.from_seed_testing();
821
- for (0..4096) |_| {
822
- var encoder = Encoder.init(buffer);
823
-
824
- switch (prng.enum_uniform(Primitives)) {
825
- .bool => {
826
- const value = prng.boolean();
827
- encoder.write_bool(value);
828
-
829
- var decoder = Decoder.init(buffer[0..encoder.index]);
830
- try testing.expectEqual(value, try decoder.read_bool());
831
- },
832
- inline .uint64, .uint32, .uint16, .uint8 => |tag| {
833
- const Int = switch (tag) {
834
- .uint64 => u64,
835
- .uint32 => u32,
836
- .uint16 => u16,
837
- .uint8 => u8,
838
- else => comptime unreachable,
839
- };
840
- const value = prng.int(Int);
841
- encoder.write_int(Int, value);
842
-
843
- var decoder = Decoder.init(buffer[0..encoder.index]);
844
- try testing.expectEqual(value, try decoder.read_int(Int));
845
- },
846
- .short_string => {
847
- const size = prng.range_inclusive(u32, 0, 255);
848
- const value = try testing.allocator.alloc(u8, size);
849
- defer testing.allocator.free(value);
850
-
851
- prng.fill(value);
852
- encoder.write_short_string(value);
853
-
854
- var decoder = Decoder.init(buffer[0..encoder.index]);
855
- try testing.expectEqualStrings(value, try decoder.read_short_string());
856
- },
857
- .long_string => {
858
- const size = prng.range_inclusive(u32, 256, frame_min_size - @sizeOf(u32));
859
- const value = try testing.allocator.alloc(u8, size);
860
- defer testing.allocator.free(value);
861
-
862
- prng.fill(value);
863
- encoder.write_long_string(value);
864
-
865
- var decoder = Decoder.init(buffer[0..encoder.index]);
866
- try testing.expectEqualStrings(value, try decoder.read_long_string());
867
- },
868
- }
869
- }
870
- }
871
-
872
- test "amqp: Encoder/Decoder enums" {
873
- var buffer = try testing.allocator.alloc(u8, frame_min_size);
874
- defer testing.allocator.free(buffer);
875
-
876
- const Enum = enum(u8) {
877
- a = 1,
878
- b = 2,
879
- c = 3,
880
- };
881
-
882
- for (std.enums.values(Enum)) |value| {
883
- var encoder: Encoder = Encoder.init(buffer);
884
- encoder.write_int(u8, @intFromEnum(value));
885
-
886
- var decoder: Decoder = Decoder.init(buffer[0..buffer.len]);
887
- try testing.expectEqual(value, try decoder.read_enum(Enum));
888
- }
889
-
890
- // Invalid enum:
891
- var encoder: Encoder = Encoder.init(buffer);
892
- encoder.write_int(u8, 0);
893
-
894
- var decoder: Decoder = Decoder.init(buffer[0..buffer.len]);
895
- try testing.expectError(error.Unexpected, decoder.read_enum(Enum));
896
- }
897
-
898
- test "amqp: BasicProperties property_flags" {
899
- // Sets the field with any value, just to compute the `property_flags`.
900
- const BasicProperties = BasicPropertiesType(.decode);
901
- const set_flag = struct {
902
- fn set_flag(set_field: std.meta.FieldEnum(BasicProperties)) u16 {
903
- var properties: BasicProperties = .{};
904
- switch (set_field) {
905
- inline else => |field| {
906
- const Field = std.meta.Child(@FieldType(BasicProperties, @tagName(field)));
907
- @field(properties, @tagName(field)) = switch (Field) {
908
- []const u8 => "",
909
- DeliveryMode => .persistent,
910
- u8, u64 => 0,
911
- Decoder.Table => Decoder.Table.init(&.{}),
912
- else => comptime unreachable,
913
- };
914
- },
915
- }
916
- return properties.property_flags();
917
- }
918
- }.set_flag;
919
-
920
- const empty: BasicProperties = .{};
921
- try testing.expectEqual(@as(u16, 0x0000), empty.property_flags());
922
-
923
- // The last bit corresponding to the first property (it's big endian).
924
- try testing.expectEqual(@as(u16, 0x8000), set_flag(.content_type));
925
- try testing.expectEqual(@as(u16, 0x4000), set_flag(.content_encoding));
926
- try testing.expectEqual(@as(u16, 0x2000), set_flag(.headers));
927
- try testing.expectEqual(@as(u16, 0x1000), set_flag(.delivery_mode));
928
- try testing.expectEqual(@as(u16, 0x0800), set_flag(.priority));
929
- try testing.expectEqual(@as(u16, 0x0400), set_flag(.correlation_id));
930
- try testing.expectEqual(@as(u16, 0x0200), set_flag(.reply_to));
931
- try testing.expectEqual(@as(u16, 0x0100), set_flag(.expiration));
932
- try testing.expectEqual(@as(u16, 0x0080), set_flag(.message_id));
933
- try testing.expectEqual(@as(u16, 0x0040), set_flag(.timestamp));
934
- try testing.expectEqual(@as(u16, 0x0020), set_flag(.type));
935
- try testing.expectEqual(@as(u16, 0x0010), set_flag(.user_id));
936
- try testing.expectEqual(@as(u16, 0x0008), set_flag(.app_id));
937
- try testing.expectEqual(@as(u16, 0x0004), set_flag(.cluster_id));
938
- }
939
-
940
- test "amqp: BasicProperties encode/decode" {
941
- var buffer = try testing.allocator.alloc(u8, frame_min_size);
942
- defer testing.allocator.free(buffer);
943
-
944
- var prng = stdx.PRNG.from_seed_testing();
945
- for (0..4096) |_| {
946
- var arena = std.heap.ArenaAllocator.init(testing.allocator);
947
- defer arena.deinit();
948
-
949
- const properties = try TestingBasicProperties.random(.{
950
- .arena = arena.allocator(),
951
- .prng = &prng,
952
- });
953
-
954
- var encoder = Encoder.init(buffer);
955
- properties.encode(&encoder);
956
-
957
- // Decoding:
958
- var decoder = Decoder.init(buffer[0..encoder.index]);
959
- const flags = try decoder.read_int(u16);
960
- const properties_decoded = try Decoder.BasicProperties.decode(
961
- flags,
962
- decoder.buffer[decoder.index..],
963
- );
964
- try testing.expect(try TestingBasicProperties.eql(
965
- arena.allocator(),
966
- properties,
967
- properties_decoded,
968
- ));
969
- }
970
- }
971
-
972
- test "amqp: Table encode/decode" {
973
- // 64k ought to be enough for any random!
974
- var buffer = try testing.allocator.alloc(u8, 64 * KiB);
975
- defer testing.allocator.free(buffer);
976
-
977
- var prng = stdx.PRNG.from_seed_testing();
978
- for (0..4096) |_| {
979
- var arena = std.heap.ArenaAllocator.init(testing.allocator);
980
- defer arena.deinit();
981
-
982
- const object = try TestingTable.random(.{
983
- .arena = arena.allocator(),
984
- .prng = &prng,
985
- .recursive = true,
986
- });
987
-
988
- // Encoding the complex object:
989
- var encoder = Encoder.init(buffer);
990
- encoder.write_table(object.table());
991
-
992
- // Decoding:
993
- var decoder = Decoder.init(buffer[0..encoder.index]);
994
- const object_decoded = try TestingTable.from_table(
995
- arena.allocator(),
996
- try decoder.read_table(),
997
- );
998
- try testing.expect(TestingTable.eql(object, object_decoded));
999
- }
1000
- }
1001
-
1002
- test "amqp: frame and header" {
1003
- const Snap = stdx.Snap;
1004
- const snap = Snap.snap_fn("src");
1005
-
1006
- var buffer = try testing.allocator.alloc(u8, frame_min_size);
1007
- defer testing.allocator.free(buffer);
1008
-
1009
- {
1010
- // Method frame.
1011
- var encoder = Encoder.init(buffer);
1012
- encoder.begin_frame(.{ .type = .method, .channel = .global });
1013
- encoder.write_method_header(.{ .class = 1, .method = 10 });
1014
- encoder.finish_frame(.method);
1015
- try snap(@src(),
1016
- \\01 00 00 00 00 00 04 00 01 00 0a ce
1017
- ).diff_hex(buffer[0..encoder.index]);
1018
- }
1019
-
1020
- {
1021
- // Method + header.
1022
- var encoder = Encoder.init(buffer);
1023
- encoder.begin_frame(.{ .type = .method, .channel = .global });
1024
- encoder.write_method_header(.{ .class = 10, .method = 100 });
1025
- encoder.finish_frame(.method);
1026
-
1027
- encoder.begin_frame(.{ .type = .header, .channel = .current });
1028
- encoder.begin_header(.{ .class = 10, .weight = 0 });
1029
- encoder.finish_frame(.header);
1030
- encoder.finish_header(0);
1031
-
1032
- try snap(@src(),
1033
- \\01 00 00 00 00 00 04 00 0a 00 64 ce 02 00 01 00
1034
- \\00 00 0c 00 0a 00 00 00 00 00 00 00 00 00 00 ce
1035
- ).diff_hex(buffer[0..encoder.index]);
1036
- }
1037
-
1038
- {
1039
- // Method + header + body.
1040
- var encoder = Encoder.init(buffer);
1041
- encoder.begin_frame(.{ .type = .method, .channel = .global });
1042
- encoder.write_method_header(.{ .class = 100, .method = 1000 });
1043
- encoder.finish_frame(.method);
1044
-
1045
- encoder.begin_frame(.{ .type = .header, .channel = .current });
1046
- encoder.begin_header(.{ .class = 100, .weight = 0 });
1047
- encoder.finish_frame(.header);
1048
-
1049
- encoder.begin_frame(.{ .type = .body, .channel = .current });
1050
- encoder.write_bytes("body");
1051
- encoder.finish_header("body".len);
1052
- encoder.finish_frame(.body);
1053
-
1054
- try snap(@src(),
1055
- \\01 00 00 00 00 00 04 00 64 03 e8 ce 02 00 01 00
1056
- \\00 00 0c 00 64 00 00 00 00 00 00 00 00 00 04 ce
1057
- \\03 00 01 00 00 00 04 62 6f 64 79 ce
1058
- ).diff_hex(buffer[0..encoder.index]);
1059
- }
1060
- }
1061
-
1062
- const TestingTable = struct {
1063
- const Timestamp = u63;
1064
-
1065
- boolean: ?bool = null,
1066
- string: ?[]const u8 = null,
1067
- int64: ?i64 = null,
1068
- uint32: ?u32 = null,
1069
- int32: ?i32 = null,
1070
- uint16: ?u16 = null,
1071
- int16: ?i16 = null,
1072
- uint8: ?u8 = null,
1073
- int8: ?i8 = null,
1074
- field_table: ?*const TestingTable = null,
1075
- timestamp: ?Timestamp = null,
1076
-
1077
- const empty: TestingTable = .{};
1078
-
1079
- fn table(self: *const TestingTable) Encoder.Table {
1080
- const vtable: Encoder.Table.VTable = comptime .{
1081
- .write = &struct {
1082
- fn write(context: *const anyopaque, encoder: *Encoder.TableEncoder) void {
1083
- const object: *const TestingTable = @ptrCast(@alignCast(context));
1084
- inline for (std.meta.fields(TestingTable)) |field| {
1085
- if (@field(object, field.name)) |value| {
1086
- encoder.put(field.name, switch (std.meta.Child(field.type)) {
1087
- bool => .{ .boolean = value },
1088
- []const u8 => .{ .string = value },
1089
- i64 => .{ .int64 = value },
1090
- u32 => .{ .uint32 = value },
1091
- i32 => .{ .int32 = value },
1092
- u16 => .{ .uint16 = value },
1093
- i16 => .{ .int16 = value },
1094
- u8 => .{ .uint8 = value },
1095
- i8 => .{ .int8 = value },
1096
- *const TestingTable => .{ .field_table = value.table() },
1097
- Timestamp => .{ .timestamp = value },
1098
- else => comptime unreachable,
1099
- });
1100
- }
1101
- }
1102
- }
1103
- }.write,
1104
- };
1105
- return .{ .context = self, .vtable = &vtable };
1106
- }
1107
-
1108
- fn from_table(arena: std.mem.Allocator, decoder: Decoder.Table) !*const TestingTable {
1109
- var object = try arena.create(TestingTable);
1110
- object.* = TestingTable.empty;
1111
-
1112
- var iterator = decoder.iterator();
1113
- while (try iterator.next()) |entry| {
1114
- const FieldEnum = std.meta.FieldEnum(TestingTable);
1115
- const entry_field = std.meta.stringToEnum(FieldEnum, entry.key).?;
1116
- switch (entry_field) {
1117
- inline else => |field| {
1118
- const Field = @FieldType(TestingTable, @tagName(field));
1119
- @field(object, @tagName(field)) = switch (std.meta.Child(Field)) {
1120
- bool => entry.value.boolean,
1121
- []const u8 => entry.value.string,
1122
- i64 => entry.value.int64,
1123
- u32 => entry.value.uint32,
1124
- i32 => entry.value.int32,
1125
- u16 => entry.value.uint16,
1126
- i16 => entry.value.int16,
1127
- u8 => entry.value.uint8,
1128
- i8 => entry.value.int8,
1129
- *const TestingTable => try from_table(arena, entry.value.field_table),
1130
- Timestamp => @intCast(entry.value.timestamp),
1131
- else => comptime unreachable,
1132
- };
1133
- },
1134
- }
1135
- }
1136
- return object;
1137
- }
1138
-
1139
- fn eql(table1: *const TestingTable, table2: *const TestingTable) bool {
1140
- inline for (std.meta.fields(TestingTable)) |field| {
1141
- const both_null = @field(table1, field.name) == null and
1142
- @field(table2, field.name) == null;
1143
- if (!both_null) {
1144
- const value1 = @field(table1, field.name) orelse return false;
1145
- const value2 = @field(table2, field.name) orelse return false;
1146
-
1147
- const equals = switch (std.meta.Child(field.type)) {
1148
- bool => value1 == value2,
1149
- []const u8 => std.mem.eql(u8, value1, value2),
1150
- i64, u32, i32, u16, i16, u8, i8 => value1 == value2,
1151
- *const TestingTable => eql(value1, value2),
1152
- Timestamp => value1 == value2,
1153
- else => comptime unreachable,
1154
- };
1155
- if (!equals) return false;
1156
- }
1157
- }
1158
-
1159
- return true;
1160
- }
1161
-
1162
- fn random(options: struct {
1163
- arena: std.mem.Allocator,
1164
- prng: *stdx.PRNG,
1165
- recursive: bool,
1166
- }) !*const TestingTable {
1167
- const ratio = stdx.PRNG.ratio;
1168
-
1169
- const is_empty = options.prng.chance(ratio(5, 100));
1170
- if (is_empty) return &TestingTable.empty;
1171
-
1172
- var object = try options.arena.create(TestingTable);
1173
- inline for (std.meta.fields(TestingTable)) |field| {
1174
- const is_null = options.prng.chance(ratio(5, 100));
1175
- if (is_null) {
1176
- @field(object, field.name) = null;
1177
- } else switch (std.meta.Child(field.type)) {
1178
- bool => {
1179
- @field(object, field.name) = options.prng.boolean();
1180
- },
1181
- []const u8 => {
1182
- const size = options.prng.range_inclusive(u32, 0, 255);
1183
- const str = try options.arena.alloc(u8, size);
1184
- options.prng.fill(str);
1185
- @field(object, field.name) = str;
1186
- },
1187
- u32, u16, u8 => |Int| {
1188
- @field(object, field.name) = options.prng.int(Int);
1189
- },
1190
- i64, i32, i16, i8 => |Int| {
1191
- const Unsigned = std.meta.Int(.unsigned, @bitSizeOf(Int));
1192
- @field(object, field.name) = @bitCast(options.prng.int(Unsigned));
1193
- },
1194
- *const TestingTable => {
1195
- @field(object, field.name) = if (options.recursive)
1196
- try random(options)
1197
- else
1198
- null;
1199
- },
1200
- Timestamp => {
1201
- @field(object, field.name) = options.prng.int(Timestamp);
1202
- },
1203
- else => comptime unreachable,
1204
- }
1205
- }
1206
- return object;
1207
- }
1208
- };
1209
-
1210
- pub const TestingBasicProperties = struct {
1211
- pub fn random(options: struct {
1212
- arena: std.mem.Allocator,
1213
- prng: *stdx.PRNG,
1214
- default: Encoder.BasicProperties = .{},
1215
- }) !Encoder.BasicProperties {
1216
- const is_null = stdx.PRNG.ratio(5, 100);
1217
- var properties: Encoder.BasicProperties = .{};
1218
- inline for (std.meta.fields(Encoder.BasicProperties)) |field| {
1219
- if (@field(options.default, field.name)) |default| {
1220
- @field(properties, field.name) = default;
1221
- } else if (options.prng.chance(is_null)) {
1222
- @field(properties, field.name) = null;
1223
- } else switch (std.meta.Child(field.type)) {
1224
- []const u8 => {
1225
- const size = options.prng.range_inclusive(u32, 0, 255);
1226
- const str = try options.arena.alloc(u8, size);
1227
- options.prng.fill(str);
1228
- @field(properties, field.name) = str;
1229
- },
1230
- u64, u8 => |Int| {
1231
- @field(properties, field.name) = options.prng.int(Int);
1232
- },
1233
- DeliveryMode => {
1234
- @field(properties, field.name) = options.prng.enum_uniform(DeliveryMode);
1235
- },
1236
- Encoder.Table => {
1237
- const object = try TestingTable.random(.{
1238
- .arena = options.arena,
1239
- .prng = options.prng,
1240
- .recursive = false,
1241
- });
1242
- @field(properties, field.name) = object.table();
1243
- },
1244
- else => comptime unreachable,
1245
- }
1246
- }
1247
- return properties;
1248
- }
1249
-
1250
- pub fn eql(
1251
- arena: std.mem.Allocator,
1252
- properties1: Encoder.BasicProperties,
1253
- properties2: Decoder.BasicProperties,
1254
- ) !bool {
1255
- inline for (std.meta.fields(Encoder.BasicProperties)) |field| {
1256
- const both_null = @field(properties1, field.name) == null and
1257
- @field(properties2, field.name) == null;
1258
- if (!both_null) {
1259
- const value1 = @field(properties1, field.name) orelse return false;
1260
- const value2 = @field(properties2, field.name) orelse return false;
1261
-
1262
- const equals = switch (std.meta.Child(field.type)) {
1263
- []const u8 => std.mem.eql(u8, value1, value2),
1264
- u64, u8 => value1 == value2,
1265
- DeliveryMode => value1 == value2,
1266
- Encoder.Table => eql: {
1267
- const encoded_object: *const TestingTable = @ptrCast(@alignCast(
1268
- value1.context,
1269
- ));
1270
- const decoded_object: *const TestingTable = try TestingTable.from_table(
1271
- arena,
1272
- value2,
1273
- );
1274
- break :eql TestingTable.eql(encoded_object, decoded_object);
1275
- },
1276
- else => comptime unreachable,
1277
- };
1278
- if (!equals) return false;
1279
- }
1280
- }
1281
- return true;
1282
- }
1283
- };