refactor(core): ask serde for a map, instead of reading the first byte
I was wrong about this one and Indy was right to push.
The object gate scanned for the first non-whitespace byte and required
`{`. I defended that by saying the pure-serde alternatives parse twice —
which is true of the two I had actually evaluated (round-tripping
through `Value` or `Map`, both of which build a whole intermediate tree)
and false as a statement about serde. Serde has a single-pass answer and
I did not go looking for it.
The derive asks the deserializer for a STRUCT, and `serde_json` answers
that request by accepting either `{` or `[`. `ObjectOnly` sits between
the two and forwards that one request as a request for a MAP, which
`serde_json` answers with `{` alone:
derive adapter serde_json input
deserialize_struct → deserialize_map → expects `{` ← {"a":1} ok
← [1] refused
One pass, no intermediate, nothing scanning bytes. Everything else
forwards untouched, so a missing field, a wrong type and a borrowed
`&'de str` behave exactly as they do without the adapter, and only the
TOP level is constrained — the same scope `loadJson`'s
`parsed.value != .object` has.
It is also a better refusal than the one it replaces. The byte scan
answered a generic "expected a JSON object" this module had to word
itself; serde answers `invalid type: sequence, expected struct Pair`,
naming the type that was wanted. Two of the tests now assert on serde's
message rather than on a string of ours.
Separately, `ssrf`'s test helpers were re-parsing whole URLs to reach a
host — duplicating the parse `endpoint` already owns, so every range
assertion was re-exercising a parser that is not this module's subject.
They build a `Host` directly now. The two meet where a URL is actually
the point, in `endpoint`'s own SSRF-range test.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> K
Kishore Kumar committed
3288bfb92fdcc53b919b7af7eed5d0c4463720cf
Parent: 3fa990e