mirror of
https://github.com/penpot/penpot.git
synced 2025-05-24 14:56:11 +02:00
🎉 Improve performance reducing unnecessary calls to set-objects
This commit is contained in:
parent
e012046f62
commit
7728d5b317
20 changed files with 360 additions and 180 deletions
|
@ -85,6 +85,7 @@
|
||||||
[app.main.streams :as ms]
|
[app.main.streams :as ms]
|
||||||
[app.main.worker :as uw]
|
[app.main.worker :as uw]
|
||||||
[app.render-wasm :as wasm]
|
[app.render-wasm :as wasm]
|
||||||
|
[app.render-wasm.api :as api]
|
||||||
[app.util.code-gen.style-css :as css]
|
[app.util.code-gen.style-css :as css]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.globals :as ug]
|
[app.util.globals :as ug]
|
||||||
|
@ -348,8 +349,10 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(log/debug :hint "initialize-workspace" :file-id (dm/str file-id))
|
(log/debug :hint "initialize-workspace" :file-id (dm/str file-id))
|
||||||
(let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
|
(let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
|
||||||
rparams (rt/get-params state)]
|
rparams (rt/get-params state)
|
||||||
|
features (features/get-team-enabled-features state)
|
||||||
|
render-wasm? (contains? features "render-wasm/v1")]
|
||||||
|
|
||||||
(->> (rx/merge
|
(->> (rx/merge
|
||||||
(rx/of (ntf/hide)
|
(rx/of (ntf/hide)
|
||||||
|
@ -395,6 +398,13 @@
|
||||||
(rx/filter dch/commit?)
|
(rx/filter dch/commit?)
|
||||||
(rx/map deref)
|
(rx/map deref)
|
||||||
(rx/mapcat (fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo?]}]
|
(rx/mapcat (fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo?]}]
|
||||||
|
(when render-wasm?
|
||||||
|
(let [added (->> redo-changes
|
||||||
|
(filter #(= (:type %) :add-obj))
|
||||||
|
(map :obj))]
|
||||||
|
(doseq [shape added]
|
||||||
|
(api/set-object [] shape))))
|
||||||
|
|
||||||
(if (and save-undo? (seq undo-changes))
|
(if (and save-undo? (seq undo-changes))
|
||||||
(let [entry {:undo-changes undo-changes
|
(let [entry {:undo-changes undo-changes
|
||||||
:redo-changes redo-changes
|
:redo-changes redo-changes
|
||||||
|
|
|
@ -292,10 +292,6 @@
|
||||||
(when @canvas-init?
|
(when @canvas-init?
|
||||||
(wasm.api/resize-viewbox (:width vport) (:height vport))))
|
(wasm.api/resize-viewbox (:width vport) (:height vport))))
|
||||||
|
|
||||||
(mf/with-effect [@canvas-init? base-objects]
|
|
||||||
(when (and @canvas-init? @initialized?)
|
|
||||||
(wasm.api/set-objects base-objects)))
|
|
||||||
|
|
||||||
(mf/with-effect [@canvas-init? preview-blend]
|
(mf/with-effect [@canvas-init? preview-blend]
|
||||||
(when (and @canvas-init? preview-blend)
|
(when (and @canvas-init? preview-blend)
|
||||||
(wasm.api/request-render "with-effect")))
|
(wasm.api/request-render "with-effect")))
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
|
[app.main.fonts :as fonts]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.render :as render]
|
[app.main.render :as render]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.shapes.text.fontfaces :as fonts]
|
|
||||||
[app.render-wasm.helpers :as h]
|
[app.render-wasm.helpers :as h]
|
||||||
[app.render-wasm.serializers :as sr]
|
[app.render-wasm.serializers :as sr]
|
||||||
[app.util.debug :as dbg]
|
[app.util.debug :as dbg]
|
||||||
|
@ -155,15 +155,24 @@
|
||||||
|
|
||||||
(defn set-shape-children
|
(defn set-shape-children
|
||||||
[shape-ids]
|
[shape-ids]
|
||||||
(h/call internal-module "_clear_shape_children")
|
(let [ENTRY-SIZE 16
|
||||||
(run! (fn [id]
|
ptr
|
||||||
(let [buffer (uuid/get-u32 id)]
|
(h/call internal-module "_alloc_bytes" (* ENTRY-SIZE (count shape-ids)))
|
||||||
(h/call internal-module "_add_shape_child"
|
|
||||||
(aget buffer 0)
|
heap
|
||||||
(aget buffer 1)
|
(js/Uint8Array.
|
||||||
(aget buffer 2)
|
(.-buffer (gobj/get ^js internal-module "HEAPU8"))
|
||||||
(aget buffer 3))))
|
ptr
|
||||||
shape-ids))
|
(* ENTRY-SIZE (count shape-ids)))]
|
||||||
|
|
||||||
|
(loop [entries (seq shape-ids)
|
||||||
|
offset 0]
|
||||||
|
(when-not (empty? entries)
|
||||||
|
(let [id (first entries)]
|
||||||
|
(.set heap (sr/uuid->u8 id) offset)
|
||||||
|
(recur (rest entries) (+ offset ENTRY-SIZE)))))
|
||||||
|
|
||||||
|
(h/call internal-module "_set_children")))
|
||||||
|
|
||||||
(defn- get-string-length [string] (+ (count string) 1))
|
(defn- get-string-length [string] (+ (count string) 1))
|
||||||
|
|
||||||
|
@ -240,7 +249,6 @@
|
||||||
color (:fill-color fill)
|
color (:fill-color fill)
|
||||||
gradient (:fill-color-gradient fill)
|
gradient (:fill-color-gradient fill)
|
||||||
image (:fill-image fill)]
|
image (:fill-image fill)]
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
(some? color)
|
(some? color)
|
||||||
(let [rgba (rgba-from-hex color opacity)]
|
(let [rgba (rgba-from-hex color opacity)]
|
||||||
|
@ -712,34 +720,7 @@
|
||||||
(aget font-id 3)
|
(aget font-id 3)
|
||||||
font-weight font-style font-size)))
|
font-weight font-style font-size)))
|
||||||
|
|
||||||
(defn set-shape-text-content [content]
|
(defn- store-fonts
|
||||||
(h/call internal-module "_clear_shape_text")
|
|
||||||
(let [paragraph-set (first (dm/get-prop content :children))
|
|
||||||
paragraphs (dm/get-prop paragraph-set :children)
|
|
||||||
total-paragraphs (count paragraphs)]
|
|
||||||
|
|
||||||
(loop [index 0]
|
|
||||||
(when (< index total-paragraphs)
|
|
||||||
(let [paragraph (nth paragraphs index)
|
|
||||||
leaves (dm/get-prop paragraph :children)
|
|
||||||
total-leaves (count leaves)]
|
|
||||||
(h/call internal-module "_add_text_paragraph")
|
|
||||||
(loop [index-leaves 0]
|
|
||||||
(when (< index-leaves total-leaves)
|
|
||||||
(let [leaf (nth leaves index-leaves)]
|
|
||||||
(add-text-leaf leaf)
|
|
||||||
(recur (inc index-leaves))))))
|
|
||||||
(recur (inc index))))))
|
|
||||||
|
|
||||||
(defn set-view-box
|
|
||||||
[zoom vbox]
|
|
||||||
(h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)))
|
|
||||||
(render nil))
|
|
||||||
|
|
||||||
(defn clear-drawing-cache []
|
|
||||||
(h/call internal-module "_clear_drawing_cache"))
|
|
||||||
|
|
||||||
(defn- store-all-fonts
|
|
||||||
[fonts]
|
[fonts]
|
||||||
(keep (fn [font]
|
(keep (fn [font]
|
||||||
(let [font-id (dm/get-prop font :font-id)
|
(let [font-id (dm/get-prop font :font-id)
|
||||||
|
@ -755,97 +736,126 @@
|
||||||
:weight weight}]
|
:weight weight}]
|
||||||
(store-font-id font-data ttf-id))) fonts))
|
(store-font-id font-data ttf-id))) fonts))
|
||||||
|
|
||||||
(defn set-fonts
|
(defn set-shape-text-content [content]
|
||||||
[objects]
|
(h/call internal-module "_clear_shape_text")
|
||||||
(let [fonts (fonts/shapes->fonts (into [] (vals objects)))
|
(let [paragraph-set (first (dm/get-prop content :children))
|
||||||
pending (into [] (store-all-fonts fonts))]
|
paragraphs (dm/get-prop paragraph-set :children)
|
||||||
(->> (rx/from pending)
|
total-paragraphs (count paragraphs)
|
||||||
(rx/mapcat identity)
|
fonts (fonts/get-content-fonts content)]
|
||||||
(rx/reduce conj [])
|
|
||||||
(rx/subs! (fn [_]
|
(loop [index 0]
|
||||||
(clear-drawing-cache)
|
(when (< index total-paragraphs)
|
||||||
(request-render "set-fonts"))))))
|
(let [paragraph (nth paragraphs index)
|
||||||
|
leaves (dm/get-prop paragraph :children)
|
||||||
|
total-leaves (count leaves)]
|
||||||
|
(h/call internal-module "_add_text_paragraph")
|
||||||
|
(loop [index-leaves 0]
|
||||||
|
(when (< index-leaves total-leaves)
|
||||||
|
(let [leaf (nth leaves index-leaves)]
|
||||||
|
(add-text-leaf leaf)
|
||||||
|
(recur (inc index-leaves))))))
|
||||||
|
(recur (inc index))))
|
||||||
|
(store-fonts fonts)))
|
||||||
|
|
||||||
|
(defn set-view-box
|
||||||
|
[zoom vbox]
|
||||||
|
(h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)))
|
||||||
|
(render nil))
|
||||||
|
|
||||||
|
(defn clear-drawing-cache []
|
||||||
|
(h/call internal-module "_clear_drawing_cache"))
|
||||||
|
|
||||||
|
(defn update-shape-tiles []
|
||||||
|
(h/call internal-module "_update_shape_tiles"))
|
||||||
|
|
||||||
|
(defn set-object
|
||||||
|
[objects shape]
|
||||||
|
(let [id (dm/get-prop shape :id)
|
||||||
|
parent-id (dm/get-prop shape :parent-id)
|
||||||
|
type (dm/get-prop shape :type)
|
||||||
|
masked (dm/get-prop shape :masked-group)
|
||||||
|
selrect (dm/get-prop shape :selrect)
|
||||||
|
constraint-h (dm/get-prop shape :constraints-h)
|
||||||
|
constraint-v (dm/get-prop shape :constraints-v)
|
||||||
|
clip-content (if (= type :frame)
|
||||||
|
(not (dm/get-prop shape :show-content))
|
||||||
|
false)
|
||||||
|
rotation (dm/get-prop shape :rotation)
|
||||||
|
transform (dm/get-prop shape :transform)
|
||||||
|
fills (if (= type :group)
|
||||||
|
[] (dm/get-prop shape :fills))
|
||||||
|
strokes (if (= type :group)
|
||||||
|
[] (dm/get-prop shape :strokes))
|
||||||
|
children (dm/get-prop shape :shapes)
|
||||||
|
blend-mode (dm/get-prop shape :blend-mode)
|
||||||
|
opacity (dm/get-prop shape :opacity)
|
||||||
|
hidden (dm/get-prop shape :hidden)
|
||||||
|
content (dm/get-prop shape :content)
|
||||||
|
blur (dm/get-prop shape :blur)
|
||||||
|
corners (when (some? (dm/get-prop shape :r1))
|
||||||
|
[(dm/get-prop shape :r1)
|
||||||
|
(dm/get-prop shape :r2)
|
||||||
|
(dm/get-prop shape :r3)
|
||||||
|
(dm/get-prop shape :r4)])
|
||||||
|
svg-attrs (dm/get-prop shape :svg-attrs)
|
||||||
|
shadows (dm/get-prop shape :shadow)]
|
||||||
|
|
||||||
|
(use-shape id)
|
||||||
|
(set-parent-id parent-id)
|
||||||
|
(set-shape-type type)
|
||||||
|
(set-shape-clip-content clip-content)
|
||||||
|
(set-shape-selrect selrect)
|
||||||
|
(set-constraints-h constraint-h)
|
||||||
|
(set-constraints-v constraint-v)
|
||||||
|
(set-shape-rotation rotation)
|
||||||
|
(set-shape-transform transform)
|
||||||
|
(set-shape-blend-mode blend-mode)
|
||||||
|
(set-shape-opacity opacity)
|
||||||
|
(set-shape-hidden hidden)
|
||||||
|
(set-shape-children children)
|
||||||
|
(when (and (= type :group) masked)
|
||||||
|
(set-masked masked))
|
||||||
|
(when (some? blur)
|
||||||
|
(set-shape-blur blur))
|
||||||
|
(when (and (some? content)
|
||||||
|
(or (= type :path)
|
||||||
|
(= type :bool)))
|
||||||
|
(set-shape-path-attrs svg-attrs)
|
||||||
|
(set-shape-path-content content))
|
||||||
|
(when (and (some? content) (= type :svg-raw))
|
||||||
|
(set-shape-svg-raw-content (get-static-markup shape)))
|
||||||
|
(when (some? corners) (set-shape-corners corners))
|
||||||
|
(when (some? shadows) (set-shape-shadows shadows))
|
||||||
|
(when (and (= type :text) (some? content))
|
||||||
|
(set-shape-text-content content))
|
||||||
|
|
||||||
|
(when (or (ctl/any-layout? shape)
|
||||||
|
(ctl/any-layout-immediate-child? objects shape))
|
||||||
|
(set-layout-child shape))
|
||||||
|
|
||||||
|
(when (ctl/flex-layout? shape)
|
||||||
|
(set-flex-layout shape))
|
||||||
|
|
||||||
|
(when (ctl/grid-layout? shape)
|
||||||
|
(set-grid-layout shape))
|
||||||
|
|
||||||
|
(into [] (concat
|
||||||
|
(if (and (= type :text) (some? content))
|
||||||
|
(set-shape-text-content content)
|
||||||
|
[])
|
||||||
|
(set-shape-fills fills)
|
||||||
|
(set-shape-strokes strokes)))))
|
||||||
|
|
||||||
(defn set-objects
|
(defn set-objects
|
||||||
[objects]
|
[objects]
|
||||||
(set-fonts objects)
|
|
||||||
(let [shapes (into [] (vals objects))
|
(let [shapes (into [] (vals objects))
|
||||||
total-shapes (count shapes)
|
total-shapes (count shapes)
|
||||||
pending
|
pending
|
||||||
(loop [index 0 pending []]
|
(loop [index 0 pending []]
|
||||||
(if (< index total-shapes)
|
(if (< index total-shapes)
|
||||||
(let [shape (nth shapes index)
|
(let [shape (nth shapes index)
|
||||||
id (dm/get-prop shape :id)
|
pending' (set-object objects shape)]
|
||||||
parent-id (dm/get-prop shape :parent-id)
|
(recur (inc index) (into pending pending')))
|
||||||
type (dm/get-prop shape :type)
|
|
||||||
masked (dm/get-prop shape :masked-group)
|
|
||||||
selrect (dm/get-prop shape :selrect)
|
|
||||||
constraint-h (dm/get-prop shape :constraints-h)
|
|
||||||
constraint-v (dm/get-prop shape :constraints-v)
|
|
||||||
clip-content (if (= type :frame)
|
|
||||||
(not (dm/get-prop shape :show-content))
|
|
||||||
false)
|
|
||||||
rotation (dm/get-prop shape :rotation)
|
|
||||||
transform (dm/get-prop shape :transform)
|
|
||||||
fills (if (= type :group)
|
|
||||||
[] (dm/get-prop shape :fills))
|
|
||||||
strokes (if (= type :group)
|
|
||||||
[] (dm/get-prop shape :strokes))
|
|
||||||
children (dm/get-prop shape :shapes)
|
|
||||||
blend-mode (dm/get-prop shape :blend-mode)
|
|
||||||
opacity (dm/get-prop shape :opacity)
|
|
||||||
hidden (dm/get-prop shape :hidden)
|
|
||||||
content (dm/get-prop shape :content)
|
|
||||||
blur (dm/get-prop shape :blur)
|
|
||||||
corners (when (some? (dm/get-prop shape :r1))
|
|
||||||
[(dm/get-prop shape :r1)
|
|
||||||
(dm/get-prop shape :r2)
|
|
||||||
(dm/get-prop shape :r3)
|
|
||||||
(dm/get-prop shape :r4)])
|
|
||||||
svg-attrs (dm/get-prop shape :svg-attrs)
|
|
||||||
shadows (dm/get-prop shape :shadow)]
|
|
||||||
|
|
||||||
(use-shape id)
|
|
||||||
(set-parent-id parent-id)
|
|
||||||
(set-shape-type type)
|
|
||||||
(set-shape-clip-content clip-content)
|
|
||||||
(set-shape-selrect selrect)
|
|
||||||
(set-constraints-h constraint-h)
|
|
||||||
(set-constraints-v constraint-v)
|
|
||||||
(set-shape-rotation rotation)
|
|
||||||
(set-shape-transform transform)
|
|
||||||
(set-shape-blend-mode blend-mode)
|
|
||||||
(set-shape-opacity opacity)
|
|
||||||
(set-shape-hidden hidden)
|
|
||||||
(set-shape-children children)
|
|
||||||
(when (and (= type :group) masked)
|
|
||||||
(set-masked masked))
|
|
||||||
(when (some? blur)
|
|
||||||
(set-shape-blur blur))
|
|
||||||
(when (and (some? content)
|
|
||||||
(or (= type :path)
|
|
||||||
(= type :bool)))
|
|
||||||
(set-shape-path-attrs svg-attrs)
|
|
||||||
(set-shape-path-content content))
|
|
||||||
(when (and (some? content) (= type :svg-raw))
|
|
||||||
(set-shape-svg-raw-content (get-static-markup shape)))
|
|
||||||
(when (some? corners) (set-shape-corners corners))
|
|
||||||
(when (some? shadows) (set-shape-shadows shadows))
|
|
||||||
(when (and (= type :text) (some? content))
|
|
||||||
(set-shape-text-content content))
|
|
||||||
|
|
||||||
(when (or (ctl/any-layout? shape)
|
|
||||||
(ctl/any-layout-immediate-child? objects shape))
|
|
||||||
(set-layout-child shape))
|
|
||||||
|
|
||||||
(when (ctl/flex-layout? shape)
|
|
||||||
(set-flex-layout shape))
|
|
||||||
|
|
||||||
(when (ctl/grid-layout? shape)
|
|
||||||
(set-grid-layout shape))
|
|
||||||
|
|
||||||
(let [pending' (concat (set-shape-fills fills) (set-shape-strokes strokes))]
|
|
||||||
(recur (inc index) (into pending pending'))))
|
|
||||||
pending))]
|
pending))]
|
||||||
(clear-drawing-cache)
|
(clear-drawing-cache)
|
||||||
(request-render "set-objects")
|
(request-render "set-objects")
|
||||||
|
@ -917,16 +927,16 @@
|
||||||
(if (empty? modifiers)
|
(if (empty? modifiers)
|
||||||
(h/call internal-module "_clean_modifiers")
|
(h/call internal-module "_clean_modifiers")
|
||||||
|
|
||||||
(let [ENTRY_SIZE 40
|
(let [ENTRY-SIZE 40
|
||||||
|
|
||||||
ptr
|
ptr
|
||||||
(h/call internal-module "_alloc_bytes" (* ENTRY_SIZE (count modifiers)))
|
(h/call internal-module "_alloc_bytes" (* ENTRY-SIZE (count modifiers)))
|
||||||
|
|
||||||
heap
|
heap
|
||||||
(js/Uint8Array.
|
(js/Uint8Array.
|
||||||
(.-buffer (gobj/get ^js internal-module "HEAPU8"))
|
(.-buffer (gobj/get ^js internal-module "HEAPU8"))
|
||||||
ptr
|
ptr
|
||||||
(* ENTRY_SIZE (count modifiers)))]
|
(* ENTRY-SIZE (count modifiers)))]
|
||||||
|
|
||||||
(loop [entries (seq modifiers)
|
(loop [entries (seq modifiers)
|
||||||
offset 0]
|
offset 0]
|
||||||
|
@ -934,7 +944,7 @@
|
||||||
(let [{:keys [id transform]} (first entries)]
|
(let [{:keys [id transform]} (first entries)]
|
||||||
(.set heap (sr/uuid->u8 id) offset)
|
(.set heap (sr/uuid->u8 id) offset)
|
||||||
(.set heap (sr/matrix->u8 transform) (+ offset 16))
|
(.set heap (sr/matrix->u8 transform) (+ offset 16))
|
||||||
(recur (rest entries) (+ offset ENTRY_SIZE)))))
|
(recur (rest entries) (+ offset ENTRY-SIZE)))))
|
||||||
|
|
||||||
(h/call internal-module "_set_modifiers")
|
(h/call internal-module "_set_modifiers")
|
||||||
|
|
||||||
|
|
|
@ -120,13 +120,14 @@
|
||||||
(api/set-shape-clip-content false))
|
(api/set-shape-clip-content false))
|
||||||
:rotation (api/set-shape-rotation v)
|
:rotation (api/set-shape-rotation v)
|
||||||
:transform (api/set-shape-transform v)
|
:transform (api/set-shape-transform v)
|
||||||
:fills (api/set-shape-fills v)
|
:fills (into [] (api/set-shape-fills v))
|
||||||
:strokes (api/set-shape-strokes v)
|
:strokes (into [] (api/set-shape-strokes v))
|
||||||
:blend-mode (api/set-shape-blend-mode v)
|
:blend-mode (api/set-shape-blend-mode v)
|
||||||
:opacity (api/set-shape-opacity v)
|
:opacity (api/set-shape-opacity v)
|
||||||
:hidden (api/set-shape-hidden v)
|
:hidden (api/set-shape-hidden v)
|
||||||
:shapes (api/set-shape-children v)
|
:shapes (api/set-shape-children v)
|
||||||
:blur (api/set-shape-blur v)
|
:blur (api/set-shape-blur v)
|
||||||
|
:shadow (api/set-shape-shadows v)
|
||||||
:constraints-h (api/set-constraints-h v)
|
:constraints-h (api/set-constraints-h v)
|
||||||
:constraints-v (api/set-constraints-v v)
|
:constraints-v (api/set-constraints-v v)
|
||||||
|
|
||||||
|
@ -139,12 +140,17 @@
|
||||||
(api/set-shape-path-content v)
|
(api/set-shape-path-content v)
|
||||||
|
|
||||||
(= (:type self) :svg-raw)
|
(= (:type self) :svg-raw)
|
||||||
(api/set-shape-svg-raw-content (api/get-static-markup self)))
|
(api/set-shape-svg-raw-content (api/get-static-markup self))
|
||||||
|
|
||||||
|
(= (:type self) :text)
|
||||||
|
(into [] (api/set-shape-text-content v)))
|
||||||
nil)
|
nil)
|
||||||
;; when something synced with wasm
|
;; when something synced with wasm
|
||||||
;; is modified, we need to request
|
;; is modified, we need to request
|
||||||
;; a new render.
|
;; a new render.
|
||||||
(api/clear-drawing-cache)
|
;; TODO: set-wasm-attrs is called twice with every set
|
||||||
|
;; (println "set-wasm-attrs" (:id self) k v)
|
||||||
|
(api/update-shape-tiles)
|
||||||
(api/request-render "set-wasm-attrs")))
|
(api/request-render "set-wasm-attrs")))
|
||||||
|
|
||||||
(defn- impl-assoc
|
(defn- impl-assoc
|
||||||
|
|
|
@ -8,13 +8,15 @@ mod render;
|
||||||
mod shapes;
|
mod shapes;
|
||||||
mod state;
|
mod state;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
mod uuid;
|
||||||
mod view;
|
mod view;
|
||||||
mod wasm;
|
mod wasm;
|
||||||
|
|
||||||
use crate::mem::SerializableResult;
|
use crate::mem::SerializableResult;
|
||||||
use crate::shapes::{BoolType, ConstraintH, ConstraintV, TransformEntry, Type};
|
use crate::shapes::{BoolType, ConstraintH, ConstraintV, TransformEntry, Type};
|
||||||
|
|
||||||
use crate::utils::uuid_from_u32_quartet;
|
use crate::utils::uuid_from_u32_quartet;
|
||||||
|
use crate::uuid::Uuid;
|
||||||
|
use indexmap::IndexSet;
|
||||||
use state::State;
|
use state::State;
|
||||||
|
|
||||||
pub(crate) static mut STATE: Option<Box<State>> = None;
|
pub(crate) static mut STATE: Option<Box<State>> = None;
|
||||||
|
@ -201,6 +203,28 @@ pub extern "C" fn add_shape_child(a: u32, b: u32, c: u32, d: u32) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn set_children() {
|
||||||
|
let bytes = mem::bytes();
|
||||||
|
let entries: IndexSet<Uuid> = bytes
|
||||||
|
.chunks(size_of::<<Uuid as SerializableResult>::BytesType>())
|
||||||
|
.map(|data| Uuid::from_bytes(data.try_into().unwrap()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut deleted = IndexSet::new();
|
||||||
|
|
||||||
|
with_current_shape!(state, |shape: &mut Shape| {
|
||||||
|
(_, deleted) = shape.compute_children_differences(&entries);
|
||||||
|
shape.children = entries.clone();
|
||||||
|
});
|
||||||
|
|
||||||
|
with_state!(state, {
|
||||||
|
for id in deleted {
|
||||||
|
state.delete_shape(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn clear_shape_children() {
|
pub extern "C" fn clear_shape_children() {
|
||||||
with_current_shape!(state, |shape: &mut Shape| {
|
with_current_shape!(state, |shape: &mut Shape| {
|
||||||
|
@ -621,6 +645,13 @@ pub extern "C" fn clear_shape_shadows() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn update_shape_tiles() {
|
||||||
|
with_state!(state, {
|
||||||
|
state.update_tile_for_current_shape();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn set_flex_layout_data(
|
pub extern "C" fn set_flex_layout_data(
|
||||||
dir: u8,
|
dir: u8,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use skia_safe::{self as skia, Matrix, RRect, Rect};
|
use skia_safe::{self as skia, Matrix, RRect, Rect};
|
||||||
|
|
||||||
|
use crate::uuid::Uuid;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::view::Viewbox;
|
use crate::view::Viewbox;
|
||||||
use crate::{run_script, run_script_int};
|
use crate::{run_script, run_script_int};
|
||||||
|
@ -474,6 +474,7 @@ impl RenderState {
|
||||||
self.surfaces.cache_visit(tile);
|
self.surfaces.cache_visit(tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.pending_nodes = vec![];
|
||||||
self.current_tile = None;
|
self.current_tile = None;
|
||||||
self.render_in_progress = true;
|
self.render_in_progress = true;
|
||||||
self.apply_drawing_to_render_canvas(None);
|
self.apply_drawing_to_render_canvas(None);
|
||||||
|
@ -751,21 +752,33 @@ impl RenderState {
|
||||||
self.update_render_context(next_tile);
|
self.update_render_context(next_tile);
|
||||||
if !self.surfaces.has_cached_tile_surface(next_tile) {
|
if !self.surfaces.has_cached_tile_surface(next_tile) {
|
||||||
if let Some(ids) = self.tiles.get_shapes_at(next_tile) {
|
if let Some(ids) = self.tiles.get_shapes_at(next_tile) {
|
||||||
for id in ids {
|
// We only need first level shapes
|
||||||
let element = tree.get_mut(&id).ok_or(
|
let mut valid_ids: Vec<Uuid> = ids
|
||||||
"Error: Element with root_id {id} not found in the tree."
|
.iter()
|
||||||
.to_string(),
|
.filter_map(|id| {
|
||||||
)?;
|
tree.get(id)
|
||||||
if element.parent_id == Some(Uuid::nil()) {
|
.filter(|element| element.parent_id == Some(Uuid::nil()))
|
||||||
self.pending_nodes.push(NodeRenderState {
|
.map(|_| *id)
|
||||||
id: *id,
|
})
|
||||||
visited_children: false,
|
.collect();
|
||||||
clip_bounds: None,
|
|
||||||
visited_mask: false,
|
// These shapes for the tile should be ordered as they are in the parent node
|
||||||
mask: false,
|
if let Some(root) = tree.get(&Uuid::nil()) {
|
||||||
});
|
let root_ids = &root.children_ids();
|
||||||
}
|
valid_ids.sort_by_key(|id| {
|
||||||
|
root_ids.iter().rev().position(|root_id| root_id == id)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.pending_nodes.extend(valid_ids.into_iter().map(|id| {
|
||||||
|
NodeRenderState {
|
||||||
|
id,
|
||||||
|
visited_children: false,
|
||||||
|
clip_bounds: None,
|
||||||
|
visited_mask: false,
|
||||||
|
mask: false,
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -783,9 +796,13 @@ impl RenderState {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_tile_for(&mut self, shape: &Shape) {
|
pub fn get_tiles_for_rect(&mut self, shape: &Shape) -> (i32, i32, i32, i32) {
|
||||||
let tile_size = tiles::get_tile_size(self.viewbox);
|
let tile_size = tiles::get_tile_size(self.viewbox);
|
||||||
let (rsx, rsy, rex, rey) = tiles::get_tiles_for_rect(shape.extrect(), tile_size);
|
tiles::get_tiles_for_rect(shape.extrect(), tile_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_tile_for(&mut self, shape: &Shape) {
|
||||||
|
let (rsx, rsy, rex, rey) = self.get_tiles_for_rect(shape);
|
||||||
|
|
||||||
// Update tiles where the shape was
|
// Update tiles where the shape was
|
||||||
if let Some(tiles) = self.tiles.get_tiles_of(shape.id) {
|
if let Some(tiles) = self.tiles.get_tiles_of(shape.id) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use crate::uuid::Uuid;
|
||||||
use skia_safe as skia;
|
use skia_safe as skia;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
pub type Image = skia::Image;
|
pub type Image = skia::Image;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use skia_safe as skia;
|
use crate::uuid::Uuid;
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::view::Viewbox;
|
use crate::view::Viewbox;
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
|
use skia_safe as skia;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
pub type Tile = (i32, i32);
|
pub type Tile = (i32, i32);
|
||||||
|
|
||||||
|
@ -64,6 +63,12 @@ impl TileHashMap {
|
||||||
return self.grid.get(&tile);
|
return self.grid.get(&tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_shape_at(&mut self, tile: Tile, id: Uuid) {
|
||||||
|
if let Some(shapes) = self.grid.get_mut(&tile) {
|
||||||
|
shapes.shift_remove(&id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_tiles_of(&mut self, shape_id: Uuid) -> Option<&HashSet<Tile>> {
|
pub fn get_tiles_of(&mut self, shape_id: Uuid) -> Option<&HashSet<Tile>> {
|
||||||
self.index.get(&shape_id)
|
self.index.get(&shape_id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use skia_safe::{self as skia};
|
use skia_safe::{self as skia};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::render::BlendMode;
|
use crate::render::BlendMode;
|
||||||
|
use crate::uuid::Uuid;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
mod blurs;
|
mod blurs;
|
||||||
mod bools;
|
mod bools;
|
||||||
|
@ -41,6 +40,7 @@ pub use transform::*;
|
||||||
|
|
||||||
use crate::math;
|
use crate::math;
|
||||||
use crate::math::{Bounds, Matrix, Point};
|
use crate::math::{Bounds, Matrix, Point};
|
||||||
|
use indexmap::IndexSet;
|
||||||
|
|
||||||
const MIN_VISIBLE_SIZE: f32 = 2.0;
|
const MIN_VISIBLE_SIZE: f32 = 2.0;
|
||||||
const ANTIALIAS_THRESHOLD: f32 = 15.0;
|
const ANTIALIAS_THRESHOLD: f32 = 15.0;
|
||||||
|
@ -160,7 +160,7 @@ pub struct Shape {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub parent_id: Option<Uuid>,
|
pub parent_id: Option<Uuid>,
|
||||||
pub shape_type: Type,
|
pub shape_type: Type,
|
||||||
pub children: Vec<Uuid>,
|
pub children: IndexSet<Uuid>,
|
||||||
pub selrect: math::Rect,
|
pub selrect: math::Rect,
|
||||||
pub transform: Matrix,
|
pub transform: Matrix,
|
||||||
pub rotation: f32,
|
pub rotation: f32,
|
||||||
|
@ -185,7 +185,7 @@ impl Shape {
|
||||||
id,
|
id,
|
||||||
parent_id: None,
|
parent_id: None,
|
||||||
shape_type: Type::Rect(Rect::default()),
|
shape_type: Type::Rect(Rect::default()),
|
||||||
children: Vec::<Uuid>::new(),
|
children: IndexSet::<Uuid>::new(),
|
||||||
selrect: math::Rect::new_empty(),
|
selrect: math::Rect::new_empty(),
|
||||||
transform: Matrix::default(),
|
transform: Matrix::default(),
|
||||||
rotation: 0.,
|
rotation: 0.,
|
||||||
|
@ -432,7 +432,16 @@ impl Shape {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_child(&mut self, id: Uuid) {
|
pub fn add_child(&mut self, id: Uuid) {
|
||||||
self.children.push(id);
|
self.children.insert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute_children_differences(
|
||||||
|
&mut self,
|
||||||
|
children: &IndexSet<Uuid>,
|
||||||
|
) -> (IndexSet<Uuid>, IndexSet<Uuid>) {
|
||||||
|
let added = children.difference(&self.children).cloned().collect();
|
||||||
|
let removed = self.children.difference(children).cloned().collect();
|
||||||
|
(added, removed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_children(&mut self) {
|
pub fn clear_children(&mut self) {
|
||||||
|
@ -655,12 +664,12 @@ impl Shape {
|
||||||
vec![]
|
vec![]
|
||||||
} else if let Type::Group(group) = self.shape_type {
|
} else if let Type::Group(group) = self.shape_type {
|
||||||
if group.masked {
|
if group.masked {
|
||||||
self.children[1..self.children.len()].to_vec()
|
self.children.iter().skip(1).cloned().collect()
|
||||||
} else {
|
} else {
|
||||||
self.children.clone()
|
self.children.clone().into_iter().collect()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.children.clone()
|
self.children.clone().into_iter().collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use skia_safe::{self as skia, Rect};
|
use skia_safe::{self as skia, Rect};
|
||||||
|
|
||||||
use super::Color;
|
use super::Color;
|
||||||
use uuid::Uuid;
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use uuid::Uuid;
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum FontStyle {
|
pub enum FontStyle {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::utils::uuid_from_u32_quartet;
|
use crate::utils::uuid_from_u32_quartet;
|
||||||
use uuid::Uuid;
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
@ -4,8 +4,6 @@ mod constraints;
|
||||||
mod flex_layout;
|
mod flex_layout;
|
||||||
mod grid_layout;
|
mod grid_layout;
|
||||||
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use common::GetBounds;
|
use common::GetBounds;
|
||||||
|
|
||||||
use crate::math::{identitish, Bounds, Matrix, Point};
|
use crate::math::{identitish, Bounds, Matrix, Point};
|
||||||
|
@ -13,6 +11,7 @@ use crate::shapes::{
|
||||||
ConstraintH, ConstraintV, Frame, Group, Layout, Modifier, Shape, TransformEntry, Type,
|
ConstraintH, ConstraintV, Frame, Group, Layout, Modifier, Shape, TransformEntry, Type,
|
||||||
};
|
};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
fn propagate_children(
|
fn propagate_children(
|
||||||
shape: &Shape,
|
shape: &Shape,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::math::Bounds;
|
use crate::math::Bounds;
|
||||||
use crate::shapes::Shape;
|
use crate::shapes::Shape;
|
||||||
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
pub trait GetBounds {
|
pub trait GetBounds {
|
||||||
fn find(&self, shape: &Shape) -> Bounds;
|
fn find(&self, shape: &Shape) -> Bounds;
|
||||||
|
|
|
@ -4,8 +4,9 @@ use crate::shapes::{
|
||||||
AlignContent, AlignItems, AlignSelf, FlexData, JustifyContent, LayoutData, LayoutItem,
|
AlignContent, AlignItems, AlignSelf, FlexData, JustifyContent, LayoutData, LayoutItem,
|
||||||
Modifier, Shape,
|
Modifier, Shape,
|
||||||
};
|
};
|
||||||
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use super::common::GetBounds;
|
use super::common::GetBounds;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#![allow(dead_code, unused_variables)]
|
#![allow(dead_code, unused_variables)]
|
||||||
use crate::math::{Bounds, Matrix, Point, Vector, VectorExt};
|
use crate::math::{Bounds, Matrix, Point, Vector, VectorExt};
|
||||||
use crate::shapes::{GridData, LayoutData, Modifier, Shape};
|
use crate::shapes::{GridData, LayoutData, Modifier, Shape};
|
||||||
|
use crate::uuid::Uuid;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use super::common::GetBounds;
|
use super::common::GetBounds;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use skia_safe as skia;
|
use skia_safe as skia;
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::mem::SerializableResult;
|
use crate::mem::SerializableResult;
|
||||||
use crate::utils::{uuid_from_u32_quartet, uuid_to_u32_quartet};
|
use crate::utils::{uuid_from_u32_quartet, uuid_to_u32_quartet};
|
||||||
|
use crate::uuid::Uuid;
|
||||||
use skia::Matrix;
|
use skia::Matrix;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
@ -101,7 +101,7 @@ impl SerializableResult for TransformEntry {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use uuid::uuid;
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialization() {
|
fn test_serialization() {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use skia_safe as skia;
|
use skia_safe as skia;
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::render::RenderState;
|
use crate::render::RenderState;
|
||||||
use crate::shapes::Shape;
|
use crate::shapes::Shape;
|
||||||
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
/// This struct holds the state of the Rust application between JS calls.
|
/// This struct holds the state of the Rust application between JS calls.
|
||||||
///
|
///
|
||||||
|
@ -59,6 +59,20 @@ impl<'a> State<'a> {
|
||||||
self.current_shape = self.shapes.get_mut(&id);
|
self.current_shape = self.shapes.get_mut(&id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn delete_shape(&mut self, id: Uuid) {
|
||||||
|
// We don't really do a self.shapes.remove so that redo/undo keep working
|
||||||
|
if let Some(shape) = self.shapes.get(&id) {
|
||||||
|
let (rsx, rsy, rex, rey) = self.render_state.get_tiles_for_rect(&shape);
|
||||||
|
for x in rsx..=rex {
|
||||||
|
for y in rsy..=rey {
|
||||||
|
let tile = (x, y);
|
||||||
|
self.render_state.surfaces.remove_cached_tile_surface(tile);
|
||||||
|
self.render_state.tiles.remove_shape_at(tile, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn current_shape(&mut self) -> Option<&mut Shape> {
|
pub fn current_shape(&mut self) -> Option<&mut Shape> {
|
||||||
self.current_shape.as_deref_mut()
|
self.current_shape.as_deref_mut()
|
||||||
}
|
}
|
||||||
|
@ -80,6 +94,19 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_tile_for_current_shape(&mut self) {
|
||||||
|
match self.current_shape.as_mut() {
|
||||||
|
Some(shape) => {
|
||||||
|
// We don't need to update the tile for the root shape.
|
||||||
|
// We can also have deleted the selected shape
|
||||||
|
if !shape.id.is_nil() && self.shapes.contains_key(&shape.id) {
|
||||||
|
self.render_state.update_tile_for(&shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => panic!("Invalid current shape"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rebuild_tiles(&mut self) {
|
pub fn rebuild_tiles(&mut self) {
|
||||||
self.render_state
|
self.render_state
|
||||||
.rebuild_tiles(&mut self.shapes, &self.modifiers);
|
.rebuild_tiles(&mut self.shapes, &self.modifiers);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use uuid::Uuid;
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
pub fn uuid_from_u32_quartet(a: u32, b: u32, c: u32, d: u32) -> Uuid {
|
pub fn uuid_from_u32_quartet(a: u32, b: u32, c: u32, d: u32) -> Uuid {
|
||||||
let hi: u64 = ((a as u64) << 32) | b as u64;
|
let hi: u64 = ((a as u64) << 32) | b as u64;
|
||||||
|
|
69
render-wasm/src/uuid.rs
Normal file
69
render-wasm/src/uuid.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
use crate::mem::SerializableResult;
|
||||||
|
use crate::utils::uuid_from_u32_quartet;
|
||||||
|
use crate::utils::uuid_to_u32_quartet;
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use uuid::Uuid as ExternalUuid;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Uuid(ExternalUuid);
|
||||||
|
|
||||||
|
impl Deref for Uuid {
|
||||||
|
type Target = ExternalUuid;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Uuid {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Uuid {
|
||||||
|
pub fn nil() -> Self {
|
||||||
|
Self(ExternalUuid::nil())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_u64_pair(high: u64, low: u64) -> Self {
|
||||||
|
Self(ExternalUuid::from_u64_pair(high, low))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Uuid {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerializableResult for Uuid {
|
||||||
|
type BytesType = [u8; 16];
|
||||||
|
|
||||||
|
fn from_bytes(bytes: Self::BytesType) -> Self {
|
||||||
|
Self(*uuid_from_u32_quartet(
|
||||||
|
u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
|
||||||
|
u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
|
||||||
|
u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]),
|
||||||
|
u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_bytes(&self) -> Self::BytesType {
|
||||||
|
let mut result: Self::BytesType = [0; 16];
|
||||||
|
let (a, b, c, d) = uuid_to_u32_quartet(&self);
|
||||||
|
result[0..4].clone_from_slice(&a.to_le_bytes());
|
||||||
|
result[4..8].clone_from_slice(&b.to_le_bytes());
|
||||||
|
result[8..12].clone_from_slice(&c.to_le_bytes());
|
||||||
|
result[12..16].clone_from_slice(&d.to_le_bytes());
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
// The generic trait doesn't know the size of the array. This is why the
|
||||||
|
// clone needs to be here even if it could be generic.
|
||||||
|
fn clone_to_slice(&self, slice: &mut [u8]) {
|
||||||
|
slice.clone_from_slice(&self.as_bytes());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue