(defmacro or
"Takes key+pred pairs, e.g.
(s/or :even even? :small #(< % 42))
Returns a destructuring spec that returns a map entry containing the
key of the first matching pred and the corresponding value. Thus the
'key' and 'val' functions can be used to refer generically to the
components of the tagged return."
[& key-pred-forms]
(let [pairs (partition 2 key-pred-forms)
keys (mapv first pairs)
pred-forms (mapv second pairs)
pf (mapv res pred-forms)]
(c/assert (c/and (even? (count key-pred-forms)) (every? keyword? keys)) "spec/or expects k1 p1 k2 p2..., where ks are keywords")
`(or-spec-impl ~keys '~pf ~pred-forms nil)))