Skip to content

Instantly share code, notes, and snippets.

@borkdude
Created May 15, 2022 16:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save borkdude/19ac04ea0b2ef9d6643ba3de6817de57 to your computer and use it in GitHub Desktop.
Save borkdude/19ac04ea0b2ef9d6643ba3de6817de57 to your computer and use it in GitHub Desktop.
emit-record2.clj
(defn- emit-defrecord2
"Do not use this directly - use defrecord"
{:added "1.2"}
[tagname cname fields interfaces methods opts]
(let [classname (with-meta (symbol (str (namespace-munge *ns*) "." cname)) (meta cname))
interfaces (vec interfaces)
interface-set (set (map resolve interfaces))
methodname-set (set (map first methods))
hinted-fields fields
fields (vec (map #(with-meta % nil) fields))
base-fields fields
fields (conj fields '__meta '__extmap 'scimeta
'^:unsynchronized-mutable __hash
'^:unsynchronized-mutable __hasheq)
type-hash (hash classname)]
(when (some #{:volatile-mutable :unsynchronized-mutable} (mapcat (comp keys meta) hinted-fields))
(throw (IllegalArgumentException. ":volatile-mutable or :unsynchronized-mutable not supported for record fields")))
(let [gs (gensym)]
(letfn
[(irecord [[i m]]
[(conj i 'clojure.lang.IRecord)
m])
(eqhash [[i m]]
[(conj i 'clojure.lang.IHashEq)
(conj m
`(hasheq [this#] (let [hq# ~'__hasheq]
(if (zero? hq#)
(let [h# (int (bit-xor ~type-hash (clojure.lang.APersistentMap/mapHasheq this#)))]
(set! ~'__hasheq h#)
h#)
hq#)))
`(hashCode [this#] (let [hash# ~'__hash]
(if (zero? hash#)
(let [h# (clojure.lang.APersistentMap/mapHash this#)]
(set! ~'__hash h#)
h#)
hash#)))
`(equals [this# ~gs] (clojure.lang.APersistentMap/mapEquals this# ~gs)))])
(iobj [[i m]]
[(conj i 'clojure.lang.IObj)
(conj m `(meta [this#] ~'__meta)
`(withMeta [this# ~gs] (new ~tagname ~@(replace {'__meta gs} fields))))])
(ilookup [[i m]]
[(conj i 'clojure.lang.ILookup 'clojure.lang.IKeywordLookup)
(conj m `(valAt [this# k#] (.valAt this# k# nil))
`(valAt [this# k# else#]
(case k# ~@(mapcat (fn [fld] [(keyword fld) fld])
base-fields)
(get ~'__extmap k# else#)))
`(getLookupThunk [this# k#]
(let [~'gclass (class this#)]
(case k#
~@(let [hinted-target (with-meta 'gtarget {:tag tagname})]
(mapcat
(fn [fld]
[(keyword fld)
`(reify clojure.lang.ILookupThunk
(get [~'thunk ~'gtarget]
(if (identical? (class ~'gtarget) ~'gclass)
(. ~hinted-target ~(symbol (str "-" fld)))
~'thunk)))])
base-fields))
nil))))])
(imap [[i m]]
[(conj i 'clojure.lang.IPersistentMap)
(conj m
`(count [this#] (+ ~(count base-fields) (count ~'__extmap)))
`(empty [this#] (throw (UnsupportedOperationException. (str "Can't create empty: " ~(str classname)))))
`(cons [this# e#] ((var clojure.core/imap-cons) this# e#))
`(equiv [this# ~gs]
(boolean
(or (identical? this# ~gs)
(when (identical? (class this#) (class ~gs))
(let [~gs ~(with-meta gs {:tag tagname})]
(and ~@(map (fn [fld] `(= ~fld (. ~gs ~(symbol (str "-" fld))))) base-fields)
(= ~'__extmap (. ~gs ~'__extmap))))))))
`(containsKey [this# k#] (not (identical? this# (.valAt this# k# this#))))
`(entryAt [this# k#] (let [v# (.valAt this# k# this#)]
(when-not (identical? this# v#)
(clojure.lang.MapEntry/create k# v#))))
`(seq [this#] (seq (concat [~@(map #(list `clojure.lang.MapEntry/create (keyword %) %) base-fields)]
~'__extmap)))
`(iterator [~gs]
(clojure.lang.RecordIterator. ~gs [~@(map keyword base-fields)] (clojure.lang.RT/iter ~'__extmap)))
`(assoc [this# k# ~gs]
(condp identical? k#
~@(mapcat (fn [fld]
[(keyword fld) (list* `new tagname (replace {fld gs} (remove '#{__hash __hasheq scimeta} fields)))])
base-fields)
(new ~tagname ~@(remove '#{__extmap __hash __hasheq scimeta} fields) (assoc ~'__extmap k# ~gs))))
`(without [this# k#] (if (contains? #{~@(map keyword base-fields)} k#)
(dissoc (with-meta (into {} this#) ~'__meta) k#)
(new ~tagname ~@(remove '#{__extmap __hash __hasheq scimeta} fields)
(not-empty (dissoc ~'__extmap k#))))))])
(ijavamap [[i m]]
[(conj i 'java.util.Map 'java.io.Serializable)
(conj m
`(size [this#] (.count this#))
`(isEmpty [this#] (= 0 (.count this#)))
`(containsValue [this# v#] (boolean (some #{v#} (vals this#))))
`(get [this# k#] (.valAt this# k#))
`(put [this# k# v#] (throw (UnsupportedOperationException.)))
`(remove [this# k#] (throw (UnsupportedOperationException.)))
`(putAll [this# m#] (throw (UnsupportedOperationException.)))
`(clear [this#] (throw (UnsupportedOperationException.)))
`(keySet [this#] (set (keys this#)))
`(values [this#] (vals this#))
`(entrySet [this#] (set this#)))])
]
(let [[i m] (-> [interfaces methods] irecord eqhash iobj ilookup imap ijavamap)]
`(deftype* ~(symbol (name (ns-name *ns*)) (name tagname)) ~classname
~(conj hinted-fields '__meta '__extmap '__sci-meta
'^int ^:unsynchronized-mutable __hash
'^int ^:unsynchronized-mutable __hasheq)
:implements ~(vec i)
~@(mapcat identity opts)
~@m))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment