Skip to content

Commit

Permalink
Fix deref with delayed non-Throwable error result
Browse files Browse the repository at this point in the history
  • Loading branch information
PawelStroinski committed May 25, 2018
1 parent 651594c commit 93eb62e
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 10 deletions.
19 changes: 9 additions & 10 deletions src/manifold/deferred.clj
Expand Up @@ -300,13 +300,16 @@
"invalid claim-token")))
false)))

(defmacro ^:private throw' [val]
`(if (instance? Throwable ~val)
(throw ~val)
(throw (ex-info "" {:error ~val}))))

(defmacro ^:private deref-deferred [timeout-value & await-args]
(let [latch-sym (with-meta (gensym "latch") {:tag "java.util.concurrent.CountDownLatch"})]
`(condp identical? ~'state
::success ~'val
::error (if (instance? Throwable ~'val)
(throw ~'val)
(throw (ex-info "" {:error ~'val})))
::error (throw' ~'val)
(let [~latch-sym (CountDownLatch. 1)
f# (fn [_#] (.countDown ~latch-sym))]
(on-realized ~'this f# f#)
Expand All @@ -318,7 +321,7 @@
(if result#
(if (identical? ::success ~'state)
~'val
(throw ~'val))
(throw' ~'val))
~timeout-value))))))

(defmacro ^:private both [body]
Expand Down Expand Up @@ -546,14 +549,10 @@
clojure.lang.IBlockingDeref
(deref [this]
(set! consumed? true)
(if (instance? Throwable error)
(throw error)
(throw (ex-info "" {:error error}))))
(throw' error))
(deref [this time timeout-value]
(set! consumed? true)
(if (instance? Throwable error)
(throw error)
(throw (ex-info "" {:error error})))))
(throw' error)))

(let [created (AtomicLong. 0)]
(defn deferred
Expand Down
16 changes: 16 additions & 0 deletions test/manifold/deferred_test.clj
Expand Up @@ -164,6 +164,22 @@
(future' (d/error! d (IllegalStateException. "boom")))
(is (thrown? IllegalStateException (deref d 1000 ::timeout))))

;; test deref with non-Throwable error result
(are [d timeout]
(= :bar
(-> (is (thrown? clojure.lang.ExceptionInfo
(if timeout (deref d 1000 ::timeout) @d)))
ex-data
:error))

(doto (d/deferred) (d/error! :bar)) true

(doto (d/deferred) (as-> d (future' (d/error! d :bar)))) true

(d/error-deferred :bar) true

(d/error-deferred :bar) false)

;; multiple callbacks w/ success
(let [n 50
d (d/deferred)
Expand Down

0 comments on commit 93eb62e

Please sign in to comment.