factor/basis/io/ports/ports.factor

244 lines
6.8 KiB
Factor
Raw Normal View History

! Copyright (C) 2005, 2010 Slava Pestov, Doug Coleman
2007-09-20 18:09:08 -04:00
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien alien.c-types alien.data assocs
byte-arrays byte-vectors classes combinators continuations
destructors dlists fry generic grouping hints io io.backend
io.buffers io.encodings io.encodings.ascii io.encodings.binary
io.encodings.private io.encodings.utf8 io.timeouts kernel libc
locals math math.order namespaces sequences specialized-arrays
specialized-arrays.instances.alien.c-types.uchar splitting
strings summary system io.files kernel.private ;
2008-05-13 19:24:46 -04:00
IN: io.ports
2007-09-20 18:09:08 -04:00
2007-11-07 14:01:45 -05:00
SYMBOL: default-buffer-size
64 1024 * default-buffer-size set-global
2007-09-20 18:09:08 -04:00
TUPLE: port < disposable handle timeout ;
2008-02-21 20:12:55 -05:00
2008-04-11 17:08:40 -04:00
M: port timeout timeout>> ;
2008-02-09 22:34:42 -05:00
M: port set-timeout timeout<< ;
2007-09-20 18:09:08 -04:00
2008-04-11 17:08:40 -04:00
: <port> ( handle class -- port )
new-disposable swap >>handle ; inline
2007-09-20 18:09:08 -04:00
2008-07-12 02:08:30 -04:00
TUPLE: buffered-port < port { buffer buffer } ;
2008-05-13 19:24:46 -04:00
: <buffered-port> ( handle class -- port )
<port>
default-buffer-size get <buffer> >>buffer ; inline
2008-05-18 20:02:50 -04:00
TUPLE: input-port < buffered-port ;
INSTANCE: input-port input-stream
INSTANCE: input-port file-reader
2009-03-15 18:11:18 -04:00
2008-05-13 19:24:46 -04:00
: <input-port> ( handle -- input-port )
input-port <buffered-port> ; inline
2007-09-20 18:09:08 -04:00
2008-05-13 19:24:46 -04:00
HOOK: (wait-to-read) io-backend ( port -- )
2007-09-20 18:09:08 -04:00
2008-05-18 20:02:50 -04:00
: wait-to-read ( port -- eof? )
dup buffer>> buffer-empty? [
dup (wait-to-read) buffer>> buffer-empty?
2008-07-12 02:08:30 -04:00
] [ drop f ] if ; inline
2007-09-20 18:09:08 -04:00
M: input-port stream-read1
2008-05-15 00:23:12 -04:00
dup check-disposed
dup wait-to-read [ drop f ] [ buffer>> buffer-pop ] if ; inline
2007-09-20 18:09:08 -04:00
! TYPED: read-step ( count: fixnum port: input-port -- count: fixnum ptr/f: c-ptr )
: (read-step) ( count: fixnum port: input-port -- count: fixnum ptr/f: c-ptr )
{
{ [ over 0 = ] [ 2drop 0 f ] }
{ [ dup wait-to-read ] [ 2drop 0 f ] }
[ buffer>> buffer-read-unsafe ]
} cond ;
: read-step ( count port -- count ptr/f )
(read-step) { fixnum c-ptr } declare ; inline
: prepare-read ( count stream -- count stream )
dup check-disposed [ 0 max >fixnum ] dip ; inline
2007-09-20 18:09:08 -04:00
M: input-port stream-read-partial-unsafe ( n dst port -- count )
[ swap ] dip prepare-read read-step
[ swap [ memcpy ] keep ] [ 2drop 0 ] if* ;
:: read-loop ( n-remaining n-read port dst -- n-total )
n-remaining 0 > [
n-remaining port read-step :> ( n-buffered ptr )
ptr [
dst ptr n-buffered memcpy
n-remaining n-buffered - :> n-remaining'
n-read n-buffered + :> n-read'
n-buffered dst <displaced-alien> :> dst'
n-remaining' n-read' port dst' read-loop
] [ n-read ] if
] [ n-read ] if ; inline recursive
M:: input-port stream-read-unsafe ( n dst port -- count )
n port prepare-read :> ( n' port' )
n' port' read-step :> ( n-buffered ptr )
ptr [
dst ptr n-buffered memcpy
n-buffered n' < [
n-buffered dst <displaced-alien> :> dst'
n' n-buffered - n-buffered port dst' read-loop
2007-09-20 18:09:08 -04:00
] [
n-buffered
2007-09-20 18:09:08 -04:00
] if
] [ 0 ] if ;
2007-09-20 18:09:08 -04:00
: read-until-step ( separators port -- string/f separator/f )
dup wait-to-read [ 2drop f f ] [ buffer>> buffer-until ] if ;
: read-until-loop ( seps port buf -- separator/f )
2over read-until-step over [
[ append! ] dip dup [
[ 3drop ] dip
] [
drop read-until-loop
] if
] [
[ 2drop 2drop ] dip
] if ;
M: input-port stream-read-until ( seps port -- str/f sep/f )
2dup read-until-step dup [ [ 2drop ] 2dip ] [
over [
drop
BV{ } like [ read-until-loop ] keep B{ } like swap
] [ [ 2drop ] 2dip ] if
] if ;
2008-05-13 19:24:46 -04:00
TUPLE: output-port < buffered-port ;
INSTANCE: output-port output-stream
INSTANCE: output-port file-writer
2008-05-13 19:24:46 -04:00
: <output-port> ( handle -- output-port )
output-port <buffered-port> ;
2007-09-20 18:09:08 -04:00
: wait-to-write ( len port -- )
2009-01-23 19:20:47 -05:00
[ nip ] [ buffer>> buffer-capacity <= ] 2bi
[ drop ] [ stream-flush ] if ; inline
2007-09-20 18:09:08 -04:00
M: output-port stream-write1
2008-05-15 00:23:12 -04:00
dup check-disposed
1 over wait-to-write
buffer>> byte>buffer ; inline
2007-09-20 18:09:08 -04:00
: write-in-groups ( byte-array port -- )
[ binary-object uchar <c-direct-array> ] dip
[ buffer>> size>> <sliced-groups> ] [ '[ _ stream-write ] ] bi
each ;
2007-09-20 18:09:08 -04:00
M: output-port stream-write
2008-05-15 00:23:12 -04:00
dup check-disposed
2dup [ byte-length ] [ buffer>> size>> ] bi* > [
write-in-groups
2007-11-09 03:01:45 -05:00
] [
[ [ byte-length ] dip wait-to-write ]
[ buffer>> >buffer ] 2bi
2007-11-09 03:01:45 -05:00
] if ;
2007-09-20 18:09:08 -04:00
2008-05-13 19:24:46 -04:00
HOOK: (wait-to-write) io-backend ( port -- )
: port-flush ( port -- )
dup buffer>> buffer-empty?
[ drop ] [ dup (wait-to-write) port-flush ] if ;
M: output-port stream-flush
[ check-disposed ] [ port-flush ] bi ;
HOOK: tell-handle os ( handle -- n )
HOOK: seek-handle os ( n seek-type handle -- )
HOOK: can-seek-handle? os ( handle -- ? )
HOOK: handle-length os ( handle -- n/f )
M: input-port stream-tell
[ check-disposed ]
[ [ handle>> tell-handle ] [ buffer>> buffer-length ] bi - ] bi ;
M: output-port stream-tell
[ check-disposed ]
[ [ handle>> tell-handle ] [ buffer>> buffer-length ] bi + ] bi ;
:: do-seek-relative ( n seek-type stream -- n seek-type stream )
! seek-relative needs special handling here, because of the
! buffer.
seek-type seek-relative eq?
[ n stream stream-tell + seek-absolute ] [ n seek-type ] if
stream ;
M: input-port stream-seek
do-seek-relative
[ check-disposed ]
[ buffer>> 0 swap buffer-reset ]
[ handle>> seek-handle ] tri ;
M: output-port stream-seek
do-seek-relative
[ check-disposed ]
[ stream-flush ]
[ handle>> seek-handle ] tri ;
M: buffered-port stream-seekable?
handle>> can-seek-handle? ;
M: buffered-port stream-length
handle>> handle-length ;
GENERIC: shutdown ( handle -- )
M: object shutdown drop ;
2007-11-07 14:01:45 -05:00
2008-05-18 18:18:28 -04:00
M: output-port dispose*
[
2008-08-15 17:13:13 -04:00
{
[ handle>> &dispose drop ]
2008-08-15 19:57:00 -04:00
[ buffer>> &dispose drop ]
2008-08-15 17:13:13 -04:00
[ port-flush ]
[ handle>> shutdown ]
} cleave
] with-destructors ;
2008-04-11 17:08:40 -04:00
2008-05-15 00:23:12 -04:00
M: buffered-port dispose*
2008-07-12 02:08:30 -04:00
[ call-next-method ] [ buffer>> dispose ] bi ;
2007-09-20 18:09:08 -04:00
M: port cancel-operation handle>> cancel-operation ;
2007-09-20 18:09:08 -04:00
M: port dispose*
[
[ handle>> &dispose drop ]
2008-05-21 16:54:27 -04:00
[ handle>> shutdown ]
bi
] with-destructors ;
2008-07-12 02:08:30 -04:00
GENERIC: underlying-port ( stream -- port )
M: port underlying-port ;
M: encoder underlying-port stream>> underlying-port ;
M: decoder underlying-port stream>> underlying-port ;
GENERIC: underlying-handle ( stream -- handle )
M: object underlying-handle underlying-port handle>> ;
2008-07-12 02:08:30 -04:00
! Fast-path optimization
HINTS: decoder-read-until { string input-port utf8 } { string input-port ascii } ;
HINTS: decoder-readln { input-port utf8 } { input-port ascii } ;
HINTS: M\ input-port stream-read-partial-unsafe
{ fixnum byte-array input-port }
{ fixnum string input-port } ;
HINTS: M\ input-port stream-read-unsafe
{ fixnum byte-array input-port }
{ fixnum string input-port } ;