diff --git a/src/promesa/exec.cljc b/src/promesa/exec.cljc index 640f9ec..7c93836 100644 --- a/src/promesa/exec.cljc +++ b/src/promesa/exec.cljc @@ -179,56 +179,58 @@ @default-scheduler (pu/maybe-deref scheduler)))) +#?(:clj + (defn- binding-conveyor-inner + [f] + (let [frame (clojure.lang.Var/cloneThreadBindingFrame)] + (fn + ([] + (clojure.lang.Var/resetThreadBindingFrame frame) + (cond + (instance? clojure.lang.IFn f) + (.invoke ^clojure.lang.IFn f) + + (instance? java.lang.Runnable f) + (.run ^java.lang.Runnable f) + + (instance? java.util.concurrent.Callable f) + (.call ^java.util.concurrent.Callable f) + + :else + (throw (ex-info "Unsupported function type" {:f f :type (type f)})))) + ([x] + (clojure.lang.Var/resetThreadBindingFrame frame) + (cond + (instance? clojure.lang.IFn f) + (.invoke ^clojure.lang.IFn f x) + + (instance? java.util.function.Function f) + (.apply ^java.util.function.Function f x) + + :else + (throw (ex-info "Unsupported function type" {:f f :type (type f)})))) + ([x y] + (clojure.lang.Var/resetThreadBindingFrame frame) + (f x y)) + ([x y z] + (clojure.lang.Var/resetThreadBindingFrame frame) + (f x y z)) + ([x y z & args] + (clojure.lang.Var/resetThreadBindingFrame frame) + (apply f x y z args)))))) + (defn wrap-bindings {:no-doc true} + ;; Passes on local bindings from one thread to another. Compatible with `clojure.lang.IFn`, + ;; `java.lang.Runnable`, `java.util.concurrent.Callable`, and `java.util.function.Function`. + ;; Adapted from `clojure.core/binding-conveyor-fn`." [f] #?(:cljs f - :clj - (let [bindings (get-thread-bindings)] - (fn - ([] - (push-thread-bindings bindings) - (try - (f) - (finally - (pop-thread-bindings)))) - ([a] - (push-thread-bindings bindings) - (try - (f a) - (finally - (pop-thread-bindings)))) - ([a b] - (push-thread-bindings bindings) - (try - (f a b) - (finally - (pop-thread-bindings)))) - ([a b c] - (push-thread-bindings bindings) - (try - (f a b c) - (finally - (pop-thread-bindings)))) - ([a b c d] - (push-thread-bindings bindings) - (try - (f a b c d) - (finally - (pop-thread-bindings)))) - ([a b c d e] - (push-thread-bindings bindings) - (try - (f a b c d e) - (finally - (pop-thread-bindings)))) - ([a b c d e & args] - (push-thread-bindings bindings) - (try - (apply f a b c d e args) - (finally - (pop-thread-bindings)))))))) - + :clj (reify + clojure.lang.IFn + (invoke [_ f] (binding-conveyor-inner f)) + java.util.function.Function + (apply [_ f] (binding-conveyor-inner f))))) #?(:clj (defn thread-factory? diff --git a/src/promesa/exec/csp.cljc b/src/promesa/exec/csp.cljc index 888921d..66b7f52 100644 --- a/src/promesa/exec/csp.cljc +++ b/src/promesa/exec/csp.cljc @@ -67,7 +67,7 @@ promise instance, has the same semantics as `go` macro." [& body] `(let [c# (chan :buf 1) - f# (px/wrap-bindings (fn [] ~@body))] + f# (px/wrap-bindings (^{:once true} fn* [] ~@body))] (->> (p/thread-call *executor* f#) (p/fnly (fn [v# e#] (if e# @@ -80,7 +80,7 @@ a promise instance." [& body] `(let [c# (chan :buf 1) - f# (px/wrap-bindings (fn [] ~@body))] + f# (px/wrap-bindings (^{:once true} fn* [] ~@body))] (->> (p/thread-call :thread f#) (p/fnly (fn [v# e#] (if e#