Host shims and protocol fixes shaken out by aws-api

Running cognitect aws-api's pure test namespaces (signing/shapes/protocols/
util/retry/endpoints) surfaced general gaps:

- extend-protocol/extend-type accept a computed class type, e.g.
  (Class/forName "[B") for the byte-array class — the byte-array idiom data.json
  and aws-api use. The macro grouping handled only symbol/nil heads (it crashed on
  a list type); type->name resolves a Class value via .getName; a byte-array
  dispatches on the "[B" host tag.
- java.nio.ByteBuffer over a jolt byte-array (wrap/allocate/get/put/array/
  remaining/position/limit/duplicate/flip), plus extend-protocol to it.
- java.util.Arrays (equals/copyOf/copyOfRange/fill) and java.util.Random
  (nextBytes/nextInt/…).
- java.net.URI/create and clojure.lang.RT/baseLoader statics.
- clojure.core.async/promise-chan (deliver-once, peek-don't-pop).
- a failed java.time parse throws DateTimeParseException (typed), so
  (catch DateTimeParseException …) matches it instead of leaking an untyped
  condition.

The XML side lives in the jolt-lang/xml library (libxml2 over jolt.ffi); ByteBuffer
stays in core as a generic java.nio primitive.

Gate: make test green (corpus +6 JVM-certified rows, 0 NEW divergence; unit
553/553; SCI 211).
This commit is contained in:
Yogthos 2026-06-25 16:56:48 -04:00
parent 05f29d1bcb
commit 829c251bca
12 changed files with 762 additions and 549 deletions

View file

@ -462,12 +462,23 @@
(or (= tn want) (suffix? tn want) (suffix? want tn))))
(extenders protocol)))))
;; The canonical name for a protocol-extension type: a symbol/keyword via name, a
;; string as-is, nil as "nil" (extends on nil values), and a Class VALUE — e.g.
;; (Class/forName "[B") for the byte-array class — via .getName. Lets a library
;; extend a protocol to a class it computes rather than names with a symbol.
(defn type->name [t]
(cond (nil? t) "nil"
(string? t) t
(symbol? t) (name t)
(keyword? t) (name t)
:else (.getName t)))
;; extend, the FUNCTION (extend-type's runtime sibling): protocol + method-map
;; pairs, methods registered under the type's (canonicalized) name — so
;; (extend 'String P {:m (fn [x] ...)}) dispatches exactly like extend-type.
(defn extend [atype & proto+mmaps]
;; nil extends on nil values; its host tag is the string "nil" (as extend-type).
(let [tname (if (nil? atype) "nil" (name atype))]
(let [tname (type->name atype)]
(loop [s (seq proto+mmaps)]
(when s
(let [proto (first s)
@ -484,21 +495,41 @@
;; `body` is one or more protocols, each followed by its method specs:
;; (extend-type T P1 (m1 [_] ..) P2 (m2 [_] ..)) — a bare symbol switches the
;; current protocol (like reify), so multiple protocols extend in one form.
(let [tname (if (nil? tsym) "nil" (name tsym))]
(loop [items (seq body) proto nil forms []]
(if (empty? items)
`(do ~@forms)
(let [x (first items)]
(if (symbol? x)
(recur (rest items) (name x) forms)
(recur (rest items) proto
(conj forms
`(register-method ~tname ~proto ~(name (first x))
(fn ~(nth x 1) ~@(drop 2 x)))))))))))
;; tsym may be a symbol/nil (name resolved at compile time) or a computed class
;; expression like (Class/forName "[B") — bind its runtime name once.
(let [literal? (or (nil? tsym) (symbol? tsym))
tn (gensym "tname")
tref (if literal? (if (nil? tsym) "nil" (name tsym)) tn)
emit (fn []
(loop [items (seq body) proto nil forms []]
(if (empty? items)
forms
(let [x (first items)]
(if (symbol? x)
(recur (rest items) (name x) forms)
(recur (rest items) proto
(conj forms
`(register-method ~tref ~proto ~(name (first x))
(fn ~(nth x 1) ~@(drop 2 x))))))))))]
(if literal?
`(do ~@(emit))
`(let [~tn (type->name ~tsym)] ~@(emit) nil))))
;; Group an extend-protocol body into [type method-spec*] groups: the type is the
;; first item and its method specs are the seqs that follow it (up to the next
;; type — a symbol/nil — or end). Handles a computed class type (a seq like
;; (Class/forName "[B")) positionally, matching Clojure's parse-impls.
(defn- parse-extend-impls [items]
(loop [s (seq items) groups []]
(if (empty? s)
groups
(let [after (rest s)]
(recur (drop-while seq? after)
(conj groups (vec (cons (first s) (take-while seq? after)))))))))
(defmacro extend-protocol [psym & type-impls]
`(do ~@(map (fn [g] `(extend-type ~(first g) ~psym ~@(rest g)))
(group-by-head type-impls))))
(parse-extend-impls type-impls))))
;; extend is a real FUNCTION — defined above extend-type.
;; JVM proxies are unsupported.