diff --git a/src/clj/com/rpl/specter.cljx b/src/clj/com/rpl/specter.cljx index 83c3c87..bed3a97 100644 --- a/src/clj/com/rpl/specter.cljx +++ b/src/clj/com/rpl/specter.cljx @@ -672,18 +672,25 @@ "A path that branches on multiple paths. For updates, applies updates to the paths in order." [& paths] - (variable-pathed-nav [compiled-paths paths] - (select* [this structure next-fn] - (doseqres NONE [c compiled-paths] - (i/compiled-traverse* c next-fn structure) - )) - (transform* [this structure next-fn] - (reduce - (fn [structure path] - (compiled-transform path next-fn structure)) - structure - compiled-paths - )))) + (let [paths-comp (mapv i/comp-paths* (vec paths)) + all-needed (mapv i/num-needed-params paths-comp) + idx-deltas (vec (cons 0 (reductions + all-needed))) + extracted (mapv i/extract-rich-tfns paths-comp) + sel-info (mapv vector (mapv first extracted) idx-deltas) + tran-info (mapv vector (mapv second extracted) idx-deltas)] + (richnav (reduce + 0 all-needed) + (select* [params params-idx vals structure next-fn] + (doseqres NONE [[s delta] sel-info] + (s params (+ params-idx delta) vals structure next-fn) + )) + (transform* [params params-idx vals structure next-fn] + (reduce + (fn [structure [t delta]] + (t params (+ params-idx delta) vals structure next-fn) + ) + structure + tran-info + ))))) (defpathedfn stay-then-continue "Navigates to the current element and then navigates via the provided path. diff --git a/src/clj/com/rpl/specter/impl.cljx b/src/clj/com/rpl/specter/impl.cljx index 9ac0f5d..d6a7a23 100644 --- a/src/clj/com/rpl/specter/impl.cljx +++ b/src/clj/com/rpl/specter/impl.cljx @@ -1095,7 +1095,7 @@ tran (if test? then-t else-t) - idx (if test? params-idx then-params)] + idx (if test? params-idx (+ params-idx then-params))] (tran params idx vals @@ -1507,3 +1507,8 @@ [(:selector tfns) (:transformer tfns)] )) +(defn mk-jump-next-fn [next-fn init-idx total-params] + (let [jumped (+ init-idx total-params)] + (fn [params params-idx vals structure] + (next-fn params jumped vals structure) + ))) \ No newline at end of file diff --git a/src/clj/com/rpl/specter/macros.clj b/src/clj/com/rpl/specter/macros.clj index 1a48f87..6f6ea0a 100644 --- a/src/clj/com/rpl/specter/macros.clj +++ b/src/clj/com/rpl/specter/macros.clj @@ -130,15 +130,25 @@ the next params index, the collected vals, and finally the next structure. This is the lowest level way of making navigators." [num-params impl1 impl2] - (let [[select-impl transform-impl] (determine-params-impls impl1 impl2)] - `(let [tfns# (i/->TransformFunctions + (let [[[s-params & s-body] [t-params & t-body]] (determine-params-impls impl1 impl2) + s-next-fn-sym (last s-params) + s-pidx-sym (second s-params) + t-next-fn-sym (last t-params) + t-pidx-sym (second t-params) + ] + `(let [num-params# ~num-params + tfns# (i/->TransformFunctions i/RichPathExecutor - (fn ~@select-impl) - (fn ~@transform-impl) + (fn ~s-params + (let [~s-next-fn-sym (i/mk-jump-next-fn ~s-next-fn-sym ~s-pidx-sym num-params#)] + ~@s-body)) + (fn ~t-params + (let [~t-next-fn-sym (i/mk-jump-next-fn ~t-next-fn-sym ~t-pidx-sym num-params#)] + ~@t-body)) )] - (if (zero? ~num-params) + (if (zero? num-params#) (i/no-params-compiled-path tfns#) - (i/->ParamsNeededPath tfns# ~num-params) + (i/->ParamsNeededPath tfns# num-params#) )))) (defmacro paramsfn [params [structure-sym] & impl] diff --git a/test/com/rpl/specter/core_test.cljx b/test/com/rpl/specter/core_test.cljx index ec8c48b..dd99017 100644 --- a/test/com/rpl/specter/core_test.cljx +++ b/test/com/rpl/specter/core_test.cljx @@ -373,11 +373,11 @@ (is (empty? (select (s/if-path odd? (s/view inc)) 2))) (is (= [6 2 10 6 14] (transform [(s/putval 2) - s/ALL - (s/if-path odd? [(s/view inc) (s/view inc)] (s/view dec))] - * - [1 2 3 4 5] - ))) + s/ALL + (s/if-path odd? [(s/view inc) (s/view inc)] (s/view dec))] + * + [1 2 3 4 5] + ))) (is (= 2 (transform [(s/putval 2) (s/if-path odd? (s/view inc))]