(defn ^:skip-wiki or-spec-impl
"Do not call this directly, use 'or'"
[keys forms preds gfn]
(let [id (java.util.UUID/randomUUID)
kps (zipmap keys preds)
specs (delay (mapv specize preds forms))
cform (case (count preds)
2 (fn [x]
(let [specs @specs
ret (conform* (specs 0) x)]
(if (invalid? ret)
(let [ret (conform* (specs 1) x)]
(if (invalid? ret)
::invalid
(tagged-ret (keys 1) ret)))
(tagged-ret (keys 0) ret))))
3 (fn [x]
(let [specs @specs
ret (conform* (specs 0) x)]
(if (invalid? ret)
(let [ret (conform* (specs 1) x)]
(if (invalid? ret)
(let [ret (conform* (specs 2) x)]
(if (invalid? ret)
::invalid
(tagged-ret (keys 2) ret)))
(tagged-ret (keys 1) ret)))
(tagged-ret (keys 0) ret))))
(fn [x]
(let [specs @specs]
(loop [i 0]
(if (< i (count specs))
(let [spec (specs i)]
(let [ret (conform* spec x)]
(if (invalid? ret)
(recur (inc i))
(tagged-ret (keys i) ret))))
::invalid)))))]
(reify
Specize
(specize* [s] s)
(specize* [s _] s)
Spec
(conform* [_ x] (cform x))
(unform* [_ [k x]] (unform (kps k) x))
(explain* [this path via in x]
(when-not (pvalid? this x)
(apply concat
(map (fn [k form pred]
(when-not (pvalid? pred x)
(explain-1 form pred (conj path k) via in x)))
keys forms preds))))
(gen* [_ overrides path rmap]
(if gfn
(gfn)
(let [gen (fn [k p f]
(let [rmap (inck rmap id)]
(when-not (recur-limit? rmap id path k)
(gen/delay
(gensub p overrides (conj path k) rmap f)))))
gs (remove nil? (map gen keys preds forms))]
(when-not (empty? gs)
(gen/one-of gs)))))
(with-gen* [_ gfn] (or-spec-impl keys forms preds gfn))
(describe* [_] `(or ~@(mapcat vector keys forms))))))