about summary refs log tree commit diff stats
path: root/src/io/bufwriter.nim
diff options
context:
space:
mode:
Diffstat (limited to 'src/io/bufwriter.nim')
-rw-r--r--src/io/bufwriter.nim175
1 files changed, 175 insertions, 0 deletions
diff --git a/src/io/bufwriter.nim b/src/io/bufwriter.nim
new file mode 100644
index 00000000..99c7ed94
--- /dev/null
+++ b/src/io/bufwriter.nim
@@ -0,0 +1,175 @@
+# Write data to streams.
+
+import std/options
+import std/sets
+import std/tables
+
+import io/dynstream
+
+import types/blob
+import types/formdata
+import types/url
+import types/opt
+
+type BufferedWriter* = object
+  stream: DynStream
+  buffer: ptr UncheckedArray[uint8]
+  bufSize: int
+  bufLen: int
+
+{.warning[Deprecated]: off.}:
+  proc `=destroy`(writer: var BufferedWriter) =
+    if writer.buffer != nil:
+      dealloc(writer.buffer)
+      writer.buffer = nil
+
+proc initWriter*(stream: DynStream; sizeInit = 64): BufferedWriter =
+  return BufferedWriter(
+    stream: stream,
+    buffer: cast[ptr UncheckedArray[uint8]](alloc(sizeInit)),
+    bufSize: sizeInit,
+    bufLen: 0
+  )
+
+proc flush*(writer: var BufferedWriter) =
+  let stream = writer.stream
+  var n = 0
+  while true:
+    n += stream.sendData(addr writer.buffer[n], writer.bufLen - n)
+    if n == writer.bufLen:
+      break
+  writer.bufLen = 0
+  stream.sflush()
+
+proc deinit*(writer: var BufferedWriter) =
+  dealloc(writer.buffer)
+  writer.buffer = nil
+  writer.bufSize = 0
+  writer.bufLen = 0
+
+template withWriter*(stream: DynStream; w, body: untyped) =
+  var w {.inject.} = stream.initWriter()
+  body
+  w.flush()
+  w.deinit()
+
+proc swrite*(writer: var BufferedWriter; n: SomeNumber)
+proc swrite*[T](writer: var BufferedWriter; s: set[T])
+proc swrite*[T: enum](writer: var BufferedWriter; x: T)
+proc swrite*(writer: var BufferedWriter; s: string)
+proc swrite*(writer: var BufferedWriter; b: bool)
+proc swrite*(writer: var BufferedWriter; url: URL)
+proc swrite*(writer: var BufferedWriter; tup: tuple)
+proc swrite*[I, T](writer: var BufferedWriter; a: array[I, T])
+proc swrite*(writer: var BufferedWriter; s: seq)
+proc swrite*[U, V](writer: var BufferedWriter; t: Table[U, V])
+proc swrite*(writer: var BufferedWriter; obj: object)
+proc swrite*(writer: var BufferedWriter; obj: ref object)
+proc swrite*(writer: var BufferedWriter; part: FormDataEntry)
+proc swrite*(writer: var BufferedWriter; blob: Blob)
+proc swrite*[T](writer: var BufferedWriter; o: Option[T])
+proc swrite*[T, E](writer: var BufferedWriter; o: Result[T, E])
+
+proc writeData(writer: var BufferedWriter; buffer: pointer; len: int) =
+  let targetLen = writer.bufLen + len
+  let missing = targetLen - writer.bufSize
+  if missing > 0:
+    let target = writer.bufSize + missing
+    writer.bufSize *= 2
+    if writer.bufSize < target:
+      writer.bufSize = target
+    let p = realloc(writer.buffer, writer.bufSize)
+    writer.buffer = cast[ptr UncheckedArray[uint8]](p)
+  copyMem(addr writer.buffer[writer.bufLen], buffer, len)
+  writer.bufLen = targetLen
+
+proc swrite*(writer: var BufferedWriter; n: SomeNumber) =
+  writer.writeData(unsafeAddr n, sizeof(n))
+
+proc swrite*[T: enum](writer: var BufferedWriter; x: T) =
+  static:
+    doAssert sizeof(int) >= sizeof(T)
+  writer.swrite(int(x))
+
+proc swrite*[T](writer: var BufferedWriter; s: set[T]) =
+  writer.swrite(s.card)
+  for e in s:
+    writer.swrite(e)
+
+proc swrite*(writer: var BufferedWriter; s: string) =
+  writer.swrite(s.len)
+  if s.len > 0:
+    writer.writeData(unsafeAddr s[0], s.len)
+
+proc swrite*(writer: var BufferedWriter; b: bool) =
+  if b:
+    writer.swrite(1u8)
+  else:
+    writer.swrite(0u8)
+
+proc swrite*(writer: var BufferedWriter; url: URL) =
+  if url != nil:
+    writer.swrite(url.serialize())
+  else:
+    writer.swrite("")
+
+proc swrite*(writer: var BufferedWriter; tup: tuple) =
+  for f in tup.fields:
+    writer.swrite(f)
+
+proc swrite*[I, T](writer: var BufferedWriter; a: array[I, T]) =
+  for x in a:
+    writer.swrite(x)
+
+proc swrite*(writer: var BufferedWriter; s: seq) =
+  writer.swrite(s.len)
+  for x in s:
+    writer.swrite(x)
+
+proc swrite*[U, V](writer: var BufferedWriter; t: Table[U, V]) =
+  writer.swrite(t.len)
+  for k, v in t:
+    writer.swrite(k)
+    writer.swrite(v)
+
+proc swrite*(writer: var BufferedWriter; obj: object) =
+  for f in obj.fields:
+    writer.swrite(f)
+
+proc swrite*(writer: var BufferedWriter; obj: ref object) =
+  writer.swrite(obj != nil)
+  if obj != nil:
+    writer.swrite(obj[])
+
+proc swrite*(writer: var BufferedWriter; part: FormDataEntry) =
+  writer.swrite(part.isstr)
+  writer.swrite(part.name)
+  writer.swrite(part.filename)
+  if part.isstr:
+    writer.swrite(part.svalue)
+  else:
+    writer.swrite(part.value)
+
+#TODO clean up this mess
+proc swrite*(writer: var BufferedWriter; blob: Blob) =
+  writer.swrite(blob.isfile)
+  if blob.isfile:
+    writer.swrite(WebFile(blob).path)
+  else:
+    writer.swrite(blob.ctype)
+    writer.swrite(blob.size)
+    writer.writeData(blob.buffer, int(blob.size))
+
+proc swrite*[T](writer: var BufferedWriter; o: Option[T]) =
+  writer.swrite(o.isSome)
+  if o.isSome:
+    writer.swrite(o.get)
+
+proc swrite*[T, E](writer: var BufferedWriter; o: Result[T, E]) =
+  writer.swrite(o.isOk)
+  if o.isOk:
+    when not (T is void):
+      writer.swrite(o.get)
+  else:
+    when not (E is void):
+      writer.swrite(o.error)