 
 (defprotocol JSONWriter
   (-write [object out options]
-    "Print object to PrintWriter out as JSON"))
-
-(defn- ->hex-string [^PrintWriter out cp]
+    "Print object to Appendable out as JSON"))
+
+(defn- ->hex-string [^Appendable out cp]
   (let [cpl (long cp)]
-    (.write out "\\u")
+    (.append out "\\u")
     (cond
       (< cpl 16)
-      (.write out "000")
+      (.append out "000")
       (< cpl 256)
-      (.write out "00")
+      (.append out "00")
       (< cpl 4096)
-      (.write out "0"))
-    (.write out (Integer/toHexString cp))))
+      (.append out "0"))
+    (.append out (Integer/toHexString cp))))
 
 (def ^{:tag "[S"} codepoint-decoder
   (let [shorts (short-array 128)]

          (if-not (= value-fn out-value)
            (do
              (when have-printed-kv
                (.print out \,))
              (write-string out-key out options)
              (.print out \:)
              (-write out-value out options)
              (when (seq nxt)
                (recur nxt true)))
            (when (seq nxt)
              (recur nxt have-printed-kv)))))))
  (.print out \}))

(defn- write-array [s ^PrintWriter out options]
  (.print out \[)
  (loop [x s]
    (when (seq x)
      (let [fst (first x)
            nxt (next x)]
        (-write fst out options)
        (when (seq nxt)
          (.print out \,)
          (recur nxt)))))
  (.print out \]))

(defn- write-bignum [x ^PrintWriter out options]
  (.print out (str x)))

(defn- write-float [^Float x ^PrintWriter out options]
  (cond (.isInfinite x)
        (throw (Exception. "JSON error: cannot write infinite Float"))
        (.isNaN x)
        (throw (Exception. "JSON error: cannot write Float NaN"))
        :else
        (.print out x)))

(defn- write-double [^Double x ^PrintWriter out options]
  (cond (.isInfinite x)
        (throw (Exception. "JSON error: cannot write infinite Double"))
        (.isNaN x)
        (throw (Exception. "JSON error: cannot write Double NaN"))
        :else
        (.print out x)))

(defn- write-plain [x ^PrintWriter out options]
  (.print out x))

(defn- write-null [x ^PrintWriter out options]
  (.print out "null"))

(defn- write-named [x out options]
  (write-string (name x) out options))

        returns itself, the key-value pair will be omitted from the
        output. This option does not apply to non-map collections."
  [x ^Writer writer & options]
  (-write x writer (merge default-write-options (apply array-map options))))

(defn write-str
  "Converts x to a JSON-formatted string. Options are the same as
  write."
  [x & options]
  (let [sw (StringBuilder.)]
    (-write x sw (merge default-write-options (apply array-map options)))
    (.toString sw)))

;;; JSON PRETTY-PRINTER
