Remove future var (#247)
This commit is contained in:
parent
c25fa1f6cd
commit
cedc603b81
|
@ -64,8 +64,6 @@ type
|
|||
## Future to hold GC seqs
|
||||
gcholder*: seq[B]
|
||||
|
||||
FutureVar*[T] = distinct Future[T]
|
||||
|
||||
FutureDefect* = object of Defect
|
||||
cause*: FutureBase
|
||||
|
||||
|
@ -113,9 +111,6 @@ proc newFutureSeqImpl[A, B](loc: ptr SrcLoc): FutureSeq[A, B] =
|
|||
proc newFutureStrImpl[T](loc: ptr SrcLoc): FutureStr[T] =
|
||||
setupFutureBase(loc)
|
||||
|
||||
proc newFutureVarImpl[T](loc: ptr SrcLoc): FutureVar[T] =
|
||||
FutureVar[T](newFutureImpl[T](loc))
|
||||
|
||||
template newFuture*[T](fromProc: static[string] = ""): Future[T] =
|
||||
## Creates a new future.
|
||||
##
|
||||
|
@ -139,28 +134,11 @@ template newFutureStr*[T](fromProc: static[string] = ""): FutureStr[T] =
|
|||
## that this future belongs to, is a good habit as it helps with debugging.
|
||||
newFutureStrImpl[T](getSrcLocation(fromProc))
|
||||
|
||||
template newFutureVar*[T](fromProc: static[string] = ""): FutureVar[T] =
|
||||
## Create a new ``FutureVar``. This Future type is ideally suited for
|
||||
## situations where you want to avoid unnecessary allocations of Futures.
|
||||
##
|
||||
## Specifying ``fromProc``, which is a string specifying the name of the proc
|
||||
## that this future belongs to, is a good habit as it helps with debugging.
|
||||
newFutureVarImpl[T](getSrcLocation(fromProc))
|
||||
|
||||
proc clean*[T](future: FutureVar[T]) =
|
||||
## Resets the ``finished`` status of ``future``.
|
||||
Future[T](future).state = FutureState.Pending
|
||||
Future[T](future).value = default(T)
|
||||
Future[T](future).error = nil
|
||||
|
||||
proc finished*(future: FutureBase | FutureVar): bool {.inline.} =
|
||||
proc finished*(future: FutureBase): bool {.inline.} =
|
||||
## Determines whether ``future`` has completed, i.e. ``future`` state changed
|
||||
## from state ``Pending`` to one of the states (``Finished``, ``Cancelled``,
|
||||
## ``Failed``).
|
||||
when future is FutureVar:
|
||||
result = (FutureBase(future).state != FutureState.Pending)
|
||||
else:
|
||||
result = (future.state != FutureState.Pending)
|
||||
result = (future.state != FutureState.Pending)
|
||||
|
||||
proc cancelled*(future: FutureBase): bool {.inline.} =
|
||||
## Determines whether ``future`` has cancelled.
|
||||
|
@ -254,31 +232,6 @@ template complete*(future: Future[void]) =
|
|||
## Completes a void ``future``.
|
||||
complete(future, getSrcLocation())
|
||||
|
||||
proc complete[T](future: FutureVar[T], loc: ptr SrcLoc) =
|
||||
if not(future.cancelled()):
|
||||
template fut: untyped = Future[T](future)
|
||||
checkFinished(FutureBase(fut), loc)
|
||||
doAssert(isNil(fut.error))
|
||||
fut.finish(FutureState.Finished)
|
||||
|
||||
template complete*[T](futvar: FutureVar[T]) =
|
||||
## Completes a ``FutureVar``.
|
||||
complete(futvar, getSrcLocation())
|
||||
|
||||
proc complete[T](futvar: FutureVar[T], val: T, loc: ptr SrcLoc) =
|
||||
if not(futvar.cancelled()):
|
||||
template fut: untyped = Future[T](futvar)
|
||||
checkFinished(FutureBase(fut), loc)
|
||||
doAssert(isNil(fut.error))
|
||||
fut.value = val
|
||||
fut.finish(FutureState.Finished)
|
||||
|
||||
template complete*[T](futvar: FutureVar[T], val: T) =
|
||||
## Completes a ``FutureVar`` with value ``val``.
|
||||
##
|
||||
## Any previously stored value will be overwritten.
|
||||
complete(futvar, val, getSrcLocation())
|
||||
|
||||
proc fail[T](future: Future[T], error: ref CatchableError, loc: ptr SrcLoc) =
|
||||
if not(future.cancelled()):
|
||||
checkFinished(FutureBase(future), loc)
|
||||
|
@ -503,12 +456,12 @@ proc internalCheckComplete*(fut: FutureBase) {.
|
|||
injectStacktrace(fut)
|
||||
raise fut.error
|
||||
|
||||
proc internalRead*[T](fut: Future[T] | FutureVar[T]): T {.inline.} =
|
||||
proc internalRead*[T](fut: Future[T]): T {.inline.} =
|
||||
# For internal use only. Used in asyncmacro
|
||||
when T isnot void:
|
||||
return fut.value
|
||||
|
||||
proc read*[T](future: Future[T] | FutureVar[T]): T {.
|
||||
proc read*[T](future: Future[T] ): T {.
|
||||
raises: [Defect, CatchableError].} =
|
||||
## Retrieves the value of ``future``. Future must be finished otherwise
|
||||
## this function will fail with a ``ValueError`` exception.
|
||||
|
@ -533,13 +486,6 @@ proc readError*[T](future: Future[T]): ref CatchableError {.
|
|||
# TODO: Make a custom exception type for this?
|
||||
raise newException(ValueError, "No error in future.")
|
||||
|
||||
proc mget*[T](future: FutureVar[T]): var T =
|
||||
## Returns a mutable value stored in ``future``.
|
||||
##
|
||||
## Unlike ``read``, this function will not raise an exception if the
|
||||
## Future has not been finished.
|
||||
result = Future[T](future).value
|
||||
|
||||
template taskFutureLocation(future: FutureBase): string =
|
||||
let loc = future.location[0]
|
||||
"[" & (
|
||||
|
|
|
@ -21,7 +21,7 @@ proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} =
|
|||
# result = node[0]
|
||||
when defined(chronosStrictException):
|
||||
template createCb(retFutureSym, iteratorNameSym,
|
||||
strName, identName, futureVarCompletions: untyped) =
|
||||
strName, identName: untyped) =
|
||||
bind finished
|
||||
|
||||
var nameIterVar = iteratorNameSym
|
||||
|
@ -51,14 +51,13 @@ when defined(chronosStrictException):
|
|||
except CancelledError:
|
||||
retFutureSym.cancelAndSchedule()
|
||||
except CatchableError as exc:
|
||||
futureVarCompletions
|
||||
retFutureSym.fail(exc)
|
||||
|
||||
identName(nil)
|
||||
{.pop.}
|
||||
else:
|
||||
template createCb(retFutureSym, iteratorNameSym,
|
||||
strName, identName, futureVarCompletions: untyped) =
|
||||
strName, identName: untyped) =
|
||||
bind finished
|
||||
|
||||
var nameIterVar = iteratorNameSym
|
||||
|
@ -88,40 +87,19 @@ else:
|
|||
except CancelledError:
|
||||
retFutureSym.cancelAndSchedule()
|
||||
except CatchableError as exc:
|
||||
futureVarCompletions
|
||||
retFutureSym.fail(exc)
|
||||
except Exception as exc:
|
||||
# TODO remove Exception handler to turn on strict mode
|
||||
if exc of Defect:
|
||||
raise (ref Defect)(exc)
|
||||
|
||||
futureVarCompletions
|
||||
retFutureSym.fail((ref ValueError)(msg: exc.msg, parent: exc))
|
||||
|
||||
identName(nil)
|
||||
{.pop.}
|
||||
|
||||
proc createFutureVarCompletions(futureVarIdents: seq[NimNode],
|
||||
fromNode: NimNode): NimNode {.compileTime.} =
|
||||
result = newNimNode(nnkStmtList, fromNode)
|
||||
# Add calls to complete each FutureVar parameter.
|
||||
for ident in futureVarIdents:
|
||||
# Only complete them if they have not been completed already by the user.
|
||||
# TODO: Once https://github.com/nim-lang/Nim/issues/5617 is fixed.
|
||||
# TODO: Add line info to the complete() call!
|
||||
# In the meantime, this was really useful for debugging :)
|
||||
#result.add(newCall(newIdentNode("echo"), newStrLitNode(fromNode.lineinfo)))
|
||||
result.add newIfStmt(
|
||||
(
|
||||
newCall(newIdentNode("not"),
|
||||
newDotExpr(ident, newIdentNode("finished"))),
|
||||
newCall(newIdentNode("complete"), ident)
|
||||
)
|
||||
)
|
||||
|
||||
proc processBody(node, retFutureSym: NimNode,
|
||||
subTypeIsVoid: bool,
|
||||
futureVarIdents: seq[NimNode]): NimNode {.compileTime.} =
|
||||
subTypeIsVoid: bool): NimNode {.compileTime.} =
|
||||
#echo(node.treeRepr)
|
||||
result = node
|
||||
case node.kind
|
||||
|
@ -129,8 +107,6 @@ proc processBody(node, retFutureSym: NimNode,
|
|||
result = newNimNode(nnkStmtList, node)
|
||||
|
||||
# As I've painfully found out, the order here really DOES matter.
|
||||
result.add createFutureVarCompletions(futureVarIdents, node)
|
||||
|
||||
if node[0].kind == nnkEmpty:
|
||||
if not subTypeIsVoid:
|
||||
result.add newCall(newIdentNode("complete"), retFutureSym,
|
||||
|
@ -138,8 +114,7 @@ proc processBody(node, retFutureSym: NimNode,
|
|||
else:
|
||||
result.add newCall(newIdentNode("complete"), retFutureSym)
|
||||
else:
|
||||
let x = node[0].processBody(retFutureSym, subTypeIsVoid,
|
||||
futureVarIdents)
|
||||
let x = node[0].processBody(retFutureSym, subTypeIsVoid)
|
||||
if x.kind == nnkYieldStmt: result.add x
|
||||
else:
|
||||
result.add newCall(newIdentNode("complete"), retFutureSym, x)
|
||||
|
@ -155,8 +130,7 @@ proc processBody(node, retFutureSym: NimNode,
|
|||
# We must not transform nested procedures of any form, otherwise
|
||||
# `retFutureSym` will be used for all nested procedures as their own
|
||||
# `retFuture`.
|
||||
result[i] = processBody(result[i], retFutureSym, subTypeIsVoid,
|
||||
futureVarIdents)
|
||||
result[i] = processBody(result[i], retFutureSym, subTypeIsVoid)
|
||||
|
||||
proc getName(node: NimNode): string {.compileTime.} =
|
||||
case node.kind
|
||||
|
@ -171,14 +145,6 @@ proc getName(node: NimNode): string {.compileTime.} =
|
|||
else:
|
||||
error("Unknown name.")
|
||||
|
||||
proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} =
|
||||
result = @[]
|
||||
for i in 1 ..< len(params):
|
||||
expectKind(params[i], nnkIdentDefs)
|
||||
if params[i][1].kind == nnkBracketExpr and
|
||||
params[i][1][0].eqIdent("futurevar"):
|
||||
result.add(params[i][0])
|
||||
|
||||
proc isInvalidReturnType(typeName: string): bool =
|
||||
return typeName notin ["Future"] #, "FutureStream"]
|
||||
|
||||
|
@ -217,8 +183,6 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
|||
let subtypeIsVoid = returnType.kind == nnkEmpty or
|
||||
(baseType.kind == nnkIdent and returnType[1].eqIdent("void"))
|
||||
|
||||
let futureVarIdents = getFutureVarIdents(prc.params)
|
||||
|
||||
var outerProcBody = newNimNode(nnkStmtList, prc.body)
|
||||
|
||||
# -> var retFuture = newFuture[T]()
|
||||
|
@ -245,8 +209,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
|||
# -> <proc_body>
|
||||
# -> complete(retFuture, result)
|
||||
var iteratorNameSym = genSym(nskIterator, $prcName)
|
||||
var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid,
|
||||
futureVarIdents)
|
||||
var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid)
|
||||
# don't do anything with forward bodies (empty)
|
||||
if procBody.kind != nnkEmpty:
|
||||
if subtypeIsVoid:
|
||||
|
@ -259,8 +222,6 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
|||
# fix #13899, `defer` should not escape its original scope
|
||||
procBody = newStmtList(newTree(nnkBlockStmt, newEmptyNode(), procBody))
|
||||
|
||||
procBody.add(createFutureVarCompletions(futureVarIdents, nil))
|
||||
|
||||
if not subtypeIsVoid:
|
||||
procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
|
||||
newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
|
||||
|
@ -329,8 +290,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
|||
var cbName = genSym(nskVar, prcName & "_continue")
|
||||
var procCb = getAst createCb(retFutureSym, iteratorNameSym,
|
||||
newStrLitNode(prcName),
|
||||
cbName,
|
||||
createFutureVarCompletions(futureVarIdents, nil))
|
||||
cbName)
|
||||
outerProcBody.add procCb
|
||||
|
||||
# -> return retFuture
|
||||
|
|
Loading…
Reference in New Issue