Skip to content

Instantly share code, notes, and snippets.

@bsless
Last active November 13, 2021 17:52
Show Gist options
  • Save bsless/db15d79f4ec9acac92e18db8fba27135 to your computer and use it in GitHub Desktop.
Save bsless/db15d79f4ec9acac92e18db8fba27135 to your computer and use it in GitHub Desktop.
defrecord which "proxies" protocols to its first field
(defmacro defrecord*
[-name fields & opts+specs]
(let [p (:proxy (meta -name))
extra (for [protocol p
:let [-ns (namespace protocol)
arg (first fields)
p' @(requiring-resolve protocol)]]
[protocol
(apply
concat
(for [[_ spec] (:sigs p')
arglist (:arglists spec)
:let [method (:name spec)
method' (symbol -ns (name method))]]
`(~method [~@arglist] (~method' ~arg ~@(rest arglist)))))])
extra (apply concat extra)
opts `(~@extra ~@opts+specs)]
`(defrecord ~-name ~fields ~@opts)))
(defrecord*
^{:proxy [clojure.core.protocols/IKVReduce]}
Foo
[m]
component/Lifecycle
(start [this])
(stop [this]))
:: TODO handle interfaces nicely
(let [arg 'arg]
(for [member (:members (clojure.reflect/reflect java.util.Map))
:let [flags (:flags member)]
:when (and (:public flags)
(not (:static flags)))
:let [{method :name
params :parameter-types} member
args (into ['_]
(map
(fn [p]
(cond-> (gensym)
(not= p java.lang.Object)
(with-meta {:tag p}))))
params)]]
`(~method [~@args] (. ~arg ~method ~@(rest args)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment