1 ! Copyright (C) 2005, 2008 Slava Pestov, Doug Coleman
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: math kernel io sequences io.buffers io.timeouts generic
4 byte-vectors system io.encodings math.order io.backend
5 continuations classes byte-arrays namespaces splitting
6 grouping dlists assocs io.encodings.binary summary accessors
7 destructors combinators ;
10 SYMBOL: default-buffer-size
11 64 1024 * default-buffer-size set-global
13 TUPLE: port < disposable handle timeout ;
15 M: port timeout timeout>> ;
17 M: port set-timeout (>>timeout) ;
19 : <port> ( handle class -- port )
20 new-disposable swap >>handle ; inline
22 TUPLE: buffered-port < port { buffer buffer } ;
24 : <buffered-port> ( handle class -- port )
26 default-buffer-size get <buffer> >>buffer ; inline
28 TUPLE: input-port < buffered-port ;
30 M: input-port stream-element-type drop +byte+ ;
32 : <input-port> ( handle -- input-port )
33 input-port <buffered-port> ;
35 HOOK: (wait-to-read) io-backend ( port -- )
37 : wait-to-read ( port -- eof? )
38 dup buffer>> buffer-empty? [
39 dup (wait-to-read) buffer>> buffer-empty?
40 ] [ drop f ] if ; inline
42 M: input-port stream-read1
44 dup wait-to-read [ drop f ] [ buffer>> buffer-pop ] if ; inline
46 : read-step ( count port -- byte-array/f )
47 dup wait-to-read [ 2drop f ] [ buffer>> buffer-read ] if ;
49 M: input-port stream-read-partial ( max stream -- byte-array/f )
51 [ 0 max >integer ] dip read-step ;
53 : read-loop ( count port accum -- )
54 pick over length - dup 0 > [
56 over push-all read-loop
64 M: input-port stream-read
76 : read-until-step ( separators port -- string/f separator/f )
77 dup wait-to-read [ 2drop f f ] [ buffer>> buffer-until ] if ;
79 : read-until-loop ( seps port buf -- separator/f )
80 2over read-until-step over [
81 [ over push-all ] dip dup [
90 M: input-port stream-read-until ( seps port -- str/f sep/f )
91 2dup read-until-step dup [ [ 2drop ] 2dip ] [
94 BV{ } like [ read-until-loop ] keep B{ } like swap
95 ] [ [ 2drop ] 2dip ] if
98 TUPLE: output-port < buffered-port ;
100 : <output-port> ( handle -- output-port )
101 output-port <buffered-port> ;
103 : wait-to-write ( len port -- )
104 [ nip ] [ buffer>> buffer-capacity <= ] 2bi
105 [ drop ] [ stream-flush ] if ; inline
107 M: output-port stream-element-type stream>> stream-element-type ;
109 M: output-port stream-write1
112 buffer>> byte>buffer ; inline
114 M: output-port stream-write
116 over length over buffer>> size>> > [
117 [ buffer>> size>> <groups> ]
118 [ [ stream-write ] curry ] bi
121 [ [ length ] dip wait-to-write ]
122 [ buffer>> >buffer ] 2bi
125 HOOK: (wait-to-write) io-backend ( port -- )
127 HOOK: seek-handle os ( n seek-type handle -- )
129 M: input-port stream-seek ( n seek-type stream -- )
131 [ buffer>> 0 swap buffer-reset ]
132 [ handle>> seek-handle ] tri ;
134 M: output-port stream-seek ( n seek-type stream -- )
137 [ handle>> seek-handle ] tri ;
139 GENERIC: shutdown ( handle -- )
141 M: object shutdown drop ;
143 : port-flush ( port -- )
144 dup buffer>> buffer-empty?
145 [ drop ] [ dup (wait-to-write) port-flush ] if ;
147 M: output-port stream-flush ( port -- )
148 [ check-disposed ] [ port-flush ] bi ;
150 M: output-port dispose*
153 [ handle>> &dispose drop ]
154 [ buffer>> &dispose drop ]
156 [ handle>> shutdown ]
160 M: buffered-port dispose*
161 [ call-next-method ] [ buffer>> dispose ] bi ;
163 M: port cancel-operation handle>> cancel-operation ;
167 [ handle>> &dispose drop ]
168 [ handle>> shutdown ]
172 GENERIC: underlying-port ( stream -- port )
174 M: port underlying-port ;
176 M: encoder underlying-port stream>> underlying-port ;
178 M: decoder underlying-port stream>> underlying-port ;
180 GENERIC: underlying-handle ( stream -- handle )
182 M: object underlying-handle underlying-port handle>> ;
184 ! Fast-path optimization
185 USING: hints strings io.encodings.utf8 io.encodings.ascii
186 io.encodings.private ;
188 HINTS: decoder-read-until { string input-port utf8 } { string input-port ascii } ;
190 HINTS: decoder-readln { input-port utf8 } { input-port ascii } ;
192 HINTS: encoder-write { object output-port utf8 } { object output-port ascii } ;