diff --git a/modules/reitit-core/src/reitit/trie.cljc b/modules/reitit-core/src/reitit/trie.cljc index 4cc415b3..f1f1f376 100644 --- a/modules/reitit-core/src/reitit/trie.cljc +++ b/modules/reitit-core/src/reitit/trie.cljc @@ -1,8 +1,8 @@ (ns reitit.trie - (:refer-clojure :exclude [compile]) + (:refer-clojure :exclude [compile -assoc!]) (:require [clojure.string :as str]) - (:import [reitit Trie Trie$Match Trie$Matcher] - (java.net URLDecoder))) + #?(:clj (:import [reitit Trie Trie$Match Trie$Matcher] + (java.net URLDecoder)))) (defrecord Wild [value]) (defrecord CatchAll [value]) @@ -13,7 +13,7 @@ (defn catch-all? [x] (instance? CatchAll x)) (defprotocol Matcher - (match [this i max ^chars path]) + (match [this i max path]) (view [this]) (depth [this])) @@ -116,27 +116,27 @@ (update :children dissoc "")) node'))) -(set! *warn-on-reflection* true) - (defn decode! - ([chars start end] - (let [s (String. ^chars chars ^int start ^int (- end start))] - (if (str/index-of s \%) - (URLDecoder/decode - (if (str/index-of s \+) (.replace ^String s "+" "%2B") s) - "UTF-8") - s))) - ([chars start end percent? plus?] - (let [s (String. ^chars chars ^int start ^int (- end start))] - (if percent? - (URLDecoder/decode - (if plus? (.replace ^String s "+" "%2B") s) - "UTF-8") - s)))) + ([path start end] + #?(:clj (let [s (subs path start end)] + (if (str/index-of s \%) + (URLDecoder/decode + (if (str/index-of s \+) (.replace ^String s "+" "%2B") s) + "UTF-8") + s)) + :cljs (js/decodeURIComponent (subs path start end)))) + ([path start end percent? plus?] + #?(:clj (let [s (String. ^chars path ^int start ^int (- end start))] + (if percent? + (URLDecoder/decode + (if plus? (.replace ^String s "+" "%2B") s) + "UTF-8") + s)) + :cljs (js/decodeURIComponent (subs path start end))))) (defn data-matcher [data] - #?(:cljx (Trie/dataMatcher data) - :clj (let [match (->Match data nil)] + #?(:clj (Trie/dataMatcher data) + :cljs (let [match (->Match data nil)] (reify Matcher (match [_ i max _] (if (= i max) @@ -144,31 +144,30 @@ (view [_] data) (depth [_] 1))))) -(defn static-matcher [^String path matcher] - #?(:cljx (Trie/staticMatcher path matcher) - :clj (let [^chars chars (.toCharArray path) - size (alength chars)] +(defn static-matcher [path matcher] + #?(:clj (Trie/staticMatcher ^String path ^Trie$Matcher matcher) + :cljs (let [size (count path)] (reify Matcher - (match [_ i max path] - (if-not (< max (+ ^int i size)) + (match [_ i max p] + (if-not (< max (+ i size)) (loop [j 0] (if (= j size) - (match matcher (+ ^int i size) max path) - (if (= ^char (aget ^chars path (+ ^int i j)) ^char (aget ^chars chars j)) + (match matcher (+ i size) max p) + (if (= (get p (+ i j)) (get path j)) (recur (inc j))))))) (view [_] [path (view matcher)]) (depth [_] (inc (depth matcher))))))) (defn wild-matcher [key matcher] - #?(:cljx (Trie/wildMatcher key matcher) - :clj (reify Matcher + #?(:clj (Trie/wildMatcher key matcher) + :cljs (reify Matcher (match [_ i max path] - (if (and (< ^int i ^int max) (not= ^char (aget ^chars path i) \/)) - (loop [percent? false, plus? false, ^int j ^int i] - (if (= ^int max j) + (if (and (< i max) (not= (get path i) \/)) + (loop [percent? false, plus? false, j i] + (if (= max j) (if-let [match (match matcher max max path)] (-assoc! match key (decode! path i max percent? plus?))) - (let [c ^char (aget ^chars path j)] + (let [c ^char (get path j)] (case c \/ (if-let [match (match matcher j max path)] (-assoc! match key (decode! path i j percent? plus?))) @@ -179,24 +178,24 @@ (depth [_] (inc (depth matcher)))))) (defn catch-all-matcher [key data] - #?(:cljx (Trie/catchAllMatcher key data) - :clj (let [match (->Match data nil)] + #?(:clj (Trie/catchAllMatcher key data) + :cljs (let [match (->Match data nil)] (reify Matcher (match [_ i max path] - (if (< ^int i max) + (if (< i max) (-assoc! match key (decode! path i max)))) (view [_] [key [data]]) (depth [_] 1))))) (defn linear-matcher [matchers] - #?(:cljx (Trie/linearMatcher matchers) - :clj (let [matchers (.toArray ^java.util.List (reverse (sort-by depth matchers))) - size (alength matchers)] + #?(:clj (Trie/linearMatcher matchers) + :cljs (let [matchers (vec (reverse (sort-by depth matchers))) + size (count matchers)] (reify Matcher (match [_ i max path] (loop [j 0] (if (< j size) - (or (match (aget matchers j) i max path) + (or (match (get matchers j) i max path) (recur (inc j)))))) (view [_] (mapv view matchers)) (depth [_] (apply max (map depth matchers))))))) @@ -227,85 +226,88 @@ (first matchers)))) (defn pretty [matcher] - #?(:cljx (-> matcher str read-string eval) - :clj (view matcher))) + #?(:clj (-> matcher str read-string eval) + :cljs (view matcher))) -(defn lookup [matcher ^String path] - #?(:cljx (if-let [match ^Trie$Match (Trie/lookup ^Trie$Matcher matcher ^String path)] +(defn lookup [matcher path] + #?(:clj (if-let [match ^Trie$Match (Trie/lookup ^Trie$Matcher matcher ^String path)] (->Match (.data match) (.parameters match))) - :clj (let [chars (.toCharArray path)] - (if-let [match (match matcher 0 (alength chars) chars)] - (let [params (if-let [path-params (:path-params match)] - (persistent! path-params) - {})] - (assoc match :path-params params)))))) + :cljs (if-let [match (match matcher 0 (count path) path)] + (let [params (if-let [path-params (:path-params match)] + (persistent! path-params) + {})] + (assoc match :path-params params))))) ;; ;; spike ;; -(-> - [["/v2/whoami" 1] - ["/v2/users/:user-id/datasets" 2] - ["/v2/public/projects/:project-id/datasets" 3] - ["/v1/public/topics/:topic" 4] - ["/v1/users/:user-id/orgs/:org-id" 5] - ["/v1/search/topics/:term" 6] - ["/v1/users/:user-id/invitations" 7] - ["/v1/users/:user-id/topics" 9] - ["/v1/users/:user-id/bookmarks/followers" 10] - ["/v2/datasets/:dataset-id" 11] - ["/v1/orgs/:org-id/usage-stats" 12] - ["/v1/orgs/:org-id/devices/:client-id" 13] - ["/v1/messages/user/:user-id" 14] - ["/v1/users/:user-id/devices" 15] - ["/v1/public/users/:user-id" 16] - ["/v1/orgs/:org-id/errors" 17] - ["/v1/public/orgs/:org-id" 18] - ["/v1/orgs/:org-id/invitations" 19] - ["/v1/users/:user-id/device-errors" 22] - ["/v2/login" 23] - ["/v1/users/:user-id/usage-stats" 24] - ["/v2/users/:user-id/devices" 25] - ["/v1/users/:user-id/claim-device/:client-id" 26] - ["/v2/public/projects/:project-id" 27] - ["/v2/public/datasets/:dataset-id" 28] - ["/v2/users/:user-id/topics/bulk" 29] - ["/v1/messages/device/:client-id" 30] - ["/v1/users/:user-id/owned-orgs" 31] - ["/v1/topics/:topic" 32] - ["/v1/users/:user-id/bookmark/:topic" 33] - ["/v1/orgs/:org-id/members/:user-id" 34] - ["/v1/users/:user-id/devices/:client-id" 35] - ["/v1/users/:user-id" 36] - ["/v1/orgs/:org-id/devices" 37] - ["/v1/orgs/:org-id/members" 38] - ["/v2/orgs/:org-id/topics" 40] - ["/v1/whoami" 41] - ["/v1/orgs/:org-id" 42] - ["/v1/users/:user-id/api-key" 43] - ["/v2/schemas" 44] - ["/v2/users/:user-id/topics" 45] - ["/v1/orgs/:org-id/confirm-membership/:token" 46] - ["/v2/topics/:topic" 47] - ["/v1/messages/topic/:topic" 48] - ["/v1/users/:user-id/devices/:client-id/reset-password" 49] - ["/v2/topics" 50] - ["/v1/login" 51] - ["/v1/users/:user-id/orgs" 52] - ["/v2/public/messages/dataset/:dataset-id" 53] - ["/v1/topics" 54] - ["/v1/orgs" 55] - ["/v1/users/:user-id/bookmarks" 56] - ["/v1/orgs/:org-id/topics" 57]] - (insert) - (compile) - (pretty)) - -(-> [["/kikka" 2] - ["/kikka/kakka/kukka" 3] - ["/kikka/:kakka/kurkku" 4] - ["/kikka/kuri/{user/doc}/html" 5]] +(comment + (-> + [["/v2/whoami" 1] + ["/v2/users/:user-id/datasets" 2] + ["/v2/public/projects/:project-id/datasets" 3] + ["/v1/public/topics/:topic" 4] + ["/v1/users/:user-id/orgs/:org-id" 5] + ["/v1/search/topics/:term" 6] + ["/v1/users/:user-id/invitations" 7] + ["/v1/users/:user-id/topics" 9] + ["/v1/users/:user-id/bookmarks/followers" 10] + ["/v2/datasets/:dataset-id" 11] + ["/v1/orgs/:org-id/usage-stats" 12] + ["/v1/orgs/:org-id/devices/:client-id" 13] + ["/v1/messages/user/:user-id" 14] + ["/v1/users/:user-id/devices" 15] + ["/v1/public/users/:user-id" 16] + ["/v1/orgs/:org-id/errors" 17] + ["/v1/public/orgs/:org-id" 18] + ["/v1/orgs/:org-id/invitations" 19] + ["/v1/users/:user-id/device-errors" 22] + ["/v2/login" 23] + ["/v1/users/:user-id/usage-stats" 24] + ["/v2/users/:user-id/devices" 25] + ["/v1/users/:user-id/claim-device/:client-id" 26] + ["/v2/public/projects/:project-id" 27] + ["/v2/public/datasets/:dataset-id" 28] + ["/v2/users/:user-id/topics/bulk" 29] + ["/v1/messages/device/:client-id" 30] + ["/v1/users/:user-id/owned-orgs" 31] + ["/v1/topics/:topic" 32] + ["/v1/users/:user-id/bookmark/:topic" 33] + ["/v1/orgs/:org-id/members/:user-id" 34] + ["/v1/users/:user-id/devices/:client-id" 35] + ["/v1/users/:user-id" 36] + ["/v1/orgs/:org-id/devices" 37] + ["/v1/orgs/:org-id/members" 38] + ["/v2/orgs/:org-id/topics" 40] + ["/v1/whoami" 41] + ["/v1/orgs/:org-id" 42] + ["/v1/users/:user-id/api-key" 43] + ["/v2/schemas" 44] + ["/v2/users/:user-id/topics" 45] + ["/v1/orgs/:org-id/confirm-membership/:token" 46] + ["/v2/topics/:topic" 47] + ["/v1/messages/topic/:topic" 48] + ["/v1/users/:user-id/devices/:client-id/reset-password" 49] + ["/v2/topics" 50] + ["/v1/login" 51] + ["/v1/users/:user-id/orgs" 52] + ["/v2/public/messages/dataset/:dataset-id" 53] + ["/v1/topics" 54] + ["/v1/orgs" 55] + ["/v1/users/:user-id/bookmarks" 56] + ["/v1/orgs/:org-id/topics" 57]] (insert) (compile) (pretty)) + + (-> [["/kikka" 2] + ["/kikka/kakka/kukka" 3] + ["/kikka/:kakka/kurkku" 4] + ["/kikka/kuri/{user/doc}/html" 5]] + (insert) + (compile) + (pretty)) + + (map str (.toCharArray "\u2215\u0048\u0065\u006C\u006C\u006F")) + (count ["∕" "H" "e" "l" "l" "o" " " "W" "o" "r" "l" "d"]))