PFuture[void] now works.
Return types can also be completely ommitted. PFuture[void] will then be implicitly deduced.
This commit is contained in:
parent
0519afba1d
commit
de64e8ec22
2 changed files with 65 additions and 39 deletions
|
|
@ -43,6 +43,14 @@ proc complete*[T](future: PFuture[T], val: T) =
|
||||||
if future.cb != nil:
|
if future.cb != nil:
|
||||||
future.cb()
|
future.cb()
|
||||||
|
|
||||||
|
proc complete*(future: PFuture[void]) =
|
||||||
|
## Completes a void ``future``.
|
||||||
|
assert(not future.finished, "Future already finished, cannot finish twice.")
|
||||||
|
assert(future.error == nil)
|
||||||
|
future.finished = true
|
||||||
|
if future.cb != nil:
|
||||||
|
future.cb()
|
||||||
|
|
||||||
proc fail*[T](future: PFuture[T], error: ref EBase) =
|
proc fail*[T](future: PFuture[T], error: ref EBase) =
|
||||||
## Completes ``future`` with ``error``.
|
## Completes ``future`` with ``error``.
|
||||||
assert(not future.finished, "Future already finished, cannot finish twice.")
|
assert(not future.finished, "Future already finished, cannot finish twice.")
|
||||||
|
|
@ -76,7 +84,8 @@ proc read*[T](future: PFuture[T]): T =
|
||||||
## If the result of the future is an error then that error will be raised.
|
## If the result of the future is an error then that error will be raised.
|
||||||
if future.finished:
|
if future.finished:
|
||||||
if future.error != nil: raise future.error
|
if future.error != nil: raise future.error
|
||||||
return future.value
|
when T isnot void:
|
||||||
|
return future.value
|
||||||
else:
|
else:
|
||||||
# TODO: Make a custom exception type for this?
|
# TODO: Make a custom exception type for this?
|
||||||
raise newException(EInvalidValue, "Future still in progress.")
|
raise newException(EInvalidValue, "Future still in progress.")
|
||||||
|
|
@ -243,13 +252,13 @@ when defined(windows) or defined(nimdoc):
|
||||||
RemoteSockaddr, RemoteSockaddrLength)
|
RemoteSockaddr, RemoteSockaddrLength)
|
||||||
|
|
||||||
proc connect*(p: PDispatcher, socket: TSocketHandle, address: string, port: TPort,
|
proc connect*(p: PDispatcher, socket: TSocketHandle, address: string, port: TPort,
|
||||||
af = AF_INET): PFuture[int] =
|
af = AF_INET): PFuture[void] =
|
||||||
## Connects ``socket`` to server at ``address:port``.
|
## Connects ``socket`` to server at ``address:port``.
|
||||||
##
|
##
|
||||||
## Returns a ``PFuture`` which will complete when the connection succeeds
|
## Returns a ``PFuture`` which will complete when the connection succeeds
|
||||||
## or an error occurs.
|
## or an error occurs.
|
||||||
verifyPresence(p, socket)
|
verifyPresence(p, socket)
|
||||||
var retFuture = newFuture[int]()# TODO: Change to void when that regression is fixed.
|
var retFuture = newFuture[void]()
|
||||||
# Apparently ``ConnectEx`` expects the socket to be initially bound:
|
# Apparently ``ConnectEx`` expects the socket to be initially bound:
|
||||||
var saddr: Tsockaddr_in
|
var saddr: Tsockaddr_in
|
||||||
saddr.sin_family = int16(toInt(af))
|
saddr.sin_family = int16(toInt(af))
|
||||||
|
|
@ -271,7 +280,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
proc (sock: TSocketHandle, bytesCount: DWord, errcode: TOSErrorCode) =
|
proc (sock: TSocketHandle, bytesCount: DWord, errcode: TOSErrorCode) =
|
||||||
if not retFuture.finished:
|
if not retFuture.finished:
|
||||||
if errcode == TOSErrorCode(-1):
|
if errcode == TOSErrorCode(-1):
|
||||||
retFuture.complete(0)
|
retFuture.complete()
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(errcode)))
|
retFuture.fail(newException(EOS, osErrorMsg(errcode)))
|
||||||
)
|
)
|
||||||
|
|
@ -281,7 +290,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
if ret:
|
if ret:
|
||||||
# Request to connect completed immediately.
|
# Request to connect completed immediately.
|
||||||
success = true
|
success = true
|
||||||
retFuture.complete(0)
|
retFuture.complete()
|
||||||
# We don't deallocate ``ol`` here because even though this completed
|
# We don't deallocate ``ol`` here because even though this completed
|
||||||
# immediately poll will still be notified about its completion and it will
|
# immediately poll will still be notified about its completion and it will
|
||||||
# free ``ol``.
|
# free ``ol``.
|
||||||
|
|
@ -362,11 +371,11 @@ when defined(windows) or defined(nimdoc):
|
||||||
# free ``ol``.
|
# free ``ol``.
|
||||||
return retFuture
|
return retFuture
|
||||||
|
|
||||||
proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[int] =
|
proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[void] =
|
||||||
## Sends ``data`` to ``socket``. The returned future will complete once all
|
## Sends ``data`` to ``socket``. The returned future will complete once all
|
||||||
## data has been sent.
|
## data has been sent.
|
||||||
verifyPresence(p, socket)
|
verifyPresence(p, socket)
|
||||||
var retFuture = newFuture[int]()
|
var retFuture = newFuture[void]()
|
||||||
|
|
||||||
var dataBuf: TWSABuf
|
var dataBuf: TWSABuf
|
||||||
dataBuf.buf = data
|
dataBuf.buf = data
|
||||||
|
|
@ -378,7 +387,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
proc (sock: TSocketHandle, bytesCount: DWord, errcode: TOSErrorCode) =
|
proc (sock: TSocketHandle, bytesCount: DWord, errcode: TOSErrorCode) =
|
||||||
if not retFuture.finished:
|
if not retFuture.finished:
|
||||||
if errcode == TOSErrorCode(-1):
|
if errcode == TOSErrorCode(-1):
|
||||||
retFuture.complete(0)
|
retFuture.complete()
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(errcode)))
|
retFuture.fail(newException(EOS, osErrorMsg(errcode)))
|
||||||
)
|
)
|
||||||
|
|
@ -391,7 +400,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(err)))
|
retFuture.fail(newException(EOS, osErrorMsg(err)))
|
||||||
dealloc(ol)
|
dealloc(ol)
|
||||||
else:
|
else:
|
||||||
retFuture.complete(0)
|
retFuture.complete()
|
||||||
# We don't deallocate ``ol`` here because even though this completed
|
# We don't deallocate ``ol`` here because even though this completed
|
||||||
# immediately poll will still be notified about its completion and it will
|
# immediately poll will still be notified about its completion and it will
|
||||||
# free ``ol``.
|
# free ``ol``.
|
||||||
|
|
@ -564,12 +573,12 @@ else:
|
||||||
# (e.g. socket disconnected).
|
# (e.g. socket disconnected).
|
||||||
|
|
||||||
proc connect*(p: PDispatcher, socket: TSocketHandle, address: string, port: TPort,
|
proc connect*(p: PDispatcher, socket: TSocketHandle, address: string, port: TPort,
|
||||||
af = AF_INET): PFuture[int] =
|
af = AF_INET): PFuture[void] =
|
||||||
var retFuture = newFuture[int]()
|
var retFuture = newFuture[void]()
|
||||||
|
|
||||||
proc cb(sock: TSocketHandle): bool =
|
proc cb(sock: TSocketHandle): bool =
|
||||||
# We have connected.
|
# We have connected.
|
||||||
retFuture.complete(0)
|
retFuture.complete()
|
||||||
return true
|
return true
|
||||||
|
|
||||||
var aiList = getAddrInfo(address, port, af)
|
var aiList = getAddrInfo(address, port, af)
|
||||||
|
|
@ -581,7 +590,7 @@ else:
|
||||||
if ret == 0:
|
if ret == 0:
|
||||||
# Request to connect completed immediately.
|
# Request to connect completed immediately.
|
||||||
success = true
|
success = true
|
||||||
retFuture.complete(0)
|
retFuture.complete()
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
lastError = osLastError()
|
lastError = osLastError()
|
||||||
|
|
@ -635,8 +644,8 @@ else:
|
||||||
addRead(p, socket, cb)
|
addRead(p, socket, cb)
|
||||||
return retFuture
|
return retFuture
|
||||||
|
|
||||||
proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[int] =
|
proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[void] =
|
||||||
var retFuture = newFuture[int]()
|
var retFuture = newFuture[void]()
|
||||||
|
|
||||||
var written = 0
|
var written = 0
|
||||||
|
|
||||||
|
|
@ -656,7 +665,7 @@ else:
|
||||||
if res != netSize:
|
if res != netSize:
|
||||||
result = false # We still have data to send.
|
result = false # We still have data to send.
|
||||||
else:
|
else:
|
||||||
retFuture.complete(0)
|
retFuture.complete()
|
||||||
addWrite(p, socket, cb)
|
addWrite(p, socket, cb)
|
||||||
return retFuture
|
return retFuture
|
||||||
|
|
||||||
|
|
@ -789,12 +798,17 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||||
|
|
||||||
hint("Processing " & prc[0].getName & " as an async proc.")
|
hint("Processing " & prc[0].getName & " as an async proc.")
|
||||||
|
|
||||||
|
let returnType = prc[3][0]
|
||||||
|
var subtypeName = ""
|
||||||
# Verify that the return type is a PFuture[T]
|
# Verify that the return type is a PFuture[T]
|
||||||
if prc[3][0].kind == nnkIdent:
|
if returnType.kind == nnkIdent:
|
||||||
error("Expected return type of 'PFuture' got '" & $prc[3][0] & "'")
|
error("Expected return type of 'PFuture' got '" & $returnType & "'")
|
||||||
elif prc[3][0].kind == nnkBracketExpr:
|
elif returnType.kind == nnkBracketExpr:
|
||||||
if $prc[3][0][0] != "PFuture":
|
if $returnType[0] != "PFuture":
|
||||||
error("Expected return type of 'PFuture' got '" & $prc[3][0][0] & "'")
|
error("Expected return type of 'PFuture' got '" & $returnType[0] & "'")
|
||||||
|
subtypeName = $returnType[1].ident
|
||||||
|
elif returnType.kind == nnkEmpty:
|
||||||
|
subtypeName = "void"
|
||||||
|
|
||||||
# TODO: Why can't I use genSym? I get illegal capture errors for Syms.
|
# TODO: Why can't I use genSym? I get illegal capture errors for Syms.
|
||||||
# TODO: It seems genSym is broken. Change all usages back to genSym when fixed
|
# TODO: It seems genSym is broken. Change all usages back to genSym when fixed
|
||||||
|
|
@ -807,20 +821,24 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||||
newVarStmt(retFutureSym,
|
newVarStmt(retFutureSym,
|
||||||
newCall(
|
newCall(
|
||||||
newNimNode(nnkBracketExpr).add(
|
newNimNode(nnkBracketExpr).add(
|
||||||
newIdentNode("newFuture"),
|
newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
|
||||||
prc[3][0][1])))) # Get type from return type of this proc.
|
newIdentNode(subtypeName))))) # Get type from return type of this proc
|
||||||
|
echo(treeRepr(outerProcBody))
|
||||||
# -> iterator nameIter(): PFutureBase {.closure.} =
|
# -> iterator nameIter(): PFutureBase {.closure.} =
|
||||||
# -> var result: T
|
# -> var result: T
|
||||||
# -> <proc_body>
|
# -> <proc_body>
|
||||||
# -> complete(retFuture, result)
|
# -> complete(retFuture, result)
|
||||||
var iteratorNameSym = newIdentNode($prc[0].getName & "Iter") #genSym(nskIterator, $prc[0].ident & "Iter")
|
var iteratorNameSym = newIdentNode($prc[0].getName & "Iter") #genSym(nskIterator, $prc[0].ident & "Iter")
|
||||||
var procBody = prc[6].processBody(retFutureSym)
|
var procBody = prc[6].processBody(retFutureSym)
|
||||||
procBody.insert(0, newNimNode(nnkVarSection).add(
|
if subtypeName != "void":
|
||||||
newIdentDefs(newIdentNode("result"), prc[3][0][1]))) # -> var result: T
|
procBody.insert(0, newNimNode(nnkVarSection).add(
|
||||||
procBody.add(
|
newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
|
||||||
newCall(newIdentNode("complete"),
|
procBody.add(
|
||||||
retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
|
newCall(newIdentNode("complete"),
|
||||||
|
retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
|
||||||
|
else:
|
||||||
|
# -> complete(retFuture)
|
||||||
|
procBody.add(newCall(newIdentNode("complete"), retFutureSym))
|
||||||
|
|
||||||
var closureIterator = newProc(iteratorNameSym, [newIdentNode("PFutureBase")],
|
var closureIterator = newProc(iteratorNameSym, [newIdentNode("PFutureBase")],
|
||||||
procBody, nnkIteratorDef)
|
procBody, nnkIteratorDef)
|
||||||
|
|
@ -855,6 +873,12 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||||
for i in 0 .. <result[4].len:
|
for i in 0 .. <result[4].len:
|
||||||
if result[4][i].ident == !"async":
|
if result[4][i].ident == !"async":
|
||||||
result[4].del(i)
|
result[4].del(i)
|
||||||
|
if subtypeName == "void":
|
||||||
|
# Add discardable pragma.
|
||||||
|
result[4].add(newIdentNode("discardable"))
|
||||||
|
if returnType.kind == nnkEmpty:
|
||||||
|
# Add PFuture[void]
|
||||||
|
result[3][0] = parseExpr("PFuture[void]")
|
||||||
|
|
||||||
result[6] = outerProcBody
|
result[6] = outerProcBody
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,18 +14,18 @@ const
|
||||||
|
|
||||||
var clientCount = 0
|
var clientCount = 0
|
||||||
|
|
||||||
proc sendMessages(disp: PDispatcher, client: TSocketHandle): PFuture[int] {.async.} =
|
proc sendMessages(disp: PDispatcher, client: TSocketHandle) {.async.} =
|
||||||
for i in 0 .. <messagesToSend:
|
for i in 0 .. <messagesToSend:
|
||||||
discard await disp.send(client, "Message " & $i & "\c\L")
|
await disp.send(client, "Message " & $i & "\c\L")
|
||||||
|
|
||||||
proc launchSwarm(disp: PDispatcher, port: TPort): PFuture[int] {.async.} =
|
proc launchSwarm(disp: PDispatcher, port: TPort) {.async.} =
|
||||||
for i in 0 .. <swarmSize:
|
for i in 0 .. <swarmSize:
|
||||||
var sock = disp.socket()
|
var sock = disp.socket()
|
||||||
|
|
||||||
#disp.register(sock)
|
#disp.register(sock)
|
||||||
discard await disp.connect(sock, "localhost", port)
|
await disp.connect(sock, "localhost", port)
|
||||||
when true:
|
when true:
|
||||||
discard await sendMessages(disp, sock)
|
await sendMessages(disp, sock)
|
||||||
disp.close(sock)
|
disp.close(sock)
|
||||||
else:
|
else:
|
||||||
# Issue #932: https://github.com/Araq/Nimrod/issues/932
|
# Issue #932: https://github.com/Araq/Nimrod/issues/932
|
||||||
|
|
@ -34,7 +34,7 @@ proc launchSwarm(disp: PDispatcher, port: TPort): PFuture[int] {.async.} =
|
||||||
proc () =
|
proc () =
|
||||||
disp.close(sock)
|
disp.close(sock)
|
||||||
|
|
||||||
proc readMessages(disp: PDispatcher, client: TSocketHandle): PFuture[int] {.async.} =
|
proc readMessages(disp: PDispatcher, client: TSocketHandle) {.async.} =
|
||||||
while true:
|
while true:
|
||||||
var line = await disp.recvLine(client)
|
var line = await disp.recvLine(client)
|
||||||
if line == "":
|
if line == "":
|
||||||
|
|
@ -47,16 +47,18 @@ proc readMessages(disp: PDispatcher, client: TSocketHandle): PFuture[int] {.asyn
|
||||||
else:
|
else:
|
||||||
doAssert false
|
doAssert false
|
||||||
|
|
||||||
proc createServer(disp: PDispatcher, port: TPort): PFuture[int] {.async.} =
|
proc createServer(disp: PDispatcher, port: TPort) {.async.} =
|
||||||
var server = disp.socket()
|
var server = disp.socket()
|
||||||
#disp.register(server)
|
#disp.register(server)
|
||||||
server.bindAddr(port)
|
server.bindAddr(port)
|
||||||
server.listen()
|
server.listen()
|
||||||
while true:
|
while true:
|
||||||
discard readMessages(disp, await disp.accept(server))
|
var client = await disp.accept(server)
|
||||||
|
readMessages(disp, client)
|
||||||
|
# TODO: Test: readMessages(disp, await disp.accept(server))
|
||||||
|
|
||||||
discard disp.createServer(TPort(10335))
|
disp.createServer(TPort(10335))
|
||||||
discard disp.launchSwarm(TPort(10335))
|
disp.launchSwarm(TPort(10335))
|
||||||
while true:
|
while true:
|
||||||
disp.poll()
|
disp.poll()
|
||||||
if clientCount == swarmSize: break
|
if clientCount == swarmSize: break
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue