hecks 3.14.0 → 4.0.0

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 (419) hide show
  1. checksums.yaml +4 -4
  2. data/examples/pizzas/adapters/fake_processor.rb +34 -0
  3. data/examples/pizzas/adapters/payment_signature.rb +66 -0
  4. data/examples/pizzas/adapters/payment_webhook.rb +87 -0
  5. data/examples/pizzas/bluebook/pizzas.behaviors +33 -0
  6. data/examples/pizzas/bluebook/pizzas.hecksagon +5 -3
  7. data/examples/pizzas/config.ru +22 -0
  8. data/lib/hecks/adapters/driven/prism.rb +0 -2
  9. data/lib/hecks/adapters/driven.rb +0 -2
  10. data/lib/hecks/adapters/driving/json.rb +1 -7
  11. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -2
  12. data/lib/hecks/bluebook/dsl/derivation_words.rb +58 -0
  13. data/lib/hecks/bluebook/dsl/translation_builder.rb +6 -37
  14. data/lib/hecks/bluebook/expression/ast_json.rb +0 -9
  15. data/lib/hecks/bluebook/hecksagon.rb +1 -1
  16. data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +7 -10
  17. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +4 -8
  18. data/lib/hecks/bluebook/meta_validator.rb +0 -11
  19. data/lib/hecks/bluebook/translation.rb +18 -10
  20. data/lib/hecks/bluebook/translation_expression/evaluator.rb +63 -0
  21. data/lib/hecks/bluebook/translation_expression/parser.rb +127 -0
  22. data/lib/hecks/bluebook/translation_expression.rb +39 -0
  23. data/lib/hecks/bluebook/translation_plan.rb +70 -0
  24. data/lib/hecks/bluebook.rb +2 -0
  25. data/lib/hecks/chapters.rb +3 -3
  26. data/lib/hecks/composer/adapters/claude_composer.adapter +3 -0
  27. data/lib/hecks/composer/adapters/claude_composer.rb +83 -0
  28. data/lib/hecks/composer/adapters/fake_agent.adapter +3 -0
  29. data/lib/hecks/composer/adapters/fake_agent.rb +55 -0
  30. data/lib/hecks/composer/adapters/jev.adapter +3 -0
  31. data/lib/hecks/composer/adapters/jev.rb +66 -0
  32. data/lib/hecks/composer/agent.rb +113 -0
  33. data/lib/hecks/composer/assistant.rb +110 -0
  34. data/lib/hecks/composer/behavior_run.rb +53 -0
  35. data/lib/hecks/composer/bluebook/composer.bluebook +178 -0
  36. data/lib/hecks/composer/bluebook/composer.hecksagon +16 -0
  37. data/lib/hecks/composer/board.rb +65 -0
  38. data/lib/hecks/composer/board_edit/command_text.rb +39 -0
  39. data/lib/hecks/composer/board_edit/source.rb +84 -0
  40. data/lib/hecks/composer/board_edit.rb +144 -0
  41. data/lib/hecks/composer/check.rb +89 -0
  42. data/lib/hecks/composer/domains.rb +81 -0
  43. data/lib/hecks/composer/jobs.rb +134 -0
  44. data/lib/hecks/composer/layout.rb +37 -0
  45. data/lib/hecks/composer/live.rb +150 -0
  46. data/lib/hecks/composer/outline.rb +48 -0
  47. data/lib/hecks/composer/page.html +989 -0
  48. data/lib/hecks/composer/panels.rb +142 -0
  49. data/lib/hecks/composer/parse.rb +83 -0
  50. data/lib/hecks/composer/plain.rb +28 -0
  51. data/lib/hecks/composer/ports/composer_agent.port +7 -0
  52. data/lib/hecks/composer/session.rb +141 -0
  53. data/lib/hecks/composer/toolbox.rb +166 -0
  54. data/lib/hecks/composer/web.rb +156 -0
  55. data/lib/hecks/composer/workbench.rb +51 -0
  56. data/lib/hecks/composer/workspace.rb +81 -0
  57. data/lib/hecks/composer.rb +17 -0
  58. data/lib/hecks/corpus/adapters.rb +22 -0
  59. data/lib/hecks/corpus/rust.rb +1 -1
  60. data/lib/hecks/corpus/worlds.rb +19 -0
  61. data/lib/hecks/corpus.rb +5 -0
  62. data/lib/hecks/forms/app/commands.rb +2 -3
  63. data/lib/hecks/forms/app/queries.rb +2 -3
  64. data/lib/hecks/forms/app/records.rb +17 -5
  65. data/lib/hecks/forms/command_form_renderer.rb +42 -16
  66. data/lib/hecks/forms/field_controls.rb +2 -2
  67. data/lib/hecks/forms/field_renderer.rb +1 -1
  68. data/lib/hecks/forms/field_shape.rb +36 -17
  69. data/lib/hecks/forms/index_renderer.rb +2 -1
  70. data/lib/hecks/forms/page.rb +1 -1
  71. data/lib/hecks/forms/params.rb +0 -13
  72. data/lib/hecks/forms/query_form_renderer.rb +7 -6
  73. data/lib/hecks/forms/record_renderer.rb +11 -7
  74. data/lib/hecks/forms/rule_words.rb +100 -0
  75. data/lib/hecks/forms/value_object_shape.rb +2 -1
  76. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -3
  77. data/lib/hecks/fuzzing/isolated_boot/worlds.rb +3 -6
  78. data/lib/hecks/fuzzing/replay/filters.rb +2 -6
  79. data/lib/hecks/gate/stages.yml +25 -0
  80. data/lib/hecks/grammar/evolve/seeds.rb +0 -6
  81. data/lib/hecks/grammar/evolve.rb +0 -3
  82. data/lib/hecks/grammar/translation.bluebook +1 -1
  83. data/lib/hecks/hecks/adapters/codebase/composing.rb +56 -0
  84. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +3 -1
  85. data/lib/hecks/hecks/adapters/journal_store/changes.rb +0 -26
  86. data/lib/hecks/hecks/adapters/journal_store/examination.rb +2 -23
  87. data/lib/hecks/hecks/adapters/journal_store/readings.rb +3 -11
  88. data/lib/hecks/hecks/adapters/journal_store.rb +0 -11
  89. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +4 -11
  90. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +0 -9
  91. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +0 -4
  92. data/lib/hecks/hecks/codebase.behaviors +6 -0
  93. data/lib/hecks/hecks/codebase.bluebook +21 -0
  94. data/lib/hecks/hecks/composer.behaviors +68 -0
  95. data/lib/hecks/hecks/context_map.hecksagon +1 -1
  96. data/lib/hecks/hecks/custodian.behaviors +0 -6
  97. data/lib/hecks/hecks/custodian.bluebook +3 -80
  98. data/lib/hecks/hecks/hecks.hecksagon +2 -2
  99. data/lib/hecks/hecks/hecks.world +1 -1
  100. data/lib/hecks/hecks/rehearsal.bluebook +7 -13
  101. data/lib/hecks/kernel_capabilities/templates.rb +4 -4
  102. data/lib/hecks/kernel_capabilities.rb +1 -1
  103. data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
  104. data/lib/hecks/language/translation/translation_aggregate.bluebook +21 -24
  105. data/lib/hecks/ports/access_control.rb +2 -2
  106. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -41
  107. data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +7 -7
  108. data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +25 -2
  109. data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +4 -4
  110. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +17 -25
  111. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +0 -12
  112. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +1 -1
  113. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -22
  114. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +0 -1
  115. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +9 -3
  116. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +3 -29
  117. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +2 -26
  118. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -33
  119. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -3
  120. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +2 -4
  121. data/lib/hecks/ports/persistence/plugins/era/translation/expression_sql.rb +52 -0
  122. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +23 -29
  123. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +1 -1
  124. data/lib/hecks/ports/persistence/plugins/era/translation.rb +0 -1
  125. data/lib/hecks/ports/persistence/plugins/era.rb +3 -6
  126. data/lib/hecks/ports.rb +0 -1
  127. data/lib/hecks/projection_files.rb +3 -1
  128. data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
  129. data/lib/hecks/projections/glossary/entries.rb +10 -4
  130. data/lib/hecks/projections/glossary/groups.rb +42 -0
  131. data/lib/hecks/projections/glossary/html/page.rb +7 -2
  132. data/lib/hecks/projections/glossary/html/parser.rb +1 -1
  133. data/lib/hecks/projections/glossary/html/sections.rb +31 -11
  134. data/lib/hecks/projections/glossary/html.rb +1 -2
  135. data/lib/hecks/projections/glossary/markdown.rb +31 -28
  136. data/lib/hecks/projections/glossary/mermaid.rb +3 -0
  137. data/lib/hecks/projections/glossary/page.css +143 -153
  138. data/lib/hecks/projections/glossary/page.js +63 -3
  139. data/lib/hecks/projections/glossary/sentences/actions.rb +88 -0
  140. data/lib/hecks/projections/glossary/sentences/paths.rb +77 -0
  141. data/lib/hecks/projections/glossary/sentences/queries.rb +90 -0
  142. data/lib/hecks/projections/glossary/sentences/value_objects.rb +32 -5
  143. data/lib/hecks/projections/glossary/sentences.rb +13 -3
  144. data/lib/hecks/projections/glossary/slugs.rb +4 -1
  145. data/lib/hecks/projections/glossary.rb +2 -1
  146. data/lib/hecks/projections/plain_english.rb +97 -0
  147. data/lib/hecks/projections/rust_vocabulary/arguments.rb +2 -2
  148. data/lib/hecks/projections/rust_vocabulary/enum_body.rb +20 -25
  149. data/lib/hecks/projections/rust_vocabulary/tests.rb +2 -2
  150. data/lib/hecks/projections/rust_vocabulary.rb +14 -6
  151. data/lib/hecks/projections/site/cms_editor/color.rb +0 -6
  152. data/lib/hecks/projections/statements/actions.rb +99 -0
  153. data/lib/hecks/projections/statements/relationships.rb +86 -0
  154. data/lib/hecks/projections/statements.rb +15 -24
  155. data/lib/hecks/projector/exporter/adapters.rb +112 -0
  156. data/lib/hecks/projector/exporter/translations.rb +18 -35
  157. data/lib/hecks/projector/exporter/worlds.rb +103 -0
  158. data/lib/hecks/projector/exporter.rb +5 -1
  159. data/lib/hecks/quality_control/adapters/agent.rb +6 -7
  160. data/lib/hecks/quality_control/adapters/agent_profile.rb +16 -114
  161. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +1 -1
  162. data/lib/hecks/runtime/loader/boot_steps.rb +0 -20
  163. data/lib/hecks/runtime/outbox.rb +2 -9
  164. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -9
  165. data/lib/hecks/runtime/remote_dispatcher.rb +2 -2
  166. data/lib/hecks/runtime/value.rb +13 -0
  167. data/lib/hecks/rust_build/project_rust/target_ir.rb +23 -4
  168. data/lib/hecks/rust_build/wasm.rb +0 -12
  169. data/lib/hecks/rust_build/write_if_changed.rb +12 -12
  170. data/lib/hecks/rust_format.rb +77 -0
  171. data/lib/hecks/tools/fuzz_sweep/findings.rb +3 -9
  172. data/lib/hecks/tools/fuzz_sweep.rb +1 -3
  173. data/lib/hecks/tools/translation_audit/verdicts.rb +3 -28
  174. data/lib/hecks/tools/translation_audit.rb +8 -10
  175. data/lib/hecks/tools/translation_scaffold/reporting.rb +1 -1
  176. data/lib/hecks/version.rb +1 -1
  177. data/lib/hecks/vocabulary.rb +2 -1
  178. data/lib/hecks.rb +3 -0
  179. data/prebuilt/{a883a7e568667aa5ac904c82daff356bdf9e996252a36af6def4a4a43efb967e.marshal → 02c09c73b272c1fb5a9ae6d87bb5e5e529208e00f6b4b597dc2c0fd70a9c0964.marshal} +0 -0
  180. data/prebuilt/{1a6f596be124228be93eba1d86dbc9d2933190fa389b284331241cb9f27115a0.marshal → bb84a835cf6a15136bad5ca03aa5bf93a5b92f5f72444618d3ef2412b987fb32.marshal} +0 -0
  181. data/prebuilt/{verdicts-872993b1aa26d73fe48f28251374b8585fed145d02aab42be0f00de386b6ff80.json → verdicts-f1f10da14c8e8f01b4c9b7e3e2d74be8cd2bf4676364ed17fa16975d2a076d75.json} +1 -1
  182. data/rust/Cargo.toml +40 -0
  183. data/rust/build/Cargo.toml +36 -0
  184. data/rust/build/clippy.toml +4 -0
  185. data/rust/build/src/adapters_pass.rs +196 -0
  186. data/rust/build/src/binding_pass.rs +54 -13
  187. data/rust/build/src/build_artifact.rs +23 -5
  188. data/rust/build/src/cargo_sync.rs +69 -26
  189. data/rust/build/src/lineage_pass.rs +101 -87
  190. data/rust/build/src/main.rs +11 -2
  191. data/rust/build/src/pipeline.rs +80 -19
  192. data/rust/build/src/reserved_names.rs +6 -50
  193. data/rust/build/src/resolve.rs +82 -35
  194. data/rust/build/src/rustfmt.rs +100 -0
  195. data/rust/build/src/seams_pass.rs +85 -16
  196. data/rust/build/src/subprocess.rs +30 -6
  197. data/rust/build/src/tmp.rs +5 -2
  198. data/rust/build/src/translation_pass.rs +72 -22
  199. data/rust/build/src/world_pass.rs +109 -0
  200. data/rust/clippy.toml +4 -0
  201. data/rust/codegen/Cargo.toml +36 -0
  202. data/rust/codegen/clippy.toml +4 -0
  203. data/rust/codegen/src/asks.rs +40 -14
  204. data/rust/codegen/src/attr.rs +2 -2
  205. data/rust/codegen/src/bridging.rs +676 -117
  206. data/rust/codegen/src/commands.rs +979 -373
  207. data/rust/codegen/src/constraints.rs +88 -25
  208. data/rust/codegen/src/dependency_planning.rs +128 -34
  209. data/rust/codegen/src/domain_generator.rs +300 -170
  210. data/rust/codegen/src/exemplar.rs +87 -32
  211. data/rust/codegen/src/expr_emitter.rs +54 -6
  212. data/rust/codegen/src/fielded.rs +193 -41
  213. data/rust/codegen/src/hecks_naming.rs +124 -16
  214. data/rust/codegen/src/hecks_naming_tests.rs +81 -0
  215. data/rust/codegen/src/json.rs +80 -44
  216. data/rust/codegen/src/json_codec.rs +585 -149
  217. data/rust/codegen/src/literal.rs +104 -138
  218. data/rust/codegen/src/main.rs +145 -52
  219. data/rust/codegen/src/manifest.rs +76 -14
  220. data/rust/codegen/src/mutations.rs +1212 -239
  221. data/rust/codegen/src/naming.rs +111 -60
  222. data/rust/codegen/src/optional_pass.rs +90 -28
  223. data/rust/codegen/src/ports.rs +5 -4
  224. data/rust/codegen/src/prelude.rs +139 -49
  225. data/rust/codegen/src/queries.rs +601 -226
  226. data/rust/codegen/src/reactions.rs +268 -74
  227. data/rust/codegen/src/read_models.rs +606 -205
  228. data/rust/codegen/src/reference_specs.rs +16 -3
  229. data/rust/codegen/src/registry.rs +128 -79
  230. data/rust/codegen/src/reserved_names.rs +6 -50
  231. data/rust/codegen/src/shared.rs +71 -22
  232. data/rust/codegen/src/sidecars.rs +15 -5
  233. data/rust/codegen/src/skip_reason.rs +8 -2
  234. data/rust/codegen/src/types.rs +306 -108
  235. data/rust/host/Cargo.lock +1 -0
  236. data/rust/host/Cargo.toml +40 -4
  237. data/rust/host/HECKS_RELEASE +1 -1
  238. data/rust/host/clippy.toml +4 -0
  239. data/rust/host/src/api.rs +698 -218
  240. data/rust/host/src/auth.rs +491 -214
  241. data/rust/host/src/b64.rs +91 -0
  242. data/rust/host/src/bin/expr_harness.rs +6 -2
  243. data/rust/host/src/bin/lineage_harness.rs +47 -11
  244. data/rust/host/src/bin/mint_harness.rs +70 -37
  245. data/rust/host/src/bin/validate_harness.rs +16 -8
  246. data/rust/host/src/boot.rs +144 -68
  247. data/rust/host/src/boundary_fuzz/api.rs +130 -32
  248. data/rust/host/src/boundary_fuzz/auth.rs +108 -23
  249. data/rust/host/src/boundary_fuzz/expr_json.rs +85 -11
  250. data/rust/host/src/boundary_fuzz/ir.rs +164 -12
  251. data/rust/host/src/boundary_fuzz/server.rs +283 -36
  252. data/rust/host/src/boundary_fuzz/web.rs +56 -8
  253. data/rust/host/src/checkout.rs +78 -32
  254. data/rust/host/src/clock.rs +8 -0
  255. data/rust/host/src/commerce_ir.rs +333 -95
  256. data/rust/host/src/crypto.rs +33 -0
  257. data/rust/host/src/dispatch.rs +990 -331
  258. data/rust/host/src/expr_json.rs +1021 -273
  259. data/rust/host/src/extension.rs +24 -4
  260. data/rust/host/src/field_hints.rs +11 -7
  261. data/rust/host/src/fuzz_support.rs +85 -13
  262. data/rust/host/src/host.rs +100 -0
  263. data/rust/host/src/http.rs +22 -0
  264. data/rust/host/src/ir.rs +326 -16
  265. data/rust/host/src/journal.rs +277 -176
  266. data/rust/host/src/lambda_client.rs +219 -53
  267. data/rust/host/src/lib.rs +16 -4
  268. data/rust/host/src/log.rs +62 -11
  269. data/rust/host/src/mint.rs +1153 -326
  270. data/rust/host/src/needs.rs +185 -44
  271. data/rust/host/src/payments/keystore.rs +197 -45
  272. data/rust/host/src/payments/roles.rs +39 -7
  273. data/rust/host/src/payments/tests.rs +1427 -282
  274. data/rust/host/src/payments.rs +391 -112
  275. data/rust/host/src/platform_signin/attack_tests.rs +5 -5
  276. data/rust/host/src/platform_signin/config.rs +11 -11
  277. data/rust/host/src/platform_signin/cookie.rs +2 -2
  278. data/rust/host/src/platform_signin/extension.rs +2 -1
  279. data/rust/host/src/platform_signin/handler.rs +9 -8
  280. data/rust/host/src/platform_signin/jti.rs +4 -2
  281. data/rust/host/src/platform_signin/jwks.rs +2 -1
  282. data/rust/host/src/platform_signin/jws.rs +2 -37
  283. data/rust/host/src/platform_signin/known_answer_tests.rs +5 -1
  284. data/rust/host/src/platform_signin/mode_tests.rs +5 -3
  285. data/rust/host/src/platform_signin/pages.rs +20 -20
  286. data/rust/host/src/platform_signin/session.rs +8 -1
  287. data/rust/host/src/platform_signin/settings.rs +6 -6
  288. data/rust/host/src/platform_signin/strict_json.rs +12 -9
  289. data/rust/host/src/platform_signin/verify.rs +41 -41
  290. data/rust/host/src/platform_signin/wiring_support.rs +13 -18
  291. data/rust/host/src/presentation.rs +207 -63
  292. data/rust/host/src/presentation_write.rs +502 -187
  293. data/rust/host/src/query_step.rs +69 -18
  294. data/rust/host/src/rate_limit.rs +541 -142
  295. data/rust/host/src/reference_transform.rs +77 -25
  296. data/rust/host/src/reference_validate.rs +443 -104
  297. data/rust/host/src/resend.rs +190 -55
  298. data/rust/host/src/secrets.rs +116 -21
  299. data/rust/host/src/server.rs +483 -104
  300. data/rust/host/src/storage_shape.rs +88 -21
  301. data/rust/host/src/test_pg.rs +17 -7
  302. data/rust/host/src/ui_schema.rs +495 -207
  303. data/rust/host/src/wasm_runner.rs +21 -6
  304. data/rust/host/src/web/commerce.rs +101 -23
  305. data/rust/host/src/web/newsletter/cooldown.rs +10 -3
  306. data/rust/host/src/web/newsletter/template.rs +26 -7
  307. data/rust/host/src/web/newsletter/tests.rs +112 -23
  308. data/rust/host/src/web/newsletter.rs +209 -59
  309. data/rust/host/src/web/newsletter_send.rs +251 -79
  310. data/rust/host/src/web/registration_receipt/tests.rs +16 -4
  311. data/rust/host/src/web/registration_receipt.rs +100 -24
  312. data/rust/host/src/web/registrations.rs +1384 -332
  313. data/rust/host/src/web/resend_webhook.rs +138 -80
  314. data/rust/host/src/web.rs +2416 -508
  315. data/rust/lsp/Cargo.toml +36 -0
  316. data/rust/lsp/clippy.toml +4 -0
  317. data/rust/lsp/src/json.rs +29 -22
  318. data/rust/lsp/src/main.rs +81 -31
  319. data/rust/lsp/src/outline.rs +23 -7
  320. data/rust/lsp/src/rpc.rs +17 -4
  321. data/rust/parser/Cargo.toml +36 -0
  322. data/rust/parser/clippy.toml +4 -0
  323. data/rust/parser/src/build/closed_sets.rs +6 -1
  324. data/rust/parser/src/build/identity.rs +4 -3
  325. data/rust/parser/src/build/mod.rs +1 -1
  326. data/rust/parser/src/build/named_pattern.rs +4 -1
  327. data/rust/parser/src/build/naming.rs +2 -80
  328. data/rust/parser/src/build/pattern_subset.rs +6 -8
  329. data/rust/parser/src/build/query_derive.rs +3 -1
  330. data/rust/parser/src/build/query_inference.rs +14 -5
  331. data/rust/parser/src/build/read_model.rs +4 -1
  332. data/rust/parser/src/build/references.rs +4 -3
  333. data/rust/parser/src/canonical.rs +34 -15
  334. data/rust/parser/src/emit.rs +187 -105
  335. data/rust/parser/src/expr/ast_json.rs +134 -42
  336. data/rust/parser/src/expr/evaluator.rs +27 -9
  337. data/rust/parser/src/expr/mod.rs +54 -13
  338. data/rust/parser/src/expr/resolver.rs +299 -92
  339. data/rust/parser/src/ir.rs +35 -3
  340. data/rust/parser/src/keywords.rs +7168 -516
  341. data/rust/parser/src/lex.rs +11 -25
  342. data/rust/parser/src/lib.rs +1 -0
  343. data/rust/parser/src/main.rs +65 -6
  344. data/rust/parser/src/parse/adapter.rs +157 -0
  345. data/rust/parser/src/parse/aggregate.rs +19 -10
  346. data/rust/parser/src/parse/chapter.rs +16 -17
  347. data/rust/parser/src/parse/command.rs +35 -16
  348. data/rust/parser/src/parse/domain_port.rs +4 -7
  349. data/rust/parser/src/parse/entity.rs +21 -11
  350. data/rust/parser/src/parse/hecksagon.rs +10 -4
  351. data/rust/parser/src/parse/lifecycle.rs +9 -5
  352. data/rust/parser/src/parse/mod.rs +22 -91
  353. data/rust/parser/src/parse/needs.rs +21 -12
  354. data/rust/parser/src/parse/policy.rs +2 -2
  355. data/rust/parser/src/parse/process_manager.rs +9 -11
  356. data/rust/parser/src/parse/query.rs +8 -4
  357. data/rust/parser/src/parse/read_model.rs +57 -16
  358. data/rust/parser/src/parse/value_object.rs +7 -2
  359. data/rust/parser/src/parse/world.rs +322 -0
  360. data/rust/parser/src/ruby_value.rs +7 -6
  361. data/rust/src/exemplar/json.rs +4 -4
  362. data/rust/src/exemplar/mutations.rs +18 -0
  363. data/rust/src/exemplar/read_models.rs +1 -10
  364. data/rust/src/kernel/attribute_shapes/composite.rs +54 -14
  365. data/rust/src/kernel/attribute_shapes/list.rs +2 -2
  366. data/rust/src/kernel/attribute_shapes/mod.rs +8 -8
  367. data/rust/src/kernel/attribute_shapes/scalar.rs +2 -2
  368. data/rust/src/kernel/cli.rs +229 -112
  369. data/rust/src/kernel/dispatch.rs +323 -115
  370. data/rust/src/kernel/dispatch_guard_tests.rs +327 -65
  371. data/rust/src/kernel/expr.rs +203 -86
  372. data/rust/src/kernel/expression_operators/arithmetic.rs +138 -25
  373. data/rust/src/kernel/expression_operators/comparison.rs +87 -2
  374. data/rust/src/kernel/expression_operators/enumeration.rs +106 -22
  375. data/rust/src/kernel/expression_operators/logical.rs +9 -3
  376. data/rust/src/kernel/expression_operators/membership.rs +3 -1
  377. data/rust/src/kernel/expression_operators/mod.rs +34 -21
  378. data/rust/src/kernel/expression_operators/pattern_match.rs +46 -11
  379. data/rust/src/kernel/expression_operators/positional.rs +84 -30
  380. data/rust/src/kernel/expression_operators/presence.rs +52 -13
  381. data/rust/src/kernel/expression_operators/sign_test.rs +3 -1
  382. data/rust/src/kernel/expression_operators/sized.rs +24 -8
  383. data/rust/src/kernel/expression_operators/text.rs +120 -27
  384. data/rust/src/kernel/expression_operators/to_string.rs +10 -4
  385. data/rust/src/kernel/json.rs +230 -148
  386. data/rust/src/kernel/mod.rs +46 -33
  387. data/rust/src/kernel/named_query.rs +63 -15
  388. data/rust/src/kernel/needs.rs +112 -25
  389. data/rust/src/kernel/orchestrate.rs +980 -581
  390. data/rust/src/kernel/orchestrate_guard_tests.rs +538 -140
  391. data/rust/src/kernel/pattern.rs +107 -34
  392. data/rust/src/kernel/query_comparators.rs +118 -41
  393. data/rust/src/kernel/query_ordering.rs +13 -5
  394. data/rust/src/kernel/read_model.rs +479 -181
  395. data/rust/src/kernel/reference_lookup.rs +122 -26
  396. data/rust/src/kernel/repository.rs +293 -66
  397. data/rust/src/kernel/routing.rs +58 -42
  398. data/rust/src/kernel/ruby_float.rs +139 -0
  399. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +57 -57
  400. data/rust/src/kernel/vocab/entity_dispatch_order.rs +54 -54
  401. data/rust/src/kernel/vocab/field_hint.rs +19 -25
  402. data/rust/src/kernel/vocab/mod.rs +6 -6
  403. data/rust/src/kernel/vocab/query_comparator.rs +23 -24
  404. data/rust/src/kernel/vocab/refusal_template.rs +501 -297
  405. data/rust/src/lib.rs +50 -0
  406. data/rust/src/main.rs +4 -1
  407. data/rust/web/Cargo.toml +36 -0
  408. data/rust/web/clippy.toml +4 -0
  409. metadata +82 -15
  410. data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +0 -36
  411. data/lib/hecks/adapters/driven/google_authentication.adapter +0 -3
  412. data/lib/hecks/adapters/driven/google_authentication.rb +0 -99
  413. data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +0 -3
  414. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +0 -32
  415. data/lib/hecks/ports/authentication.port +0 -6
  416. data/lib/hecks/ports/authentication.rb +0 -67
  417. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +0 -255
  418. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +0 -22
  419. data/rust/host/src/approval.rs +0 -652
@@ -303,7 +303,7 @@ fn rejects_a_tampered_signature_one_bit_flipped_and_every_wrong_length() {
303
303
  wrong.len()
304
304
  );
305
305
  }
306
- let mut longer = bytes.clone();
306
+ let mut longer = bytes;
307
307
  longer.extend_from_slice(&[0, 0]);
308
308
  assert_eq!(
309
309
  raw_token_reason(Some(&format!(
@@ -441,11 +441,11 @@ fn rejects_claims_of_the_wrong_json_type() {
441
441
  Reason::Malformed
442
442
  );
443
443
  assert_eq!(
444
- refused_with(|s| set(s, "exp", json!(1800000060.0))),
444
+ refused_with(|s| set(s, "exp", json!(1_800_000_060.0))),
445
445
  Reason::Malformed
446
446
  );
447
447
  assert_eq!(
448
- refused_with(|s| set(s, "iat", json!(1800000000.5))),
448
+ refused_with(|s| set(s, "iat", json!(1_800_000_000.5))),
449
449
  Reason::Malformed
450
450
  );
451
451
  assert_eq!(
@@ -911,7 +911,7 @@ fn bad_env(s: &mut Scenario) {
911
911
  set(s, "env", json!("staging"));
912
912
  }
913
913
  fn float_exp(s: &mut Scenario) {
914
- set(s, "exp", json!(1800000060.5));
914
+ set(s, "exp", json!(1_800_000_060.5));
915
915
  }
916
916
  fn not_yet_valid(s: &mut Scenario) {
917
917
  set(s, "nbf", json!(NOW + 100));
@@ -1048,7 +1048,7 @@ fn every_single_character_mutation_of_a_good_token_is_answered_without_panicking
1048
1048
  continue;
1049
1049
  }
1050
1050
  let mut mutated = good.clone();
1051
- mutated.replace_range(position..position + 1, &replacement.to_string());
1051
+ mutated.replace_range(position..=position, &replacement.to_string());
1052
1052
  let request = SigninRequest {
1053
1053
  token: Some(&mutated),
1054
1054
  state: Some(STATE),
@@ -62,19 +62,19 @@ pub enum ConfigProblem {
62
62
  }
63
63
 
64
64
  impl ConfigProblem {
65
- fn describe(self) -> &'static str {
65
+ const fn describe(self) -> &'static str {
66
66
  match self {
67
- ConfigProblem::Missing => "is not set",
68
- ConfigProblem::NotHttps => "must be an https URL",
69
- ConfigProblem::CredentialsInUrl => "must not carry credentials",
70
- ConfigProblem::PathQueryOrFragment => {
67
+ Self::Missing => "is not set",
68
+ Self::NotHttps => "must be an https URL",
69
+ Self::CredentialsInUrl => "must not carry credentials",
70
+ Self::PathQueryOrFragment => {
71
71
  "must not carry a path, query or fragment (no trailing slash)"
72
72
  }
73
- ConfigProblem::BadHost => "must name a plain lowercase host and an optional port",
74
- ConfigProblem::UpperCase => "must be lowercase",
75
- ConfigProblem::BadShape => "has an invalid shape",
76
- ConfigProblem::WrongHostForIssuer => "must be on the issuer's host",
77
- ConfigProblem::NotAnEnvironment => "must be production or staging",
73
+ Self::BadHost => "must name a plain lowercase host and an optional port",
74
+ Self::UpperCase => "must be lowercase",
75
+ Self::BadShape => "has an invalid shape",
76
+ Self::WrongHostForIssuer => "must be on the issuer's host",
77
+ Self::NotAnEnvironment => "must be production or staging",
78
78
  }
79
79
  }
80
80
  }
@@ -135,7 +135,7 @@ impl PlatformSigninConfig {
135
135
  }
136
136
  }
137
137
 
138
- fn fail(variable: &'static str, problem: ConfigProblem) -> ConfigError {
138
+ const fn fail(variable: &'static str, problem: ConfigProblem) -> ConfigError {
139
139
  ConfigError { variable, problem }
140
140
  }
141
141
 
@@ -101,7 +101,7 @@ fn parse_value(value: &str) -> Option<SigninCookie> {
101
101
  })
102
102
  }
103
103
 
104
- fn is_url_safe(byte: u8) -> bool {
104
+ const fn is_url_safe(byte: u8) -> bool {
105
105
  byte.is_ascii_alphanumeric() || byte == b'-' || byte == b'_'
106
106
  }
107
107
 
@@ -121,7 +121,7 @@ mod tests {
121
121
  }
122
122
 
123
123
  fn pairs(items: &[&str]) -> Vec<String> {
124
- items.iter().map(|s| s.to_string()).collect()
124
+ items.iter().map(std::string::ToString::to_string).collect()
125
125
  }
126
126
 
127
127
  #[test]
@@ -50,7 +50,7 @@ pub struct PlatformSignin {
50
50
 
51
51
  impl PlatformSignin {
52
52
  /// Wraps a handler that is already built.
53
- pub fn new(handler: SigninHandler) -> Self {
53
+ pub const fn new(handler: SigninHandler) -> Self {
54
54
  Self { handler }
55
55
  }
56
56
 
@@ -181,6 +181,7 @@ impl HostExtension for RefusedSettings {
181
181
 
182
182
  /// The extensions that platform sign-in contributes for these settings: none when it is off, the
183
183
  /// flow when it is on, and a boot refusal when the settings are wrong.
184
+ #[allow(clippy::implicit_hasher)] // reason: the settings map always comes from this crate's own default-hashed env reader
184
185
  pub fn extensions_for(vars: &HashMap<String, String>) -> Vec<Arc<dyn HostExtension>> {
185
186
  match PlatformSignin::from_env_map(vars) {
186
187
  Ok(None) => Vec::new(),
@@ -16,6 +16,7 @@
16
16
  //! The token, the nonce, the state and the cookie are never written to a log, and an email only as
17
17
  //! a short hash. A refusal logs its stable code.
18
18
 
19
+ use std::fmt::Write;
19
20
  use std::sync::Arc;
20
21
 
21
22
  use serde_json::{json, Value};
@@ -38,7 +39,7 @@ pub trait TokenVerifier: Send + Sync {
38
39
 
39
40
  impl<K: KeySource + Send + Sync> TokenVerifier for Verifier<K> {
40
41
  fn verify(&self, request: &SigninRequest<'_>, now: i64) -> Result<VerifiedClaims, Refusal> {
41
- Verifier::verify(self, request, now)
42
+ Self::verify(self, request, now)
42
43
  }
43
44
  }
44
45
 
@@ -72,10 +73,7 @@ pub fn fresh_value() -> String {
72
73
 
73
74
  /// Reads the system clock.
74
75
  pub fn system_clock() -> i64 {
75
- std::time::SystemTime::now()
76
- .duration_since(std::time::UNIX_EPOCH)
77
- .map(|elapsed| elapsed.as_secs() as i64)
78
- .unwrap_or(0)
76
+ crate::clock::unix_now()
79
77
  }
80
78
 
81
79
  /// What a callback request carried, already separated from any headers.
@@ -125,7 +123,7 @@ impl SigninHandler {
125
123
  }
126
124
 
127
125
  /// Returns the validated settings.
128
- pub fn settings(&self) -> &SigninSettings {
126
+ pub const fn settings(&self) -> &SigninSettings {
129
127
  &self.settings
130
128
  }
131
129
 
@@ -235,7 +233,7 @@ impl SigninHandler {
235
233
 
236
234
  /// The page a verifier refusal earns: the browser's own cookie and state are told apart, the rest
237
235
  /// share one answer so the page teaches nothing about which later check failed.
238
- fn failure_for(reason: Reason) -> Failure {
236
+ const fn failure_for(reason: Reason) -> Failure {
239
237
  match reason {
240
238
  Reason::MissingCookie => Failure::Cookie,
241
239
  Reason::StateMismatch => Failure::State,
@@ -246,6 +244,9 @@ fn failure_for(reason: Reason) -> Failure {
246
244
  /// The first four bytes of the lowercased email's SHA-256, enough to tell people apart in a log.
247
245
  fn short_hash(email: &str) -> String {
248
246
  let digest = Sha256::digest(email.to_lowercase().as_bytes());
249
- let hex: String = digest.iter().take(4).map(|b| format!("{b:02x}")).collect();
247
+ let hex = digest.iter().take(4).fold(String::new(), |mut hex, b| {
248
+ let _ = write!(hex, "{b:02x}"); // writing to a String cannot fail
249
+ hex
250
+ });
250
251
  format!("h:{hex}")
251
252
  }
@@ -63,7 +63,7 @@ impl JtiStore {
63
63
  // forever would be a lock-out, so a poisoned lock is simply taken over.
64
64
  self.seen
65
65
  .lock()
66
- .unwrap_or_else(|poisoned| poisoned.into_inner())
66
+ .unwrap_or_else(std::sync::PoisonError::into_inner)
67
67
  }
68
68
 
69
69
  /// Counts the identifiers still remembered at `now`; expired ones are not counted.
@@ -176,7 +176,9 @@ mod tests {
176
176
  })
177
177
  })
178
178
  .collect();
179
- handles.into_iter().for_each(|h| h.join().unwrap());
179
+ for handle in handles {
180
+ handle.join().unwrap();
181
+ }
180
182
  assert_eq!(winners.load(Ordering::SeqCst), 1, "round {round}");
181
183
  }
182
184
  }
@@ -201,7 +201,7 @@ impl<F: JwksFetcher> JwksCache<F> {
201
201
  // The state is only ever replaced whole, so a panic elsewhere cannot leave it half-written.
202
202
  self.state
203
203
  .lock()
204
- .unwrap_or_else(|poisoned| poisoned.into_inner())
204
+ .unwrap_or_else(std::sync::PoisonError::into_inner)
205
205
  }
206
206
 
207
207
  fn is_stale(&self, state: &CacheState, now: i64) -> bool {
@@ -445,6 +445,7 @@ mod tests {
445
445
  (JwksCache::new(fetcher), calls)
446
446
  }
447
447
 
448
+ #[allow(clippy::unnecessary_wraps)] // reason: a scripted fetch answer has the fetcher's Result type
448
449
  fn one_key(x: &str) -> Result<String, FetchFailed> {
449
450
  Ok(document(&[format!(
450
451
  r#"{{"kty":"OKP","crv":"Ed25519","x":"{x}"}}"#
@@ -14,22 +14,9 @@
14
14
 
15
15
  use super::strict_json::{self, JsonObject};
16
16
 
17
- const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
18
-
19
17
  /// Encodes bytes as unpadded base64url (RFC 4648 section 5).
20
18
  pub fn encode_base64url(bytes: &[u8]) -> String {
21
- let mut out = String::with_capacity(bytes.len().div_ceil(3) * 4);
22
- for chunk in bytes.chunks(3) {
23
- let word = chunk
24
- .iter()
25
- .enumerate()
26
- .fold(0u32, |acc, (i, b)| acc | (*b as u32) << (16 - 8 * i));
27
- let characters = chunk.len() + 1;
28
- for i in 0..characters {
29
- out.push(ALPHABET[((word >> (18 - 6 * i)) & 0x3f) as usize] as char);
30
- }
31
- }
32
- out
19
+ crate::b64::url_encode(bytes)
33
20
  }
34
21
 
35
22
  /// Decodes canonical unpadded base64url.
@@ -37,29 +24,7 @@ pub fn encode_base64url(bytes: &[u8]) -> String {
37
24
  /// Returns `None` for padding, any character outside the URL-safe alphabet, a length that no byte
38
25
  /// string encodes to, and spare trailing bits that are not zero.
39
26
  pub fn decode_base64url(text: &str) -> Option<Vec<u8>> {
40
- if text.len() % 4 == 1 {
41
- return None;
42
- }
43
- let mut out = Vec::with_capacity(text.len() / 4 * 3 + 2);
44
- let (mut accumulator, mut bits) = (0u32, 0u32);
45
- for byte in text.bytes() {
46
- accumulator = accumulator << 6 | sextet(byte)?;
47
- bits += 6;
48
- if bits >= 8 {
49
- bits -= 8;
50
- out.push((accumulator >> bits) as u8);
51
- accumulator &= (1 << bits) - 1;
52
- }
53
- }
54
- // Spare bits must be zero, or a second spelling would decode to the same bytes.
55
- (accumulator == 0).then_some(out)
56
- }
57
-
58
- fn sextet(byte: u8) -> Option<u32> {
59
- ALPHABET
60
- .iter()
61
- .position(|candidate| *candidate == byte)
62
- .map(|index| index as u32)
27
+ crate::b64::url_decode(text)
63
28
  }
64
29
 
65
30
  /// Why a token text was refused before any claim was read.
@@ -32,7 +32,11 @@ fn document() -> Value {
32
32
  }
33
33
 
34
34
  fn hex(digest: &[u8]) -> String {
35
- digest.iter().map(|b| format!("{b:02x}")).collect()
35
+ use std::fmt::Write;
36
+ digest.iter().fold(String::new(), |mut out, b| {
37
+ let _ = write!(out, "{b:02x}"); // writing to a String cannot fail
38
+ out
39
+ })
36
40
  }
37
41
 
38
42
  fn text<'a>(value: &'a Value, name: &str) -> &'a str {
@@ -69,13 +69,14 @@ fn an_unset_switch_installs_nothing() {
69
69
  let mut vars = env_map("alongside");
70
70
  vars.remove("PLATFORM_SIGNIN");
71
71
  assert!(extensions_for(&vars).is_empty());
72
- assert!(extensions_for(&Default::default()).is_empty());
72
+ assert!(extensions_for(&std::collections::HashMap::default()).is_empty());
73
73
  assert!(PlatformSignin::from_env_map(&vars).unwrap().is_none());
74
74
  }
75
75
 
76
76
  #[test]
77
77
  fn the_default_extension_list_is_unchanged_when_the_switch_is_unset() {
78
- let installed = crate::extension::default_extensions_from(&Default::default());
78
+ let installed =
79
+ crate::extension::default_extensions_from(&std::collections::HashMap::default());
79
80
  assert_eq!(installed.len(), 1);
80
81
  assert!(installed[0]
81
82
  .rate_rules()
@@ -95,7 +96,8 @@ fn a_switched_on_site_adds_exactly_one_extension() {
95
96
  async fn off_means_the_new_paths_reach_the_hosts_own_handling() {
96
97
  // With no extension installed the loop in `web::render` finds nobody; this pins what a
97
98
  // request for the new path meets instead: the hosts own routes, which know nothing of it.
98
- let installed = crate::extension::default_extensions_from(&Default::default());
99
+ let installed =
100
+ crate::extension::default_extensions_from(&std::collections::HashMap::default());
99
101
  assert_eq!(installed.len(), 1);
100
102
  assert!(installed
101
103
  .iter()
@@ -28,40 +28,40 @@ pub enum Failure {
28
28
 
29
29
  impl Failure {
30
30
  /// Every code the flow can show, in a fixed order.
31
- pub const ALL: [Failure; 6] = [
32
- Failure::Cookie,
33
- Failure::State,
34
- Failure::Params,
35
- Failure::Token,
36
- Failure::Unlinked,
37
- Failure::Unavailable,
31
+ pub const ALL: [Self; 6] = [
32
+ Self::Cookie,
33
+ Self::State,
34
+ Self::Params,
35
+ Self::Token,
36
+ Self::Unlinked,
37
+ Self::Unavailable,
38
38
  ];
39
39
 
40
40
  /// Returns the stable code shown on the page and logged.
41
- pub fn code(self) -> &'static str {
41
+ pub const fn code(self) -> &'static str {
42
42
  match self {
43
- Failure::Cookie => "platform_cookie",
44
- Failure::State => "platform_state",
45
- Failure::Params => "platform_params",
46
- Failure::Token => "platform_token",
47
- Failure::Unlinked => "google_unlinked",
48
- Failure::Unavailable => "platform_unavailable",
43
+ Self::Cookie => "platform_cookie",
44
+ Self::State => "platform_state",
45
+ Self::Params => "platform_params",
46
+ Self::Token => "platform_token",
47
+ Self::Unlinked => "google_unlinked",
48
+ Self::Unavailable => "platform_unavailable",
49
49
  }
50
50
  }
51
51
 
52
52
  /// Returns the HTTP status.
53
- pub fn status(self) -> u16 {
53
+ pub const fn status(self) -> u16 {
54
54
  match self {
55
- Failure::Unlinked => 403,
56
- Failure::Unavailable => 500,
55
+ Self::Unlinked => 403,
56
+ Self::Unavailable => 500,
57
57
  _ => 400,
58
58
  }
59
59
  }
60
60
 
61
- fn message(self) -> &'static str {
61
+ const fn message(self) -> &'static str {
62
62
  match self {
63
- Failure::Unlinked => "This account does not have access to this site.",
64
- Failure::Unavailable => "Sign-in is unavailable. Please try again later.",
63
+ Self::Unlinked => "This account does not have access to this site.",
64
+ Self::Unavailable => "Sign-in is unavailable. Please try again later.",
65
65
  _ => "This sign-in link is not valid or has expired. Please start again from the site you came from.",
66
66
  }
67
67
  }
@@ -123,7 +123,14 @@ pub struct HostMembers<'a> {
123
123
  #[async_trait]
124
124
  impl MemberDirectory for HostMembers<'_> {
125
125
  async fn identity_for(&self, issuer: &str, subject: &str) -> anyhow::Result<Option<String>> {
126
- auth::resolve_identity_anywhere(self.client, self.wasm_path, self.domain_ir, issuer, subject).await
126
+ auth::resolve_identity_anywhere(
127
+ self.client,
128
+ self.wasm_path,
129
+ self.domain_ir,
130
+ issuer,
131
+ subject,
132
+ )
133
+ .await
127
134
  }
128
135
 
129
136
  async fn session_for_identity(&self, identity_id: &str) -> anyhow::Result<Option<Session>> {
@@ -74,8 +74,8 @@ pub enum SettingsError {
74
74
  impl fmt::Display for SettingsError {
75
75
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76
76
  match self {
77
- SettingsError::Config(error) => write!(f, "{error}"),
78
- SettingsError::Setting { variable, problem } => write!(f, "{variable} {problem}"),
77
+ Self::Config(error) => write!(f, "{error}"),
78
+ Self::Setting { variable, problem } => write!(f, "{variable} {problem}"),
79
79
  }
80
80
  }
81
81
  }
@@ -84,10 +84,10 @@ impl std::error::Error for SettingsError {}
84
84
 
85
85
  impl SettingsError {
86
86
  /// Returns the name of the variable at fault.
87
- pub fn variable(&self) -> &'static str {
87
+ pub const fn variable(&self) -> &'static str {
88
88
  match self {
89
- SettingsError::Config(error) => error.variable,
90
- SettingsError::Setting { variable, .. } => variable,
89
+ Self::Config(error) => error.variable,
90
+ Self::Setting { variable, .. } => variable,
91
91
  }
92
92
  }
93
93
  }
@@ -117,7 +117,7 @@ impl SigninSettings {
117
117
  }
118
118
  }
119
119
 
120
- fn setting(variable: &'static str, problem: &'static str) -> SettingsError {
120
+ const fn setting(variable: &'static str, problem: &'static str) -> SettingsError {
121
121
  SettingsError::Setting { variable, problem }
122
122
  }
123
123
 
@@ -19,7 +19,7 @@ pub enum Json {
19
19
  /// Any number that is not an integer literal (a fraction or an exponent).
20
20
  Number,
21
21
  Str(String),
22
- Array(Vec<Json>),
22
+ Array(Vec<Self>),
23
23
  Object(JsonObject),
24
24
  }
25
25
 
@@ -258,21 +258,24 @@ impl Parser<'_> {
258
258
  self.digits()?;
259
259
  }
260
260
  let integer_end = self.at;
261
- let mut integral = true;
262
- if self.peek() == Some(b'.') {
261
+ let has_fraction = if self.peek() == Some(b'.') {
263
262
  self.at += 1;
264
263
  self.digits()?;
265
- integral = false;
266
- }
267
- if matches!(self.peek(), Some(b'e' | b'E')) {
264
+ true
265
+ } else {
266
+ false
267
+ };
268
+ let has_exponent = if matches!(self.peek(), Some(b'e' | b'E')) {
268
269
  self.at += 1;
269
270
  if matches!(self.peek(), Some(b'+' | b'-')) {
270
271
  self.at += 1;
271
272
  }
272
273
  self.digits()?;
273
- integral = false;
274
- }
275
- if !integral {
274
+ true
275
+ } else {
276
+ false
277
+ };
278
+ if has_fraction || has_exponent {
276
279
  return Some(Json::Number);
277
280
  }
278
281
  let text = std::str::from_utf8(&self.bytes[integer_start..integer_end]).ok()?;
@@ -74,53 +74,53 @@ pub enum Reason {
74
74
 
75
75
  impl Reason {
76
76
  /// Every reason, in the order the checks run.
77
- pub const ALL: [Reason; 18] = [
78
- Reason::MissingCookie,
79
- Reason::StateMismatch,
80
- Reason::TooLarge,
81
- Reason::Malformed,
82
- Reason::BadAlg,
83
- Reason::UnknownKid,
84
- Reason::BadSignature,
85
- Reason::BadIss,
86
- Reason::BadAud,
87
- Reason::BadEnv,
88
- Reason::MissingClaim,
89
- Reason::NotYetValid,
90
- Reason::Expired,
91
- Reason::Lifetime,
92
- Reason::NonceMismatch,
93
- Reason::Replay,
94
- Reason::EmailUnverified,
95
- Reason::SubjectMismatch,
77
+ pub const ALL: [Self; 18] = [
78
+ Self::MissingCookie,
79
+ Self::StateMismatch,
80
+ Self::TooLarge,
81
+ Self::Malformed,
82
+ Self::BadAlg,
83
+ Self::UnknownKid,
84
+ Self::BadSignature,
85
+ Self::BadIss,
86
+ Self::BadAud,
87
+ Self::BadEnv,
88
+ Self::MissingClaim,
89
+ Self::NotYetValid,
90
+ Self::Expired,
91
+ Self::Lifetime,
92
+ Self::NonceMismatch,
93
+ Self::Replay,
94
+ Self::EmailUnverified,
95
+ Self::SubjectMismatch,
96
96
  ];
97
97
 
98
98
  /// Returns the stable lowercase code, such as `"bad_aud"`.
99
- pub fn code(self) -> &'static str {
99
+ pub const fn code(self) -> &'static str {
100
100
  match self {
101
- Reason::MissingCookie => "missing_cookie",
102
- Reason::StateMismatch => "state_mismatch",
103
- Reason::TooLarge => "too_large",
104
- Reason::Malformed => "malformed",
105
- Reason::BadAlg => "bad_alg",
106
- Reason::UnknownKid => "unknown_kid",
107
- Reason::BadSignature => "bad_signature",
108
- Reason::BadIss => "bad_iss",
109
- Reason::BadAud => "bad_aud",
110
- Reason::BadEnv => "bad_env",
111
- Reason::MissingClaim => "missing_claim",
112
- Reason::NotYetValid => "not_yet_valid",
113
- Reason::Expired => "expired",
114
- Reason::Lifetime => "lifetime",
115
- Reason::NonceMismatch => "nonce_mismatch",
116
- Reason::Replay => "replay",
117
- Reason::EmailUnverified => "email_unverified",
118
- Reason::SubjectMismatch => "subject_mismatch",
101
+ Self::MissingCookie => "missing_cookie",
102
+ Self::StateMismatch => "state_mismatch",
103
+ Self::TooLarge => "too_large",
104
+ Self::Malformed => "malformed",
105
+ Self::BadAlg => "bad_alg",
106
+ Self::UnknownKid => "unknown_kid",
107
+ Self::BadSignature => "bad_signature",
108
+ Self::BadIss => "bad_iss",
109
+ Self::BadAud => "bad_aud",
110
+ Self::BadEnv => "bad_env",
111
+ Self::MissingClaim => "missing_claim",
112
+ Self::NotYetValid => "not_yet_valid",
113
+ Self::Expired => "expired",
114
+ Self::Lifetime => "lifetime",
115
+ Self::NonceMismatch => "nonce_mismatch",
116
+ Self::Replay => "replay",
117
+ Self::EmailUnverified => "email_unverified",
118
+ Self::SubjectMismatch => "subject_mismatch",
119
119
  }
120
120
  }
121
121
 
122
122
  /// Finds the reason that has this code.
123
- pub fn from_code(code: &str) -> Option<Reason> {
123
+ pub fn from_code(code: &str) -> Option<Self> {
124
124
  Self::ALL.into_iter().find(|reason| reason.code() == code)
125
125
  }
126
126
  }
@@ -133,7 +133,7 @@ pub struct Refusal {
133
133
 
134
134
  impl Refusal {
135
135
  /// Returns the stable reason code.
136
- pub fn code(&self) -> &'static str {
136
+ pub const fn code(&self) -> &'static str {
137
137
  self.reason.code()
138
138
  }
139
139
  }
@@ -221,7 +221,7 @@ impl<K: KeySource> Verifier<K> {
221
221
  }
222
222
 
223
223
  /// Exposes the single-use record, so a caller can share or inspect it.
224
- pub fn jti_store(&self) -> &JtiStore {
224
+ pub const fn jti_store(&self) -> &JtiStore {
225
225
  &self.jti_store
226
226
  }
227
227
 
@@ -5,7 +5,7 @@ use std::collections::HashMap;
5
5
  use std::sync::{Arc, Mutex};
6
6
 
7
7
  use async_trait::async_trait;
8
- use serde_json::{json, Value};
8
+ use serde_json::Value;
9
9
 
10
10
  use super::config::PlatformSigninConfig;
11
11
  use super::handler::{CallbackRequest, Random, SigninHandler, SigninLog};
@@ -235,17 +235,17 @@ pub fn request_for(step: &Value) -> CallbackRequest {
235
235
  if let Some(state) = step["state"].as_str() {
236
236
  query.push(format!("state={}", encode(state)));
237
237
  }
238
- let cookie_pairs = match step.get("cookie").filter(|c| !c.is_null()) {
239
- None => vec![],
240
- Some(cookie) => {
241
- let part = |n: &str| cookie.get(n).and_then(Value::as_str);
242
- let value = match part("state") {
243
- Some(state) => format!("{}.{state}", part("nonce").unwrap_or("")),
244
- None => part("nonce").unwrap_or("").to_string(),
245
- };
246
- vec![format!("__Host-signin={value}")]
247
- }
248
- };
238
+ let cookie_pairs =
239
+ step.get("cookie")
240
+ .filter(|c| !c.is_null())
241
+ .map_or_else(Vec::new, |cookie| {
242
+ let part = |n: &str| cookie.get(n).and_then(Value::as_str);
243
+ let value = part("state").map_or_else(
244
+ || part("nonce").unwrap_or("").to_string(),
245
+ |state| format!("{}.{state}", part("nonce").unwrap_or("")),
246
+ );
247
+ vec![format!("__Host-signin={value}")]
248
+ });
249
249
  CallbackRequest {
250
250
  raw_query: query.join("&"),
251
251
  cookie_pairs,
@@ -257,7 +257,7 @@ pub fn scripted_random(values: &[&str]) -> Random {
257
257
  let queue = Mutex::new(
258
258
  values
259
259
  .iter()
260
- .map(|v| v.to_string())
260
+ .map(std::string::ToString::to_string)
261
261
  .collect::<std::collections::VecDeque<_>>(),
262
262
  );
263
263
  Box::new(move || queue.lock().unwrap().pop_front().expect("a scripted value"))
@@ -312,8 +312,3 @@ pub fn single(doc: &Value, name: &str) -> Value {
312
312
  .unwrap_or_else(|| panic!("vector {name}"))
313
313
  .clone()
314
314
  }
315
-
316
- #[allow(dead_code)]
317
- fn _unused() -> Value {
318
- json!({})
319
- }