Skip to content

Commit 0ec6077

Browse files
committed
~wip
1 parent defd88a commit 0ec6077

4 files changed

Lines changed: 215 additions & 228 deletions

File tree

src/taoensso/nippy.clj

Lines changed: 14 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@
2424
APersistentMap APersistentVector APersistentSet
2525
IPersistentMap ; IPersistentVector IPersistentSet IPersistentList
2626
PersistentQueue PersistentTreeMap PersistentTreeSet PersistentList
27-
MapEntry LazySeq IRecord ISeq IType]
28-
29-
[taoensso.nippy.impl Cached]))
27+
MapEntry LazySeq IRecord ISeq IType]))
3028

3129
(enc/assert-min-encore-version [3 160 1])
3230

@@ -364,190 +362,6 @@
364362
(call-with-bindings :freeze {} (fn [] *freeze-fallback*))
365363
(call-with-bindings :freeze {:freeze-fallback "foo"} (fn [] *freeze-fallback*))))
366364

367-
;;;; Freeze interface
368-
369-
(defprotocol IFreezable
370-
"Private implementation detail.
371-
Protocol that types must implement to support native freezing by Nippy.
372-
Don't use this directly, instead see `extend-freeze`."
373-
(-freezable? [_])
374-
(-freeze-without-meta! [_ data-output]))
375-
376-
(defprotocol IFreezableWithMeta
377-
"Private implementation detail.
378-
Wrapper protocol around `IFreezable` used to handle possible metadata."
379-
(-freeze-with-meta! [_ data-output]))
380-
381-
;;;; Freeze implementations
382-
383-
(extend-protocol IFreezableWithMeta
384-
clojure.lang.IObj ; IMeta => `meta` will work, IObj => `with-meta` will work
385-
(-freeze-with-meta! [x ^DataOutput data-output]
386-
(when-let [m (when *incl-metadata?* (not-empty (meta x)))]
387-
(io/write-id data-output sc/id-meta)
388-
(io/write-map data-output m :is-metadata))
389-
(-freeze-without-meta! x data-output))
390-
391-
nil (-freeze-with-meta! [x data-output] (-freeze-without-meta! x data-output))
392-
Object (-freeze-with-meta! [x data-output] (-freeze-without-meta! x data-output)))
393-
394-
(defmacro ^:private freezer
395-
"Convenience util / short-hand."
396-
[atype id freezable? impl-form]
397-
(let [atype (or (when (symbol? atype) (when-let [r (resolve atype)] (when (var? r) @r))) atype)
398-
x (with-meta 'x {:tag atype})
399-
out (with-meta 'out {:tag 'DataOutput})
400-
id-form (when id `(io/write-id ~'out ~id))]
401-
402-
`(extend ~atype IFreezable
403-
{:-freezable? (fn [~x] ~freezable?)
404-
:-freeze-without-meta! (fn [~x ~out] ~id-form ~impl-form)})))
405-
406-
;; @TODO Inline, or move this stuff to io ns
407-
408-
(freezer nil sc/id-nil true nil)
409-
(freezer (type ()) sc/id-list-0 true nil)
410-
(freezer Character sc/id-char true (.writeChar out (int x)))
411-
(freezer Byte sc/id-byte true (.writeByte out x))
412-
(freezer Short sc/id-short true (.writeShort out x))
413-
(freezer Integer sc/id-integer true (.writeInt out x))
414-
(freezer BigInt sc/id-bigint true (io/write-biginteger out (.toBigInteger x)))
415-
(freezer BigInteger sc/id-biginteger true (io/write-biginteger out x))
416-
(freezer Pattern sc/id-regex true (io/write-str out (str x)))
417-
(freezer Float sc/id-float true (.writeFloat out x))
418-
(freezer BigDecimal sc/id-bigdec true
419-
(do
420-
(io/write-biginteger out (.unscaledValue x))
421-
(.writeInt out (.scale x))))
422-
423-
(freezer Cached nil true
424-
(let [x-val (.-val x)]
425-
(if-let [cache_ (.get impl/tl:cache)]
426-
(io/write-cached out x-val cache_)
427-
(-freeze-with-meta! x-val out))))
428-
429-
(freezer Ratio sc/id-ratio true
430-
(do
431-
(io/write-biginteger out (.numerator x))
432-
(io/write-biginteger out (.denominator x))))
433-
434-
(freezer MapEntry sc/id-map-entry true
435-
(do
436-
(-freeze-with-meta! (key x) out)
437-
(-freeze-with-meta! (val x) out)))
438-
439-
(freezer java.util.Date sc/id-util-date true (.writeLong out (.getTime x)))
440-
(freezer java.sql.Date sc/id-sql-date true (.writeLong out (.getTime x)))
441-
(freezer URI sc/id-uri true (io/write-str out (.toString x)))
442-
(freezer UUID sc/id-uuid true
443-
(do
444-
(.writeLong out (.getMostSignificantBits x))
445-
(.writeLong out (.getLeastSignificantBits x))))
446-
447-
(freezer Boolean nil true (if (boolean x) (io/write-id out sc/id-true) (io/write-id out sc/id-false)))
448-
(freezer String nil true (io/write-str out x))
449-
(freezer Keyword nil true (io/write-kw out x))
450-
(freezer Symbol nil true (io/write-sym out x))
451-
(freezer Long nil true (io/write-long out x))
452-
(freezer Double nil true
453-
(if (zero? ^double x)
454-
(do (io/write-id out sc/id-double-0))
455-
(do (io/write-id out sc/id-double) (.writeDouble out x))))
456-
457-
(freezer impl/array-class-bytes nil true (io/write-bytes out x))
458-
(freezer impl/array-class-objects nil true (io/write-array-lg out x (alength ^objects x) sc/id-object-array-lg))
459-
460-
(when (impl/target-release>= 350)
461-
(freezer impl/array-class-ints nil true (io/write-array-lg out x (alength ^ints x) sc/id-int-array-lg))
462-
(freezer impl/array-class-longs nil true (io/write-array-lg out x (alength ^longs x) sc/id-long-array-lg))
463-
(freezer impl/array-class-floats nil true (io/write-array-lg out x (alength ^floats x) sc/id-float-array-lg))
464-
(freezer impl/array-class-doubles nil true (io/write-array-lg out x (alength ^doubles x) sc/id-double-array-lg))
465-
(freezer impl/array-class-strings nil true (io/write-array-lg out x (alength ^"[Ljava.lang.String;" x) sc/id-string-array-lg)))
466-
467-
(freezer PersistentQueue nil true (io/write-counted-coll out sc/id-queue-lg x))
468-
(freezer PersistentTreeSet nil true (io/write-counted-coll out sc/id-sorted-set-lg x))
469-
(freezer PersistentTreeMap nil true (io/write-kvs out sc/id-sorted-map-lg x))
470-
(freezer APersistentVector nil true (io/write-vec out x))
471-
(freezer APersistentSet nil true (io/write-set out x))
472-
(freezer APersistentMap nil true (io/write-map out x false))
473-
(freezer PersistentList nil true (io/write-counted-coll out sc/id-list-0 sc/id-list-sm sc/id-list-md sc/id-list-lg x))
474-
(freezer LazySeq nil true (io/write-uncounted-coll out sc/id-seq-0 sc/id-seq-sm sc/id-seq-md sc/id-seq-lg x))
475-
(freezer ISeq nil true (io/write-coll out sc/id-seq-0 sc/id-seq-sm sc/id-seq-md sc/id-seq-lg x))
476-
(freezer IRecord nil true
477-
(let [class-name (.getName (class x)) ; Reflect
478-
class-name-ba (.getBytes class-name StandardCharsets/UTF_8)
479-
len (alength class-name-ba)]
480-
(enc/cond
481-
(io/sm-count? len) (do (io/write-id out sc/id-record-sm) (io/write-bytes-sm out class-name-ba))
482-
(io/md-count? len) (do (io/write-id out sc/id-record-md) (io/write-bytes-md out class-name-ba))
483-
;; :else (do (io/write-id out sc/id-record-lg) (io/write-bytes-md out class-name-ba)) ; Unrealistic
484-
:else (truss/ex-info! "Record class name too long" {:name class-name}))
485-
486-
(-freeze-without-meta! (into {} x) out)))
487-
488-
(freezer IType nil true
489-
(let [c (class x)]
490-
(io/write-id out sc/id-type)
491-
(io/write-str out (.getName c))
492-
(run! (fn [^java.lang.reflect.Field f] (-freeze-without-meta! (.get f x) out))
493-
(impl/get-basis-fields c))))
494-
495-
(enc/compile-if java.time.Instant
496-
(freezer java.time.Instant sc/id-time-instant true
497-
(do
498-
(.writeLong out (.getEpochSecond x))
499-
(.writeInt out (.getNano x)))))
500-
501-
(enc/compile-if java.time.Duration
502-
(freezer java.time.Duration sc/id-time-duration true
503-
(do
504-
(.writeLong out (.getSeconds x))
505-
(.writeInt out (.getNano x)))))
506-
507-
(enc/compile-if java.time.Period
508-
(freezer java.time.Period sc/id-time-period true
509-
(do
510-
(.writeInt out (.getYears x))
511-
(.writeInt out (.getMonths x))
512-
(.writeInt out (.getDays x)))))
513-
514-
(defn ^:no-doc ^:deprecated try-write-serializable [out x] (truss/catching :all (io/write-serializable out x)))
515-
(defn ^:no-doc ^:deprecated try-write-readable [out x] (truss/catching :all (io/write-readable out x)))
516-
517-
(defn write-unfreezable [out x]
518-
(-freeze-without-meta!
519-
{:nippy/unfreezable
520-
{:type (type x)
521-
:content (impl/try-pr-edn x)}}
522-
out))
523-
524-
(freezer Object nil nil
525-
(do
526-
(impl/when-debug (println (str "freeze-fallback: " (type x))))
527-
(if-let [ff *freeze-fallback*]
528-
(if-not (identical? ff :write-unfreezable)
529-
(ff out x) ; Modern approach with ff
530-
(or ; Legacy approach with ff
531-
(try-write-serializable out x)
532-
(try-write-readable out x)
533-
(write-unfreezable out x)))
534-
535-
;; Without ff
536-
(enc/cond
537-
:let [[r1 e1] (try [(io/write-serializable out x)] (catch Throwable t [nil t]))], r1 r1
538-
:let [[r2 e2] (try [(io/write-readable out x)] (catch Throwable t [nil t]))], r2 r2
539-
540-
:if-let [fff *final-freeze-fallback*] (fff out x) ; Deprecated
541-
:else
542-
(let [t (type x)]
543-
(truss/ex-info! (str "Failed to freeze type: " t)
544-
(enc/assoc-some
545-
{:type t
546-
:as-str (impl/try-pr-edn x)}
547-
{:serializable-error e1
548-
:readable-error e2})
549-
(or e1 e2)))))))
550-
551365
;;;; Freeze API
552366

553367
(defn freeze
@@ -576,11 +390,11 @@
576390
(when-not no-header? ; Avoid `wrap-header`'s array copy:
577391
(let [head-ba (sc/get-head-ba {:compressor-id nil :encryptor-id nil})]
578392
(.write dos head-ba 0 4)))
579-
(impl/with-cache (-freeze-with-meta! x dos))
393+
(impl/with-cache (io/write-typed+meta x dos))
580394
(.toByteArray baos))
581395

582396
(do
583-
(impl/with-cache (-freeze-with-meta! x dos))
397+
(impl/with-cache (io/write-typed+meta x dos))
584398
(let [ba (.toByteArray baos)
585399

586400
compressor
@@ -626,13 +440,13 @@
626440
^bytes [x]
627441
(let [baos (ByteArrayOutputStream. 64)
628442
dos (DataOutputStream. baos)]
629-
(impl/with-cache (-freeze-with-meta! x dos))
443+
(impl/with-cache (io/write-typed+meta x dos))
630444
(.toByteArray baos)))
631445

632446
(defn freeze-to-out!
633447
"Low-level util. Serializes given arg (any Clojure data type) to given `DataOutput`.
634448
In most cases you want `freeze` instead."
635-
[^DataOutput data-output x] (-freeze-with-meta! x data-output))
449+
[^DataOutput data-output x] (io/write-typed+meta x data-output))
636450

637451
(defn freeze-to-string
638452
"Like `freeze`, but returns a Base64-encoded string.
@@ -848,9 +662,8 @@
848662
`(io/write-id ~out ~(impl/coerce-custom-type-id custom-type-id)))]
849663

850664
`(extend-type ~type
851-
IFreezable
852-
(~'-freezable? [~'_] true)
853-
(~'-freeze-without-meta! [~x ~(with-meta out {:tag 'java.io.DataOutput})] ~write-id-form ~@body))))
665+
impl/IFreezable (~'freezable? [~'_] true)
666+
io/IWriteTypedNoMeta (~'write-typed [~x ~(with-meta out {:tag 'java.io.DataOutput})] ~write-id-form ~@body))))
854667

855668
(defmacro extend-thaw
856669
"Extends Nippy to support thawing of a custom type with given id:
@@ -901,7 +714,7 @@
901714

902715
(or
903716
(and
904-
(-freezable? x)
717+
(impl/freezable? x)
905718
(and
906719
(or
907720
(not recursive?) (not (coll? x))
@@ -943,7 +756,7 @@
943756
(do (inspect-ba (freeze "hello")))
944757
(seq (:data-ba (inspect-ba (freeze "hello")))))
945758

946-
(enc/defaliases io/read-quarantined-serializable-object-unsafe!)
759+
(enc/defalias io/read-quarantined-serializable-object-unsafe!)
947760

948761
(comment
949762
(read-quarantined-serializable-object-unsafe!
@@ -958,6 +771,11 @@
958771
(mapv meta
959772
(thaw (freeze [(cache v1) (cache v2) (cache v1) (cache v2)])))))
960773

774+
(enc/defalias io/write-unfreezable)
775+
776+
(defn ^:no-doc ^:deprecated try-write-serializable [dout x] (truss/catching :all (io/write-serializable dout x)))
777+
(defn ^:no-doc ^:deprecated try-write-readable [dout x] (truss/catching :all (io/write-readable dout x)))
778+
961779
;;;; Stress data (for tests, benching, etc.)
962780

963781
(defrecord StressRecord [x])

src/taoensso/nippy/impl.clj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,8 @@
329329

330330
;;;;
331331

332+
(defprotocol IFreezable (freezable? [_] "Returns truthy iff given arg has a native Nippy freeze implementation."))
333+
332334
(def array-class-ints (Class/forName "[I")) ; ^ints
333335
(def array-class-longs (Class/forName "[J")) ; ^longs
334336
(def array-class-floats (Class/forName "[F")) ; ^floats

0 commit comments

Comments
 (0)