Better name and docs for the 'nonBlockingReads' facility

This commit is contained in:
Zahary Karadjov 2020-05-07 12:12:46 +03:00
commit dd63bbfd1c
No known key found for this signature in database
GPG key ID: C8936F8A3073D609
3 changed files with 18 additions and 18 deletions

View file

@ -317,13 +317,13 @@ proc performHandshake(c: Connection): bool {.async.} =
It is assumed that in traditional async code, timeouts will be managed more It is assumed that in traditional async code, timeouts will be managed more
explicitly with `sleepAsync` and the `or` operator defined over futures. explicitly with `sleepAsync` and the `or` operator defined over futures.
#### Non-blocking reads #### Range-restricted reads
Protocols transmitting serialized payloads often provide information regarding Protocols transmitting serialized payloads often provide information regarding
the size of the payload. When you invoke the deserialization routine, it's the size of the payload. When you invoke the deserialization routine, it's
preferable if the provided boundaries are treated like an "end of file" marker preferable if the provided boundaries are treated like an "end of file" marker
for the deserializer. FastStreams provides an easy way to achieve this without for the deserializer. FastStreams provides an easy way to achieve this without
extra copies and memory allocations through the `nonBlockingReads` facility. extra copies and memory allocations through the `withReadableRange` facility.
Here is a typical usage: Here is a typical usage:
```nim ```nim
@ -333,18 +333,20 @@ proc decodeFrame(s: AsyncInputStream, DecodedType: type): Option[DecodedType] =
let lengthPrefix = toInt32 s.read(4) let lengthPrefix = toInt32 s.read(4)
if s.readable(lengthPrefix): if s.readable(lengthPrefix):
s.nonBlockingReads(lengthPrefix): s.withReadableRange(lengthPrefix, range):
s.readValue(Json, DecodedType) range.readValue(Json, DecodedType)
``` ```
Please note that the above example uses the [nim-serialization library](https://github.com/status-im/nim-serialization/) Please note that the above example uses the [nim-serialization library](https://github.com/status-im/nim-serialization/)
Simply, inside the `nonBlockingReads` block, `s.readable` will return `false` Simply, inside the `withReadableRange` block, `range` becomes a stream for
as soon as the Json parser has consumed the specified number of bytes. which `s.readable` will return `false` as soon as the Json parser has consumed
Furthermore, it's guaranteed that no blocking operations are possible and the specified number of bytes.
thus our `AsyncInputStream` will be treated like a normal `InputStream`.
Depending on the complexity of the stream processors, this will often lead Furthermore, `withReadableRange` guarantees that all stream operations within
to much more optimal code. the block will be non-blocking, so it will transform the `AsyncInputStream`
into a regular `InputStream`. Depending on the complexity of the stream
processing functions, this will often lead to significant performance gains.
### `OutputStream` and `AsyncOutputStream` ### `OutputStream` and `AsyncOutputStream`

View file

@ -274,22 +274,20 @@ func getBestContiguousRunway(s: InputStream): Natural =
flipPage s flipPage s
result = s.span.len result = s.span.len
template nonBlockingReads*(sp: InputStream|AsyncInputStream, newName, blk: untyped) = template withReadableRange*(sp: InputStream|AsyncInputStream,
rangeLen: Natural,
rangeStreamVarName, blk: untyped) =
let s = InputStream sp let s = InputStream sp
const sname = astToStr(sp)
let vtable = s.vtable let vtable = s.vtable
s.vtable = nil s.vtable = nil
try: try:
let `newName` {.inject.} = s let `rangeStreamVarName` {.inject.} = s
blk blk
finally: finally:
s.vtable = vtable s.vtable = vtable
template nonBlockingReads*(sp: InputStream|AsyncInputStream, blk: untyped) =
nonBlockingReads(sp, astToStr(sp), blk)
func totalUnconsumedBytes*(s: InputStream): Natural = func totalUnconsumedBytes*(s: InputStream): Natural =
## Returns the number of bytes that are currently sitting within the stream ## Returns the number of bytes that are currently sitting within the stream
## buffers and that can be consumed with `read` or `advance`. ## buffers and that can be consumed with `read` or `advance`.

View file

@ -139,8 +139,8 @@ procSuite "input stream":
test "non-blocking reads": test "non-blocking reads":
let s = fileInput(asciiTableFile, pageSize = 20) let s = fileInput(asciiTableFile, pageSize = 20)
if s.readable: if s.readable:
s.nonBlockingReads: s.withReadableRange(20, r):
check s.readAll.len == 20 check r.readAll.len == 20
check s.readable check s.readable
test "simple": test "simple":