From 84a36624a652e521ab74757e8e074f77fdf7a219 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 24 Feb 2022 23:36:53 +0100 Subject: [PATCH] :tada: Add specific namespace for data macros And additionally add optimized macros for get-in, select-keys and str. --- backend/src/app/storage.clj | 3 +- common/src/app/common/data.cljc | 40 ------ common/src/app/common/data/macros.cljc | 130 ++++++++++++++++++ common/src/app/common/geom/shapes.cljc | 81 +++++------ common/src/app/common/pages.cljc | 34 ++--- common/src/app/common/uri.cljc | 12 +- common/src/app/common/uuid.cljc | 4 +- frontend/src/app/main/data/workspace.cljs | 101 +++++++------- .../src/app/main/data/workspace/path.cljs | 56 ++++---- 9 files changed, 277 insertions(+), 184 deletions(-) create mode 100644 common/src/app/common/data/macros.cljc diff --git a/backend/src/app/storage.clj b/backend/src/app/storage.clj index e084c4633..40b3b6d5f 100644 --- a/backend/src/app/storage.clj +++ b/backend/src/app/storage.clj @@ -8,6 +8,7 @@ "Objects storage abstraction layer." (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.exceptions :as ex] [app.common.logging :as l] [app.common.spec :as us] @@ -248,7 +249,7 @@ (-> (assoc storage :conn (or conn pool)) (delete-database-object (if (uuid? id-or-obj) id-or-obj (:id id-or-obj))))) -(d/export impl/resolve-backend) +(dm/export impl/resolve-backend) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Garbage Collection: Permanently delete objects diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index 9dfba00ad..9b0dc0fb1 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -417,45 +417,6 @@ (not (mth/finite? v)) (mth/nan? v)) default v))) - -(defmacro export - "A helper macro that allows reexport a var in a current namespace." - [v] - (if (boolean (:ns &env)) - - ;; Code for ClojureScript - (let [mdata (aapi/resolve &env v) - arglists (second (get-in mdata [:meta :arglists])) - sym (symbol (core/name v)) - andsym (symbol "&") - procarg #(if (= % andsym) % (gensym "param"))] - (if (pos? (count arglists)) - `(def - ~(with-meta sym (:meta mdata)) - (fn ~@(for [args arglists] - (let [args (map procarg args)] - (if (some #(= andsym %) args) - (let [[sargs dargs] (split-with #(not= andsym %) args)] - `([~@sargs ~@dargs] (apply ~v ~@sargs ~@(rest dargs)))) - `([~@args] (~v ~@args))))))) - `(def ~(with-meta sym (:meta mdata)) ~v))) - - ;; Code for Clojure - (let [vr (resolve v) - m (meta vr) - n (:name m) - n (with-meta n - (cond-> {} - (:dynamic m) (assoc :dynamic true) - (:protocol m) (assoc :protocol (:protocol m))))] - `(let [m# (meta ~vr)] - (def ~n (deref ~vr)) - (alter-meta! (var ~n) merge (dissoc m# :name)) - ;; (when (:macro m#) - ;; (.setMacro (var ~n))) - ~vr)))) - - (defn any-key? [element & rest] (some #(contains? element %) rest)) @@ -692,4 +653,3 @@ (recur acc (step k)) acc))) acc)))))) - diff --git a/common/src/app/common/data/macros.cljc b/common/src/app/common/data/macros.cljc new file mode 100644 index 000000000..4312e8a2a --- /dev/null +++ b/common/src/app/common/data/macros.cljc @@ -0,0 +1,130 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) UXBOX Labs SL + +(ns app.common.data.macros + "Data retrieval & manipulation specific macros." + (:refer-clojure :exclude [get-in select-keys str]) + #?(:cljs (:require-macros [app.common.data.macros])) + (:require + #?(:clj [clojure.core :as c] + :cljs [cljs.core :as c]) + [cljs.analyzer.api :as aapi])) + +(defmacro select-keys + "A macro version of `select-keys`. Usefull when keys vector is known + at compile time (aprox 600% performance boost). + + It is not 100% equivalent, this macro does not removes not existing + keys in contrast to clojure.core/select-keys" + [target keys] + (assert (vector? keys) "keys expected to be a vector") + `{ ~@(mapcat (fn [key] [key (list `c/get target key)]) keys) ~@[] }) + +(defmacro get-in + "A macro version of `get-in`. Usefull when the keys vector is known at + compile time (20-40% performance improvement)." + ([target keys] + (assert (vector? keys) "keys expected to be a vector") + `(-> ~target ~@(map (fn [key] (list `c/get key)) keys))) + ([target keys default] + (assert (vector? keys) "keys expected to be a vector") + `(let [v# (-> ~target ~@(map (fn [key] (list `c/get key)) keys))] + (if (some? v#) v# ~default)))) + + +;; => benchmarking: clojure.core/str +;; --> WARM: 100000 +;; --> BENCH: 500000 +;; --> TOTAL: 197.82ms +;; --> MEAN: 395.64ns +;; => benchmarking: app.commons.data.macros/str +;; --> WARM: 100000 +;; --> BENCH: 500000 +;; --> TOTAL: 20.31ms +;; --> MEAN: 40.63ns + +(defmacro str + "CLJS only macro variant of `str` function that performs string concat much faster." + ([a] + (if (:ns &env) + (list 'js* "\"\"+~{}" a) + (list `c/str a))) + ([a b] + (if (:ns &env) + (list 'js* "\"\"+~{}+~{}" a b) + (list `c/str a b))) + ([a b c] + (if (:ns &env) + (list 'js* "\"\"+~{}+~{}+~{}" a b c) + (list `c/str a b c))) + ([a b c d] + (if (:ns &env) + (list 'js* "\"\"+~{}+~{}+~{}+~{}" a b c d) + (list `c/str a b c d))) + ([a b c d e] + (if (:ns &env) + (list 'js* "\"\"+~{}+~{}+~{}+~{}+~{}" a b c d e) + (list `c/str a b c d e))) + ([a b c d e f] + (if (:ns &env) + (list 'js* "\"\"+~{}+~{}+~{}+~{}+~{}+~{}" a b c d e f) + (list `c/str a b c d e f))) + ([a b c d e f g] + (if (:ns &env) + (list 'js* "\"\"+~{}+~{}+~{}+~{}+~{}+~{}+~{}" a b c d e f g) + (list `c/str a b c d e f g))) + ([a b c d e f g h] + (if (:ns &env) + (list 'js* "\"\"+~{}+~{}+~{}+~{}+~{}+~{}+~{}+~{}" a b c d e f g h) + (list `c/str a b c d e f g h))) + ([a b c d e f g h & rest] + (let [all (into [a b c d e f g h] rest)] + (if (:ns &env) + (let [xf (map (fn [items] `(str ~@items))) + pall (partition-all 8 all)] + (if (<= (count all) 64) + `(str ~@(sequence xf pall)) + `(c/str ~@(sequence xf pall)))) + `(c/str ~@all))))) + +(defmacro export + "A helper macro that allows reexport a var in a current namespace." + [v] + (if (boolean (:ns &env)) + + ;; Code for ClojureScript + (let [mdata (aapi/resolve &env v) + arglists (second (get-in mdata [:meta :arglists])) + sym (symbol (c/name v)) + andsym (symbol "&") + procarg #(if (= % andsym) % (gensym "param"))] + (if (pos? (count arglists)) + `(def + ~(with-meta sym (:meta mdata)) + (fn ~@(for [args arglists] + (let [args (map procarg args)] + (if (some #(= andsym %) args) + (let [[sargs dargs] (split-with #(not= andsym %) args)] + `([~@sargs ~@dargs] (apply ~v ~@sargs ~@(rest dargs)))) + `([~@args] (~v ~@args))))))) + `(def ~(with-meta sym (:meta mdata)) ~v))) + + ;; Code for Clojure + (let [vr (resolve v) + m (meta vr) + n (:name m) + n (with-meta n + (cond-> {} + (:dynamic m) (assoc :dynamic true) + (:protocol m) (assoc :protocol (:protocol m))))] + `(let [m# (meta ~vr)] + (def ~n (deref ~vr)) + (alter-meta! (var ~n) merge (dissoc m# :name)) + ;; (when (:macro m#) + ;; (.setMacro (var ~n))) + ~vr)))) + + diff --git a/common/src/app/common/geom/shapes.cljc b/common/src/app/common/geom/shapes.cljc index bf63582e5..aab6ebb1b 100644 --- a/common/src/app/common/geom/shapes.cljc +++ b/common/src/app/common/geom/shapes.cljc @@ -7,6 +7,7 @@ (ns app.common.geom.shapes (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.bool :as gsb] [app.common.geom.shapes.common :as gco] @@ -137,55 +138,55 @@ ;; EXPORTS -(d/export gco/center-shape) -(d/export gco/center-selrect) -(d/export gco/center-rect) -(d/export gco/center-points) -(d/export gco/make-centered-rect) -(d/export gco/transform-points) +(dm/export gco/center-shape) +(dm/export gco/center-selrect) +(dm/export gco/center-rect) +(dm/export gco/center-points) +(dm/export gco/make-centered-rect) +(dm/export gco/transform-points) -(d/export gpr/rect->selrect) -(d/export gpr/rect->points) -(d/export gpr/points->selrect) -(d/export gpr/points->rect) -(d/export gpr/center->rect) -(d/export gpr/join-rects) -(d/export gpr/contains-selrect?) +(dm/export gpr/rect->selrect) +(dm/export gpr/rect->points) +(dm/export gpr/points->selrect) +(dm/export gpr/points->rect) +(dm/export gpr/center->rect) +(dm/export gpr/join-rects) +(dm/export gpr/contains-selrect?) -(d/export gtr/move) -(d/export gtr/absolute-move) -(d/export gtr/transform-matrix) -(d/export gtr/inverse-transform-matrix) -(d/export gtr/transform-point-center) -(d/export gtr/transform-rect) -(d/export gtr/calculate-adjust-matrix) -(d/export gtr/update-group-selrect) -(d/export gtr/resize-modifiers) -(d/export gtr/rotation-modifiers) -(d/export gtr/merge-modifiers) -(d/export gtr/transform-shape) -(d/export gtr/transform-selrect) -(d/export gtr/modifiers->transform) -(d/export gtr/empty-modifiers?) +(dm/export gtr/move) +(dm/export gtr/absolute-move) +(dm/export gtr/transform-matrix) +(dm/export gtr/inverse-transform-matrix) +(dm/export gtr/transform-point-center) +(dm/export gtr/transform-rect) +(dm/export gtr/calculate-adjust-matrix) +(dm/export gtr/update-group-selrect) +(dm/export gtr/resize-modifiers) +(dm/export gtr/rotation-modifiers) +(dm/export gtr/merge-modifiers) +(dm/export gtr/transform-shape) +(dm/export gtr/transform-selrect) +(dm/export gtr/modifiers->transform) +(dm/export gtr/empty-modifiers?) ;; Constratins -(d/export gct/calc-child-modifiers) +(dm/export gct/calc-child-modifiers) ;; PATHS -(d/export gsp/content->selrect) -(d/export gsp/transform-content) -(d/export gsp/open-path?) +(dm/export gsp/content->selrect) +(dm/export gsp/transform-content) +(dm/export gsp/open-path?) ;; Intersection -(d/export gin/overlaps?) -(d/export gin/has-point?) -(d/export gin/has-point-rect?) -(d/export gin/rect-contains-shape?) +(dm/export gin/overlaps?) +(dm/export gin/has-point?) +(dm/export gin/has-point-rect?) +(dm/export gin/rect-contains-shape?) ;; Bool -(d/export gsb/update-bool-selrect) -(d/export gsb/calc-bool-content) +(dm/export gsb/update-bool-selrect) +(dm/export gsb/calc-bool-content) ;; Constraints -(d/export gct/default-constraints-h) -(d/export gct/default-constraints-v) +(dm/export gct/default-constraints-h) +(dm/export gct/default-constraints-v) diff --git a/common/src/app/common/pages.cljc b/common/src/app/common/pages.cljc index 3c10910d4..dce949453 100644 --- a/common/src/app/common/pages.cljc +++ b/common/src/app/common/pages.cljc @@ -7,32 +7,32 @@ (ns app.common.pages "A common (clj/cljs) functions and specs for pages." (:require - [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.pages.changes :as changes] [app.common.pages.common :as common] [app.common.pages.indices :as indices] [app.common.pages.init :as init])) ;; Common -(d/export common/root) -(d/export common/file-version) -(d/export common/default-color) -(d/export common/component-sync-attrs) +(dm/export common/root) +(dm/export common/file-version) +(dm/export common/default-color) +(dm/export common/component-sync-attrs) ;; Indices -(d/export indices/calculate-z-index) -(d/export indices/update-z-index) -(d/export indices/generate-child-all-parents-index) -(d/export indices/generate-child-parent-index) -(d/export indices/create-clip-index) +(dm/export indices/calculate-z-index) +(dm/export indices/update-z-index) +(dm/export indices/generate-child-all-parents-index) +(dm/export indices/generate-child-parent-index) +(dm/export indices/create-clip-index) ;; Process changes -(d/export changes/process-changes) +(dm/export changes/process-changes) ;; Initialization -(d/export init/default-frame-attrs) -(d/export init/default-shape-attrs) -(d/export init/make-file-data) -(d/export init/make-minimal-shape) -(d/export init/make-minimal-group) -(d/export init/empty-file-data) +(dm/export init/default-frame-attrs) +(dm/export init/default-shape-attrs) +(dm/export init/make-file-data) +(dm/export init/make-minimal-shape) +(dm/export init/make-minimal-group) +(dm/export init/empty-file-data) diff --git a/common/src/app/common/uri.cljc b/common/src/app/common/uri.cljc index dbe03bf79..8560c2a5e 100644 --- a/common/src/app/common/uri.cljc +++ b/common/src/app/common/uri.cljc @@ -7,15 +7,15 @@ (ns app.common.uri (:refer-clojure :exclude [uri?]) (:require - [app.common.data :as d] + [app.common.data.macros :as dm] [lambdaisland.uri :as u] [lambdaisland.uri.normalize :as un])) -(d/export u/uri) -(d/export u/join) -(d/export u/query-encode) -(d/export un/percent-encode) -(d/export u/uri?) +(dm/export u/uri) +(dm/export u/join) +(dm/export u/query-encode) +(dm/export un/percent-encode) +(dm/export u/uri?) (defn query-string->map [s] diff --git a/common/src/app/common/uuid.cljc b/common/src/app/common/uuid.cljc index 4d0e48359..604502900 100644 --- a/common/src/app/common/uuid.cljc +++ b/common/src/app/common/uuid.cljc @@ -7,7 +7,7 @@ (ns app.common.uuid (:refer-clojure :exclude [next uuid zero?]) (:require - #?(:clj [app.common.data :as d]) + #?(:clj [app.common.data.macros :as dm]) #?(:clj [clj-uuid :as impl]) #?(:clj [clojure.core :as c]) #?(:cljs [app.common.uuid-impl :as impl]) @@ -47,4 +47,4 @@ ([b a] #?(:clj (UUID. b a) :cljs (c/uuid (impl/custom b a))))) #?(:clj - (d/export impl/get-word-high)) + (dm/export impl/get-word-high)) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index f88fb657d..b0479a333 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -8,6 +8,7 @@ (:require [app.common.attrs :as attrs] [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.geom.align :as gal] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] @@ -1768,18 +1769,18 @@ ptk/UpdateEvent (update [_ state] - (assoc-in state [:workspace-local :show-distances?] value)))) + (assoc-in state [:workspace-global :show-distances?] value)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Interactions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(d/export dwi/start-edit-interaction) -(d/export dwi/move-edit-interaction) -(d/export dwi/finish-edit-interaction) -(d/export dwi/start-move-overlay-pos) -(d/export dwi/move-overlay-pos) -(d/export dwi/finish-move-overlay-pos) +(dm/export dwi/start-edit-interaction) +(dm/export dwi/move-edit-interaction) +(dm/export dwi/finish-edit-interaction) +(dm/export dwi/start-move-overlay-pos) +(dm/export dwi/move-overlay-pos) +(dm/export dwi/finish-move-overlay-pos) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; CANVAS OPTIONS @@ -1832,62 +1833,62 @@ ;; Transform -(d/export dwt/start-resize) -(d/export dwt/update-dimensions) -(d/export dwt/start-rotate) -(d/export dwt/increase-rotation) -(d/export dwt/start-move-selected) -(d/export dwt/move-selected) -(d/export dwt/update-position) -(d/export dwt/flip-horizontal-selected) -(d/export dwt/flip-vertical-selected) -(d/export dwly/set-opacity) +(dm/export dwt/start-resize) +(dm/export dwt/update-dimensions) +(dm/export dwt/start-rotate) +(dm/export dwt/increase-rotation) +(dm/export dwt/start-move-selected) +(dm/export dwt/move-selected) +(dm/export dwt/update-position) +(dm/export dwt/flip-horizontal-selected) +(dm/export dwt/flip-vertical-selected) +(dm/export dwly/set-opacity) ;; Persistence -(d/export dwp/set-file-shared) -(d/export dwp/fetch-shared-files) -(d/export dwp/link-file-to-library) -(d/export dwp/unlink-file-from-library) -(d/export dwp/upload-media-asset) -(d/export dwp/upload-media-workspace) -(d/export dwp/clone-media-object) -(d/export dwc/image-uploaded) +(dm/export dwp/set-file-shared) +(dm/export dwp/fetch-shared-files) +(dm/export dwp/link-file-to-library) +(dm/export dwp/unlink-file-from-library) +(dm/export dwp/upload-media-asset) +(dm/export dwp/upload-media-workspace) +(dm/export dwp/clone-media-object) +(dm/export dwc/image-uploaded) ;; Selection -(d/export dws/select-shape) -(d/export dws/deselect-shape) -(d/export dws/select-all) -(d/export dws/deselect-all) -(d/export dwc/select-shapes) -(d/export dws/shift-select-shapes) -(d/export dws/duplicate-selected) -(d/export dws/handle-area-selection) -(d/export dws/select-inside-group) -(d/export dwd/select-for-drawing) -(d/export dwc/clear-edition-mode) -(d/export dwc/add-shape) -(d/export dwc/start-edition-mode) +(dm/export dws/select-shape) +(dm/export dws/deselect-shape) +(dm/export dws/select-all) +(dm/export dws/deselect-all) +(dm/export dwc/select-shapes) +(dm/export dws/shift-select-shapes) +(dm/export dws/duplicate-selected) +(dm/export dws/handle-area-selection) +(dm/export dws/select-inside-group) +(dm/export dwd/select-for-drawing) +(dm/export dwc/clear-edition-mode) +(dm/export dwc/add-shape) +(dm/export dwc/start-edition-mode) ;; Groups -(d/export dwg/mask-group) -(d/export dwg/unmask-group) -(d/export dwg/group-selected) -(d/export dwg/ungroup-selected) +(dm/export dwg/mask-group) +(dm/export dwg/unmask-group) +(dm/export dwg/group-selected) +(dm/export dwg/ungroup-selected) ;; Boolean -(d/export dwb/create-bool) -(d/export dwb/group-to-bool) -(d/export dwb/bool-to-group) -(d/export dwb/change-bool-type) +(dm/export dwb/create-bool) +(dm/export dwb/group-to-bool) +(dm/export dwb/bool-to-group) +(dm/export dwb/change-bool-type) ;; Shapes to path -(d/export dwps/convert-selected-to-path) +(dm/export dwps/convert-selected-to-path) ;; Guides -(d/export dwgu/update-guides) -(d/export dwgu/remove-guide) -(d/export dwgu/set-hover-guide) +(dm/export dwgu/update-guides) +(dm/export dwgu/remove-guide) +(dm/export dwgu/set-hover-guide) diff --git a/frontend/src/app/main/data/workspace/path.cljs b/frontend/src/app/main/data/workspace/path.cljs index ada2f22a8..d16ad394e 100644 --- a/frontend/src/app/main/data/workspace/path.cljs +++ b/frontend/src/app/main/data/workspace/path.cljs @@ -6,7 +6,7 @@ (ns app.main.data.workspace.path (:require - [app.common.data :as d] + [app.common.data.macros :as dm] [app.main.data.workspace.path.drawing :as drawing] [app.main.data.workspace.path.edition :as edition] [app.main.data.workspace.path.selection :as selection] @@ -14,38 +14,38 @@ [app.main.data.workspace.path.undo :as undo])) ;; Drawing -(d/export drawing/handle-new-shape) -(d/export drawing/start-path-from-point) -(d/export drawing/close-path-drag-start) -(d/export drawing/change-edit-mode) -(d/export drawing/reset-last-handler) +(dm/export drawing/handle-new-shape) +(dm/export drawing/start-path-from-point) +(dm/export drawing/close-path-drag-start) +(dm/export drawing/change-edit-mode) +(dm/export drawing/reset-last-handler) ;; Edition -(d/export edition/start-move-handler) -(d/export edition/start-move-path-point) -(d/export edition/start-path-edit) -(d/export edition/create-node-at-position) -(d/export edition/move-selected) +(dm/export edition/start-move-handler) +(dm/export edition/start-move-path-point) +(dm/export edition/start-path-edit) +(dm/export edition/create-node-at-position) +(dm/export edition/move-selected) ;; Selection -(d/export selection/handle-area-selection) -(d/export selection/select-node) -(d/export selection/path-handler-enter) -(d/export selection/path-handler-leave) -(d/export selection/path-pointer-enter) -(d/export selection/path-pointer-leave) +(dm/export selection/handle-area-selection) +(dm/export selection/select-node) +(dm/export selection/path-handler-enter) +(dm/export selection/path-handler-leave) +(dm/export selection/path-pointer-enter) +(dm/export selection/path-pointer-leave) ;; Path tools -(d/export tools/make-curve) -(d/export tools/make-corner) -(d/export tools/add-node) -(d/export tools/remove-node) -(d/export tools/merge-nodes) -(d/export tools/join-nodes) -(d/export tools/separate-nodes) -(d/export tools/toggle-snap) +(dm/export tools/make-curve) +(dm/export tools/make-corner) +(dm/export tools/add-node) +(dm/export tools/remove-node) +(dm/export tools/merge-nodes) +(dm/export tools/join-nodes) +(dm/export tools/separate-nodes) +(dm/export tools/toggle-snap) ;; Undo/redo -(d/export undo/undo-path) -(d/export undo/redo-path) -(d/export undo/merge-head) +(dm/export undo/undo-path) +(dm/export undo/redo-path) +(dm/export undo/merge-head)