From e2978533c777283718417ab76997cb8ec65de591 Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Tue, 22 Oct 2024 23:06:23 +0400 Subject: [PATCH 1/4] wip --- src/darkleaf/di/core.clj | 112 ++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 44 deletions(-) diff --git a/src/darkleaf/di/core.clj b/src/darkleaf/di/core.clj index 58c0018a..4f04955d 100644 --- a/src/darkleaf/di/core.clj +++ b/src/darkleaf/di/core.clj @@ -21,7 +21,8 @@ (clojure.lang IDeref IFn Var Indexed ILookup) (java.io FileNotFoundException Writer) (java.lang AutoCloseable) - (java.util List))) + (java.util List) + (java.util.concurrent.atomic AtomicInteger))) (set! *warn-on-reflection* true) @@ -43,6 +44,10 @@ (defn- seq-contains? [xs x] (not (neg? (index-of xs x)))) +(defn- try-namespace [x] + (when (ident? x) + (namespace x))) + (def ^:private dependency-type-priority {:required 1 :optional 2}) @@ -197,6 +202,16 @@ (System/getenv key)) (registry key)))) +(defn- with-per-system-objects + "" + [registry] + (let [id (AtomicInteger.) + next-id (fn next-id [] (.incrementAndGet id))] + (fn [key] + (case key + ::next-id next-id + (registry key))))) + (declare ref template) (defn- key->key®istry [key] @@ -257,7 +272,11 @@ [key & middlewares] (let [[key root-registry] (key->key®istry key) - middlewares (concat [with-env with-ns root-registry] middlewares) + middlewares (concat [with-per-system-objects + with-env + with-ns + root-registry] + middlewares) registry (apply-middleware nil-registry middlewares) ctx {:registry registry :*stop-list (volatile! '())} @@ -493,24 +512,25 @@ See `start`, `derive`." [target f & args] {:pre [(key? target)]} - (let [prefix (gensym (str (symbol target) "+di-update-key#")) - new-key (symbol (str prefix "-target")) - f-key (symbol (str prefix "-f")) - arg-keys (for [i (-> args count range)] - (symbol (str prefix "-arg#" i))) - new-factory (reify p/Factory - (dependencies [_] - (zipmap (concat [new-key f-key] arg-keys) - (repeat :optional))) - (build [_ deps] - (let [t (deps new-key) - f (deps f-key) - args (map deps arg-keys)] - (apply f t args))) - (demolish [_ _])) - own-registry (zipmap (cons f-key arg-keys) - (cons f args))] - (fn [registry] + (fn [registry] + (let [next-id (registry ::next-id) + prefix (str (symbol target) "+di-update-key#" (next-id)) + new-key (symbol (str prefix "-target")) + f-key (symbol (str prefix "-f")) + arg-keys (for [i (-> args count range)] + (symbol (str prefix "-arg#" i))) + new-factory (reify p/Factory + (dependencies [_] + (zipmap (concat [new-key f-key] arg-keys) + (repeat :optional))) + (build [_ deps] + (let [t (deps new-key) + f (deps f-key) + args (map deps arg-keys)] + (apply f t args))) + (demolish [_ _])) + own-registry (zipmap (cons f-key arg-keys) + (cons f args))] (fn [key] (cond (= new-key key) @@ -536,27 +556,35 @@ (di/start ::root (di/add-side-dependency `flyway)) ```" [dep-key] - (let [*orig-key (volatile! nil) - *orig-factory (volatile! nil) - new-key (gensym "darkleaf.di.core/new-key#") - new-factory (reify p/Factory - (dependencies [_] - ;; array-map preserves order of keys - {new-key :required - dep-key :required}) - (build [_ deps] - (new-key deps)) - (demolish [_ _]))] - (fn [registry] + (fn [registry] + (let [next-id (registry ::next-id) + *orig-key (volatile! nil) + *orig-factory (volatile! nil) + new-key (symbol (str "darkleaf.di.generated/new-key#" (next-id))) + new-factory (reify p/Factory + (dependencies [_] + ;; array-map preserves order of keys + {new-key :required + dep-key :required}) + (build [_ deps] + (new-key deps)) + (demolish [_ _]))] (fn [key] - (when (nil? @*orig-key) - (vreset! *orig-key key)) - (when (nil? @*orig-factory) - (vreset! *orig-factory (registry key))) - (cond - (= @*orig-key key) new-factory - (= new-key key) @*orig-factory - :else (registry key)))))) + ;; + ;; ну такое + ;; в update-key тоже самое же нужно делать? + ;; + (if (= "darkleaf.di.core" (try-namespace key)) + (registry key) + (do + (when (nil? @*orig-key) + (vreset! *orig-key key)) + (when (nil? @*orig-factory) + (vreset! *orig-factory (registry key))) + (cond + (= @*orig-key key) new-factory + (= new-key key) @*orig-factory + :else (registry key)))))))) (defn- arglists [variable] (-> variable meta :arglists)) @@ -667,10 +695,6 @@ (binding [*out* w] (pr (-> o meta ::print)))) -(defn- try-namespace [x] - (when (ident? x) - (namespace x))) - (defn env-parsing "A registry middleware for parsing environment variables. You can define a dependency of env as a string key like \"PORT\", From cba5eafc09acea381dc7e685d52e890bda8a6985 Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Wed, 23 Oct 2024 11:10:23 +0400 Subject: [PATCH 2/4] wip2 --- src/darkleaf/di/core.clj | 230 ++++++++++++++---------------- test/darkleaf/di/next_id_test.clj | 14 ++ 2 files changed, 125 insertions(+), 119 deletions(-) create mode 100644 test/darkleaf/di/next_id_test.clj diff --git a/src/darkleaf/di/core.clj b/src/darkleaf/di/core.clj index 4f04955d..cd6a5d93 100644 --- a/src/darkleaf/di/core.clj +++ b/src/darkleaf/di/core.clj @@ -44,9 +44,10 @@ (defn- seq-contains? [xs x] (not (neg? (index-of xs x)))) -(defn- try-namespace [x] - (when (ident? x) - (namespace x))) +(defn ^:dynamic *next-id* + "" + [] + (throw (IllegalStateException. "Unbound"))) (def ^:private dependency-type-priority {:required 1 @@ -125,8 +126,9 @@ built-map)) :else - (let [obj (build-obj built-map factory)] - (vswap! *stop-list conj #(p/demolish factory obj)) + (let [obj (build-obj built-map factory) + stop (bound-fn* #(p/demolish factory obj))] + (vswap! *stop-list conj stop) (case [obj dep-type] [nil :optional] (recur tail built-map) [nil :required] (missing-dependency! stack) @@ -202,16 +204,6 @@ (System/getenv key)) (registry key)))) -(defn- with-per-system-objects - "" - [registry] - (let [id (AtomicInteger.) - next-id (fn next-id [] (.incrementAndGet id))] - (fn [key] - (case key - ::next-id next-id - (registry key))))) - (declare ref template) (defn- key->key®istry [key] @@ -220,6 +212,11 @@ (map? key) [::implicit-root {::implicit-root (-> key (update-vals ref) template)}] true [key nil])) +(defn- ->next-id [] + (let [id (AtomicInteger.)] + (fn next-id [] + (.incrementAndGet id)))) + (defn ^AutoCloseable start "Starts a system of dependent objects. @@ -270,90 +267,90 @@ See the tests for use cases. See `update-key`." [key & middlewares] - (let [[key root-registry] (key->key®istry key) - - middlewares (concat [with-per-system-objects - with-env - with-ns - root-registry] - middlewares) - registry (apply-middleware nil-registry middlewares) - ctx {:registry registry - :*stop-list (volatile! '())} - obj (try-build ctx key)] - ^{:type ::root - ::print obj} - (reify - AutoCloseable - (close [_] - (->> (try-stop-started ctx) - (throw-many!))) - IDeref - (deref [_] - obj) - Indexed - (nth [_ i] - (nth obj i)) - (nth [_ i not-found] - (nth obj i not-found)) - (count [_] - (count obj)) - ILookup - (valAt [_ key] - (get obj key)) - (valAt [_ key not-found] - (get obj key not-found)) - IFn - (call [_] - (.call ^IFn obj)) - (run [_] - (.run ^IFn obj)) - (invoke [this] - (.invoke ^IFn obj)) - (invoke [_ a1] - (.invoke ^IFn obj a1)) - (invoke [_ a1 a2] - (.invoke ^IFn obj a1 a2)) - (invoke [_ a1 a2 a3] - (.invoke ^IFn obj a1 a2 a3)) - (invoke [_ a1 a2 a3 a4] - (.invoke ^IFn obj a1 a2 a3 a4)) - (invoke [_ a1 a2 a3 a4 a5] - (.invoke ^IFn obj a1 a2 a3 a4 a5)) - (invoke [_ a1 a2 a3 a4 a5 a6] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20)) - (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 args] - (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 args)) - (applyTo [_ args] - (.applyTo ^IFn obj args))))) + (binding [*next-id* (->next-id)] + (let [[key root-registry] (key->key®istry key) + + middlewares (concat [with-env + with-ns + root-registry] + middlewares) + registry (apply-middleware nil-registry middlewares) + ctx {:registry registry + :*stop-list (volatile! '())} + obj (try-build ctx key)] + ^{:type ::root + ::print obj} + (reify + AutoCloseable + (close [_] + (->> (try-stop-started ctx) + (throw-many!))) + IDeref + (deref [_] + obj) + Indexed + (nth [_ i] + (nth obj i)) + (nth [_ i not-found] + (nth obj i not-found)) + (count [_] + (count obj)) + ILookup + (valAt [_ key] + (get obj key)) + (valAt [_ key not-found] + (get obj key not-found)) + IFn + (call [_] + (.call ^IFn obj)) + (run [_] + (.run ^IFn obj)) + (invoke [this] + (.invoke ^IFn obj)) + (invoke [_ a1] + (.invoke ^IFn obj a1)) + (invoke [_ a1 a2] + (.invoke ^IFn obj a1 a2)) + (invoke [_ a1 a2 a3] + (.invoke ^IFn obj a1 a2 a3)) + (invoke [_ a1 a2 a3 a4] + (.invoke ^IFn obj a1 a2 a3 a4)) + (invoke [_ a1 a2 a3 a4 a5] + (.invoke ^IFn obj a1 a2 a3 a4 a5)) + (invoke [_ a1 a2 a3 a4 a5 a6] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20)) + (invoke [_ a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 args] + (.invoke ^IFn obj a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 args)) + (applyTo [_ args] + (.applyTo ^IFn obj args)))))) (defn stop "Stops the root of a system" @@ -513,8 +510,7 @@ [target f & args] {:pre [(key? target)]} (fn [registry] - (let [next-id (registry ::next-id) - prefix (str (symbol target) "+di-update-key#" (next-id)) + (let [prefix (str (symbol target) "+di-update-key#" (*next-id*)) new-key (symbol (str prefix "-target")) f-key (symbol (str prefix "-f")) arg-keys (for [i (-> args count range)] @@ -557,10 +553,9 @@ ```" [dep-key] (fn [registry] - (let [next-id (registry ::next-id) - *orig-key (volatile! nil) + (let [*orig-key (volatile! nil) *orig-factory (volatile! nil) - new-key (symbol (str "darkleaf.di.generated/new-key#" (next-id))) + new-key (symbol (str "darkleaf.di.generated/new-key#" (*next-id*))) new-factory (reify p/Factory (dependencies [_] ;; array-map preserves order of keys @@ -570,21 +565,14 @@ (new-key deps)) (demolish [_ _]))] (fn [key] - ;; - ;; ну такое - ;; в update-key тоже самое же нужно делать? - ;; - (if (= "darkleaf.di.core" (try-namespace key)) - (registry key) - (do - (when (nil? @*orig-key) - (vreset! *orig-key key)) - (when (nil? @*orig-factory) - (vreset! *orig-factory (registry key))) - (cond - (= @*orig-key key) new-factory - (= new-key key) @*orig-factory - :else (registry key)))))))) + (when (nil? @*orig-key) + (vreset! *orig-key key)) + (when (nil? @*orig-factory) + (vreset! *orig-factory (registry key))) + (cond + (= @*orig-key key) new-factory + (= new-key key) @*orig-factory + :else (registry key)))))) (defn- arglists [variable] (-> variable meta :arglists)) @@ -695,6 +683,10 @@ (binding [*out* w] (pr (-> o meta ::print)))) +(defn- try-namespace [x] + (when (ident? x) + (namespace x))) + (defn env-parsing "A registry middleware for parsing environment variables. You can define a dependency of env as a string key like \"PORT\", diff --git a/test/darkleaf/di/next_id_test.clj b/test/darkleaf/di/next_id_test.clj new file mode 100644 index 00000000..b8094e99 --- /dev/null +++ b/test/darkleaf/di/next_id_test.clj @@ -0,0 +1,14 @@ +(ns darkleaf.di.next-id-test + (:require + [clojure.test :as t] + [darkleaf.di.core :as di])) + +(defn a + {::di/stop #(swap! % assoc :stop-id (di/*next-id*))} + [] + (atom {:start-id (di/*next-id*)})) + +(t/deftest a-test + (let [root (di/start `a)] + (di/stop root) + (t/is (= {:start-id 1 :stop-id 2} @@root)))) From fbdef3f65d765e0c005e5b2f2a14ff0546d9d0e9 Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Wed, 23 Oct 2024 13:12:38 +0400 Subject: [PATCH 3/4] atomicinteger -> atom+inc --- src/darkleaf/di/core.clj | 9 ++++----- test/darkleaf/di/next_id_test.clj | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/darkleaf/di/core.clj b/src/darkleaf/di/core.clj index cd6a5d93..a36f0937 100644 --- a/src/darkleaf/di/core.clj +++ b/src/darkleaf/di/core.clj @@ -21,8 +21,7 @@ (clojure.lang IDeref IFn Var Indexed ILookup) (java.io FileNotFoundException Writer) (java.lang AutoCloseable) - (java.util List) - (java.util.concurrent.atomic AtomicInteger))) + (java.util List))) (set! *warn-on-reflection* true) @@ -213,9 +212,9 @@ true [key nil])) (defn- ->next-id [] - (let [id (AtomicInteger.)] - (fn next-id [] - (.incrementAndGet id)))) + (let [id (atom -1)] + (fn next-id [] + (swap! id inc)))) (defn ^AutoCloseable start "Starts a system of dependent objects. diff --git a/test/darkleaf/di/next_id_test.clj b/test/darkleaf/di/next_id_test.clj index b8094e99..744f2a4f 100644 --- a/test/darkleaf/di/next_id_test.clj +++ b/test/darkleaf/di/next_id_test.clj @@ -11,4 +11,4 @@ (t/deftest a-test (let [root (di/start `a)] (di/stop root) - (t/is (= {:start-id 1 :stop-id 2} @@root)))) + (t/is (= {:start-id 0 :stop-id 1} @@root)))) From fe7d8de0802fdccfeb371e725892f4c8068b6c26 Mon Sep 17 00:00:00 2001 From: Mikhail Kuzmin Date: Wed, 23 Oct 2024 14:04:47 +0400 Subject: [PATCH 4/4] wip --- src/darkleaf/di/core.clj | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/darkleaf/di/core.clj b/src/darkleaf/di/core.clj index a36f0937..2e33f7c5 100644 --- a/src/darkleaf/di/core.clj +++ b/src/darkleaf/di/core.clj @@ -43,10 +43,8 @@ (defn- seq-contains? [xs x] (not (neg? (index-of xs x)))) -(defn ^:dynamic *next-id* - "" - [] - (throw (IllegalStateException. "Unbound"))) +(defn ^:dynamic *next-id* [] + (throw (IllegalStateException. "Attempting to call unbound `di/*next-id*`"))) (def ^:private dependency-type-priority {:required 1