diff --git a/src/sieppari/async.cljc b/src/sieppari/async.cljc index 724b65e..19db0a3 100644 --- a/src/sieppari/async.cljc +++ b/src/sieppari/async.cljc @@ -5,6 +5,12 @@ java.util.concurrent.CompletionException java.util.function.Function))) +#?(:clj + (defn -forward-bindings [f] + (fn [ctx] + (with-bindings (or (:bindings ctx) {}) + ((bound-fn* f) ctx))))) + (defprotocol AsyncContext (async? [t]) (continue [t f]) @@ -21,6 +27,9 @@ (extend-protocol AsyncContext Object (async? [_] false) + ; Given the implementation of enter/leave, + ; `continue` won't be called, and therefore, + ; the function call does not need to be bound (continue [t f] (f t)) (await [t] t))) @@ -28,13 +37,23 @@ (extend-protocol AsyncContext default (async? [_] false) + ; Given the implementation of enter/leave, + ; `continue` won't be called, and therefore, + ; the function call does not need to be bound (continue [t f] (f t)))) #?(:clj (extend-protocol AsyncContext clojure.lang.IDeref (async? [_] true) - (continue [c f] (future (f @c))) + (continue [c f] + (cond + ; Make sure there is + (map? @c) + (with-bindings (or (:bindings @c) {}) + (future ((bound-fn* f) @c))) + :else + (future (f @c)))) (catch [c f] (future (let [c @c] (if (exception? c) (f c) c)))) (await [c] @c))) @@ -44,6 +63,8 @@ CompletionStage (async? [_] true) (continue [this f] + ; Given the "context" is a completion stage, there isn't + ; a means (.thenApply ^CompletionStage this ^Function (->FunctionWrapper f))) diff --git a/src/sieppari/async/core_async.cljc b/src/sieppari/async/core_async.cljc index d62123c..f6eb093 100644 --- a/src/sieppari/async/core_async.cljc +++ b/src/sieppari/async/core_async.cljc @@ -9,7 +9,11 @@ #?(:clj clojure.core.async.impl.protocols.Channel :cljs cljs.core.async.impl.channels/ManyToManyChannel) (async? [_] true) - (continue [c f] (go (f (cca/ 43)) + diff --git a/test/clj/sieppari/core_execute_test.clj b/test/clj/sieppari/core_execute_test.clj index 1f9d8ed..74fa921 100644 --- a/test/clj/sieppari/core_execute_test.clj +++ b/test/clj/sieppari/core_execute_test.clj @@ -6,8 +6,7 @@ [clojure.string :as str])) ;; -;; Following tests use a test-chain that has some interceptors -;; that fail on each stage function (enter, leave, error). The +;; Following tests use a test-chain that has some interceptors that fail on each stage function (enter, leave, error). The ;; idea is that the tests override the expected stage functions ;; with test specific function. This ensures that no unexpected ;; stage functions are called. @@ -269,6 +268,26 @@ [:leave :x] [:leave :a]])) + +(def ^:dynamic *boundv* 41) + +(defn bindings-handler [_] + (is (= 42 *boundv*)) + *boundv*) + +(def bindings-chain + [{:enter (fn [ctx] (assoc ctx + :bindings + {#'*boundv* 42}))} + {:enter (fn [ctx] + (is (= 42 *boundv*)) + ctx)} + bindings-handler]) + +(deftest use-bindings-test + (fact "bindings are conveyed across interceptor chain" + (s/execute bindings-chain {}) => 42)) + ; TODO: figure out how enqueue should work? Should enqueue add interceptors just ; before the handler? #_(deftest enqueue-interceptor-test diff --git a/test/clj/sieppari/manifold_test.clj b/test/clj/sieppari/manifold_test.clj index a8af771..0e27f2e 100644 --- a/test/clj/sieppari/manifold_test.clj +++ b/test/clj/sieppari/manifold_test.clj @@ -228,3 +228,45 @@ [:error :c] [:error :b] [:leave :a]]))) + +(def ^:dynamic *boundv* 41) + +(defn bindings-handler [_] + (is (= 43 *boundv*)) + (d/chain + nil + (fn [_] + *boundv*))) + +(def bindings-chain + [{:enter (fn [ctx] + (d/future + (assoc ctx + :bindings + {#'*boundv* 42}))) + :leave (fn [ctx] + (d/chain + ctx + (fn [ctx'] + (is (= 42 *boundv*)) + ctx')))} + {:enter (fn [ctx] + (is (= 42 *boundv*) + "In interceptor failed") + (d/chain + ctx + #(update-in + % + [:bindings #'*boundv*] inc))) + :leave (fn [ctx] + (d/chain + ctx + #(update-in + % + [:bindings #'*boundv*] dec)))} + bindings-handler]) + +(deftest async-bindings-test + (fact "bindings are conveyed across interceptor chain" + (sc/execute bindings-chain {}) => 43)) + diff --git a/test/clj/sieppari/promesa_test.clj b/test/clj/sieppari/promesa_test.clj index 23de0a9..b6f34e5 100644 --- a/test/clj/sieppari/promesa_test.clj +++ b/test/clj/sieppari/promesa_test.clj @@ -228,3 +228,38 @@ [:error :c] [:error :b] [:leave :a]]))) + +(def ^:dynamic *boundv* 41) + +(defn bindings-handler [_] + (is (= 43 *boundv*)) + (p/resolved + *boundv*)) + +(def bindings-chain + [{:enter (fn [ctx] + (p/resolved + (assoc ctx + :bindings + {#'*boundv* 42}))) + :leave (fn [ctx] + (is (= 42 *boundv*)) + ctx)} + {:enter (fn [ctx] + (is (= 42 *boundv*)) + (-> ctx + (update-in [:bindings #'*boundv*] + inc) + (p/resolved))) + :leave (fn [ctx] + (is (= 43 *boundv*)) + (-> ctx + (update-in [:bindings #'*boundv*] + dec) + (p/resolved)))} + bindings-handler]) + +(deftest async-bindings-test + (fact "bindings are conveyed across interceptor chain" + (sc/execute bindings-chain {}) => 43)) +