Skip to content

Instantly share code, notes, and snippets.

@mccraigmccraig
Created July 8, 2015 20:09
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 mccraigmccraig/ebaeaf495e5c9bf1be87 to your computer and use it in GitHub Desktop.
Save mccraigmccraig/ebaeaf495e5c9bf1be87 to your computer and use it in GitHub Desktop.
(ns delaymap
(:require [schema.core :as s])
(:import [clojure.lang MapEntry]))
(defn ^:private deref-seq [underlying]
(when-first [[k v] underlying]
(lazy-seq (cons (MapEntry. k @v) (deref-seq (rest underlying))))))
(defprotocol IValidatable
(schema [this])
(validate [this]))
(defmacro defcontext
[nm sch]
(let [constructor (symbol (str (name nm) "."))]
`(deftype ~nm [~'m]
clojure.lang.IPersistentMap
(~'assoc [_# k# v#] (~constructor (.assoc ~'m k# (delay v#))))
(~'assocEx [_# k# v#] (~constructor (.assocEx ~'m k# (delay v#))))
(~'without [_# k#] (~constructor (.without ~'m k#)))
clojure.lang.IPersistentCollection
(~'count [_#] (count ~'m))
(~'cons [_# o#] (let [[k# v#] o#] (~constructor (.cons ~'m [k# (delay v#)]))))
(~'empty [_#] (.empty ~'m))
(~'equiv [_# o#] (and (isa? (class o#) ~name)
(.equiv ~'m (.m o#))))
clojure.lang.Seqable
(~'seq [_#] (@#'delaymap/deref-seq (seq ~'m)))
clojure.lang.ILookup
(~'valAt [_# k#] (let [d# (.valAt ~'m k#)]
(when-not (nil? d#)
@d#)))
(~'valAt [_# k# v#] (if (.containsKey ~'m k#)
(deref (.valAt ~'m k#))
v#))
clojure.lang.Associative
(~'containsKey [_# k#] (.containsKey ~'m k#))
(~'entryAt [_# k#] (let [[k# v#] (.entryAt ~'m k#)]
(MapEntry. k# @v#)))
java.lang.Iterable
(~'iterator [this#] (.iterator (seq this#)))
IValidatable
(schema [this#] ~sch)
(validate [this#] (schema.core/validate ~sch this#)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment