     [ n>> ] [ hashtable>> array>> ] bi
     [ nth-unsafe ] [ [ 1 + ] dip nth-unsafe ] 2bi ; inline
 
-INSTANCE: hashtable collection
+INSTANCE: hashtable-cursor input-cursor
+
+M: hashtable-cursor cursor-value
+    cursor-key-value 2array ; inline
+
+INSTANCE: hashtable container
 
 M: hashtable begin-cursor
     dup array>> 0 (inc-hashtable-cursor) <hashtable-cursor> ; inline

    { growable read-only } ;
C: <pusher-cursor> pusher-cursor

INSTANCE: pusher-cursor forward-cursor

! XXX define a protocol for stream cursors that don't actually move
M: pusher-cursor cursor-compatible? 2drop f ; inline
M: pusher-cursor cursor-valid? drop t ; inline
M: pusher-cursor cursor= 2drop f ; inline
M: pusher-cursor inc-cursor ; inline

INSTANCE: pusher-cursor output-cursor

M: pusher-cursor set-cursor-value growable>> push ; inline

M: output-cursor set-cursor-value-unsafe set-cursor-value ; inline
M: output-cursor set-cursor-value
    dup cursor-valid? [ set-cursor-value-unsafe ] [ invalid-cursor ] if ; inline

!
! stream cursors
!

MIXIN: stream-cursor
INSTANCE: stream-cursor forward-cursor

M: stream-cursor cursor-compatible? 2drop f ; inline
M: stream-cursor cursor-valid? drop t ; inline
M: stream-cursor cursor= 2drop f ; inline

MIXIN: infinite-stream-cursor
INSTANCE: infinite-stream-cursor stream-cursor

M: infinite-stream-cursor inc-cursor ; inline

MIXIN: finite-stream-cursor
INSTANCE: finite-stream-cursor stream-cursor

SINGLETON: end-of-stream

GENERIC: cursor-stream-ended? ( cursor -- ? )

M: finite-stream-cursor inc-cursor
    dup cursor-stream-ended? [ drop end-of-stream ] when ; inline

INSTANCE: end-of-stream finite-stream-cursor

M: end-of-stream cursor-compatible? drop finite-stream-cursor? ; inline
M: end-of-stream cursor-valid? drop f ; inline
M: end-of-stream cursor= eq? ; inline
M: end-of-stream inc-cursor ; inline
M: end-of-stream cursor-stream-ended? drop t ; inline

!
! basic iterator
