Skip to content

Commit 6f72dbc

Browse files
committed
Add ThenCompose CompletionStage method
1 parent 39ce39b commit 6f72dbc

File tree

2 files changed

+81
-2
lines changed

2 files changed

+81
-2
lines changed

src/manifold/deferred.clj

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@
6464

6565
apply-to-either apply-to-either-async
6666
accept-either accept-either-async
67-
run-after-either run-after-either-async)
67+
run-after-either run-after-either-async
68+
69+
then-compose then-compose-async)
6870

6971
;; The potemkin abstract type for
7072
;; implementations such as CompletionStage
@@ -132,7 +134,14 @@
132134
(runAfterEitherAsync [this operator other]
133135
(run-after-either-async this operator other))
134136
(runAfterEitherAsync [this operator other executor]
135-
(run-after-either-async this operator other executor)))
137+
(run-after-either-async this operator other executor))
138+
139+
(thenCompose [this operator]
140+
(then-compose this operator))
141+
(thenComposeAsync [this operator]
142+
(then-compose-async this operator))
143+
(thenComposeAsync [this operator executor]
144+
(then-compose-async this operator executor)))
136145

137146
(definline realized?
138147
"Returns true if the manifold deferred is realized."
@@ -1575,6 +1584,12 @@
15751584

15761585
(def ^:private run-after-either-async (async-for-dual run-after-either))
15771586

1587+
(defn- then-compose [this ^java.util.function.Function operator]
1588+
(assert-some operator)
1589+
(chain this (fn [value] (.apply operator value))))
1590+
1591+
(def ^:private then-compose-async (async-for then-compose))
1592+
15781593

15791594

15801595

test/manifold/deferred_stage_test.clj

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
[clojure.test :refer [deftest is testing]])
44
(:import [java.util.concurrent
55
CompletionStage
6+
CompletableFuture
67
Executors]))
78

89
(defn fn->Function [function]
@@ -323,3 +324,66 @@
323324
(dorun (for [method-info alt-method-info
324325
mode [:raw :async :with-executor]]
325326
(test-alt-error method-info mode executor))))))
327+
328+
329+
330+
(def compose-method-info
331+
{:methods {:raw
332+
(fn [^CompletionStage this operator _]
333+
(.thenCompose this operator))
334+
:async
335+
(fn [^CompletionStage this operator _]
336+
(.thenComposeAsync this operator))
337+
:with-executor
338+
(fn [^CompletionStage this operator executor]
339+
(.thenComposeAsync this operator executor))}
340+
:interface fn->Function
341+
:inner-assertion #(is (= 1 %))
342+
:post-assertion #(is (= 2 %))})
343+
344+
(defn- test-compose-success [method-info mode executor]
345+
346+
(let [was-called (atom false)
347+
348+
method (get-in method-info [:methods mode])
349+
{:keys [inner-assertion post-assertion]
350+
to-java-interface :interface} method-info
351+
352+
d1 (d/success-deferred 1)
353+
d2 (method
354+
d1
355+
(to-java-interface
356+
(fn [x]
357+
(inner-assertion x)
358+
(reset! was-called true)
359+
(d/success-deferred 2)))
360+
executor)]
361+
362+
(is (= @d1 1))
363+
(post-assertion @d2)
364+
(is (= true @was-called))))
365+
366+
367+
(deftest test-compose
368+
369+
(let [executor (Executors/newSingleThreadExecutor)]
370+
(testing "compose success"
371+
(dorun (for [method-info [compose-method-info]
372+
mode [:raw :async :with-executor]]
373+
(test-compose-success method-info mode executor))))
374+
375+
(testing "compose error"
376+
(dorun (for [method-info [compose-method-info]
377+
mode [:raw :async :with-executor]]
378+
(test-functor-error method-info mode executor))))))
379+
380+
(deftest test-compose-into-completable-future
381+
382+
(testing "deferred can compose into CompletableFuture"
383+
(let [d1 ^CompletionStage (d/success-deferred 10)
384+
d2 (.thenCompose
385+
d1
386+
(fn->Function
387+
(fn [x] (CompletableFuture/completedFuture (inc x)))
388+
))]
389+
(is (= @d2 11)))))

0 commit comments

Comments
 (0)