Skip to content

Commit 56551c1

Browse files
committed
feat: port diff implementation from gen.jl
1 parent 868346a commit 56551c1

File tree

2 files changed

+90
-5
lines changed

2 files changed

+90
-5
lines changed

src/gen/diff.cljc

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,75 @@
1-
(ns gen.diff)
1+
(ns gen.diff
2+
"Implementations of the [[IDiff]] protocol, for recording distinct differences
3+
between Clojure values seen by a function at different invocations.")
24

3-
(defrecord NoChange [])
5+
;; ## IDiff
6+
;;
7+
;; [[IDiff]] This is a marker protocol, used by types that record some diff to a
8+
;; Clojure data type.
49

5-
(def no-change (->NoChange))
10+
(defprotocol IDiff)
611

7-
(defrecord UnknownChange [])
12+
(defn diff?
13+
"Returns true if `x` satisfies [[IDiff]], false otherwise."
14+
[x]
15+
(satisfies? IDiff x))
816

9-
(def unknown-change (->UnknownChange))
17+
;; ### Implementations
18+
19+
(defrecord UnknownChange []
20+
IDiff)
21+
22+
(def unknown-change
23+
"Used to note that no information is provided about the change to the value."
24+
(UnknownChange.))
25+
26+
(defrecord NoChange []
27+
IDiff)
28+
29+
(def no-change
30+
"The value definitely did not change."
31+
(NoChange.))
32+
33+
;; Composite of
34+
;;
35+
;; - a set of elements added
36+
;; - a set of elements deleted
37+
38+
(defrecord SetDiff [added deleted]
39+
IDiff)
40+
41+
;; Composite of
42+
;;
43+
;; - a map of entries added
44+
;; - a set of keys deleted
45+
;; - a map of key => diff value for the key
46+
47+
(defrecord DictDiff [added deleted updated]
48+
IDiff)
49+
50+
;; Composite of
51+
52+
;; - new length
53+
;; - previous length
54+
;; - a map of updated index => diff..
55+
56+
(defrecord VectorDiff [new-length prev-length updated]
57+
IDiff)
58+
59+
;; ## IDiffed
60+
;;
61+
;; Extend this protocol to wrapper types used for composing a value with
62+
;; information about a change to the value.
63+
64+
(defprotocol IDiffed
65+
(get-diff [x]
66+
"If `x` is an instance of [[IDiffed]], returns the attached [[IDiff]]
67+
instance. Else, acts as identity.")
68+
(strip-diff [x]
69+
"If `x` is an instance of [[IDiffed]], returns the wrapped value. Else, acts
70+
as identity."))
71+
72+
(extend-protocol IDiffed
73+
#?(:clj Object :cljs default)
74+
(get-diff [_] no-change)
75+
(strip-diff [x] x))

test/gen/diff_test.cljc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
(ns gen.diff-test
2+
"Tests for the [[gen.diff]] namespace."
3+
(:require [clojure.test :refer [deftest is]]
4+
[clojure.test.check.generators :as gen]
5+
[com.gfredericks.test.chuck.clojure-test :refer [checking]]
6+
[gen.diff :as diff]))
7+
8+
(deftest diffed-tests
9+
(checking "strip-diff / get-diff"
10+
[x gen/any-equatable]
11+
(is (= x (diff/strip-diff x))
12+
"Non-wrapped values strip to themselves.")
13+
14+
(is (= diff/no-change (diff/get-diff x))
15+
"Non-wrapped values report no change."))
16+
17+
(checking "diff? is false for non-implementers"
18+
[x gen/any-equatable]
19+
(is (not (diff/diff? x)))))

0 commit comments

Comments
 (0)