-
-
Save borkdude/19ac04ea0b2ef9d6643ba3de6817de57 to your computer and use it in GitHub Desktop.
emit-record2.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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