         (apply = resolved-nodes)
         true))))
 
-(defn matches-requirement [requirement s]
-  (s/validate
-    {(s/optional-key :session-id) s/Str
-     (s/optional-key :session) SessionInRedis
-     (s/optional-key :node) NodeInRedis}
-    s)
+(s/defn matches-requirement :- s/Bool
+  [requirement :- Requirement
+   s :- {(s/optional-key :session-id) s/Str
+         (s/optional-key :session) SessionInRedis
+         (s/optional-key :node) NodeInRedis}]
   (let [arg (second requirement)]
     (match (first requirement)
       :session-tag  (some #{arg} (get-in s [:session :tags]))

   (s/optional-key :create) CreateArg     ; how to create, if creating
   (s/optional-key :modify) [ModifyArg]}) ; modifications to perform always

(defn get-or-create-session [arg]
  (let [arg (s/validate OldGetOrCreateArg (merge get-or-create-defaults arg))]
    (with-car*
      (car/return

   :action   (s/either :add :remove)
   :tag      s/Str})

(defmacro literal-pred
  "Yields a predicate schema that only matches one value. Takes an optional
  name."
  [kw & rest]
  (let [pred-name (first (split-at 1 rest))]
    `(s/pred #(= ~kw %) ~@pred-name)))

(defmacro keyword-schema-pair
  "Yields a predicate that matches keyword / schema pairs like
  [:my-keyword \"My Value\"].
  "
  [kw schema]
  `(s/pair (literal-pred ~kw) "keyword" ~schema ~kw))

(defmacro any-pair
  [& pairs]
  (s/validate (s/pred even? 'even?) (count pairs))
  (let [pairs (vec (map vec (partition 2 pairs)))]
    `(let [pred-pairs# (map #(keyword-schema-pair (first %) (second %))
                            ~pairs)]
       (apply s/either pred-pairs#))))

(def Requirement
  "A schema for a session requirement."
  (any-pair
    :session-tag   s/Str
    :node-tag      s/Str
    :reserved      s/Str
    :session-id    s/Str
    :node-id       s/Str
    :browser-name  s/Str
    :current-url   s/Str
    :not           (s/recursive #'Requirement)
    :and           (s/recursive #'Requirement)
    :or            (s/recursive #'Requirement)))

(defn maybe-bigdec [x]
  (try (bigdec x) (catch NumberFormatException e nil)))
