about summary refs log tree commit diff stats
path: root/src/io/dynstream.nim
diff options
context:
space:
mode:
Diffstat (limited to 'src/io/dynstream.nim')
-rw-r--r--src/io/dynstream.nim82
1 files changed, 82 insertions, 0 deletions
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