-
Notifications
You must be signed in to change notification settings - Fork 0
/
internals.clj
58 lines (50 loc) · 1.75 KB
/
internals.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
(ns conquerant.internals
(:refer-clojure :exclude [promise])
(:import [java.util.concurrent CompletableFuture CompletionStage Executor ForkJoinPool]
java.util.function.Function))
(defonce ^:dynamic *executor*
(ForkJoinPool/commonPool))
(defn ^CompletableFuture promise* [f]
(let [p (CompletableFuture.)
reject #(.completeExceptionally p %)
resolve #(.complete p %)]
(try
(f resolve reject)
(catch Throwable e
(reject e)))
p))
(defn promise? [v]
(instance? CompletionStage v))
(defn bind [^CompletionStage p callback]
(let [binds (clojure.lang.Var/getThreadBindingFrame)
func (reify Function
(apply [_ v]
(clojure.lang.Var/resetThreadBindingFrame binds)
(callback v)))]
(.thenComposeAsync p ^Function func ^Executor *executor*)))
(defn then [p f]
(bind p (fn promise-wrap [in]
(let [out (f in)]
(if (promise? out)
out
(promise* out))))))
(defn attempt [callback]
(promise* (fn [resolve reject]
(let [result (callback)]
(if (promise? result)
(then result resolve)
(resolve result))))))
(defmacro ado [& body]
`(attempt #(do ~@body)))
(defmacro alet [bindings & body]
(->> (reverse (partition 2 bindings))
(reduce (fn [acc [l r]]
(if (and (coll? r)
(symbol? (first r))
(not= "." (subs (name (first r)) 0 1)))
(if (= 'await (first r))
`(bind ~(second r)
(fn [~l] ~acc))
`(let [~l ~r] ~acc))
`(let [~l ~r] ~acc)))
`(ado ~@body))))