use single backtick (#17166)

This commit is contained in:
flywind
2021-02-23 23:05:39 -06:00
committed by GitHub
parent c274e67198
commit 47c078e29c
12 changed files with 305 additions and 305 deletions

View File

@@ -8,25 +8,25 @@
#
## This module implements asynchronous IO. This includes a dispatcher,
## a ``Future`` type implementation, and an ``async`` macro which allows
## asynchronous code to be written in a synchronous style with the ``await``
## a `Future` type implementation, and an `async` macro which allows
## asynchronous code to be written in a synchronous style with the `await`
## keyword.
##
## The dispatcher acts as a kind of event loop. You must call ``poll`` on it
## (or a function which does so for you such as ``waitFor`` or ``runForever``)
## The dispatcher acts as a kind of event loop. You must call `poll` on it
## (or a function which does so for you such as `waitFor` or `runForever`)
## in order to poll for any outstanding events. The underlying implementation
## is based on epoll on Linux, IO Completion Ports on Windows and select on
## other operating systems.
##
## The ``poll`` function will not, on its own, return any events. Instead
## an appropriate ``Future`` object will be completed. A ``Future`` is a
## The `poll` function will not, on its own, return any events. Instead
## an appropriate `Future` object will be completed. A `Future` is a
## type which holds a value which is not yet available, but which *may* be
## available in the future. You can check whether a future is finished
## by using the ``finished`` function. When a future is finished it means that
## by using the `finished` function. When a future is finished it means that
## either the value that it holds is now available or it holds an error instead.
## The latter situation occurs when the operation to complete a future fails
## with an exception. You can distinguish between the two situations with the
## ``failed`` function.
## `failed` function.
##
## Future objects can also store a callback procedure which will be called
## automatically once the future completes.
@@ -35,9 +35,9 @@
## pattern. In this
## pattern you make a request for an action, and once that action is fulfilled
## a future is completed with the result of that action. Requests can be
## made by calling the appropriate functions. For example: calling the ``recv``
## made by calling the appropriate functions. For example: calling the `recv`
## function will create a request for some data to be read from a socket. The
## future which the ``recv`` function returns will then complete once the
## future which the `recv` function returns will then complete once the
## requested amount of data is read **or** an exception occurs.
##
## Code to read some data from a socket may look something like this:
@@ -49,18 +49,18 @@
## echo(future.read)
## )
##
## All asynchronous functions returning a ``Future`` will not block. They
## All asynchronous functions returning a `Future` will not block. They
## will not however return immediately. An asynchronous function will have
## code which will be executed before an asynchronous request is made, in most
## cases this code sets up the request.
##
## In the above example, the ``recv`` function will return a brand new
## ``Future`` instance once the request for data to be read from the socket
## is made. This ``Future`` instance will complete once the requested amount
## In the above example, the `recv` function will return a brand new
## `Future` instance once the request for data to be read from the socket
## is made. This `Future` instance will complete once the requested amount
## of data is read, in this case it is 100 bytes. The second line sets a
## callback on this future which will be called once the future completes.
## All the callback does is write the data stored in the future to ``stdout``.
## The ``read`` function is used for this and it checks whether the future
## All the callback does is write the data stored in the future to `stdout`.
## The `read` function is used for this and it checks whether the future
## completes with an error for you (if it did it will simply raise the
## error), if there is no error however it returns the value of the future.
##
@@ -71,14 +71,14 @@
## this by allowing you to write asynchronous code the same way as you would
## write synchronous code.
##
## An asynchronous procedure is marked using the ``{.async.}`` pragma.
## When marking a procedure with the ``{.async.}`` pragma it must have a
## ``Future[T]`` return type or no return type at all. If you do not specify
## a return type then ``Future[void]`` is assumed.
## An asynchronous procedure is marked using the `{.async.}` pragma.
## When marking a procedure with the `{.async.}` pragma it must have a
## `Future[T]` return type or no return type at all. If you do not specify
## a return type then `Future[void]` is assumed.
##
## Inside asynchronous procedures ``await`` can be used to call any
## Inside asynchronous procedures `await` can be used to call any
## procedures which return a
## ``Future``; this includes asynchronous procedures. When a procedure is
## `Future`; this includes asynchronous procedures. When a procedure is
## "awaited", the asynchronous procedure it is awaited in will
## suspend its execution
## until the awaited procedure's Future completes. At which point the
@@ -86,23 +86,23 @@
## when an asynchronous procedure is suspended other asynchronous procedures
## will be run by the dispatcher.
##
## The ``await`` call may be used in many contexts. It can be used on the right
## hand side of a variable declaration: ``var data = await socket.recv(100)``,
## The `await` call may be used in many contexts. It can be used on the right
## hand side of a variable declaration: `var data = await socket.recv(100)`,
## in which case the variable will be set to the value of the future
## automatically. It can be used to await a ``Future`` object, and it can
## be used to await a procedure returning a ``Future[void]``:
## ``await socket.send("foobar")``.
## automatically. It can be used to await a `Future` object, and it can
## be used to await a procedure returning a `Future[void]`:
## `await socket.send("foobar")`.
##
## If an awaited future completes with an error, then ``await`` will re-raise
## this error. To avoid this, you can use the ``yield`` keyword instead of
## ``await``. The following section shows different ways that you can handle
## If an awaited future completes with an error, then `await` will re-raise
## this error. To avoid this, you can use the `yield` keyword instead of
## `await`. The following section shows different ways that you can handle
## exceptions in async procs.
##
## Handling Exceptions
## -------------------
##
## The most reliable way to handle exceptions is to use ``yield`` on a future
## then check the future's ``failed`` property. For example:
## The most reliable way to handle exceptions is to use `yield` on a future
## then check the future's `failed` property. For example:
##
## .. code-block:: Nim
## var future = sock.recv(100)
@@ -110,7 +110,7 @@
## if future.failed:
## # Handle exception
##
## The ``async`` procedures also offer limited support for the try statement.
## The `async` procedures also offer limited support for the try statement.
##
## .. code-block:: Nim
## try:
@@ -129,9 +129,9 @@
##
## Futures should **never** be discarded. This is because they may contain
## errors. If you do not care for the result of a Future then you should
## use the ``asyncCheck`` procedure instead of the ``discard`` keyword. Note
## use the `asyncCheck` procedure instead of the `discard` keyword. Note
## however that this does not wait for completion, and you should use
## ``waitFor`` for that purpose.
## `waitFor` for that purpose.
##
## Examples
## ========
@@ -144,14 +144,14 @@
## =============================
##
## It's possible to get into a situation where an async proc, or more accurately
## a ``Future[T]`` gets stuck and
## a `Future[T]` gets stuck and
## never completes. This can happen for various reasons and can cause serious
## memory leaks. When this occurs it's hard to identify the procedure that is
## stuck.
##
## Thankfully there is a mechanism which tracks the count of each pending future.
## All you need to do to enable it is compile with ``-d:futureLogging`` and
## use the ``getFuturesInProgress`` procedure to get the list of pending futures
## All you need to do to enable it is compile with `-d:futureLogging` and
## use the `getFuturesInProgress` procedure to get the list of pending futures
## together with the stack traces to the moment of their creation.
##
## You may also find it useful to use this
@@ -164,7 +164,7 @@
## Limitations/Bugs
## ================
##
## * The effect system (``raises: []``) does not work with async procedures.
## * The effect system (`raises: []`) does not work with async procedures.
import os, tables, strutils, times, heapqueue, options, asyncstreams
import options, math, std/monotimes
@@ -232,7 +232,7 @@ template implementSetInheritable() {.dirty.} =
when declared(setInheritable):
proc setInheritable*(fd: AsyncFD, inheritable: bool): bool =
## Control whether a file handle can be inherited by child processes.
## Returns ``true`` on success.
## Returns `true` on success.
##
## This procedure is not guaranteed to be available for all platforms.
## Test for availability with `declared() <system.html#declared,untyped>`_.
@@ -307,7 +307,7 @@ when defined(windows) or defined(nimdoc):
return disp.ioPort
proc register*(fd: AsyncFD) =
## Registers ``fd`` with the dispatcher.
## Registers `fd` with the dispatcher.
let p = getGlobalDispatcher()
if createIoCompletionPort(fd.Handle, p.ioPort,
@@ -430,16 +430,16 @@ when defined(windows) or defined(nimdoc):
proc recv*(socket: AsyncFD, size: int,
flags = {SocketFlag.SafeDisconn}): owned(Future[string]) =
## Reads **up to** ``size`` bytes from ``socket``. Returned future will
## Reads **up to** `size` bytes from `socket`. Returned future will
## complete once all the data requested is read, a part of the data has been
## read, or the socket has disconnected in which case the future will
## complete with a value of ``""``.
## complete with a value of `""`.
##
## **Warning**: The ``Peek`` socket flag is not supported on Windows.
## **Warning**: The `Peek` socket flag is not supported on Windows.
# Things to note:
# * When WSARecv completes immediately then ``bytesReceived`` is very
# * When WSARecv completes immediately then `bytesReceived` is very
# unreliable.
# * Still need to implement message-oriented socket disconnection,
# '\0' in the message currently signifies a socket disconnect. Who
@@ -503,17 +503,17 @@ when defined(windows) or defined(nimdoc):
proc recvInto*(socket: AsyncFD, buf: pointer, size: int,
flags = {SocketFlag.SafeDisconn}): owned(Future[int]) =
## Reads **up to** ``size`` bytes from ``socket`` into ``buf``, which must
## Reads **up to** `size` bytes from `socket` into `buf`, which must
## at least be of that size. Returned future will complete once all the
## data requested is read, a part of the data has been read, or the socket
## has disconnected in which case the future will complete with a value of
## ``0``.
## `0`.
##
## **Warning**: The ``Peek`` socket flag is not supported on Windows.
## **Warning**: The `Peek` socket flag is not supported on Windows.
# Things to note:
# * When WSARecv completes immediately then ``bytesReceived`` is very
# * When WSARecv completes immediately then `bytesReceived` is very
# unreliable.
# * Still need to implement message-oriented socket disconnection,
# '\0' in the message currently signifies a socket disconnect. Who
@@ -569,10 +569,10 @@ when defined(windows) or defined(nimdoc):
proc send*(socket: AsyncFD, buf: pointer, size: int,
flags = {SocketFlag.SafeDisconn}): owned(Future[void]) =
## Sends ``size`` bytes from ``buf`` to ``socket``. The returned future
## Sends `size` bytes from `buf` to `socket`. The returned future
## will complete once all data has been sent.
##
## **WARNING**: Use it with caution. If ``buf`` refers to GC'ed object,
## **WARNING**: Use it with caution. If `buf` refers to GC'ed object,
## you must use GC_ref/GC_unref calls to avoid early freeing of the buffer.
verifyPresence(socket)
var retFuture = newFuture[void]("send")
@@ -607,16 +607,16 @@ when defined(windows) or defined(nimdoc):
retFuture.fail(newException(OSError, osErrorMsg(err)))
else:
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
# free ``ol``.
# free `ol`.
return retFuture
proc sendTo*(socket: AsyncFD, data: pointer, size: int, saddr: ptr SockAddr,
saddrLen: SockLen,
flags = {SocketFlag.SafeDisconn}): owned(Future[void]) =
## Sends ``data`` to specified destination ``saddr``, using
## socket ``socket``. The returned future will complete once all data
## Sends `data` to specified destination `saddr`, using
## socket `socket`. The returned future will complete once all data
## has been sent.
verifyPresence(socket)
var retFuture = newFuture[void]("sendTo")
@@ -652,17 +652,17 @@ when defined(windows) or defined(nimdoc):
retFuture.fail(newException(OSError, osErrorMsg(err)))
else:
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
# free ``ol``.
# free `ol`.
return retFuture
proc recvFromInto*(socket: AsyncFD, data: pointer, size: int,
saddr: ptr SockAddr, saddrLen: ptr SockLen,
flags = {SocketFlag.SafeDisconn}): owned(Future[int]) =
## Receives a datagram data from ``socket`` into ``buf``, which must
## be at least of size ``size``, address of datagram's sender will be
## stored into ``saddr`` and ``saddrLen``. Returned future will complete
## Receives a datagram data from `socket` into `buf`, which must
## be at least of size `size`, address of datagram's sender will be
## stored into `saddr` and `saddrLen`. Returned future will complete
## once one datagram has been received, and will return size of packet
## received.
verifyPresence(socket)
@@ -715,11 +715,11 @@ when defined(windows) or defined(nimdoc):
## The resulting client socket is automatically registered to the
## dispatcher.
##
## If ``inheritable`` is false (the default), the resulting client socket will
## If `inheritable` is false (the default), the resulting client socket will
## not be inheritable by child processes.
##
## The ``accept`` call may result in an error if the connecting socket
## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
## The `accept` call may result in an error if the connecting socket
## disconnects during the duration of the `accept`. If the `SafeDisconn`
## flag is specified then this error will not be raised and instead
## accept will be called again.
verifyPresence(socket)
@@ -796,9 +796,9 @@ when defined(windows) or defined(nimdoc):
GC_unref(ol)
else:
completeAccept()
# 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
# free ``ol``.
# free `ol`.
return retFuture
@@ -810,7 +810,7 @@ when defined(windows) or defined(nimdoc):
getGlobalDispatcher().handles.excl(socket)
proc unregister*(fd: AsyncFD) =
## Unregisters ``fd``.
## Unregisters `fd`.
getGlobalDispatcher().handles.excl(fd)
proc contains*(disp: PDispatcher, fd: AsyncFD): bool =
@@ -910,9 +910,9 @@ when defined(windows) or defined(nimdoc):
proc addRead*(fd: AsyncFD, cb: Callback) =
## Start watching the file descriptor for read availability and then call
## the callback ``cb``.
## the callback `cb`.
##
## This is not ``pure`` mechanism for Windows Completion Ports (IOCP),
## This is not `pure` mechanism for Windows Completion Ports (IOCP),
## so if you can avoid it, please do it. Use `addRead` only if really
## need it (main usecase is adaptation of unix-like libraries to be
## asynchronous on Windows).
@@ -921,16 +921,16 @@ when defined(windows) or defined(nimdoc):
## or asyncdispatch.accept(), because they are using IOCP, please use
## nativesockets.recv() and nativesockets.accept() instead.
##
## Be sure your callback ``cb`` returns ``true``, if you want to remove
## watch of `read` notifications, and ``false``, if you want to continue
## Be sure your callback `cb` returns `true`, if you want to remove
## watch of `read` notifications, and `false`, if you want to continue
## receiving notifications.
registerWaitableEvent(fd, cb, FD_READ or FD_ACCEPT or FD_OOB or FD_CLOSE)
proc addWrite*(fd: AsyncFD, cb: Callback) =
## Start watching the file descriptor for write availability and then call
## the callback ``cb``.
## the callback `cb`.
##
## This is not ``pure`` mechanism for Windows Completion Ports (IOCP),
## This is not `pure` mechanism for Windows Completion Ports (IOCP),
## so if you can avoid it, please do it. Use `addWrite` only if really
## need it (main usecase is adaptation of unix-like libraries to be
## asynchronous on Windows).
@@ -939,8 +939,8 @@ when defined(windows) or defined(nimdoc):
## or asyncdispatch.connect(), because they are using IOCP, please use
## nativesockets.send() and nativesockets.connect() instead.
##
## Be sure your callback ``cb`` returns ``true``, if you want to remove
## watch of `write` notifications, and ``false``, if you want to continue
## Be sure your callback `cb` returns `true`, if you want to remove
## watch of `write` notifications, and `false`, if you want to continue
## receiving notifications.
registerWaitableEvent(fd, cb, FD_WRITE or FD_CONNECT or FD_CLOSE)
@@ -980,12 +980,12 @@ when defined(windows) or defined(nimdoc):
raiseOSError(osLastError())
proc addTimer*(timeout: int, oneshot: bool, cb: Callback) =
## Registers callback ``cb`` to be called when timer expired.
## Registers callback `cb` to be called when timer expired.
##
## Parameters:
##
## * ``timeout`` - timeout value in milliseconds.
## * ``oneshot``
## * `timeout` - timeout value in milliseconds.
## * `oneshot`
## * `true` - generate only one timeout event
## * `false` - generate timeout events periodically
@@ -1014,8 +1014,8 @@ when defined(windows) or defined(nimdoc):
registerWaitableHandle(p, hEvent, flags, pcd, timeout, timercb)
proc addProcess*(pid: int, cb: Callback) =
## Registers callback ``cb`` to be called when process with process ID
## ``pid`` exited.
## Registers callback `cb` to be called when process with process ID
## `pid` exited.
const NULL = Handle(0)
let p = getGlobalDispatcher()
let procFlags = SYNCHRONIZE
@@ -1033,10 +1033,10 @@ when defined(windows) or defined(nimdoc):
registerWaitableHandle(p, hProcess, flags, pcd, INFINITE, proccb)
proc newAsyncEvent*(): AsyncEvent =
## Creates a new thread-safe ``AsyncEvent`` object.
## Creates a new thread-safe `AsyncEvent` object.
##
## New ``AsyncEvent`` object is not automatically registered with
## dispatcher like ``AsyncSocket``.
## New `AsyncEvent` object is not automatically registered with
## dispatcher like `AsyncSocket`.
var sa = SECURITY_ATTRIBUTES(
nLength: sizeof(SECURITY_ATTRIBUTES).cint,
bInheritHandle: 1
@@ -1048,12 +1048,12 @@ when defined(windows) or defined(nimdoc):
result.hEvent = event
proc trigger*(ev: AsyncEvent) =
## Set event ``ev`` to signaled state.
## Set event `ev` to signaled state.
if setEvent(ev.hEvent) == 0:
raiseOSError(osLastError())
proc unregister*(ev: AsyncEvent) =
## Unregisters event ``ev``.
## Unregisters event `ev`.
doAssert(ev.hWaiter != 0, "Event is not registered in the queue!")
let p = getGlobalDispatcher()
p.handles.excl(AsyncFD(ev.hEvent))
@@ -1064,14 +1064,14 @@ when defined(windows) or defined(nimdoc):
ev.hWaiter = 0
proc close*(ev: AsyncEvent) =
## Closes event ``ev``.
## Closes event `ev`.
let res = closeHandle(ev.hEvent)
deallocShared(cast[pointer](ev))
if res == 0:
raiseOSError(osLastError())
proc addEvent*(ev: AsyncEvent, cb: Callback) =
## Registers callback ``cb`` to be called when ``ev`` will be signaled
## Registers callback `cb` to be called when `ev` will be signaled
doAssert(ev.hWaiter == 0, "Event is already registered in the queue!")
let p = getGlobalDispatcher()
@@ -1460,8 +1460,8 @@ else:
proc sendTo*(socket: AsyncFD, data: pointer, size: int, saddr: ptr SockAddr,
saddrLen: SockLen,
flags = {SocketFlag.SafeDisconn}): owned(Future[void]) =
## Sends ``data`` of size ``size`` in bytes to specified destination
## (``saddr`` of size ``saddrLen`` in bytes, using socket ``socket``.
## Sends `data` of size `size` in bytes to specified destination
## (`saddr` of size `saddrLen` in bytes, using socket `socket`.
## The returned future will complete once all data has been sent.
var retFuture = newFuture[void]("sendTo")
@@ -1491,9 +1491,9 @@ else:
proc recvFromInto*(socket: AsyncFD, data: pointer, size: int,
saddr: ptr SockAddr, saddrLen: ptr SockLen,
flags = {SocketFlag.SafeDisconn}): owned(Future[int]) =
## Receives a datagram data from ``socket`` into ``data``, which must
## be at least of size ``size`` in bytes, address of datagram's sender
## will be stored into ``saddr`` and ``saddrLen``. Returned future will
## Receives a datagram data from `socket` into `data`, which must
## be at least of size `size` in bytes, address of datagram's sender
## will be stored into `saddr` and `saddrLen`. Returned future will
## complete once one datagram has been received, and will return size
## of packet received.
var retFuture = newFuture[int]("recvFromInto")
@@ -1563,45 +1563,45 @@ else:
proc addTimer*(timeout: int, oneshot: bool, cb: Callback) =
## Start watching for timeout expiration, and then call the
## callback ``cb``.
## ``timeout`` - time in milliseconds,
## ``oneshot`` - if ``true`` only one event will be dispatched,
## if ``false`` continuous events every ``timeout`` milliseconds.
## callback `cb`.
## `timeout` - time in milliseconds,
## `oneshot` - if `true` only one event will be dispatched,
## if `false` continuous events every `timeout` milliseconds.
let p = getGlobalDispatcher()
var data = newAsyncData()
data.readList.add(cb)
p.selector.registerTimer(timeout, oneshot, data)
proc addSignal*(signal: int, cb: Callback) =
## Start watching signal ``signal``, and when signal appears, call the
## callback ``cb``.
## Start watching signal `signal`, and when signal appears, call the
## callback `cb`.
let p = getGlobalDispatcher()
var data = newAsyncData()
data.readList.add(cb)
p.selector.registerSignal(signal, data)
proc addProcess*(pid: int, cb: Callback) =
## Start watching for process exit with pid ``pid``, and then call
## the callback ``cb``.
## Start watching for process exit with pid `pid`, and then call
## the callback `cb`.
let p = getGlobalDispatcher()
var data = newAsyncData()
data.readList.add(cb)
p.selector.registerProcess(pid, data)
proc newAsyncEvent*(): AsyncEvent =
## Creates new ``AsyncEvent``.
## Creates new `AsyncEvent`.
result = AsyncEvent(newSelectEvent())
proc trigger*(ev: AsyncEvent) =
## Sets new ``AsyncEvent`` to signaled state.
## Sets new `AsyncEvent` to signaled state.
trigger(SelectEvent(ev))
proc close*(ev: AsyncEvent) =
## Closes ``AsyncEvent``
## Closes `AsyncEvent`
close(SelectEvent(ev))
proc addEvent*(ev: AsyncEvent, cb: Callback) =
## Start watching for event ``ev``, and call callback ``cb``, when
## Start watching for event `ev`, and call callback `cb`, when
## ev will be set to signaled state.
let p = getGlobalDispatcher()
var data = newAsyncData()
@@ -1609,8 +1609,8 @@ else:
p.selector.registerEvent(SelectEvent(ev), data)
proc drain*(timeout = 500) =
## Waits for completion of **all** events and processes them. Raises ``ValueError``
## if there are no pending operations. In contrast to ``poll`` this
## Waits for completion of **all** events and processes them. Raises `ValueError`
## if there are no pending operations. In contrast to `poll` this
## processes as many events as are available until the timeout has elapsed.
var curTimeout = timeout
let start = now()
@@ -1621,7 +1621,7 @@ proc drain*(timeout = 500) =
break
proc poll*(timeout = 500) =
## Waits for completion events and processes them. Raises ``ValueError``
## Waits for completion events and processes them. Raises `ValueError`
## if there are no pending operations. This runs the underlying OS
## `epoll`:idx: or `kqueue`:idx: primitive only once.
discard runOnce(timeout)
@@ -1686,13 +1686,13 @@ when defined(windows) or defined(nimdoc):
if ret:
# Request to connect completed immediately.
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 free ``ol``.
# will free `ol`.
else:
let lastError = osLastError()
if lastError.int32 != ERROR_IO_PENDING:
# With ERROR_IO_PENDING ``ol`` will be deallocated in ``poll``,
# With ERROR_IO_PENDING `ol` will be deallocated in `poll`,
# and the future will be completed/failed there, too.
GC_unref(ol)
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
@@ -1802,9 +1802,9 @@ template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped,
proc dial*(address: string, port: Port,
protocol: Protocol = IPPROTO_TCP): owned(Future[AsyncFD]) =
## Establishes connection to the specified ``address``:``port`` pair via the
## Establishes connection to the specified `address`:`port` pair via the
## specified protocol. The procedure iterates through possible
## resolutions of the ``address`` until it succeeds, meaning that it
## resolutions of the `address` until it succeeds, meaning that it
## seamlessly works with both IPv4 and IPv6.
## Returns the async file descriptor, registered in the dispatcher of
## the current thread, ready to send or receive data.
@@ -1832,7 +1832,7 @@ proc connect*(socket: AsyncFD, address: string, port: Port,
proc sleepAsync*(ms: int | float): owned(Future[void]) =
## Suspends the execution of the current async procedure for the next
## ``ms`` milliseconds.
## `ms` milliseconds.
var retFuture = newFuture[void]("sleepAsync")
let p = getGlobalDispatcher()
when ms is int:
@@ -1843,11 +1843,11 @@ proc sleepAsync*(ms: int | float): owned(Future[void]) =
return retFuture
proc withTimeout*[T](fut: Future[T], timeout: int): owned(Future[bool]) =
## Returns a future which will complete once ``fut`` completes or after
## ``timeout`` milliseconds has elapsed.
## Returns a future which will complete once `fut` completes or after
## `timeout` milliseconds has elapsed.
##
## If ``fut`` completes first the returned future will hold true,
## otherwise, if ``timeout`` milliseconds has elapsed first, the returned
## If `fut` completes first the returned future will hold true,
## otherwise, if `timeout` milliseconds has elapsed first, the returned
## future will hold false.
var retFuture = newFuture[bool]("asyncdispatch.`withTimeout`")
@@ -1870,7 +1870,7 @@ proc accept*(socket: AsyncFD,
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection.
##
## If ``inheritable`` is false (the default), the resulting client socket
## If `inheritable` is false (the default), the resulting client socket
## will not be inheritable by child processes.
##
## The future will complete when the connection is successfully accepted.
@@ -1890,7 +1890,7 @@ proc keepAlive(x: string) =
proc send*(socket: AsyncFD, data: string,
flags = {SocketFlag.SafeDisconn}): owned(Future[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.
var retFuture = newFuture[void]("send")
if data.len > 0:

View File

@@ -90,8 +90,8 @@ proc newAsyncFile*(fd: AsyncFD): AsyncFile =
register(fd)
proc openAsync*(filename: string, mode = fmRead): AsyncFile =
## Opens a file specified by the path in ``filename`` using
## the specified FileMode ``mode`` asynchronously.
## Opens a file specified by the path in `filename` using
## the specified FileMode `mode` asynchronously.
when defined(windows) or defined(nimdoc):
let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
let desiredAccess = getDesiredAccess(mode)
@@ -124,11 +124,11 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
result = newAsyncFile(fd.AsyncFD)
proc readBuffer*(f: AsyncFile, buf: pointer, size: int): Future[int] =
## Read ``size`` bytes from the specified file asynchronously starting at
## Read `size` bytes from the specified file asynchronously starting at
## the current position of the file pointer.
##
## If the file pointer is past the end of the file then zero is returned
## and no bytes are read into ``buf``
## and no bytes are read into `buf`
var retFuture = newFuture[int]("asyncfile.readBuffer")
when defined(windows) or defined(nimdoc):
@@ -201,7 +201,7 @@ proc readBuffer*(f: AsyncFile, buf: pointer, size: int): Future[int] =
return retFuture
proc read*(f: AsyncFile, size: int): Future[string] =
## Read ``size`` bytes from the specified file asynchronously starting at
## Read `size` bytes from the specified file asynchronously starting at
## the current position of the file pointer.
##
## If the file pointer is past the end of the file then an empty string is
@@ -332,7 +332,7 @@ proc readAll*(f: AsyncFile): Future[string] {.async.} =
result.add data
proc writeBuffer*(f: AsyncFile, buf: pointer, size: int): Future[void] =
## Writes ``size`` bytes from ``buf`` to the file specified asynchronously.
## Writes `size` bytes from `buf` to the file specified asynchronously.
##
## The returned Future will complete once all data has been written to the
## specified file.
@@ -401,7 +401,7 @@ proc writeBuffer*(f: AsyncFile, buf: pointer, size: int): Future[void] =
return retFuture
proc write*(f: AsyncFile, data: string): Future[void] =
## Writes ``data`` to the file specified asynchronously.
## Writes `data` to the file specified asynchronously.
##
## The returned Future will complete once all data has been written to the
## specified file.

View File

@@ -19,7 +19,7 @@
## ===========================
##
## In order to begin any sort of transfer of files you must first
## connect to an FTP server. You can do so with the ``connect`` procedure.
## connect to an FTP server. You can do so with the `connect` procedure.
##
## .. code-block::nim
## import asyncdispatch, asyncftpclient
@@ -29,16 +29,16 @@
## echo("Connected")
## waitFor(main())
##
## A new ``main`` async procedure must be declared to allow the use of the
## ``await`` keyword. The connection will complete asynchronously and the
## client will be connected after the ``await ftp.connect()`` call.
## A new `main` async procedure must be declared to allow the use of the
## `await` keyword. The connection will complete asynchronously and the
## client will be connected after the `await ftp.connect()` call.
##
## Uploading a new file
## ====================
##
## After a connection is made you can use the ``store`` procedure to upload
## After a connection is made you can use the `store` procedure to upload
## a new file to the FTP server. Make sure to check you are in the correct
## working directory before you do so with the ``pwd`` procedure, you can also
## working directory before you do so with the `pwd` procedure, you can also
## instead specify an absolute path.
##
## .. code-block::nim
@@ -56,11 +56,11 @@
## ========================================
##
## The progress of either a file upload or a file download can be checked
## by specifying a ``onProgressChanged`` procedure to the ``store`` or
## ``retrFile`` procedures.
## by specifying a `onProgressChanged` procedure to the `store` or
## `retrFile` procedures.
##
## Procs that take an ``onProgressChanged`` callback will call this every
## ``progressInterval`` milliseconds.
## Procs that take an `onProgressChanged` callback will call this every
## `progressInterval` milliseconds.
##
## .. code-block::nim
## import asyncdispatch, asyncftpclient
@@ -148,10 +148,10 @@ proc expectReply(ftp: AsyncFtpClient): Future[string] {.async.} =
proc send*(ftp: AsyncFtpClient, m: string): Future[string] {.async.} =
## Send a message to the server, and wait for a primary reply.
## ``\c\L`` is added for you.
## `\c\L` is added for you.
##
## You need to make sure that the message ``m`` doesn't contain any newline
## characters. Failing to do so will raise ``AssertionDefect``.
## You need to make sure that the message `m` doesn't contain any newline
## characters. Failing to do so will raise `AssertionDefect`.
##
## **Note:** The server may return multiple lines of coded replies.
doAssert(not m.contains({'\c', '\L'}), "message shouldn't contain any newline characters")
@@ -183,7 +183,7 @@ proc normalizePathSep(path: string): string =
return replace(path, '\\', '/')
proc connect*(ftp: AsyncFtpClient) {.async.} =
## Connect to the FTP server specified by ``ftp``.
## Connect to the FTP server specified by `ftp`.
await ftp.csock.connect(ftp.address, ftp.port)
var reply = await ftp.expectReply()
@@ -208,7 +208,7 @@ proc pwd*(ftp: AsyncFtpClient): Future[string] {.async.} =
return wd.captureBetween('"') # "
proc cd*(ftp: AsyncFtpClient, dir: string) {.async.} =
## Changes the current directory on the remote FTP server to ``dir``.
## Changes the current directory on the remote FTP server to `dir`.
assertReply(await(ftp.send("CWD " & dir.normalizePathSep)), "250")
proc cdup*(ftp: AsyncFtpClient) {.async.} =
@@ -229,10 +229,10 @@ proc getLines(ftp: AsyncFtpClient): Future[string] {.async.} =
assertReply(await(ftp.expectReply()), "226")
proc listDirs*(ftp: AsyncFtpClient, dir = ""): Future[seq[string]] {.async.} =
## Returns a list of filenames in the given directory. If ``dir`` is "",
## the current directory is used. If ``async`` is true, this
## Returns a list of filenames in the given directory. If `dir` is "",
## the current directory is used. If `async` is true, this
## function will return immediately and it will be your job to
## use asyncdispatch's ``poll`` to progress this operation.
## use asyncdispatch's `poll` to progress this operation.
await ftp.pasv()
assertReply(await(ftp.send("NLST " & dir.normalizePathSep)), ["125", "150"])
@@ -240,15 +240,15 @@ proc listDirs*(ftp: AsyncFtpClient, dir = ""): Future[seq[string]] {.async.} =
result = splitLines(await ftp.getLines())
proc fileExists*(ftp: AsyncFtpClient, file: string): Future[bool] {.async.} =
## Determines whether ``file`` exists.
## Determines whether `file` exists.
var files = await ftp.listDirs()
for f in items(files):
if f.normalizePathSep == file.normalizePathSep: return true
proc createDir*(ftp: AsyncFtpClient, dir: string, recursive = false){.async.} =
## Creates a directory ``dir``. If ``recursive`` is true, the topmost
## subdirectory of ``dir`` will be created first, following the secondmost...
## etc. this allows you to give a full path as the ``dir`` without worrying
## Creates a directory `dir`. If `recursive` is true, the topmost
## subdirectory of `dir` will be created first, following the secondmost...
## etc. this allows you to give a full path as the `dir` without worrying
## about subdirectories not existing.
if not recursive:
assertReply(await(ftp.send("MKD " & dir.normalizePathSep)), "257")
@@ -264,7 +264,7 @@ proc createDir*(ftp: AsyncFtpClient, dir: string, recursive = false){.async.} =
proc chmod*(ftp: AsyncFtpClient, path: string,
permissions: set[FilePermission]) {.async.} =
## Changes permission of ``path`` to ``permissions``.
## Changes permission of `path` to `permissions`.
var userOctal = 0
var groupOctal = 0
var otherOctal = 0
@@ -285,7 +285,7 @@ proc chmod*(ftp: AsyncFtpClient, path: string,
" " & path.normalizePathSep)), "200")
proc list*(ftp: AsyncFtpClient, dir = ""): Future[string] {.async.} =
## Lists all files in ``dir``. If ``dir`` is ``""``, uses the current
## Lists all files in `dir`. If `dir` is `""`, uses the current
## working directory.
await ftp.pasv()
@@ -295,7 +295,7 @@ proc list*(ftp: AsyncFtpClient, dir = ""): Future[string] {.async.} =
result = await ftp.getLines()
proc retrText*(ftp: AsyncFtpClient, file: string): Future[string] {.async.} =
## Retrieves ``file``. File must be ASCII text.
## Retrieves `file`. File must be ASCII text.
await ftp.pasv()
let reply = await ftp.send("RETR " & file.normalizePathSep)
assertReply(reply, ["125", "150"])
@@ -331,17 +331,17 @@ proc getFile(ftp: AsyncFtpClient, file: File, total: BiggestInt,
proc defaultOnProgressChanged*(total, progress: BiggestInt,
speed: float): Future[void] {.nimcall, gcsafe.} =
## Default FTP ``onProgressChanged`` handler. Does nothing.
## Default FTP `onProgressChanged` handler. Does nothing.
result = newFuture[void]()
#echo(total, " ", progress, " ", speed)
result.complete()
proc retrFile*(ftp: AsyncFtpClient, file, dest: string,
onProgressChanged: ProgressChangedProc = defaultOnProgressChanged) {.async.} =
## Downloads ``file`` and saves it to ``dest``.
## The ``EvRetr`` event is passed to the specified ``handleEvent`` function
## when the download is finished. The event's ``filename`` field will be equal
## to ``file``.
## Downloads `file` and saves it to `dest`.
## The `EvRetr` event is passed to the specified `handleEvent` function
## when the download is finished. The event's `filename` field will be equal
## to `file`.
var destFile = open(dest, mode = fmWrite)
await ftp.pasv()
var reply = await ftp.send("RETR " & file.normalizePathSep)
@@ -390,12 +390,12 @@ proc doUpload(ftp: AsyncFtpClient, file: File,
proc store*(ftp: AsyncFtpClient, file, dest: string,
onProgressChanged: ProgressChangedProc = defaultOnProgressChanged) {.async.} =
## Uploads ``file`` to ``dest`` on the remote FTP server. Usage of this
## Uploads `file` to `dest` on the remote FTP server. Usage of this
## function asynchronously is recommended to view the progress of
## the download.
## The ``EvStore`` event is passed to the specified ``handleEvent`` function
## when the upload is finished, and the ``filename`` field will be
## equal to ``file``.
## The `EvStore` event is passed to the specified `handleEvent` function
## when the upload is finished, and the `filename` field will be
## equal to `file`.
var destFile = open(file)
await ftp.pasv()
@@ -406,21 +406,21 @@ proc store*(ftp: AsyncFtpClient, file, dest: string,
proc rename*(ftp: AsyncFtpClient, nameFrom: string, nameTo: string) {.async.} =
## Rename a file or directory on the remote FTP Server from current name
## ``name_from`` to new name ``name_to``
## `name_from` to new name `name_to`
assertReply(await ftp.send("RNFR " & nameFrom), "350")
assertReply(await ftp.send("RNTO " & nameTo), "250")
proc removeFile*(ftp: AsyncFtpClient, filename: string) {.async.} =
## Delete a file ``filename`` on the remote FTP server
## Delete a file `filename` on the remote FTP server
assertReply(await ftp.send("DELE " & filename), "250")
proc removeDir*(ftp: AsyncFtpClient, dir: string) {.async.} =
## Delete a directory ``dir`` on the remote FTP server
## Delete a directory `dir` on the remote FTP server
assertReply(await ftp.send("RMD " & dir), "250")
proc newAsyncFtpClient*(address: string, port = Port(21),
user, pass = "", progressInterval: int = 1000): AsyncFtpClient =
## Creates a new ``AsyncFtpClient`` object.
## Creates a new `AsyncFtpClient` object.
new result
result.user = user
result.pass = pass

View File

@@ -86,19 +86,19 @@ when isFutureLoggingEnabled:
var callSoonProc {.threadvar.}: proc (cbproc: proc ()) {.gcsafe.}
proc getCallSoonProc*(): (proc(cbproc: proc ()) {.gcsafe.}) =
## Get current implementation of ``callSoon``.
## Get current implementation of `callSoon`.
return callSoonProc
proc setCallSoonProc*(p: (proc(cbproc: proc ()) {.gcsafe.})) =
## Change current implementation of ``callSoon``. This is normally called when dispatcher from ``asyncdispatcher`` is initialized.
## Change current implementation of `callSoon`. This is normally called when dispatcher from `asyncdispatcher` is initialized.
callSoonProc = p
proc callSoon*(cbproc: proc ()) =
## Call ``cbproc`` "soon".
## Call `cbproc` "soon".
##
## If async dispatcher is running, ``cbproc`` will be executed during next dispatcher tick.
## If async dispatcher is running, `cbproc` will be executed during next dispatcher tick.
##
## If async dispatcher is not running, ``cbproc`` will be executed immediately.
## If async dispatcher is not running, `cbproc` will be executed immediately.
if callSoonProc.isNil:
# Loop not initialized yet. Call the function directly to allow setup code to use futures.
cbproc()
@@ -117,29 +117,29 @@ template setupFutureBase(fromProc: string) =
proc newFuture*[T](fromProc: string = "unspecified"): owned(Future[T]) =
## Creates a new future.
##
## Specifying ``fromProc``, which is a string specifying the name of the proc
## 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.
setupFutureBase(fromProc)
when isFutureLoggingEnabled: logFutureStart(result)
proc newFutureVar*[T](fromProc = "unspecified"): owned(FutureVar[T]) =
## Create a new ``FutureVar``. This Future type is ideally suited for
## 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
## 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.
let fo = newFuture[T](fromProc)
result = typeof(result)(fo)
when isFutureLoggingEnabled: logFutureStart(Future[T](result))
proc clean*[T](future: FutureVar[T]) =
## Resets the ``finished`` status of ``future``.
## Resets the `finished` status of `future`.
Future[T](future).finished = false
Future[T](future).error = nil
proc checkFinished[T](future: Future[T]) =
## Checks whether `future` is finished. If it is then raises a
## ``FutureError``.
## `FutureError`.
when not defined(release):
if future.finished:
var msg = ""
@@ -190,7 +190,7 @@ proc add(callbacks: var CallbackList, function: CallbackFunc) =
last.next = newCallback
proc complete*[T](future: Future[T], val: T) =
## Completes ``future`` with value ``val``.
## Completes `future` with value `val`.
#assert(not future.finished, "Future already finished, cannot finish twice.")
checkFinished(future)
assert(future.error == nil)
@@ -200,7 +200,7 @@ proc complete*[T](future: Future[T], val: T) =
when isFutureLoggingEnabled: logFutureFinish(future)
proc complete*(future: Future[void]) =
## Completes a void ``future``.
## Completes a void `future`.
#assert(not future.finished, "Future already finished, cannot finish twice.")
checkFinished(future)
assert(future.error == nil)
@@ -209,7 +209,7 @@ proc complete*(future: Future[void]) =
when isFutureLoggingEnabled: logFutureFinish(future)
proc complete*[T](future: FutureVar[T]) =
## Completes a ``FutureVar``.
## Completes a `FutureVar`.
template fut: untyped = Future[T](future)
checkFinished(fut)
assert(fut.error == nil)
@@ -218,7 +218,7 @@ proc complete*[T](future: FutureVar[T]) =
when isFutureLoggingEnabled: logFutureFinish(Future[T](future))
proc complete*[T](future: FutureVar[T], val: T) =
## Completes a ``FutureVar`` with value ``val``.
## Completes a `FutureVar` with value `val`.
##
## Any previously stored value will be overwritten.
template fut: untyped = Future[T](future)
@@ -230,7 +230,7 @@ proc complete*[T](future: FutureVar[T], val: T) =
when isFutureLoggingEnabled: logFutureFinish(future)
proc fail*[T](future: Future[T], error: ref Exception) =
## Completes ``future`` with ``error``.
## Completes `future` with `error`.
#assert(not future.finished, "Future already finished, cannot finish twice.")
checkFinished(future)
future.finished = true
@@ -247,7 +247,7 @@ proc clearCallbacks*(future: FutureBase) =
proc addCallback*(future: FutureBase, cb: proc() {.closure, gcsafe.}) =
## Adds the callbacks proc to be called when the future completes.
##
## If future has already completed then ``cb`` will be called immediately.
## If future has already completed then `cb` will be called immediately.
assert cb != nil
if future.finished:
callSoon(cb)
@@ -258,7 +258,7 @@ proc addCallback*[T](future: Future[T],
cb: proc (future: Future[T]) {.closure, gcsafe.}) =
## Adds the callbacks proc to be called when the future completes.
##
## If future has already completed then ``cb`` will be called immediately.
## If future has already completed then `cb` will be called immediately.
future.addCallback(
proc() =
cb(future)
@@ -267,9 +267,9 @@ proc addCallback*[T](future: Future[T],
proc `callback=`*(future: FutureBase, cb: proc () {.closure, gcsafe.}) =
## Clears the list of callbacks and sets the callback proc to be called when the future completes.
##
## If future has already completed then ``cb`` will be called immediately.
## If future has already completed then `cb` will be called immediately.
##
## It's recommended to use ``addCallback`` or ``then`` instead.
## It's recommended to use `addCallback` or `then` instead.
future.clearCallbacks
future.addCallback cb
@@ -277,7 +277,7 @@ proc `callback=`*[T](future: Future[T],
cb: proc (future: Future[T]) {.closure, gcsafe.}) =
## Sets the callback proc to be called when the future completes.
##
## If future has already completed then ``cb`` will be called immediately.
## If future has already completed then `cb` will be called immediately.
future.callback = proc () = cb(future)
proc getHint(entry: StackTraceEntry): string =
@@ -359,8 +359,8 @@ proc injectStacktrace[T](future: Future[T]) =
future.error.msg = newMsg
proc read*[T](future: Future[T] | FutureVar[T]): T =
## Retrieves the value of ``future``. Future must be finished otherwise
## this function will fail with a ``ValueError`` exception.
## Retrieves the value of `future`. Future must be finished otherwise
## this function will fail with a `ValueError` exception.
##
## If the result of the future is an error then that error will be raised.
{.push hint[ConvFromXtoItselfNotNeeded]: off.}
@@ -380,40 +380,40 @@ proc read*[T](future: Future[T] | FutureVar[T]): T =
raise newException(ValueError, "Future still in progress.")
proc readError*[T](future: Future[T]): ref Exception =
## Retrieves the exception stored in ``future``.
## Retrieves the exception stored in `future`.
##
## An ``ValueError`` exception will be thrown if no exception exists
## An `ValueError` exception will be thrown if no exception exists
## in the specified Future.
if future.error != nil: return future.error
else:
raise newException(ValueError, "No error in future.")
proc mget*[T](future: FutureVar[T]): var T =
## Returns a mutable value stored in ``future``.
## Returns a mutable value stored in `future`.
##
## Unlike ``read``, this function will not raise an exception if the
## Unlike `read`, this function will not raise an exception if the
## Future has not been finished.
result = Future[T](future).value
proc finished*(future: FutureBase | FutureVar): bool =
## Determines whether ``future`` has completed.
## Determines whether `future` has completed.
##
## ``True`` may indicate an error or a value. Use ``failed`` to distinguish.
## `True` may indicate an error or a value. Use `failed` to distinguish.
when future is FutureVar:
result = (FutureBase(future)).finished
else:
result = future.finished
proc failed*(future: FutureBase): bool =
## Determines whether ``future`` completed with an error.
## Determines whether `future` completed with an error.
return future.error != nil
proc asyncCheck*[T](future: Future[T]) =
## Sets a callback on ``future`` which raises an exception if the future
## Sets a callback on `future` which raises an exception if the future
## finished with an error.
##
## This should be used instead of ``discard`` to discard void futures,
## or use ``waitFor`` if you need to wait for the future's completion.
## This should be used instead of `discard` to discard void futures,
## or use `waitFor` if you need to wait for the future's completion.
assert(not future.isNil, "Future is nil")
# TODO: We can likely look at the stack trace here and inject the location
# where the `asyncCheck` was called to give a better error stack message.
@@ -424,7 +424,7 @@ proc asyncCheck*[T](future: Future[T]) =
future.callback = asyncCheckCallback
proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
## Returns a future which will complete once both ``fut1`` and ``fut2``
## Returns a future which will complete once both `fut1` and `fut2`
## complete.
var retFuture = newFuture[void]("asyncdispatch.`and`")
fut1.callback =
@@ -440,7 +440,7 @@ proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
return retFuture
proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
## Returns a future which will complete once either ``fut1`` or ``fut2``
## Returns a future which will complete once either `fut1` or `fut2`
## complete.
var retFuture = newFuture[void]("asyncdispatch.`or`")
proc cb[X](fut: Future[X]) =
@@ -453,14 +453,14 @@ proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
proc all*[T](futs: varargs[Future[T]]): auto =
## Returns a future which will complete once
## all futures in ``futs`` complete.
## all futures in `futs` complete.
## If the argument is empty, the returned future completes immediately.
##
## If the awaited futures are not ``Future[void]``, the returned future
## If the awaited futures are not `Future[void]`, the returned future
## will hold the values of all awaited futures in a sequence.
##
## If the awaited futures *are* ``Future[void]``,
## this proc returns ``Future[void]``.
## If the awaited futures *are* `Future[void]`,
## this proc returns `Future[void]`.
when T is void:
var

View File

@@ -73,7 +73,7 @@ type
maxFDs: int
func getSocket*(a: AsyncHttpServer): AsyncSocket {.since: (1, 5, 1).} =
## Returns the ``AsyncHttpServer``s internal ``AsyncSocket`` instance.
## Returns the `AsyncHttpServer`s internal `AsyncSocket` instance.
##
## Useful for identifying what port the AsyncHttpServer is bound to, if it
## was chosen automatically.
@@ -90,7 +90,7 @@ func getSocket*(a: AsyncHttpServer): AsyncSocket {.since: (1, 5, 1).} =
proc newAsyncHttpServer*(reuseAddr = true, reusePort = false,
maxBody = 8388608): AsyncHttpServer =
## Creates a new ``AsyncHttpServer`` instance.
## Creates a new `AsyncHttpServer` instance.
result = AsyncHttpServer(reuseAddr: reuseAddr, reusePort: reusePort, maxBody: maxBody)
proc addHeaders(msg: var string, headers: HttpHeaders) =
@@ -105,7 +105,7 @@ proc sendHeaders*(req: Request, headers: HttpHeaders): Future[void] =
proc respond*(req: Request, code: HttpCode, content: string,
headers: HttpHeaders = nil): Future[void] =
## Responds to the request with the specified ``HttpCode``, headers and
## Responds to the request with the specified `HttpCode`, headers and
## content.
##
## This procedure will **not** close the client socket.
@@ -138,7 +138,7 @@ proc respond*(req: Request, code: HttpCode, content: string,
result = req.client.send(msg)
proc respondError(req: Request, code: HttpCode): Future[void] =
## Responds to the request with the specified ``HttpCode``.
## Responds to the request with the specified `HttpCode`.
let content = $code
var msg = "HTTP/1.1 " & content & "\c\L"

View File

@@ -8,27 +8,27 @@
#
## This module implements a high-level asynchronous sockets API based on the
## asynchronous dispatcher defined in the ``asyncdispatch`` module.
## asynchronous dispatcher defined in the `asyncdispatch` module.
##
## Asynchronous IO in Nim
## ======================
##
## Async IO in Nim consists of multiple layers (from highest to lowest):
##
## * ``asyncnet`` module
## * `asyncnet` module
##
## * Async await
##
## * ``asyncdispatch`` module (event loop)
## * `asyncdispatch` module (event loop)
##
## * ``selectors`` module
## * `selectors` module
##
## Each builds on top of the layers below it. The selectors module is an
## abstraction for the various system ``select()`` mechanisms such as epoll or
## abstraction for the various system `select()` mechanisms such as epoll or
## kqueue. If you wish you can use it directly, and some people have done so
## `successfully <http://goran.krampe.se/2014/10/25/nim-socketserver/>`_.
## But you must be aware that on Windows it only supports
## ``select()``.
## `select()`.
##
## The async dispatcher implements the proactor pattern and also has an
## implementation of IOCP. It implements the proactor pattern for other
@@ -45,16 +45,16 @@
## layers interchangeably (as long as you only care about non-Windows
## platforms).
##
## For most applications using ``asyncnet`` is the way to go as it builds
## For most applications using `asyncnet` is the way to go as it builds
## over all the layers, providing some extra features such as buffering.
##
## SSL
## ===
##
## SSL can be enabled by compiling with the ``-d:ssl`` flag.
## SSL can be enabled by compiling with the `-d:ssl` flag.
##
## You must create a new SSL context with the ``newContext`` function defined
## in the ``net`` module. You may then call ``wrapSocket`` on your socket using
## You must create a new SSL context with the `newContext` function defined
## in the `net` module. You may then call `wrapSocket` on your socket using
## the newly created SSL context to get an SSL socket.
##
## Examples
@@ -134,16 +134,16 @@ proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET,
protocol: Protocol = IPPROTO_TCP,
buffered = true,
inheritable = defined(nimInheritHandles)): owned(AsyncSocket) =
## Creates a new ``AsyncSocket`` based on the supplied params.
## Creates a new `AsyncSocket` based on the supplied params.
##
## The supplied ``fd``'s non-blocking state will be enabled implicitly.
## The supplied `fd`'s non-blocking state will be enabled implicitly.
##
## If ``inheritable`` is false (the default), the supplied ``fd`` will not
## If `inheritable` is false (the default), the supplied `fd` will not
## be inheritable by child processes.
##
## **Note**: This procedure will **NOT** register ``fd`` with the global
## **Note**: This procedure will **NOT** register `fd` with the global
## async dispatcher. You need to do this manually. If you have used
## ``newAsyncNativeSocket`` to create ``fd`` then it's already registered.
## `newAsyncNativeSocket` to create `fd` then it's already registered.
assert fd != osInvalidSocket.AsyncFD
new(result)
result.fd = fd.SocketHandle
@@ -165,7 +165,7 @@ proc newAsyncSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
## This procedure will also create a brand new file descriptor for
## this socket.
##
## If ``inheritable`` is false (the default), the new file descriptor will not
## If `inheritable` is false (the default), the new file descriptor will not
## be inheritable by child processes.
let fd = createAsyncNativeSocket(domain, sockType, protocol, inheritable)
if fd.SocketHandle == osInvalidSocket:
@@ -192,7 +192,7 @@ proc newAsyncSocket*(domain, sockType, protocol: cint,
## This procedure will also create a brand new file descriptor for
## this socket.
##
## If ``inheritable`` is false (the default), the new file descriptor will not
## If `inheritable` is false (the default), the new file descriptor will not
## be inheritable by child processes.
let fd = createAsyncNativeSocket(domain, sockType, protocol, inheritable)
if fd.SocketHandle == osInvalidSocket:
@@ -233,7 +233,7 @@ when defineSsl:
proc appeaseSsl(socket: AsyncSocket, flags: set[SocketFlag],
sslError: cint): owned(Future[bool]) {.async.} =
## Returns ``true`` if ``socket`` is still connected, otherwise ``false``.
## Returns `true` if `socket` is still connected, otherwise `false`.
result = true
case sslError
of SSL_ERROR_WANT_WRITE:
@@ -279,9 +279,9 @@ when defineSsl:
proc dial*(address: string, port: Port, protocol = IPPROTO_TCP,
buffered = true): owned(Future[AsyncSocket]) {.async.} =
## Establishes connection to the specified ``address``:``port`` pair via the
## Establishes connection to the specified `address`:`port` pair via the
## specified protocol. The procedure iterates through possible
## resolutions of the ``address`` until it succeeds, meaning that it
## resolutions of the `address` until it succeeds, meaning that it
## seamlessly works with both IPv4 and IPv6.
## Returns AsyncSocket ready to send or receive data.
let asyncFd = await asyncdispatch.dial(address, port, protocol)
@@ -290,9 +290,9 @@ proc dial*(address: string, port: Port, protocol = IPPROTO_TCP,
result = newAsyncSocket(asyncFd, domain, sockType, protocol, buffered)
proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
## Connects ``socket`` to server at ``address:port``.
## Connects `socket` to server at `address:port`.
##
## Returns a ``Future`` which will complete when the connection succeeds
## Returns a `Future` which will complete when the connection succeeds
## or an error occurs.
await connect(socket.fd.AsyncFD, address, port, socket.domain)
if socket.isSsl:
@@ -308,7 +308,7 @@ proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
template readInto(buf: pointer, size: int, socket: AsyncSocket,
flags: set[SocketFlag]): int =
## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. Note that
## Reads **up to** `size` bytes from `socket` into `buf`. Note that
## this is a template and not a proc.
assert(not socket.closed, "Cannot `recv` on a closed socket")
var res = 0
@@ -332,10 +332,10 @@ template readIntoBuf(socket: AsyncSocket,
proc recvInto*(socket: AsyncSocket, buf: pointer, size: int,
flags = {SocketFlag.SafeDisconn}): owned(Future[int]) {.async.} =
## Reads **up to** ``size`` bytes from ``socket`` into ``buf``.
## Reads **up to** `size` bytes from `socket` into `buf`.
##
## For buffered sockets this function will attempt to read all the requested
## data. It will read this data in ``BufferSize`` chunks.
## data. It will read this data in `BufferSize` chunks.
##
## For unbuffered sockets this function makes no effort to read
## all the data requested. It will return as much data as the operating system
@@ -346,7 +346,7 @@ proc recvInto*(socket: AsyncSocket, buf: pointer, size: int,
## requested data.
##
## If socket is disconnected and no data is available
## to be read then the future will complete with a value of ``0``.
## to be read then the future will complete with a value of `0`.
if socket.isBuffered:
let originalBufPos = socket.currPos
@@ -380,10 +380,10 @@ proc recvInto*(socket: AsyncSocket, buf: pointer, size: int,
proc recv*(socket: AsyncSocket, size: int,
flags = {SocketFlag.SafeDisconn}): owned(Future[string]) {.async.} =
## Reads **up to** ``size`` bytes from ``socket``.
## Reads **up to** `size` bytes from `socket`.
##
## For buffered sockets this function will attempt to read all the requested
## data. It will read this data in ``BufferSize`` chunks.
## data. It will read this data in `BufferSize` chunks.
##
## For unbuffered sockets this function makes no effort to read
## all the data requested. It will return as much data as the operating system
@@ -394,7 +394,7 @@ proc recv*(socket: AsyncSocket, size: int,
## requested data.
##
## If socket is disconnected and no data is available
## to be read then the future will complete with a value of ``""``.
## to be read then the future will complete with a value of `""`.
if socket.isBuffered:
result = newString(size)
shallow(result)
@@ -432,7 +432,7 @@ proc recv*(socket: AsyncSocket, size: int,
proc send*(socket: AsyncSocket, buf: pointer, size: int,
flags = {SocketFlag.SafeDisconn}) {.async.} =
## Sends ``size`` bytes from ``buf`` to ``socket``. The returned future will complete once all
## Sends `size` bytes from `buf` to `socket`. The returned future will complete once all
## data has been sent.
assert socket != nil
assert(not socket.closed, "Cannot `send` on a closed socket")
@@ -446,7 +446,7 @@ proc send*(socket: AsyncSocket, buf: pointer, size: int,
proc send*(socket: AsyncSocket, data: string,
flags = {SocketFlag.SafeDisconn}) {.async.} =
## 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.
assert socket != nil
if socket.isSsl:
@@ -464,7 +464,7 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn},
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection and the remote address of the client.
##
## If ``inheritable`` is false (the default), the resulting client socket will
## If `inheritable` is false (the default), the resulting client socket will
## not be inheritable by child processes.
##
## The future will complete when the connection is successfully accepted.
@@ -486,7 +486,7 @@ proc accept*(socket: AsyncSocket,
flags = {SocketFlag.SafeDisconn}): owned(Future[AsyncSocket]) =
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection.
## If ``inheritable`` is false (the default), the resulting client socket will
## If `inheritable` is false (the default), the resulting client socket will
## not be inheritable by child processes.
## The future will complete when the connection is successfully accepted.
var retFut = newFuture[AsyncSocket]("asyncnet.accept")
@@ -502,25 +502,25 @@ proc accept*(socket: AsyncSocket,
proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
flags = {SocketFlag.SafeDisconn}, maxLength = MaxLineLength) {.async.} =
## Reads a line of data from ``socket`` into ``resString``.
## Reads a line of data from `socket` into `resString`.
##
## If a full line is read ``\r\L`` is not
## added to ``line``, however if solely ``\r\L`` is read then ``line``
## If a full line is read `\r\L` is not
## added to `line`, however if solely `\r\L` is read then `line`
## will be set to it.
##
## If the socket is disconnected, ``line`` will be set to ``""``.
## If the socket is disconnected, `line` will be set to `""`.
##
## If the socket is disconnected in the middle of a line (before ``\r\L``
## is read) then line will be set to ``""``.
## If the socket is disconnected in the middle of a line (before `\r\L`
## is read) then line will be set to `""`.
## The partial line **will be lost**.
##
## The ``maxLength`` parameter determines the maximum amount of characters
## that can be read. ``resString`` will be truncated after that.
## The `maxLength` parameter determines the maximum amount of characters
## that can be read. `resString` will be truncated after that.
##
## **Warning**: The ``Peek`` flag is not yet implemented.
## **Warning**: The `Peek` flag is not yet implemented.
##
## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the
## protocol uses ``\r\L`` to delimit a new line.
## **Warning**: `recvLineInto` on unbuffered sockets assumes that the
## protocol uses `\r\L` to delimit a new line.
assert SocketFlag.Peek notin flags ## TODO:
result = newFuture[void]("asyncnet.recvLineInto")
@@ -595,26 +595,26 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
proc recvLine*(socket: AsyncSocket,
flags = {SocketFlag.SafeDisconn},
maxLength = MaxLineLength): owned(Future[string]) {.async.} =
## Reads a line of data from ``socket``. Returned future will complete once
## Reads a line of data from `socket`. Returned future will complete once
## a full line is read or an error occurs.
##
## If a full line is read ``\r\L`` is not
## added to ``line``, however if solely ``\r\L`` is read then ``line``
## If a full line is read `\r\L` is not
## added to `line`, however if solely `\r\L` is read then `line`
## will be set to it.
##
## If the socket is disconnected, ``line`` will be set to ``""``.
## If the socket is disconnected, `line` will be set to `""`.
##
## If the socket is disconnected in the middle of a line (before ``\r\L``
## is read) then line will be set to ``""``.
## If the socket is disconnected in the middle of a line (before `\r\L`
## is read) then line will be set to `""`.
## The partial line **will be lost**.
##
## The ``maxLength`` parameter determines the maximum amount of characters
## The `maxLength` parameter determines the maximum amount of characters
## that can be read. The result is truncated after that.
##
## **Warning**: The ``Peek`` flag is not yet implemented.
## **Warning**: The `Peek` flag is not yet implemented.
##
## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
## uses ``\r\L`` to delimit a new line.
## **Warning**: `recvLine` on unbuffered sockets assumes that the protocol
## uses `\r\L` to delimit a new line.
assert SocketFlag.Peek notin flags ## TODO:
# TODO: Optimise this
@@ -625,8 +625,8 @@ proc recvLine*(socket: AsyncSocket,
proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [
ReadIOEffect].} =
## Marks ``socket`` as accepting connections.
## ``Backlog`` specifies the maximum length of the
## Marks `socket` as accepting connections.
## `Backlog` specifies the maximum length of the
## queue of pending connections.
##
## Raises an OSError error upon failure.
@@ -634,9 +634,9 @@ proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [
proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
tags: [ReadIOEffect].} =
## Binds ``address``:``port`` to the socket.
## Binds `address`:`port` to the socket.
##
## If ``address`` is "" then ADDR_ANY will be bound.
## If `address` is "" then ADDR_ANY will be bound.
var realaddr = address
if realaddr == "":
case socket.domain
@@ -735,7 +735,7 @@ proc close*(socket: AsyncSocket) =
when defineSsl:
proc wrapSocket*(ctx: SslContext, socket: AsyncSocket) =
## Wraps a socket in an SSL context. This function effectively turns
## ``socket`` into an SSL socket.
## `socket` into an SSL socket.
##
## **Disclaimer**: This code is not well tested, may be very unsafe and
## prone to security vulnerabilities.
@@ -755,8 +755,8 @@ when defineSsl:
handshake: SslHandshakeType,
hostname: string = "") =
## Wraps a connected socket in an SSL context. This function effectively
## turns ``socket`` into an SSL socket.
## ``hostname`` should be specified so that the client knows which hostname
## turns `socket` into an SSL socket.
## `hostname` should be specified so that the client knows which hostname
## the server certificate should be validated against.
##
## This should be called on a connected socket, and will perform
@@ -789,18 +789,18 @@ when defineSsl:
proc getSockOpt*(socket: AsyncSocket, opt: SOBool, level = SOL_SOCKET): bool {.
tags: [ReadIOEffect].} =
## Retrieves option ``opt`` as a boolean value.
## Retrieves option `opt` as a boolean value.
var res = getSockOptInt(socket.fd, cint(level), toCInt(opt))
result = res != 0
proc setSockOpt*(socket: AsyncSocket, opt: SOBool, value: bool,
level = SOL_SOCKET) {.tags: [WriteIOEffect].} =
## Sets option ``opt`` to a boolean value specified by ``value``.
## Sets option `opt` to a boolean value specified by `value`.
var valuei = cint(if value: 1 else: 0)
setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
proc isSsl*(socket: AsyncSocket): bool =
## Determines whether ``socket`` is a SSL socket.
## Determines whether `socket` is a SSL socket.
socket.isSsl
proc getFd*(socket: AsyncSocket): SocketHandle =
@@ -814,7 +814,7 @@ proc isClosed*(socket: AsyncSocket): bool =
proc sendTo*(socket: AsyncSocket, address: string, port: Port, data: string,
flags = {SocketFlag.SafeDisconn}): owned(Future[void])
{.async, since: (1, 3).} =
## This proc sends ``data`` to the specified ``address``, which may be an IP
## This proc sends `data` to the specified `address`, which may be an IP
## address or a hostname. If a hostname is specified this function will try
## each IP of that hostname. The returned future will complete once all data
## has been sent.
@@ -861,9 +861,9 @@ proc recvFrom*(socket: AsyncSocket, data: FutureVar[string], size: int,
address: FutureVar[string], port: FutureVar[Port],
flags = {SocketFlag.SafeDisconn}): owned(Future[int])
{.async, since: (1, 3).} =
## Receives a datagram data from ``socket`` into ``data``, which must be at
## least of size ``size``. The address and port of datagram's sender will be
## stored into ``address`` and ``port``, respectively. Returned future will
## Receives a datagram data from `socket` into `data`, which must be at
## least of size `size`. The address and port of datagram's sender will be
## stored into `address` and `port`, respectively. Returned future will
## complete once one datagram has been received, and will return size of
## packet received.
##
@@ -872,8 +872,8 @@ proc recvFrom*(socket: AsyncSocket, data: FutureVar[string], size: int,
## This proc is normally used with connectionless sockets (UDP sockets).
##
## **Notes**
## * ``data`` must be initialized to the length of ``size``.
## * ``address`` must be initialized to 46 in length.
## * `data` must be initialized to the length of `size`.
## * `address` must be initialized to 46 in length.
template adaptRecvFromToDomain(domain: Domain) =
var lAddr = sizeof(sAddr).SockLen
@@ -915,8 +915,8 @@ proc recvFrom*(socket: AsyncSocket, size: int,
flags = {SocketFlag.SafeDisconn}):
owned(Future[tuple[data: string, address: string, port: Port]])
{.async, since: (1, 3).} =
## Receives a datagram data from ``socket``, which must be at least of size
## ``size``. Returned future will complete once one datagram has been received
## Receives a datagram data from `socket`, which must be at least of size
## `size`. Returned future will complete once one datagram has been received
## and will return tuple with: data of packet received; and address and port
## of datagram's sender.
##

View File

@@ -24,14 +24,14 @@ type
error*: ref Exception
proc newFutureStream*[T](fromProc = "unspecified"): FutureStream[T] =
## Create a new ``FutureStream``. This future's callback is activated when
## Create a new `FutureStream`. This future's callback is activated when
## two events occur:
##
## * New data is written into the future stream.
## * The future stream is completed (this means that no more data will be
## written).
##
## Specifying ``fromProc``, which is a string specifying the name of the proc
## 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.
##
## **Note:** The API of FutureStream is still new and so has a higher
@@ -40,14 +40,14 @@ proc newFutureStream*[T](fromProc = "unspecified"): FutureStream[T] =
result.queue = initDeque[T]()
proc complete*[T](future: FutureStream[T]) =
## Completes a ``FutureStream`` signalling the end of data.
## Completes a `FutureStream` signalling the end of data.
assert(future.error == nil, "Trying to complete failed stream")
future.finished = true
if not future.cb.isNil:
future.cb()
proc fail*[T](future: FutureStream[T], error: ref Exception) =
## Completes ``future`` with ``error``.
## Completes `future` with `error`.
assert(not future.finished)
future.finished = true
future.error = error
@@ -60,9 +60,9 @@ proc `callback=`*[T](future: FutureStream[T],
## future stream.
##
## The callback is also called when the future is completed. So you should
## use ``finished`` to check whether data is available.
## use `finished` to check whether data is available.
##
## If the future stream already has data or is finished then ``cb`` will be
## If the future stream already has data or is finished then `cb` will be
## called immediately.
proc named() = cb(future)
future.cb = named
@@ -70,19 +70,19 @@ proc `callback=`*[T](future: FutureStream[T],
callSoon(future.cb)
proc finished*[T](future: FutureStream[T]): bool =
## Check if a ``FutureStream`` is finished. ``true`` value means that
## Check if a `FutureStream` is finished. `true` value means that
## no more data will be placed inside the stream *and* that there is
## no data waiting to be retrieved.
result = future.finished and future.queue.len == 0
proc failed*[T](future: FutureStream[T]): bool =
## Determines whether ``future`` completed with an error.
## Determines whether `future` completed with an error.
return future.error != nil
proc write*[T](future: FutureStream[T], value: T): Future[void] =
## Writes the specified value inside the specified future stream.
##
## This will raise ``ValueError`` if ``future`` is finished.
## This will raise `ValueError` if `future` is finished.
result = newFuture[void]("FutureStream.put")
if future.finished:
let msg = "FutureStream is finished and so no longer accepts new data."
@@ -95,14 +95,14 @@ proc write*[T](future: FutureStream[T], value: T): Future[void] =
result.complete()
proc read*[T](future: FutureStream[T]): owned(Future[(bool, T)]) =
## Returns a future that will complete when the ``FutureStream`` has data
## Returns a future that will complete when the `FutureStream` has data
## placed into it. The future will be completed with the oldest
## value stored inside the stream. The return value will also determine
## whether data was retrieved, ``false`` means that the future stream was
## whether data was retrieved, `false` means that the future stream was
## completed and no data was retrieved.
##
## This function will remove the data that was returned from the underlying
## ``FutureStream``.
## `FutureStream`.
var resFut = newFuture[(bool, T)]("FutureStream.take")
let savedCb = future.cb
proc newCb(fs: FutureStream[T]) =

View File

@@ -27,7 +27,7 @@ else:
const osOpenCmd* =
when defined(macos) or defined(macosx) or defined(windows): "open" else: "xdg-open" ## \
## Alias for the operating system specific *"open"* command,
## ``"open"`` on OSX, MacOS and Windows, ``"xdg-open"`` on Linux, BSD, etc.
## `"open"` on OSX, MacOS and Windows, `"xdg-open"` on Linux, BSD, etc.
proc prepare(s: string): string =
if s.contains("://"):
@@ -47,7 +47,7 @@ proc openDefaultBrowserImpl(url: string) =
if execShellCmd(osOpenCmd & " " & u) == 0: return
for b in getEnv("BROWSER").split(PathSep):
try:
# we use ``startProcess`` here because we don't want to block!
# we use `startProcess` here because we don't want to block!
discard startProcess(command = b, args = [url], options = {poUsePath})
return
except OSError:
@@ -57,9 +57,9 @@ proc openDefaultBrowser*(url: string) =
## Opens `url` with the user's default browser. This does not block.
## The URL must not be empty string, to open on a blank page see `openDefaultBrowser()`.
##
## Under Windows, ``ShellExecute`` is used. Under Mac OS X the ``open``
## command is used. Under Unix, it is checked if ``xdg-open`` exists and
## used if it does. Otherwise the environment variable ``BROWSER`` is
## Under Windows, `ShellExecute` is used. Under Mac OS X the `open`
## command is used. Under Unix, it is checked if `xdg-open` exists and
## used if it does. Otherwise the environment variable `BROWSER` is
## used to determine the default browser to use.
##
## This proc doesn't raise an exception on error, beware.
@@ -73,9 +73,9 @@ proc openDefaultBrowser*() {.since: (1, 1).} =
## Opens the user's default browser without any `url` (blank page). This does not block.
## Implements IETF RFC-6694 Section 3, "about:blank" must be reserved for a blank page.
##
## Under Windows, ``ShellExecute`` is used. Under Mac OS X the ``open``
## command is used. Under Unix, it is checked if ``xdg-open`` exists and
## used if it does. Otherwise the environment variable ``BROWSER`` is
## Under Windows, `ShellExecute` is used. Under Mac OS X the `open`
## command is used. Under Unix, it is checked if `xdg-open` exists and
## used if it does. Otherwise the environment variable `BROWSER` is
## used to determine the default browser to use.
##
## This proc doesn't raise an exception on error, beware.

View File

@@ -440,7 +440,7 @@ proc colorNameCmp(x: tuple[name: string, col: Color], y: string): int =
proc parseColor*(name: string): Color =
## Parses `name` to a color value.
##
## If no valid color could be parsed ``ValueError`` is raised.
## If no valid color could be parsed `ValueError` is raised.
## Case insensitive.
##
runnableExamples:
@@ -461,7 +461,7 @@ proc parseColor*(name: string): Color =
proc isColor*(name: string): bool =
## Returns true if `name` is a known color name or a hexadecimal color
## prefixed with ``#``. Case insensitive.
## prefixed with `#`. Case insensitive.
##
runnableExamples:
var

View File

@@ -229,7 +229,7 @@ proc switchTo(current, to: CoroutinePtr) =
nimGC_setStackBottom(ctx.ncbottom)
proc suspend*(sleepTime: float = 0) =
## Stops coroutine execution and resumes no sooner than after ``sleeptime`` seconds.
## Stops coroutine execution and resumes no sooner than after `sleeptime` seconds.
## Until then other coroutines are executed.
var current = getCurrent()
current.sleepTime = sleepTime
@@ -335,9 +335,9 @@ proc run*() =
ctx.current = ctx.current.next
proc alive*(c: CoroutineRef): bool = c.coro != nil and c.coro.state != CORO_FINISHED
## Returns ``true`` if coroutine has not returned, ``false`` otherwise.
## Returns `true` if coroutine has not returned, `false` otherwise.
proc wait*(c: CoroutineRef, interval = 0.01) =
## Returns only after coroutine ``c`` has returned. ``interval`` is time in seconds how often.
## Returns only after coroutine `c` has returned. `interval` is time in seconds how often.
while alive(c):
suspend(interval)

View File

@@ -7,7 +7,7 @@
# distribution, for details about the copyright.
#
## Common datatypes and definitions for all ``db_*.nim`` (
## Common datatypes and definitions for all `db_*.nim` (
## `db_mysql <db_mysql.html>`_, `db_postgres <db_postgres.html>`_,
## and `db_sqlite <db_sqlite.html>`_) modules.
@@ -86,7 +86,7 @@ type
template sql*(query: string): SqlQuery =
## constructs a SqlQuery from the string `query`. This is supposed to be
## used as a raw-string-literal modifier:
## ``sql"update user set counter = counter + 1"``
## `sql"update user set counter = counter + 1"`
##
## If assertions are turned off, it does nothing. If assertions are turned
## on, later versions will check the string for valid syntax.

View File

@@ -201,7 +201,7 @@ proc detectOsImpl(d: Distribution): bool =
template detectOs*(d: untyped): bool =
## Distro/OS detection. For convenience the
## required ``Distribution.`` qualifier is added to the
## required `Distribution.` qualifier is added to the
## enum value.
detectOsImpl(Distribution.d)