|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Build & Test Commands |
| 6 | + |
| 7 | +```bash |
| 8 | +TORQUE_BUILD=true mix deps.get # fetch deps + force local Rust build |
| 9 | +TORQUE_BUILD=true mix compile # build (includes Rust NIF compilation) |
| 10 | +TORQUE_BUILD=true mix test # run all tests |
| 11 | +mix test test/torque_test.exs:42 # run single test by line number |
| 12 | +mix compile --warnings-as-errors # build with strict warnings |
| 13 | +mix format # format Elixir code |
| 14 | +mix format --check-formatted # check Elixir formatting |
| 15 | +mix dialyzer # static type analysis |
| 16 | +cargo fmt # format Rust code (run from repo root) |
| 17 | +cargo fmt --check # check Rust formatting |
| 18 | +cargo clippy -- -D warnings # Rust linter |
| 19 | +mix run bench/torque_bench.exs # run benchmarks (requires simdjsone + jiffy) |
| 20 | +``` |
| 21 | + |
| 22 | +`TORQUE_BUILD=true` is required for local development to force compilation from Rust source instead of downloading precompiled binaries. Without it, `RustlerPrecompiled` will try to fetch binaries from GitHub releases. |
| 23 | + |
| 24 | +## Releasing |
| 25 | + |
| 26 | +```bash |
| 27 | +./scripts/release.sh # tags, pushes, waits for CI, generates checksums |
| 28 | +``` |
| 29 | + |
| 30 | +The script reads the version from `mix.exs`, creates a git tag, waits for the release workflow to build precompiled NIFs for all targets, then generates checksums. After it completes, commit the checksum file and run `mix hex.publish`. |
| 31 | + |
| 32 | +## Architecture |
| 33 | + |
| 34 | +Torque is a high-performance JSON library for Elixir using Rustler NIFs backed by sonic-rs (SIMD-accelerated JSON). |
| 35 | + |
| 36 | +### Decoding Strategies |
| 37 | + |
| 38 | +1. **Parse + Get** — `parse/1` returns an opaque reference to a parsed document. `get/2,3` extracts fields by JSON Pointer (RFC 6901) path. `get_many/2` extracts multiple fields in a single NIF call. Ideal when only a subset of fields is needed (e.g. OpenRTB bid request processing). |
| 39 | + |
| 40 | +2. **Full decode** — `decode/1` converts an entire JSON binary into Elixir terms in one pass. |
| 41 | + |
| 42 | +### Encoding |
| 43 | + |
| 44 | +`encode/1` walks Elixir terms directly (no intermediate representation) and writes JSON bytes to a buffer. Supports maps (atom/binary keys), lists, numbers, booleans, nil, and jiffy-style `{proplist}` tuples. |
| 45 | + |
| 46 | +### Scheduler Awareness |
| 47 | + |
| 48 | +Inputs larger than 10 KB are automatically dispatched to dirty CPU schedulers to avoid blocking normal BEAM schedulers. The `get/2` NIF always runs on a normal scheduler (sub-microsecond pointer traversal). |
| 49 | + |
| 50 | +### Type Conversion |
| 51 | + |
| 52 | +| JSON | Elixir | |
| 53 | +|------|--------| |
| 54 | +| object | map with binary keys | |
| 55 | +| array | list | |
| 56 | +| string | binary | |
| 57 | +| integer | integer (i64/u64) | |
| 58 | +| float | float | |
| 59 | +| true/false | true/false | |
| 60 | +| null | nil | |
| 61 | + |
| 62 | +### Key Files |
| 63 | + |
| 64 | +- `lib/torque.ex` — public API with `@doc`, typespecs, dirty scheduler dispatch |
| 65 | +- `lib/torque/native.ex` — RustlerPrecompiled NIF stubs (set `TORQUE_BUILD=true` to compile from source) |
| 66 | +- `native/torque_nif/src/lib.rs` — NIF registration, `ParsedDocument` resource |
| 67 | +- `native/torque_nif/src/decoder.rs` — parse, get, get_many, decode NIFs |
| 68 | +- `native/torque_nif/src/encoder.rs` — direct term-walking JSON encoder |
| 69 | +- `native/torque_nif/src/types.rs` — sonic_rs Value → Erlang term conversion |
| 70 | +- `native/torque_nif/src/atoms.rs` — cached atoms (ok, error, no_such_field, nil) |
0 commit comments