 strings generic splitting continuations destructors
 io.streams.plain io.encodings math.order growable ;
 IN: io.streams.string
+
+<PRIVATE
+
+: harden-as ( seq growble-exemplar -- newseq )
+    underlying>> like ;
+
+: growable-read-until ( growable n -- str )
+    >fixnum dupd tail-slice swap harden-as dup reverse-here ;
+
+SINGLETON: null-encoding
+
+M: null-encoding decode-char drop stream-read1 ;
+
+: format-column ( seq ? -- seq )
+    [
+        [ 0 [ length max ] reduce ] keep
+        swap [ CHAR: \s pad-right ] curry map
+    ] unless ;
+
+: map-last ( seq quot -- seq )
+    >r dup length <reversed> [ zero? ] r> compose 2map ; inline
+
+: format-table ( table -- seq )
+    flip [ format-column ] map-last
+    flip [ " " join ] map ;
+
+PRIVATE>
 
 M: growable dispose drop ;
 

M: growable stream-read-partial
    stream-read ;

SINGLETON: null
M: null decode-char drop stream-read1 ;

: <string-reader> ( str -- stream )
    >sbuf dup reverse-here null <decoder> ;

: with-string-reader ( str quot -- )
    >r <string-reader> r> with-input-stream ; inline

INSTANCE: growable plain-writer

: format-column ( seq ? -- seq )
    [
        [ 0 [ length max ] reduce ] keep
        swap [ CHAR: \s pad-right ] curry map
    ] unless ;

: map-last ( seq quot -- seq )
    >r dup length <reversed> [ zero? ] r> compose 2map ; inline

: format-table ( table -- seq )
    flip [ format-column ] map-last
    flip [ " " join ] map ;

M: plain-writer stream-write-table
    [ drop format-table [ print ] each ] with-output-stream* ;


    >string ; inline

M: growable stream-read1 [ f ] [ pop ] if-empty ;

: find-last-sep ( seq seps -- n )
    swap [ memq? ] curry find-last drop ;
