diff --git a/src/taoensso/nippy/tools.clj b/src/taoensso/nippy/tools.clj index 09bfa5a..ca7eb39 100644 --- a/src/taoensso/nippy/tools.clj +++ b/src/taoensso/nippy/tools.clj @@ -1,60 +1,74 @@ (ns taoensso.nippy.tools - "Utils for 3rd-party tools that want to add user-configurable Nippy support. + "Utils for community tools that want to add user-configurable Nippy support. Used by Carmine, Faraday, etc." (:require [taoensso.nippy :as nippy])) (def ^:dynamic *freeze-opts* nil) (def ^:dynamic *thaw-opts* nil) -(defmacro with-freeze-opts [opts & body] `(binding [*freeze-opts* ~opts] ~@body)) -(defmacro with-thaw-opts [opts & body] `(binding [*thaw-opts* ~opts] ~@body)) +(defn ^:no-doc -merge-opts + "Private, implementation detail." + ([x y ] (if x (conj x y) y)) + ([x y z] (-merge-opts (-merge-opts x y) z))) + +(do + (defmacro with-freeze-opts [opts & body] `(binding [*freeze-opts* ~opts ] ~@body)) + (defmacro with-freeze-opts+ [opts & body] `(binding [*freeze-opts* (-merge-opts *freeze-opts* ~opts)] ~@body)) + (defmacro with-thaw-opts [opts & body] `(binding [*thaw-opts* ~opts ] ~@body)) + (defmacro with-thaw-opts+ [opts & body] `(binding [*thaw-opts* (-merge-opts *thaw-opts* ~opts)] ~@body))) (deftype WrappedForFreezing [val opts]) (defn wrapped-for-freezing? [x] (instance? WrappedForFreezing x)) -(defn wrap-for-freezing - "Ensures that given arg (any freezable data type) is wrapped so that - (tools/freeze ) will serialize as - (nippy/freeze ). - See also `nippy.tools/freeze`, `nippy.tools/thaw`." - ([x ] (wrap-for-freezing x nil)) - ([x opts] - (if (instance? WrappedForFreezing x) - (let [^WrappedForFreezing x x] - (if (= (.-opts x) opts) - x - (WrappedForFreezing. (.-val x) opts))) - (WrappedForFreezing. x opts)))) +(let [-merge-opts -merge-opts] + (defn wrap-for-freezing + "Captures (merge `tools/*thaw-opts*` `wrap-opts`), and returns + the given argument in a wrapped form so that `tools/freeze` will + use the captured options when freezing the wrapper argument. -(defn freeze - "Like `nippy/freeze` but uses as opts the following merged in order of - ascending preference: + See also `tools/freeze`." + ([x ] (wrap-for-freezing x nil)) + ([x wrap-opts] + (let [captured-opts (-merge-opts *freeze-opts* wrap-opts)] ; wrap > dynamic + (if (instance? WrappedForFreezing x) + (let [^WrappedForFreezing x x] + (if (= (.-opts x) captured-opts) + x + (WrappedForFreezing. (.-val x) captured-opts))) + (WrappedForFreezing. x captured-opts)))))) - - Optional `default-opts` arg given to this fn (default nil). - - Optional `*freeze-opts*` dynamic value (default nil). - - Optional opts provided to `wrap-for-freezing` (default nil)." +(let [-merge-opts -merge-opts] + (defn freeze + "Like `nippy/freeze` but uses as options the following, merged in + order of ascending preference: - ([x ] (freeze x nil)) - ([x default-opts] - (let [default-opts (get default-opts :default-opts default-opts) ; For back compatibility - merged-opts (conj (or default-opts {}) *freeze-opts*)] + 1. `default-opts` given to this fn (default nil). + 2. `tools/*freeze-opts*` dynamic value (default nil). + 3. Opts captured by `tools/wrap-for-freezing` (default nil). - (if (instance? WrappedForFreezing x) - (let [^WrappedForFreezing x x] - (nippy/freeze (.-val x) (conj merged-opts (.-opts x)))) - (nippy/freeze x merged-opts))))) + See also `tools/wrap-for-freezing`." + ([x ] (freeze x nil)) + ([x default-opts] + (let [default-opts (get default-opts :default-opts default-opts) ; Back compatibility + active-opts (-merge-opts default-opts *freeze-opts*)] ; dynamic > default -(defn thaw - "Like `nippy/thaw` but uses as opts the following merged in order of - ascending preference: + (if (instance? WrappedForFreezing x) + (let [^WrappedForFreezing x x] + (nippy/freeze (.-val x) (-merge-opts active-opts (.-opts x)))) ; captured > active! + (nippy/freeze x active-opts)))))) - - Optional `default-opts` arg given to this fn (default nil). - - Optional `*thaw-opts*` dynamic value (default nil)." +(let [-merge-opts -merge-opts] + (defn thaw + "Like `nippy/thaw` but uses as options the following, merged in + order of ascending preference: - ([ba ] (thaw ba nil)) - ([ba default-opts] - (let [default-opts (get default-opts :default-opts default-opts) ; For back compatibility - merged-opts (conj (or default-opts {}) *thaw-opts*)] - (nippy/thaw ba merged-opts)))) + 1. `default-opts` given to this fn (default nil). + 2. `tools/*thaw-opts*` dynamic value (default nil)." + ([ba ] (thaw ba nil)) + ([ba default-opts] + (let [default-opts (get default-opts :default-opts default-opts) ; Back compatibility + active-opts (-merge-opts default-opts *thaw-opts*)] ; dynamic > default + + (nippy/thaw ba active-opts))))) (comment (thaw (freeze (wrap-for-freezing "wrapped"))))