mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-03 10:24:44 +00:00
PFuture[void] now works.
Return types can also be completely ommitted. PFuture[void] will then be implicitly deduced.
This commit is contained in:
@@ -43,6 +43,14 @@ proc complete*[T](future: PFuture[T], val: T) =
|
||||
if future.cb != nil:
|
||||
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) =
|
||||
## Completes ``future`` with ``error``.
|
||||
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 future.finished:
|
||||
if future.error != nil: raise future.error
|
||||
return future.value
|
||||
when T isnot void:
|
||||
return future.value
|
||||
else:
|
||||
# TODO: Make a custom exception type for this?
|
||||
raise newException(EInvalidValue, "Future still in progress.")
|
||||
@@ -243,13 +252,13 @@ when defined(windows) or defined(nimdoc):
|
||||
RemoteSockaddr, RemoteSockaddrLength)
|
||||
|
||||
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``.
|
||||
##
|
||||
## Returns a ``PFuture`` which will complete when the connection succeeds
|
||||
## or an error occurs.
|
||||
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:
|
||||
var saddr: Tsockaddr_in
|
||||
saddr.sin_family = int16(toInt(af))
|
||||
@@ -271,7 +280,7 @@ when defined(windows) or defined(nimdoc):
|
||||
proc (sock: TSocketHandle, bytesCount: DWord, errcode: TOSErrorCode) =
|
||||
if not retFuture.finished:
|
||||
if errcode == TOSErrorCode(-1):
|
||||
retFuture.complete(0)
|
||||
retFuture.complete()
|
||||
else:
|
||||
retFuture.fail(newException(EOS, osErrorMsg(errcode)))
|
||||
)
|
||||
@@ -281,7 +290,7 @@ when defined(windows) or defined(nimdoc):
|
||||
if ret:
|
||||
# Request to connect completed immediately.
|
||||
success = true
|
||||
retFuture.complete(0)
|
||||
retFuture.complete()
|
||||
# We don't deallocate ``ol`` here because even though this completed
|
||||
# immediately poll will still be notified about its completion and it will
|
||||
# free ``ol``.
|
||||
@@ -362,11 +371,11 @@ when defined(windows) or defined(nimdoc):
|
||||
# free ``ol``.
|
||||
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
|
||||
## data has been sent.
|
||||
verifyPresence(p, socket)
|
||||
var retFuture = newFuture[int]()
|
||||
var retFuture = newFuture[void]()
|
||||
|
||||
var dataBuf: TWSABuf
|
||||
dataBuf.buf = data
|
||||
@@ -378,7 +387,7 @@ when defined(windows) or defined(nimdoc):
|
||||
proc (sock: TSocketHandle, bytesCount: DWord, errcode: TOSErrorCode) =
|
||||
if not retFuture.finished:
|
||||
if errcode == TOSErrorCode(-1):
|
||||
retFuture.complete(0)
|
||||
retFuture.complete()
|
||||
else:
|
||||
retFuture.fail(newException(EOS, osErrorMsg(errcode)))
|
||||
)
|
||||
@@ -391,7 +400,7 @@ when defined(windows) or defined(nimdoc):
|
||||
retFuture.fail(newException(EOS, osErrorMsg(err)))
|
||||
dealloc(ol)
|
||||
else:
|
||||
retFuture.complete(0)
|
||||
retFuture.complete()
|
||||
# We don't deallocate ``ol`` here because even though this completed
|
||||
# immediately poll will still be notified about its completion and it will
|
||||
# free ``ol``.
|
||||
@@ -564,12 +573,12 @@ else:
|
||||
# (e.g. socket disconnected).
|
||||
|
||||
proc connect*(p: PDispatcher, socket: TSocketHandle, address: string, port: TPort,
|
||||
af = AF_INET): PFuture[int] =
|
||||
var retFuture = newFuture[int]()
|
||||
af = AF_INET): PFuture[void] =
|
||||
var retFuture = newFuture[void]()
|
||||
|
||||
proc cb(sock: TSocketHandle): bool =
|
||||
# We have connected.
|
||||
retFuture.complete(0)
|
||||
retFuture.complete()
|
||||
return true
|
||||
|
||||
var aiList = getAddrInfo(address, port, af)
|
||||
@@ -581,7 +590,7 @@ else:
|
||||
if ret == 0:
|
||||
# Request to connect completed immediately.
|
||||
success = true
|
||||
retFuture.complete(0)
|
||||
retFuture.complete()
|
||||
break
|
||||
else:
|
||||
lastError = osLastError()
|
||||
@@ -635,8 +644,8 @@ else:
|
||||
addRead(p, socket, cb)
|
||||
return retFuture
|
||||
|
||||
proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[int] =
|
||||
var retFuture = newFuture[int]()
|
||||
proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[void] =
|
||||
var retFuture = newFuture[void]()
|
||||
|
||||
var written = 0
|
||||
|
||||
@@ -656,7 +665,7 @@ else:
|
||||
if res != netSize:
|
||||
result = false # We still have data to send.
|
||||
else:
|
||||
retFuture.complete(0)
|
||||
retFuture.complete()
|
||||
addWrite(p, socket, cb)
|
||||
return retFuture
|
||||
|
||||
@@ -789,12 +798,17 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||
|
||||
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]
|
||||
if prc[3][0].kind == nnkIdent:
|
||||
error("Expected return type of 'PFuture' got '" & $prc[3][0] & "'")
|
||||
elif prc[3][0].kind == nnkBracketExpr:
|
||||
if $prc[3][0][0] != "PFuture":
|
||||
error("Expected return type of 'PFuture' got '" & $prc[3][0][0] & "'")
|
||||
if returnType.kind == nnkIdent:
|
||||
error("Expected return type of 'PFuture' got '" & $returnType & "'")
|
||||
elif returnType.kind == nnkBracketExpr:
|
||||
if $returnType[0] != "PFuture":
|
||||
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: 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,
|
||||
newCall(
|
||||
newNimNode(nnkBracketExpr).add(
|
||||
newIdentNode("newFuture"),
|
||||
prc[3][0][1])))) # Get type from return type of this proc.
|
||||
|
||||
newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
|
||||
newIdentNode(subtypeName))))) # Get type from return type of this proc
|
||||
echo(treeRepr(outerProcBody))
|
||||
# -> iterator nameIter(): PFutureBase {.closure.} =
|
||||
# -> var result: T
|
||||
# -> <proc_body>
|
||||
# -> complete(retFuture, result)
|
||||
var iteratorNameSym = newIdentNode($prc[0].getName & "Iter") #genSym(nskIterator, $prc[0].ident & "Iter")
|
||||
var procBody = prc[6].processBody(retFutureSym)
|
||||
procBody.insert(0, newNimNode(nnkVarSection).add(
|
||||
newIdentDefs(newIdentNode("result"), prc[3][0][1]))) # -> var result: T
|
||||
procBody.add(
|
||||
newCall(newIdentNode("complete"),
|
||||
retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
|
||||
if subtypeName != "void":
|
||||
procBody.insert(0, newNimNode(nnkVarSection).add(
|
||||
newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
|
||||
procBody.add(
|
||||
newCall(newIdentNode("complete"),
|
||||
retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
|
||||
else:
|
||||
# -> complete(retFuture)
|
||||
procBody.add(newCall(newIdentNode("complete"), retFutureSym))
|
||||
|
||||
var closureIterator = newProc(iteratorNameSym, [newIdentNode("PFutureBase")],
|
||||
procBody, nnkIteratorDef)
|
||||
@@ -855,6 +873,12 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||
for i in 0 .. <result[4].len:
|
||||
if result[4][i].ident == !"async":
|
||||
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
|
||||
|
||||
|
||||
@@ -14,18 +14,18 @@ const
|
||||
|
||||
var clientCount = 0
|
||||
|
||||
proc sendMessages(disp: PDispatcher, client: TSocketHandle): PFuture[int] {.async.} =
|
||||
proc sendMessages(disp: PDispatcher, client: TSocketHandle) {.async.} =
|
||||
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:
|
||||
var sock = disp.socket()
|
||||
|
||||
#disp.register(sock)
|
||||
discard await disp.connect(sock, "localhost", port)
|
||||
await disp.connect(sock, "localhost", port)
|
||||
when true:
|
||||
discard await sendMessages(disp, sock)
|
||||
await sendMessages(disp, sock)
|
||||
disp.close(sock)
|
||||
else:
|
||||
# Issue #932: https://github.com/Araq/Nimrod/issues/932
|
||||
@@ -34,7 +34,7 @@ proc launchSwarm(disp: PDispatcher, port: TPort): PFuture[int] {.async.} =
|
||||
proc () =
|
||||
disp.close(sock)
|
||||
|
||||
proc readMessages(disp: PDispatcher, client: TSocketHandle): PFuture[int] {.async.} =
|
||||
proc readMessages(disp: PDispatcher, client: TSocketHandle) {.async.} =
|
||||
while true:
|
||||
var line = await disp.recvLine(client)
|
||||
if line == "":
|
||||
@@ -47,16 +47,18 @@ proc readMessages(disp: PDispatcher, client: TSocketHandle): PFuture[int] {.asyn
|
||||
else:
|
||||
doAssert false
|
||||
|
||||
proc createServer(disp: PDispatcher, port: TPort): PFuture[int] {.async.} =
|
||||
proc createServer(disp: PDispatcher, port: TPort) {.async.} =
|
||||
var server = disp.socket()
|
||||
#disp.register(server)
|
||||
server.bindAddr(port)
|
||||
server.listen()
|
||||
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))
|
||||
discard disp.launchSwarm(TPort(10335))
|
||||
disp.createServer(TPort(10335))
|
||||
disp.launchSwarm(TPort(10335))
|
||||
while true:
|
||||
disp.poll()
|
||||
if clientCount == swarmSize: break
|
||||
|
||||
Reference in New Issue
Block a user