From 817e4bb2fe0538a60f169d37e254b30e3dc3ab1d Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 7 Aug 2018 17:36:56 +0200 Subject: AsyncHttpClient: return from requests before body completion Store the body completion future at the client and wait for it to complete before issuing additional requests. This allows the body FutureStream reader to drain the stream and read buffers to be freed asynchronously. Fix #8109 --- lib/pure/httpclient.nim | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 8b4fb0f8c..72de72718 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -807,6 +807,7 @@ type lastProgressReport: float when SocketType is AsyncSocket: bodyStream: FutureStream[string] + parseBodyFut: Future[void] else: bodyStream: Stream getBody: bool ## When `false`, the body is never read in requestAux. @@ -1066,10 +1067,14 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, if getBody: when client is HttpClient: client.bodyStream = newStringStream() + result.bodyStream = client.bodyStream + parseBody(client, result.headers, result.version) else: client.bodyStream = newFutureStream[string]("parseResponse") - await parseBody(client, result.headers, result.version) - result.bodyStream = client.bodyStream + result.bodyStream = client.bodyStream + assert(client.parseBodyFut.isNil or client.parseBodyFut.finished) + client.parseBodyFut = parseBody(client, result.headers, result.version) + # do not wait here for the body request to complete proc newConnection(client: HttpClient | AsyncHttpClient, url: Uri) {.multisync.} = @@ -1159,6 +1164,12 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: string, # Helper that actually makes the request. Does not handle redirects. let requestUrl = parseUri(url) + when client is AsyncHttpClient: + if not client.parseBodyFut.isNil: + # let the current operation finish before making another request + await client.parseBodyFut + client.parseBodyFut = nil + await newConnection(client, requestUrl) let effectiveHeaders = client.headers.override(headers) -- cgit 1.4.1-2-gfad0 From 32b62097a2636c5053d842939d34e2a0fa3f9e33 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 8 Aug 2018 15:34:21 +0200 Subject: Fix regression for mapIt (#8567) Don't try to be too smart and limit the use of `evalOnce` where strictly needed as not every value can be assigned with a `let`. Fixes #8566 --- lib/pure/collections/sequtils.nim | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 8f81fe4f5..99ce91979 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -676,8 +676,8 @@ template mapIt*(s, op: untyped): untyped = var it{.inject.}: type(items(s)); op)) var result: seq[outType] - evalOnce(t, s) - when compiles(t.len): + when compiles(s.len): + evalOnce(t, s) var i = 0 result = newSeq[outType](t.len) for it {.inject.} in t: @@ -685,7 +685,7 @@ template mapIt*(s, op: untyped): untyped = i += 1 else: result = @[] - for it {.inject.} in t: + for it {.inject.} in s: result.add(op) result @@ -1071,5 +1071,10 @@ when isMainModule: proc foo(x: openArray[int]): seq[int] = x.mapIt(it + 1) doAssert foo([1,2,3]) == @[2,3,4] + block: # mapIt with invalid RHS for `let` (#8566) + type X = enum + A, B + doAssert mapIt(X, $it) == @["A", "B"] + when not defined(testing): echo "Finished doc tests" -- cgit 1.4.1-2-gfad0 From 98225ca207e4057c1da7966430d0699c0151e3e7 Mon Sep 17 00:00:00 2001 From: Grant Date: Thu, 9 Aug 2018 00:40:21 -0700 Subject: Update channels.nim (#8583) Fix typo in channels.nim --- lib/system/channels.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/system/channels.nim b/lib/system/channels.nim index 254b87dfc..14d3a3005 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -233,7 +233,7 @@ proc send*[TMsg](c: var Channel[TMsg], msg: TMsg) {.inline.} = proc trySend*[TMsg](c: var Channel[TMsg], msg: TMsg): bool {.inline.} = ## Tries to send a message to a thread. `msg` is deeply copied. Doesn't block. ## Returns `false` if the message was not sent because number of pending items - ## in the cannel exceeded `maxItems`. + ## in the channel exceeded `maxItems`. sendImpl(cast[PRawChannel](addr c), cast[PNimType](getTypeInfo(msg)), unsafeAddr(msg), true) proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) = -- cgit 1.4.1-2-gfad0 From 43f634db8dfac4fb13c8454958d35e776410dac1 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 10 Aug 2018 00:20:14 -0700 Subject: fixes #8519; implements T.distinctBase to reverse T = distinct A (#8531) --- doc/manual.rst | 3 ++- lib/pure/sugar.nim | 38 ++++++++++++++++++++++++++++++++++++++ tests/stdlib/tsugar.nim | 29 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/stdlib/tsugar.nim (limited to 'lib') diff --git a/doc/manual.rst b/doc/manual.rst index abdc4ce69..de0a13143 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1673,7 +1673,8 @@ A ``distinct`` type is new type derived from a `base type`:idx: that is incompatible with its base type. In particular, it is an essential property of a distinct type that it **does not** imply a subtype relation between it and its base type. Explicit type conversions from a distinct type to its -base type and vice versa are allowed. +base type and vice versa are allowed. See also ``distinctBase`` to get the +reverse operation. Modelling currencies diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 258b40191..8ded552d9 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -198,3 +198,41 @@ macro dump*(x: typed): untyped = let r = quote do: debugEcho `s`, " = ", `x` return r + +# TODO: consider exporting this in macros.nim +proc freshIdentNodes(ast: NimNode): NimNode = + # Replace NimIdent and NimSym by a fresh ident node + # see also https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458 + proc inspect(node: NimNode): NimNode = + case node.kind: + of nnkIdent, nnkSym: + result = ident($node) + of nnkEmpty, nnkLiterals: + result = node + else: + result = node.kind.newTree() + for child in node: + result.add inspect(child) + result = inspect(ast) + +macro distinctBase*(T: typedesc): untyped = + ## reverses ``type T = distinct A``; works recursively. + runnableExamples: + type T = distinct int + doAssert distinctBase(T) is int + doAssert: not compiles(distinctBase(int)) + type T2 = distinct T + doAssert distinctBase(T2) is int + + let typeNode = getTypeImpl(T) + expectKind(typeNode, nnkBracketExpr) + if typeNode[0].typeKind != ntyTypeDesc: + error "expected typeDesc, got " & $typeNode[0] + var typeSym = typeNode[1] + typeSym = getTypeImpl(typeSym) + if typeSym.typeKind != ntyDistinct: + error "type is not distinct" + typeSym = typeSym[0] + while typeSym.typeKind == ntyDistinct: + typeSym = getTypeImpl(typeSym)[0] + typeSym.freshIdentNodes diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim new file mode 100644 index 000000000..a870bf6fe --- /dev/null +++ b/tests/stdlib/tsugar.nim @@ -0,0 +1,29 @@ +discard """ + file: "tsugar.nim" + output: "" +""" +import sugar +import macros + +block distinctBase: + block: + type + Foo[T] = distinct seq[T] + var a: Foo[int] + doAssert a.type.distinctBase is seq[int] + + block: + # simplified from https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458 + macro uintImpl(bits: static[int]): untyped = + if bits >= 128: + let inner = getAST(uintImpl(bits div 2)) + result = newTree(nnkBracketExpr, ident("UintImpl"), inner) + else: + result = ident("uint64") + + type + BaseUint = UintImpl or SomeUnsignedInt + UintImpl[Baseuint] = object + Uint[bits: static[int]] = distinct uintImpl(bits) + + doAssert Uint[128].distinctBase is UintImpl[uint64] -- cgit 1.4.1-2-gfad0