Skip to content

Commit

Permalink
add support for StringStream read
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Apr 29, 2020
1 parent 800ce5b commit 43d6e74
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 20 deletions.
78 changes: 78 additions & 0 deletions lib/js/jsarrays.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
##[
This module provides a wrapper for ArrayBuffer, DataView and related API's such
as `getInt8`, `setInt16`.
]##

#[
`BigInt` could be homed here.
]#

static: doAssert defined(js)

type
ArrayBuffer* = ref object {.importjs.}
DataView* = ref object {.importjs.}
## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView

proc newArrayBuffer*(n: int): ArrayBuffer {.importjs: "new ArrayBuffer(#)".}
proc newDataView*(a: ArrayBuffer, offset: int): DataView {.importjs: "new DataView(#, #)".}
proc toArrayBuffer*(a: string): ArrayBuffer =
let n = a.len
result = newArrayBuffer(n)
{.emit:"""
const view = new Uint8Array(`result`);
for(i=0;i<`n`;i++){
view[i] = `a`[i];
}
""".}

template genGetSet(T, funGet, funSet): untyped =
proc funGet(a: DataView, byteOffset: int, littleEndian: bool): T {.importcpp.}
proc funSet(a: DataView, byteOffset: int, value: T, littleEndian: bool): T {.importcpp.}

genGetSet int8, getInt8, setInt8
genGetSet int16, getInt16, setInt16
genGetSet int32, getInt32, setInt32

proc getTyped*(a: DataView, T: typedesc, offset: int, littleEndian: bool): T =
when false: discard
elif T is int8: getInt8(a, offset, littleEndian)
elif T is int16: getInt16(a, offset, littleEndian)
elif T is int32: getInt32(a, offset, littleEndian)
else: static doAssert false, $T # add as needed

when false: ## scratch below
# view[i] = str.charCodeAt(i); // check whether would be needed for cstring

# proc `[]=`(a: ArrayBuffer, index: int, val: char) =
# {.emit: """`a`[`index`] = `val`;""".}

# DataView.prototype.getBigInt64()
# DataView.prototype.getBigUint64()
# DataView.prototype.getFloat32()
# DataView.prototype.getFloat64()
# DataView.prototype.getInt16()
# DataView.prototype.getInt32()
# DataView.prototype.getInt8()
# DataView.prototype.getUint16()
# DataView.prototype.getUint32()
# DataView.prototype.getUint8()
# DataView.prototype.setBigInt64()
# DataView.prototype.setBigUint64()
# DataView.prototype.setFloat32()
# DataView.prototype.setFloat64()
# DataView.prototype.setInt16()
# DataView.prototype.setInt32()
# DataView.prototype.setInt8()
# DataView.prototype.setUint16()
# DataView.prototype.setUint32()
# DataView.prototype.setUint8()

proc decode() =
case bufLen
of int32.sizeof:
cast[ptr int](buffer)[] = s2.getInt32(0, true)
of int16.sizeof:
cast[ptr int16](buffer)[] = s2.getInt16(0, true)
else:
doAssert false
33 changes: 24 additions & 9 deletions lib/pure/streams.nim
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@

include "system/inclrtl"

when defined(js):
import std/jsarrays

const taintMode = compileOption("taintmode")

proc newEIO(msg: string): owned(ref IOError) =
Expand Down Expand Up @@ -393,8 +396,6 @@ proc writeLine*(s: Stream, args: varargs[string, `$`]) =

proc read*[T](s: Stream, result: var T) =
## Generic read procedure. Reads `result` from the stream `s`.
##
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
runnableExamples:
var strm = newStringStream("012")
## readInt
Expand All @@ -412,8 +413,6 @@ proc read*[T](s: Stream, result: var T) =

proc peek*[T](s: Stream, result: var T) =
## Generic peek procedure. Peeks `result` from the stream `s`.
##
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
runnableExamples:
var strm = newStringStream("012")
## peekInt
Expand Down Expand Up @@ -1134,6 +1133,10 @@ type
## This is updated when called `writeLine` etc.
pos: int

when defined js:
data2: ArrayBuffer
dataView: DataView

when (NimMajor, NimMinor) < (1, 3) and defined(js):
proc ssAtEnd(s: Stream): bool {.compileTime.} =
var s = StringStream(s)
Expand Down Expand Up @@ -1217,11 +1220,19 @@ else: # after 1.3 or JS not defined
result = min(bufLen, s.data.len - s.pos)
if result > 0:
when defined(js):
try:
cast[ptr string](buffer)[][0..<result] = s.data[s.pos..<s.pos+result]
except:
raise newException(Defect, "could not read string stream, " &
"did you use a non-string buffer pointer?", getCurrentException())
let view = s.dataView
template fun(T) =
cast[ptr T](buffer)[] = view.getTyped(T, 0, true)
case bufLen
of int8.sizeof: fun(int8)
of int32.sizeof: fun(int32)
of int16.sizeof: fun(int16)
else: doAssert false, $bufLen
# try:
# cast[ptr string](buffer)[][0..<result] = s.data[s.pos..<s.pos+result]
# except:
# raise newException(Defect, "could not read string stream, " &
# "did you use a non-string buffer pointer?", getCurrentException())
elif not defined(nimscript):
copyMem(buffer, addr(s.data[s.pos]), result)
inc(s.pos, result)
Expand Down Expand Up @@ -1285,6 +1296,10 @@ else: # after 1.3 or JS not defined

new(result)
result.data = s
when defined js:
# IMPROVE, move
result.data2 = s.toArrayBuffer
result.dataView = newDataView(result.data2, 0)
result.pos = 0
result.closeImpl = ssClose
result.atEndImpl = ssAtEnd
Expand Down
46 changes: 35 additions & 11 deletions tests/js/tstreams.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,39 @@ GROOT

import streams

var s = newStringStream("I\nAM\nGROOT")
doAssert s.peekStr(1) == "I"
doAssert s.peekChar() == 'I'
for line in s.lines:
echo line
s.close
block:
var s = newStringStream("I\nAM\nGROOT")
doAssert s.peekStr(1) == "I"
doAssert s.peekChar() == 'I'
for line in s.lines:
echo line
s.close

var s2 = newStringStream("abc")
doAssert s2.readAll == "abc"
s2.write("def")
doAssert s2.data == "abcdef"
s2.close
var s2 = newStringStream("abc")
doAssert s2.readAll == "abc"
s2.write("def")
doAssert s2.data == "abcdef"
s2.close


block:
proc fun[T](x: T) =
# todo: this could be done via `write` on a StringStream
var str: string
str.setLen 10
for i in 0..<T.sizeof: # improve
str[i] = cast[char](255 and (x shr (i*8)))

var s = newStringStream(str)
var x2: T
s.read(x2)
doAssert x2 == x
# echo (x, x2)

fun(234_560.int32)
fun(234.int16)
fun(0.int16)
fun(12.uint8)
fun(123123.int32)
fun(123123.uint32)
fun((-123).int8)

0 comments on commit 43d6e74

Please sign in to comment.