 
 ;; Reactive Sequence Projection Protocols
 
-(defprotocol IReactiveProjectionTarget
-  (-proj-insert-elem [this projected-elem before-idx])
-  (-proj-get-elem [this elem-idx])
-  (-proj-move-elem [this elem-idx before-idx])
-  (-proj-remove-elem [this elem-idx])
-  (-proj-clear [this]))
-
-(defprotocol IReactiveProjection
-  (-project-elements [this target enqueue-fn]))
-
-(defn project-elements [projection target enqueue-fn]
-  (-project-elements projection target enqueue-fn))
+(defprotocol IProjectionSource
+  (-source-pull [this idx]))
+
+(defn source-pull [this idx] (-source-pull this idx))
+
+(defprotocol IProjectionTarget
+  (-target-init [this source])
+  (-target-insert [this projected-elem before-idx])
+  (-target-peek [this elem-idx])
+  (-target-take [this elem-idx])
+  (-target-count [this])
+  (-target-move [this elem-idx before-idx])
+  (-target-remove [this elem-idx])
+  (-target-clear [this]))
+
+(defn target-init [this source] (-target-init this source))
+
+(defn target-insert [this elem before-idx] (-target-insert this elem before-idx))
+
+(defn target-peek [this idx] (-target-peek this idx))
+
+(defn target-take [this idx] (-target-take this idx))
+
+(defn target-count [this] (-target-count this))
+
+(defn target-move [this idx before-idx] (-target-move this idx before-idx))
+
+(defn target-remove [this idx] (-target-remove this idx))
+
+(defn target-clear [this] (-target-clear this))
+
+(defprotocol IProjection
+  (-project [this target enqueue-fn]))
+
+(defn project [projection target enqueue-fn]
+  (-project projection target enqueue-fn))
 
 ;; Reactive Sequence Projection Implementations
 
 #?(:cljs
    (do
-     (deftype KeysetCursorProjection [cur proj-fn opts
+     (deftype FilterCursor [parent ^:mutable filter-fn ^:mutable change-watches ^:mutable active]
+       Object
+       (setFilterFn [this new-filter-fn])
+       (onChanges [this updates]
+         (map
+          (fn [[k v :as update]]
+            (cond
+              (= (count update) 1)
+              update
+
+              (not (filter-fn v))
+              [k]
+
+              :default
+              update))
+          updates))
+
+       ICursor
+       (-cursor-key [this])
+       (-child-cursor [this key]
+         (child-cursor parent key))
+       (-parent-cursor [this] parent)
+       (-cursor-kvseq [this]
+         (map (fn [[k v]] (when (filter-fn v) [k v]))
+              (cursor-kvseq parent)))
+
+       IChangeNotifications
+       (-add-change-watch [this key f]
+         (set! change-watches (assoc changes-watches key f))
+         (when-not active
+           (set! active true)))
+       (-remove-change-watch [this key]
+         (set! change-watches (dissoc changes-watches key))
+         (when (empty? change-watches)
+           (set! active false))))
+
+     (defn cursor-filter [cursor filter])
+
+     (deftype LensingCursor [parent getter setter ^:mutable change-watches]
+       Object
+       (onUpdates [this updates]
+         (let [updates*
+               (for [[k v :as update] updates]
+                 (if (= (count update) 1)
+                   update
+                   [k (getter v)]))]
+           (doseq [[k f] change-watches]
+             (f k this updates*))))
+       ICursor
+       (-cursor-key [this])
+       (-child-cursor [this key]
+         (let [cur (lens-cursor (child-cursor parent key) getter settter)]
+           (set! (.-tkey cur) key)
+           cur))
+       (-parent-cursor [this] parent)
+       (-cursor-kvseq [this]
+         (map (fn [[k v]] [k (getter v)])
+              (cursor-kvseq parent)))
+
+       IChangeNotifications
+       (-add-change-watch [this key f]
+         (set! change-watches (assoc changes-watches key f)))
+       (-remove-change-watch [this key]
+         (set! change-watches (dissoc changes-watches key))))
+
+     (defn cursor-mapping [cursor getter setter])
+
+     (defn cursor-sort [cursor {:keys [by-value by-key direction] :as sort-opts}])
+     
+     (deftype KeysetCursorProjection [cur target-fn opts
                                       ^:mutable avl-set ^:mutable target
                                       ^:mutable enqueue-fn
                                       ^:mutable filter-fn

                           (fn [k r updates] (.onUpdates this updates)))
         (.project this)))

     (defn cmap*
       [f keyset-cursor opts]
       (KeysetCursorProjection. keyset-cursor f opts nil nil nil identity 0 nil nil nil nil))

  (-parent-cursor [this]
    (when tkey
      parent))
  (-cursor-kvseq [this]
    (when state
      (cond
        (map? state)
        (seq state)

        (counted? state)
        (zipmap (range (count state)) (seq state)))))

  IChangeNotifications
  (-add-change-watch [this key f]
