                                   "/topics" [:route9 user-id]
                                   "/bookmarks/followers" [:test/route10 user-id]
                                   "/devices" {"" [:route15 user-id]
-                                              "/bulk" [:test/route21 user-id]
+                                              #_#_"/bulk" [:test/route21 user-id]
                                               ["/" client-id] [:test/route35 user-id client-id]
                                               ["/" client-id "/reset-password"] [:test/route49 user-id client-id]}
                                   "/device-errors" [:test/route22 user-id]

              "topics" [:test/route50]}}))

(def opensensors-compojure-api-routes
  (let [handler (constantly {:status 200, :body ""})]
    (routes
      (context "/v1" []
        (context "/public" []
          (ANY "/topics/:topic" [] {:name :test/route4} handler)
          (ANY "/users/:user-id" [] {:name :test/route16} handler)
          (ANY "/orgs/:org-id" [] {:name :test/route18} handler))
        (context "/users/:user-id" []
          (ANY "/orgs/:org-id" [] {:name :test/route5} handler)
          (ANY "/invitations" [] {:name :test/route7} handler)
          (ANY "/topics" [] {:name :test/route9} handler)
          (ANY "/bookmarks/followers" [] {:name :test/route10} handler)
          (context "/devices" []
            (ANY "/" [] {:name :test/route15} handler)
            (ANY "/bulk" [] {:name :test/route21} handler)
            (ANY "/:client-id" [] {:name :test/route35} handler)
            (ANY "/:client-id/reset-password" [] {:name :test/route49} handler))
          (ANY "/device-errors" [] {:name :test/route22} handler)
          (ANY "/usage-stats" [] {:name :test/route24} handler)
          (ANY "/claim-device/:client-id" [] {:name :test/route26} handler)
          (ANY "/owned-orgs" [] {:name :test/route31} handler)
          (ANY "/bookmark/:topic" [] {:name :test/route33} handler)
          (ANY "/" [] {:name :test/route36} handler)
          (ANY "/orgs" [] {:name :test/route52} handler)
          (ANY "/api-key" [] {:name :test/route43} handler)
          (ANY "/bookmarks" [] {:name :test/route56} handler))
        (ANY "/search/topics/:term" [] {:name :test/route6} handler)
        (context "/orgs" []
          (ANY "/" [] {:name :test/route55} handler)
          (context "/:org-id" []
            (context "/devices" []
              (ANY "/" [] {:name :test/route37} handler)
              (ANY "/:device-id" [] {:name :test/route13} handler)
              (ANY "/:batch/:type" [] {:name :test/route8} handler))
            (ANY "/usage-stats" [] {:name :test/route12} handler)
            (ANY "/invitations" [] {:name :test/route19} handler)
            (context "/members" []
              (ANY "/:user-id" [] {:name :test/route34} handler)
              (ANY "/" [] {:name :test/route38} handler)
              (ANY "/invitation-data/:user-id" [] {:name :test/route39} handler))
            (ANY "/errors" [] {:name :test/route17} handler)
            (ANY "/" [] {:name :test/route42} handler)
            (ANY "/confirm-membership/:token" [] {:name :test/route46} handler)
            (ANY "/topics" [] {:name :test/route57} handler)))
        (context "/messages" []
          (ANY "/user/:user-id" [] {:name :test/route14} handler)
          (ANY "/device/:client-id" [] {:name :test/route30} handler)
          (ANY "/topic/:topic" [] {:name :test/route48} handler))
        (context "/topics" []
          (ANY "/:topic" [] {:name :test/route32} handler)
          (ANY "/" [] {:name :test/route54} handler))
        (ANY "/whoami" [] {:name :test/route41} handler)
        (ANY "/login" [] {:name :test/route51} handler))
      (context "/v2" []
        (ANY "/whoami" [] {:name :test/route1} handler)
        (context "/users/:user-id" []
          (ANY "/datasets" [] {:name :test/route2} handler)
          (ANY "/devices" [] {:name :test/route25} handler)
          (context "/topics" []
            (ANY "/bulk" [] {:name :test/route29} handler)
            (ANY "/" [] {:name :test/route54} handler))
          (ANY "/" [] {:name :test/route45} handler))
        (context "/public" []
          (context "/projects/:project-id" []
            (ANY "/datasets" [] {:name :test/route3} handler)
            (ANY "/" [] {:name :test/route27} handler))
          (ANY "/messages/dataset/bulk" [] {:name :test/route20} handler)
          (ANY "/datasets/:dataset-id" [] {:name :test/route28} handler)
          (ANY "/messages/dataset/:dataset-id" [] {:name :test/route53} handler))
        (ANY "/datasets/:dataset-id" [] {:name :test/route11} handler)
        (ANY "/login" [] {:name :test/route23} handler)
        (ANY "/orgs/:org-id/topics" [] {:name :test/route40} handler)
        (ANY "/schemas" [] {:name :test/route44} handler)
        (ANY "/topics/:topic" [] {:name :test/route47} handler)
        (ANY "/topics" [] {:name :test/route50} handler)))))

(comment
  (bench opensensors-routes false)
  (bench opensensors-routes true))

(comment
  (doseq [route (valid-urls (reitit/router opensensors-routes))]
    (let [match (bidi/match-route opensensors-bidi-routes route)]
      (if-not match
        (println route)))))

(comment
  (let [ataraxy-routes (ataraxy/compile opensensors-ataraxy-routes)]
    (doseq [route (valid-urls (reitit/router opensensors-routes))]
      (let [match (ataraxy/matches ataraxy-routes {:uri route})]
        (if-not match
          (println route))))))

(comment
  (doseq [route (valid-urls (reitit/router opensensors-routes))]
    (let [match (opensensors-compojure-api-routes {:uri route :request-method :get})]
      (if-not match
        (println route)))))

(defn bench! [routes name f]
  (System/gc)
  (println)
  (title name)
  (println)
  (doseq [[path time] (bench-routes routes f)]
    (println (format "%7s" time) "\t" path)))

(defn bench-all! []
  (let [routes opensensors-routes
        router (reitit/router routes)
        reitit-f #(reitit/match-by-path router %)
        bidi-f #(bidi/match-route opensensors-bidi-routes %)
        ataraxy-f #(ataraxy/matches opensensors-ataraxy-routes {:uri %})
        compojure-api-f #(opensensors-compojure-api-routes {:uri % :request-method :get})]
    (bench! routes "reitit" reitit-f)                       ;;  2958ns    11%
    (bench! routes "bidi" bidi-f)                           ;; 18919ns    71%
    (bench! routes "ataraxy" ataraxy-f)                     ;; 26461ns   100%
    (bench! routes "compojure-api" compojure-api-f)))       ;; 10463ns    40%

(comment
  (bench-all!))

;; Perf tests
;;

(def handler (constantly {:status 200, :body ""}))

(def opensensors-routes
  [["/v2/whoami" {:handler handler, :name :test/route1}]
   ["/v2/users/:user-id/datasets" {:handler handler, :name :test/route2}]
   ["/v2/public/projects/:project-id/datasets" {:handler handler, :name :test/route3}]
   ["/v1/public/topics/:topic" {:handler handler, :name :test/route4}]
   ["/v1/users/:user-id/orgs/:org-id" {:handler handler, :name :test/route5}]
   ["/v1/search/topics/:term" {:handler handler, :name :test/route6}]
   ["/v1/users/:user-id/invitations" {:handler handler, :name :test/route7}]
   #_["/v1/orgs/:org-id/devices/:batch/:type" {:handler handler, :name :test/route8}]
   ["/v1/users/:user-id/topics" {:handler handler, :name :test/route9}]
   ["/v1/users/:user-id/bookmarks/followers" {:handler handler, :name :test/route10}]
   ["/v2/datasets/:dataset-id" {:handler handler, :name :test/route11}]
   ["/v1/orgs/:org-id/usage-stats" {:handler handler, :name :test/route12}]
   ["/v1/orgs/:org-id/devices/:client-id" {:handler handler, :name :test/route13}]
   ["/v1/messages/user/:user-id" {:handler handler, :name :test/route14}]
   ["/v1/users/:user-id/devices" {:handler handler, :name :test/route15}]
   ["/v1/public/users/:user-id" {:handler handler, :name :test/route16}]
   ["/v1/orgs/:org-id/errors" {:handler handler, :name :test/route17}]
   ["/v1/public/orgs/:org-id" {:handler handler, :name :test/route18}]
   ["/v1/orgs/:org-id/invitations" {:handler handler, :name :test/route19}]
   ["/v2/public/messages/dataset/bulk" {:handler handler, :name :test/route20}]
   #_["/v1/users/:user-id/devices/bulk" {:handler handler, :name :test/route21}]
   ["/v1/users/:user-id/device-errors" {:handler handler, :name :test/route22}]
   ["/v2/login" {:handler handler, :name :test/route23}]
   ["/v1/users/:user-id/usage-stats" {:handler handler, :name :test/route24}]
   ["/v2/users/:user-id/devices" {:handler handler, :name :test/route25}]
   ["/v1/users/:user-id/claim-device/:client-id" {:handler handler, :name :test/route26}]
   ["/v2/public/projects/:project-id" {:handler handler, :name :test/route27}]
   ["/v2/public/datasets/:dataset-id" {:handler handler, :name :test/route28}]
   ["/v2/users/:user-id/topics/bulk" {:handler handler, :name :test/route29}]
   ["/v1/messages/device/:client-id" {:handler handler, :name :test/route30}]
   ["/v1/users/:user-id/owned-orgs" {:handler handler, :name :test/route31}]
   ["/v1/topics/:topic" {:handler handler, :name :test/route32}]
   ["/v1/users/:user-id/bookmark/:topic" {:handler handler, :name :test/route33}]
   ["/v1/orgs/:org-id/members/:user-id" {:handler handler, :name :test/route34}]
   ["/v1/users/:user-id/devices/:client-id" {:handler handler, :name :test/route35}]
   ["/v1/users/:user-id" {:handler handler, :name :test/route36}]
   ["/v1/orgs/:org-id/devices" {:handler handler, :name :test/route37}]
   ["/v1/orgs/:org-id/members" {:handler handler, :name :test/route38}]
   #_["/v1/orgs/:org-id/members/invitation-data/:user-id" {:handler handler, :name :test/route39}]
   ["/v2/orgs/:org-id/topics" {:handler handler, :name :test/route40}]
   ["/v1/whoami" {:handler handler, :name :test/route41}]
   ["/v1/orgs/:org-id" {:handler handler, :name :test/route42}]
   ["/v1/users/:user-id/api-key" {:handler handler, :name :test/route43}]
   ["/v2/schemas" {:handler handler, :name :test/route44}]
   ["/v2/users/:user-id/topics" {:handler handler, :name :test/route45}]
   ["/v1/orgs/:org-id/confirm-membership/:token" {:handler handler, :name :test/route46}]
   ["/v2/topics/:topic" {:handler handler, :name :test/route47}]
   ["/v1/messages/topic/:topic" {:handler handler, :name :test/route48}]
   ["/v1/users/:user-id/devices/:client-id/reset-password" {:handler handler, :name :test/route49}]
   ["/v2/topics" {:handler handler, :name :test/route50}]
   ["/v1/login" {:handler handler, :name :test/route51}]
   ["/v1/users/:user-id/orgs" {:handler handler, :name :test/route52}]
   ["/v2/public/messages/dataset/:dataset-id" {:handler handler, :name :test/route53}]
   ["/v1/topics" {:handler handler, :name :test/route54}]
   ["/v1/orgs" {:handler handler, :name :test/route55}]
   ["/v1/users/:user-id/bookmarks" {:handler handler, :name :test/route56}]
   ["/v1/orgs/:org-id/topics" {:handler handler, :name :test/route57}]])

(def opensensors-bidi-routes
  ["/" {"v1/" {"public/" {["topics/" :topic] :test/route4
