Created
April 19, 2012 17:04
-
-
Save megakorre/2422332 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; file core.cljs | |
(ns ^{:doc ""} | |
async-kit.core) | |
(defprotocol Future | |
(error [this] | |
"gives you the error associated with this request or nil if no error") | |
(completed? [this] | |
"true if request is completed") | |
(await* [this callback] | |
"subscribe to the future if it hasent alreddy completed then | |
executes callback directly")) | |
(defrecord AsyncFuture [ | |
value ;; atom for value nil if not completed | |
error-a ;; atom for error nil if no error | |
subscribers ;; subscribers atom to the future [] default | |
] | |
Future | |
(error [this] @error-a) | |
(completed? [this] (or @error-a @value)) | |
(await* [this callback] | |
(cond | |
(error this) (callback (error this) nil) | |
@value-state (callback nil @value) | |
:else (swap! subscribers conj callback)))) | |
(defn async* [callback] | |
(let [value-delivered (atom false) | |
future (new AsyncFuture (atom nil) (atom nil) (atom [])) | |
value-cb | |
(fn [v] | |
(cond | |
(error future) (throw "exception: AsyncFuture recived a value after alreddy thrown a error") | |
@value-delivered (throw "exception: tried to deliver value multiple times to a AsyncFuture") | |
:else (do | |
(reset! value-delivered true) | |
(reset! (:value future) v) | |
(doseq [sub @(:subscribers future)] | |
(sub nil v)))) | |
error-cb | |
(fn [e] | |
(cond | |
@value-delivered (throw "error thrown on alreddy delivered future") | |
:else (do (reset! (:error-a future) e) | |
(doseq [sub @(:subscribers future)] | |
(sub e nil)))] | |
(callback value-cb error-cb) | |
future)) | |
;; file macros.clj | |
(ns async-kit.macros) | |
(defmacro async [bindings & body] | |
`(async-kit/async* | |
(fn ~bindings ~@body))) | |
(defn make-bindings | |
[remaining-bindings body | |
completed-sym error-sym] | |
(cond | |
(= (count remaining-bindings) 1) | |
(throw "wrong number of bindings in let-async needs to be event") | |
(= (count remaining-bindings) 0) | |
`(~completed-sym (do ~@body)) | |
:else | |
(let [[binding-name binding-expression & rest] | |
remaining-bindings] | |
(cond | |
(= (first (name binding-name) "-")) | |
`(let [~binding-name ~binding-expression] | |
~(make-bindings rest body completed-sym error-sym))) | |
(= binding-name :if-error) | |
(let [new-error-sym (gen-sym "error")] | |
`(let [~new-error-sym (fn ~(first binding-expression) | |
(~completed-sym (do ~@(rest binding-expression))))] | |
~(make-bindings rest body completed-sym new-error-sym)))) | |
:else | |
`(async-kit/await* | |
~binding-expression | |
(fn [error# value#] | |
(if error# | |
(~error-sym error#) | |
(let [~binding-name value#] | |
~(make-bindings rest body completed-sym error-sym)))))))) | |
(defmacro let-async [bindings & body] | |
(let [complete-sym (gen-sym "completed") | |
error-sym (gen-sym "error")] | |
´(async-kit/async* | |
(fn [~complete-sym ~error-sym] | |
~(make-bindings bindings body complete-sym error-sym))) | |
(comment | |
;; some sudo code | |
(let-async [some-site (http :GET "/something") | |
:let some-normal-exp (process some-site) | |
some-data (-> parse-site :user-id (xhr "/something")] | |
(render-something "some-template" some-data))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment