1 ! Copyright (C) 2005, 2010 Slava Pestov, Doug Coleman
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien classes combinators destructors hints io
4 io.backend io.buffers io.encodings io.files io.timeouts kernel
5 kernel.private libc locals math math.order math.private
6 namespaces sequences strings system ;
9 SYMBOL: default-buffer-size
10 64 1024 * default-buffer-size set-global
12 TUPLE: port < disposable handle timeout ;
14 M: port timeout timeout>> ;
16 M: port set-timeout timeout<< ;
18 : <port> ( handle class -- port )
19 new-disposable swap >>handle ; inline
21 TUPLE: buffered-port < port { buffer buffer } ;
23 : <buffered-port> ( handle class -- port )
25 default-buffer-size get <buffer> >>buffer ; inline
27 TUPLE: input-port < buffered-port ;
28 INSTANCE: input-port input-stream
29 INSTANCE: input-port file-reader
31 : <input-port> ( handle -- input-port )
32 input-port <buffered-port> ; inline
34 HOOK: (wait-to-read) io-backend ( port -- )
36 : wait-to-read ( port -- eof? )
37 dup buffer>> buffer-empty? [
38 dup (wait-to-read) buffer>> buffer-empty?
39 ] [ drop f ] if ; inline
41 M: input-port stream-read1
43 dup wait-to-read [ drop f ] [ buffer>> buffer-pop ] if ; inline
47 : read-step ( count port -- count ptr/f )
49 { [ over 0 = ] [ 2drop 0 f ] }
50 { [ dup wait-to-read ] [ 2drop 0 f ] }
51 [ buffer>> buffer-read-unsafe ]
53 { fixnum c-ptr } declare ; inline
55 : prepare-read ( count port -- count' port )
56 [ integer>fixnum-strict 0 max ] dip check-disposed ; inline
58 :: read-loop ( dst n-remaining port n-read -- n-total )
59 n-remaining port read-step :> ( n-buffered ptr )
61 dst ptr n-buffered memcpy
62 n-remaining n-buffered fixnum-fast :> n-remaining'
63 n-read n-buffered fixnum+fast :> n-read'
64 n-buffered dst <displaced-alien> :> dst'
65 dst' n-remaining' port n-read' read-loop
66 ] [ n-read ] if ; inline recursive
70 M: input-port stream-read-partial-unsafe
71 [ c-ptr check-instance swap ] dip prepare-read read-step
72 [ swap [ memcpy ] keep ] [ 2drop 0 ] if* ;
74 M: input-port stream-read-unsafe
75 [ c-ptr check-instance swap ] dip prepare-read 0 read-loop ;
79 : read-until-step ( seps port -- byte-array/f sep/f )
80 dup wait-to-read [ 2drop f f ] [
81 buffer>> buffer-read-until
84 : read-until-loop ( seps port accum -- sep/f )
85 2over read-until-step over [
93 ] if ; inline recursive
97 M: input-port stream-read-until
98 2dup read-until-step dup [
103 BV{ } like [ read-until-loop ] keep B{ } like swap
109 TUPLE: output-port < buffered-port ;
110 INSTANCE: output-port output-stream
111 INSTANCE: output-port file-writer
113 : <output-port> ( handle -- output-port )
114 output-port <buffered-port> ;
116 HOOK: (wait-to-write) io-backend ( port -- )
120 : port-flush ( port -- )
121 dup buffer>> buffer-empty?
122 [ drop ] [ dup (wait-to-write) port-flush ] if ; inline recursive
126 M: output-port stream-flush
127 check-disposed port-flush ;
129 : wait-to-write ( len port -- )
130 [ nip ] [ buffer>> buffer-capacity <= ] 2bi
131 [ drop ] [ port-flush ] if ; inline
133 M: output-port stream-write1
136 buffer>> buffer-write1 ; inline
140 :: port-write ( c-ptr n-remaining port -- )
141 port buffer>> :> buffer
142 n-remaining buffer size>> min :> n-write
144 n-write port wait-to-write
145 c-ptr n-write buffer buffer-write
147 n-remaining n-write fixnum-fast dup 0 > [
148 n-write c-ptr <displaced-alien> swap port port-write
149 ] [ drop ] if ; inline recursive
153 M: output-port stream-write
156 [ c-ptr check-instance ] [ integer>fixnum-strict ] bi*
157 ] [ port-write ] bi* ;
159 HOOK: tell-handle os ( handle -- n )
161 HOOK: seek-handle os ( n seek-type handle -- )
163 HOOK: can-seek-handle? os ( handle -- ? )
165 HOOK: handle-length os ( handle -- n/f )
169 : port-tell ( port -- tell-handle buffer-length )
170 [ handle>> tell-handle ] [ buffer>> buffer-length ] bi ; inline
174 M: input-port stream-tell
175 check-disposed port-tell - ;
177 M: output-port stream-tell
178 check-disposed port-tell + ;
182 :: do-seek-relative ( n seek-type stream -- n seek-type stream )
183 ! seek-relative needs special handling here, because of the
185 seek-type seek-relative eq?
186 [ n stream stream-tell + seek-absolute ] [ n seek-type ] if
191 M: input-port stream-seek
194 [ buffer>> 0 swap buffer-reset ]
195 [ handle>> seek-handle ] bi ;
197 M: output-port stream-seek
201 [ handle>> seek-handle ] bi ;
203 M: buffered-port stream-seekable?
204 handle>> can-seek-handle? ;
206 M: buffered-port stream-length
207 handle>> handle-length [ f ] when-zero ;
209 GENERIC: shutdown ( handle -- )
211 M: object shutdown drop ;
213 M: output-port dispose*
216 [ handle>> &dispose drop ]
217 [ buffer>> &dispose drop ]
219 [ handle>> shutdown ]
223 M: buffered-port dispose*
225 [ buffer>> &dispose drop ]
226 [ call-next-method ] bi
229 M: port cancel-operation handle>> cancel-operation ;
232 [ handle>> &dispose shutdown ] with-destructors ;
234 GENERIC: underlying-port ( stream -- port )
236 M: port underlying-port ;
238 M: encoder underlying-port stream>> underlying-port ;
240 M: decoder underlying-port stream>> underlying-port ;
242 GENERIC: underlying-handle ( stream -- handle )
244 M: object underlying-handle underlying-port handle>> ;
246 ! Fast-path optimization
248 HINTS: (decode-until)
249 { string input-port object } ;