diff options
author | bptato <nincsnevem662@gmail.com> | 2024-03-12 14:09:53 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-03-12 14:09:53 +0100 |
commit | 0cc8f357d8f44fcfccd141c078d34ed4530fec5b (patch) | |
tree | d07478d4895e9ae008d4d0cba704db3f6bd4ecbf /src/io | |
parent | 2ac31dd859c84697d108c88dd1b22b5ffa5beb95 (diff) | |
download | chawan-0cc8f357d8f44fcfccd141c078d34ed4530fec5b.tar.gz |
io: add dynstream
a new abstraction that we derive posixstream from; hopefully with time we can get rid of std/streams
Diffstat (limited to 'src/io')
-rw-r--r-- | src/io/bufstream.nim | 4 | ||||
-rw-r--r-- | src/io/dynstream.nim | 82 | ||||
-rw-r--r-- | src/io/posixstream.nim | 60 | ||||
-rw-r--r-- | src/io/socketstream.nim | 1 |
4 files changed, 92 insertions, 55 deletions
diff --git a/src/io/bufstream.nim b/src/io/bufstream.nim index eb9d6d6b..0558b61c 100644 --- a/src/io/bufstream.nim +++ b/src/io/bufstream.nim @@ -1,7 +1,8 @@ +import io/dynstream import io/posixstream type - BufStream* = ref object of PosixStream + BufStream* = ref object of DynStream source*: PosixStream registerFun: proc(fd: int) registered: bool @@ -46,7 +47,6 @@ proc flushWrite*(s: BufStream): bool = proc newBufStream*(ps: PosixStream, registerFun: proc(fd: int)): BufStream = result = BufStream( - fd: ps.fd, source: ps, blocking: ps.blocking, registerFun: registerFun diff --git a/src/io/dynstream.nim b/src/io/dynstream.nim new file mode 100644 index 00000000..d4c7760f --- /dev/null +++ b/src/io/dynstream.nim @@ -0,0 +1,82 @@ +import std/streams + +type + DynStream* = ref object of Stream #TODO should be of RootObj + isend*: bool + blocking*: bool #TODO move to posixstream + +# Semantics of this function are those of POSIX read(2): that is, it may return +# a result that is lower than `len`, and that does not mean the stream is +# finished. +# isend must be set by implementations when the end of the stream is reached. +# An exception should be raised if recvData is called with the 'isend' flag set +# to true. +method recvData*(s: DynStream; buffer: pointer; len: int): int {.base.} = + assert false + +# See above, but with write(2) +method sendData*(s: DynStream; buffer: pointer; len: int): int {.base.} = + assert false + +method seek*(s: DynStream; off: int) {.base.} = + assert false + +method sclose*(s: DynStream) {.base.} = + assert false + +proc recvData*(s: DynStream; buffer: var openArray[uint8]): int {.inline.} = + return s.recvData(addr buffer[0], buffer.len) + +proc recvData*(s: DynStream; buffer: var openArray[char]): int {.inline.} = + return s.recvData(addr buffer[0], buffer.len) + +proc sendData*(s: DynStream; buffer: openArray[char]): int {.inline.} = + return s.sendData(unsafeAddr buffer[0], buffer.len) + +proc sendData*(s: DynStream; buffer: openArray[uint8]): int {.inline.} = + return s.sendData(unsafeAddr buffer[0], buffer.len) + +proc dsClose(s: Stream) = + DynStream(s).sclose() + +proc dsReadData(s: Stream, buffer: pointer, len: int): int = + let s = DynStream(s) + assert len != 0 and s.blocking + result = 0 + while result < len: + let p = addr cast[ptr UncheckedArray[uint8]](buffer)[result] + let n = s.recvData(p, len - result) + if n == 0: + break + result += n + +proc dsWriteData(s: Stream, buffer: pointer, len: int) = + let s = DynStream(s) + assert len != 0 and s.blocking + discard s.sendData(buffer, len) + +proc dsReadLine(s: Stream, line: var string): bool = + let s = DynStream(s) + assert s.blocking + line = "" + var c: char + while true: + if s.recvData(addr c, 1) == 0: + return false + if c == '\r': + if s.recvData(addr c, 1) == 0: + return false + if c == '\n': + break + line &= c + true + +proc dsAtEnd(s: Stream): bool = + return DynStream(s).isend + +proc addStreamIface*(s: DynStream) = + s.closeImpl = cast[typeof(s.closeImpl)](dsClose) + s.readDataImpl = cast[typeof(s.readDataImpl)](dsReadData) + s.writeDataImpl = cast[typeof(s.writeDataImpl)](dsWriteData) + s.readLineImpl = cast[typeof(s.readLineImpl)](dsReadLine) + s.atEndImpl = dsAtEnd diff --git a/src/io/posixstream.nim b/src/io/posixstream.nim index dfb6f85b..baf3238c 100644 --- a/src/io/posixstream.nim +++ b/src/io/posixstream.nim @@ -1,12 +1,11 @@ # stdlib file handling is broken, so we use this instead of FileStream. import std/posix -import std/streams + +import io/dynstream type - PosixStream* = ref object of Stream + PosixStream* = ref object of DynStream fd*: cint - isend*: bool - blocking*: bool ErrorAgain* = object of IOError ErrorBadFD* = object of IOError @@ -34,7 +33,7 @@ proc raisePosixIOError*() = else: raise newException(IOError, $strerror(errno)) -method recvData*(s: PosixStream, buffer: pointer, len: int): int {.base.} = +method recvData*(s: PosixStream, buffer: pointer, len: int): int = let n = read(s.fd, buffer, len) if n < 0: raisePosixIOError() @@ -50,7 +49,7 @@ proc recvData*(s: PosixStream, buffer: var openArray[uint8]): int {.inline.} = proc recvData*(s: PosixStream, buffer: var openArray[char]): int {.inline.} = return s.recvData(addr buffer[0], buffer.len) -method sendData*(s: PosixStream, buffer: pointer, len: int): int {.base.} = +method sendData*(s: PosixStream, buffer: pointer, len: int): int = let n = write(s.fd, buffer, len) if n < 0: raisePosixIOError() @@ -70,57 +69,12 @@ method setBlocking*(s: PosixStream, blocking: bool) {.base.} = else: discard fcntl(s.fd, F_SETFL, ofl or O_NONBLOCK) -method seek*(s: PosixStream; off: int) {.base.} = +method seek*(s: PosixStream; off: int) = discard lseek(s.fd, Off(off), SEEK_SET) -method sclose*(s: PosixStream) {.base.} = +method sclose*(s: PosixStream) = discard close(s.fd) -proc psClose(s: Stream) = - PosixStream(s).sclose() - -proc psReadData(s: Stream, buffer: pointer, len: int): int = - let s = PosixStream(s) - assert len != 0 and s.blocking - result = 0 - while result < len: - let p = addr cast[ptr UncheckedArray[uint8]](buffer)[result] - let n = s.recvData(p, len - result) - if n == 0: - break - result += n - -proc psWriteData(s: Stream, buffer: pointer, len: int) = - let s = PosixStream(s) - assert len != 0 and s.blocking - discard s.sendData(buffer, len) - -proc psReadLine(s: Stream, line: var string): bool = - let s = PosixStream(s) - assert s.blocking - line = "" - var c: char - while true: - if s.recvData(addr c, 1) == 0: - return false - if c == '\r': - if s.recvData(addr c, 1) == 0: - return false - if c == '\n': - break - line &= c - true - -proc psAtEnd(s: Stream): bool = - return PosixStream(s).isend - -proc addStreamIface*(ps: PosixStream) = - ps.closeImpl = cast[typeof(ps.closeImpl)](psClose) - ps.readDataImpl = cast[typeof(ps.readDataImpl)](psReadData) - ps.writeDataImpl = cast[typeof(ps.writeDataImpl)](psWriteData) - ps.readLineImpl = cast[typeof(ps.readLineImpl)](psReadLine) - ps.atEndImpl = psAtEnd - proc newPosixStream*(fd: FileHandle): PosixStream = let ps = PosixStream(fd: fd, blocking: true) ps.addStreamIface() diff --git a/src/io/socketstream.nim b/src/io/socketstream.nim index 168b7a4f..e02108ce 100644 --- a/src/io/socketstream.nim +++ b/src/io/socketstream.nim @@ -2,6 +2,7 @@ import std/nativesockets import std/net import std/os +import io/dynstream import io/posixstream import io/serversocket |