Caching in transit-cljs

So I've been doing alot of coding in clojurescript lately and I had to do some work with transit-cljs.
One of the things I had to test was if I could do comprehensive caching and de-duping of objects serialized with transit-cljs. I based my tests on transit-js-caching but this article has an example in javascript and not clojurescript. So I needed to convert it. Here is how I did it but you will need to read the previous article for the motivation of each step.
1) include the transit-cljs library in your code
(ns main.transit
(:require [cognitect.transit :as t]))
2) define an Object in clojurescript
(defrecord Point [x y])
you can also use deftype but defrecord provides more helper functions like equality etc
3) define a custom write handler with transit-cljs and a function that uses it
(def PointHandler
(t/write-handler (fn [v, h] "point") (fn [v, h] [v.x v.y])))
(def writer (t/writer "json" {:handlers {Point PointHandler}}))
(defn write [x]
(t/write writer x))
3) use this writing function
(def p (Point. 1 2))
(print (write p))
(print (write [p p p p]))
gives
"[\"~#point\",[1,2]]"
"[[\"~#point\",[1,2]],[\"^0\",[1,2]],
[\"^0\",[1,2]],[\"^0\",[1,2]]]"
see by default transit-cljs caches the keys in the JSON
4) create a custom reader
(defn read [x]
(t/read (t/reader "json"
{:handlers {"point"
(fn [v]
(Point. (aget v 0)
(aget v 1)))}})
x))
5) now we can do a roundtrip!
(print (= p (read (write p))))
(print (= [p p p p] (read (write [p p p p]))))
true
true
6) How do we write a caching writer
(defn caching-point-handler
([] (caching-point-handler (atom {})))
([cache]
(t/write-handler
(fn [v, h] (if (get @cache v)
"cache"
"point"))
(fn [v, h] (let [id (get @cache v)]
(if (nil? id)
(do
(swap! cache
#(assoc % v (count %)))
[v.x v.y])
id))))))
(defn c-writer
[]
(t/writer "json" {:handlers {Point (caching-point-handler)}}))
(defn c-write [x]
(t/write (c-writer) x))
7) what does this produce
(print (c-write p))
(print (c-write [p p p p]))
"[\"~#point\",[1,2]]"
"[[\"~#point\",[1,2]],[\"~#cache\",0],
[\"^1\",0],[\"^1\",0]]"
note that the second item is cached and the "cache" keyword is replaced by ^1 in the third item
8) what does the reader look like
(defn c-read [x]
(let [cache (atom {})]
(t/read (t/reader "json"
{:handlers {"point"
(fn [v]
(let [point (Point.
(aget v 0)
(aget v 1))]
(swap! cache
#(assoc %
(count %) point))
point))
"cache"
(fn [v]
(get @cache v))}})
x)))
9) now we can roundtrip
(print (= p (c-read (c-write p))))
(print (= [p p p p] (c-read (c-write [p p p p]))))))
true
true