Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
commit
218679fc95
24 changed files with 1363 additions and 1041 deletions
110
lib/js/asyncjs.nim
Normal file
110
lib/js/asyncjs.nim
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2017 Nim Authors
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
||||
## This module implements types and macros for writing asynchronous code
|
||||
## for the JS backend. It provides tools for interaction with JavaScript async API-s
|
||||
## and libraries, writing async procedures in Nim and converting callback-based code
|
||||
## to promises.
|
||||
##
|
||||
## A Nim procedure is asynchronous when it includes the ``{.async.}`` pragma. It
|
||||
## should always have a ``Future[T]`` return type or not have a return type at all.
|
||||
## A ``Future[void]`` return type is assumed by default.
|
||||
##
|
||||
## This is roughly equivalent to the ``async`` keyword in JavaScript code.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## proc loadGame(name: string): Future[Game] {.async.} =
|
||||
## # code
|
||||
##
|
||||
## should be equivalent to
|
||||
##
|
||||
## .. code-block:: javascript
|
||||
## async function loadGame(name) {
|
||||
## // code
|
||||
## }
|
||||
##
|
||||
## A call to an asynchronous procedure usually needs ``await`` to wait for
|
||||
## the completion of the ``Future``.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var game = await loadGame(name)
|
||||
##
|
||||
## Often, you might work with callback-based API-s. You can wrap them with
|
||||
## asynchronous procedures using promises and ``newPromise``:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## proc loadGame(name: string): Future[Game] =
|
||||
## var promise = newPromise() do (resolve: proc(response: Game)):
|
||||
## cbBasedLoadGame(name) do (game: Game):
|
||||
## resolve(game)
|
||||
## return promise
|
||||
##
|
||||
## Forward definitions work properly, you just don't need to add the ``{.async.}`` pragma:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## proc loadGame(name: string): Future[Game]
|
||||
##
|
||||
## JavaScript compatibility
|
||||
## ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
##
|
||||
## Nim currently generates `async/await` JavaScript code which is supported in modern
|
||||
## EcmaScript and most modern versions of browsers, Node.js and Electron.
|
||||
## If you need to use this module with older versions of JavaScript, you can
|
||||
## use a tool that backports the resulting JavaScript code, as babel.
|
||||
|
||||
import jsffi
|
||||
import macros
|
||||
|
||||
when not defined(js) and not defined(nimdoc) and not defined(nimsuggest):
|
||||
{.fatal: "Module asyncjs is designed to be used with the JavaScript backend.".}
|
||||
|
||||
type
|
||||
Future*[T] = ref object
|
||||
future*: T
|
||||
## Wraps the return type of an asynchronous procedure.
|
||||
|
||||
PromiseJs* {.importcpp: "Promise".} = ref object
|
||||
## A JavaScript Promise
|
||||
|
||||
proc replaceReturn(node: var NimNode) =
|
||||
var z = 0
|
||||
for s in node:
|
||||
var son = node[z]
|
||||
if son.kind == nnkReturnStmt:
|
||||
node[z] = nnkReturnStmt.newTree(nnkCall.newTree(ident("jsResolve"), son[0]))
|
||||
elif son.kind == nnkAsgn and son[0].kind == nnkIdent and $son[0] == "result":
|
||||
node[z] = nnkAsgn.newTree(son[0], nnkCall.newTree(ident("jsResolve"), son[1]))
|
||||
else:
|
||||
replaceReturn(son)
|
||||
inc z
|
||||
|
||||
proc generateJsasync(arg: NimNode): NimNode =
|
||||
assert arg.kind == nnkProcDef
|
||||
result = arg
|
||||
if arg.params[0].kind == nnkEmpty:
|
||||
result.params[0] = nnkBracketExpr.newTree(ident("Future"), ident("void"))
|
||||
var code = result.body
|
||||
replaceReturn(code)
|
||||
result.body = nnkStmtList.newTree()
|
||||
var q = quote:
|
||||
proc await[T](f: Future[T]): T {.importcpp: "(await #)".}
|
||||
proc jsResolve[T](a: T): Future[T] {.importcpp: "#".}
|
||||
result.body.add(q)
|
||||
for child in code:
|
||||
result.body.add(child)
|
||||
result.pragma = quote:
|
||||
{.codegenDecl: "async function $2($3)".}
|
||||
|
||||
macro async*(arg: untyped): untyped =
|
||||
## Macro which converts normal procedures into
|
||||
## javascript-compatible async procedures
|
||||
generateJsasync(arg)
|
||||
|
||||
proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".}
|
||||
## A helper for wrapping callback-based functions
|
||||
## into promises and async procedures
|
||||
|
|
@ -609,11 +609,12 @@ proc clock_nanosleep*(a1: ClockId, a2: cint, a3: var Timespec,
|
|||
proc clock_settime*(a1: ClockId, a2: var Timespec): cint {.
|
||||
importc, header: "<time.h>".}
|
||||
|
||||
proc `==`*(a, b: Time): bool {.borrow.}
|
||||
proc `-`*(a, b: Time): Time {.borrow.}
|
||||
proc ctime*(a1: var Time): cstring {.importc, header: "<time.h>".}
|
||||
proc ctime_r*(a1: var Time, a2: cstring): cstring {.importc, header: "<time.h>".}
|
||||
proc difftime*(a1, a2: Time): cdouble {.importc, header: "<time.h>".}
|
||||
proc getdate*(a1: cstring): ptr Tm {.importc, header: "<time.h>".}
|
||||
|
||||
proc gmtime*(a1: var Time): ptr Tm {.importc, header: "<time.h>".}
|
||||
proc gmtime_r*(a1: var Time, a2: var Tm): ptr Tm {.importc, header: "<time.h>".}
|
||||
proc localtime*(a1: var Time): ptr Tm {.importc, header: "<time.h>".}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
# To be included from posix.nim!
|
||||
|
||||
from times import Time
|
||||
|
||||
const
|
||||
hasSpawnH = not defined(haiku) # should exist for every Posix system nowadays
|
||||
hasAioH = defined(linux)
|
||||
|
|
@ -40,13 +38,15 @@ type
|
|||
const SIG_HOLD* = cast[SigHandler](2)
|
||||
|
||||
type
|
||||
Time* {.importc: "time_t", header: "<time.h>".} = distinct clong
|
||||
|
||||
Timespec* {.importc: "struct timespec",
|
||||
header: "<time.h>", final, pure.} = object ## struct timespec
|
||||
tv_sec*: Time ## Seconds.
|
||||
tv_nsec*: clong ## Nanoseconds.
|
||||
|
||||
Dirent* {.importc: "struct dirent",
|
||||
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
|
||||
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
|
||||
d_ino*: Ino
|
||||
d_off*: Off
|
||||
d_reclen*: cushort
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
{.deadCodeElim:on.}
|
||||
|
||||
from times import Time
|
||||
|
||||
const
|
||||
hasSpawnH = not defined(haiku) # should exist for every Posix system nowadays
|
||||
hasAioH = defined(linux)
|
||||
|
|
@ -36,6 +34,8 @@ type
|
|||
{.deprecated: [TSocketHandle: SocketHandle].}
|
||||
|
||||
type
|
||||
Time* {.importc: "time_t", header: "<time.h>".} = distinct int
|
||||
|
||||
Timespec* {.importc: "struct timespec",
|
||||
header: "<time.h>", final, pure.} = object ## struct timespec
|
||||
tv_sec*: Time ## Seconds.
|
||||
|
|
@ -209,24 +209,24 @@ type
|
|||
st_gid*: Gid ## Group ID of file.
|
||||
st_rdev*: Dev ## Device ID (if file is character or block special).
|
||||
st_size*: Off ## For regular files, the file size in bytes.
|
||||
## For symbolic links, the length in bytes of the
|
||||
## pathname contained in the symbolic link.
|
||||
## For a shared memory object, the length in bytes.
|
||||
## For a typed memory object, the length in bytes.
|
||||
## For other file types, the use of this field is
|
||||
## unspecified.
|
||||
## For symbolic links, the length in bytes of the
|
||||
## pathname contained in the symbolic link.
|
||||
## For a shared memory object, the length in bytes.
|
||||
## For a typed memory object, the length in bytes.
|
||||
## For other file types, the use of this field is
|
||||
## unspecified.
|
||||
when defined(macosx) or defined(android):
|
||||
st_atime*: Time ## Time of last access.
|
||||
st_mtime*: Time ## Time of last data modification.
|
||||
st_ctime*: Time ## Time of last status change.
|
||||
st_atime*: Time ## Time of last access.
|
||||
st_mtime*: Time ## Time of last data modification.
|
||||
st_ctime*: Time ## Time of last status change.
|
||||
else:
|
||||
st_atim*: Timespec ## Time of last access.
|
||||
st_mtim*: Timespec ## Time of last data modification.
|
||||
st_ctim*: Timespec ## Time of last status change.
|
||||
st_blksize*: Blksize ## A file system-specific preferred I/O block size
|
||||
## for this object. In some file system types, this
|
||||
## may vary from file to file.
|
||||
st_blocks*: Blkcnt ## Number of blocks allocated for this object.
|
||||
st_atim*: Timespec ## Time of last access.
|
||||
st_mtim*: Timespec ## Time of last data modification.
|
||||
st_ctim*: Timespec ## Time of last status change.
|
||||
st_blksize*: Blksize ## A file system-specific preferred I/O block size
|
||||
## for this object. In some file system types, this
|
||||
## may vary from file to file.
|
||||
st_blocks*: Blkcnt ## Number of blocks allocated for this object.
|
||||
|
||||
|
||||
Statvfs* {.importc: "struct statvfs", header: "<sys/statvfs.h>",
|
||||
|
|
|
|||
|
|
@ -168,18 +168,20 @@ type
|
|||
timers*: HeapQueue[tuple[finishAt: float, fut: Future[void]]]
|
||||
callbacks*: Deque[proc ()]
|
||||
|
||||
proc processTimers(p: PDispatcherBase) {.inline.} =
|
||||
proc processTimers(p: PDispatcherBase; didSomeWork: var bool) {.inline.} =
|
||||
#Process just part if timers at a step
|
||||
var count = p.timers.len
|
||||
let t = epochTime()
|
||||
while count > 0 and t >= p.timers[0].finishAt:
|
||||
p.timers.pop().fut.complete()
|
||||
dec count
|
||||
didSomeWork = true
|
||||
|
||||
proc processPendingCallbacks(p: PDispatcherBase) =
|
||||
proc processPendingCallbacks(p: PDispatcherBase; didSomeWork: var bool) =
|
||||
while p.callbacks.len > 0:
|
||||
var cb = p.callbacks.popFirst()
|
||||
cb()
|
||||
didSomeWork = true
|
||||
|
||||
proc adjustedTimeout(p: PDispatcherBase, timeout: int): int {.inline.} =
|
||||
# If dispatcher has active timers this proc returns the timeout
|
||||
|
|
@ -284,14 +286,13 @@ when defined(windows) or defined(nimdoc):
|
|||
let p = getGlobalDispatcher()
|
||||
p.handles.len != 0 or p.timers.len != 0 or p.callbacks.len != 0
|
||||
|
||||
proc poll*(timeout = 500) =
|
||||
## Waits for completion events and processes them. Raises ``ValueError``
|
||||
## if there are no pending operations.
|
||||
proc runOnce(timeout = 500): bool =
|
||||
let p = getGlobalDispatcher()
|
||||
if p.handles.len == 0 and p.timers.len == 0 and p.callbacks.len == 0:
|
||||
raise newException(ValueError,
|
||||
"No handles or timers registered in dispatcher.")
|
||||
|
||||
result = false
|
||||
if p.handles.len != 0:
|
||||
let at = p.adjustedTimeout(timeout)
|
||||
var llTimeout =
|
||||
|
|
@ -304,6 +305,7 @@ when defined(windows) or defined(nimdoc):
|
|||
let res = getQueuedCompletionStatus(p.ioPort,
|
||||
addr lpNumberOfBytesTransferred, addr lpCompletionKey,
|
||||
cast[ptr POVERLAPPED](addr customOverlapped), llTimeout).bool
|
||||
result = true
|
||||
|
||||
# http://stackoverflow.com/a/12277264/492186
|
||||
# TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
|
||||
|
|
@ -333,13 +335,14 @@ when defined(windows) or defined(nimdoc):
|
|||
else:
|
||||
if errCode.int32 == WAIT_TIMEOUT:
|
||||
# Timed out
|
||||
discard
|
||||
result = false
|
||||
else: raiseOSError(errCode)
|
||||
|
||||
# Timer processing.
|
||||
processTimers(p)
|
||||
processTimers(p, result)
|
||||
# Callback queue processing
|
||||
processPendingCallbacks(p)
|
||||
processPendingCallbacks(p, result)
|
||||
|
||||
|
||||
var acceptEx: WSAPROC_ACCEPTEX
|
||||
var connectEx: WSAPROC_CONNECTEX
|
||||
|
|
@ -1202,7 +1205,7 @@ else:
|
|||
# descriptor was unregistered in callback via `unregister()`.
|
||||
discard
|
||||
|
||||
proc poll*(timeout = 500) =
|
||||
proc runOnce(timeout = 500): bool =
|
||||
let p = getGlobalDispatcher()
|
||||
when ioselSupportedPlatform:
|
||||
let customSet = {Event.Timer, Event.Signal, Event.Process,
|
||||
|
|
@ -1212,6 +1215,7 @@ else:
|
|||
raise newException(ValueError,
|
||||
"No handles or timers registered in dispatcher.")
|
||||
|
||||
result = false
|
||||
if not p.selector.isEmpty():
|
||||
var keys: array[64, ReadyKey]
|
||||
var count = p.selector.selectInto(p.adjustedTimeout(timeout), keys)
|
||||
|
|
@ -1224,20 +1228,24 @@ else:
|
|||
|
||||
if Event.Read in events or events == {Event.Error}:
|
||||
processBasicCallbacks(fd, readList)
|
||||
result = true
|
||||
|
||||
if Event.Write in events or events == {Event.Error}:
|
||||
processBasicCallbacks(fd, writeList)
|
||||
result = true
|
||||
|
||||
if Event.User in events or events == {Event.Error}:
|
||||
processBasicCallbacks(fd, readList)
|
||||
custom = true
|
||||
if rLength == 0:
|
||||
p.selector.unregister(fd)
|
||||
result = true
|
||||
|
||||
when ioselSupportedPlatform:
|
||||
if (customSet * events) != {}:
|
||||
custom = true
|
||||
processCustomCallbacks(fd)
|
||||
result = true
|
||||
|
||||
# because state `data` can be modified in callback we need to update
|
||||
# descriptor events with currently registered callbacks.
|
||||
|
|
@ -1249,9 +1257,9 @@ else:
|
|||
p.selector.updateHandle(SocketHandle(fd), newEvents)
|
||||
|
||||
# Timer processing.
|
||||
processTimers(p)
|
||||
processTimers(p, result)
|
||||
# Callback queue processing
|
||||
processPendingCallbacks(p)
|
||||
processPendingCallbacks(p, result)
|
||||
|
||||
proc recv*(socket: AsyncFD, size: int,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[string] =
|
||||
|
|
@ -1474,6 +1482,19 @@ else:
|
|||
data.readList.add(cb)
|
||||
p.selector.registerEvent(SelectEvent(ev), data)
|
||||
|
||||
proc drain*(timeout = 500) =
|
||||
## Waits for completion events and processes them. Raises ``ValueError``
|
||||
## if there are no pending operations. In contrast to ``poll`` this
|
||||
## processes as many events as are available.
|
||||
if runOnce(timeout):
|
||||
while runOnce(0): discard
|
||||
|
||||
proc poll*(timeout = 500) =
|
||||
## 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()
|
||||
|
||||
# Common procedures between current and upcoming asyncdispatch
|
||||
include includes.asynccommon
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ proc setCookie*(key, value: string, domain = "", path = "",
|
|||
if secure: result.add("; Secure")
|
||||
if httpOnly: result.add("; HttpOnly")
|
||||
|
||||
proc setCookie*(key, value: string, expires: TimeInfo,
|
||||
proc setCookie*(key, value: string, expires: DateTime,
|
||||
domain = "", path = "", noName = false,
|
||||
secure = false, httpOnly = false): string =
|
||||
## Creates a command in the format of
|
||||
|
|
@ -63,9 +63,9 @@ proc setCookie*(key, value: string, expires: TimeInfo,
|
|||
noname, secure, httpOnly)
|
||||
|
||||
when isMainModule:
|
||||
var tim = Time(int(getTime()) + 76 * (60 * 60 * 24))
|
||||
var tim = fromUnix(getTime().toUnix + 76 * (60 * 60 * 24))
|
||||
|
||||
let cookie = setCookie("test", "value", tim.getGMTime())
|
||||
let cookie = setCookie("test", "value", tim.utc)
|
||||
when not defined(testing):
|
||||
echo cookie
|
||||
let start = "Set-Cookie: test=value; Expires="
|
||||
|
|
|
|||
|
|
@ -277,15 +277,16 @@ proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool,
|
|||
var events = {Event.Timer}
|
||||
var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP)
|
||||
epv.data.u64 = fdi.uint
|
||||
|
||||
if oneshot:
|
||||
new_ts.it_interval.tv_sec = 0.Time
|
||||
new_ts.it_interval.tv_sec = posix.Time(0)
|
||||
new_ts.it_interval.tv_nsec = 0
|
||||
new_ts.it_value.tv_sec = (timeout div 1_000).Time
|
||||
new_ts.it_value.tv_sec = posix.Time(timeout div 1_000)
|
||||
new_ts.it_value.tv_nsec = (timeout %% 1_000) * 1_000_000
|
||||
incl(events, Event.Oneshot)
|
||||
epv.events = epv.events or EPOLLONESHOT
|
||||
else:
|
||||
new_ts.it_interval.tv_sec = (timeout div 1000).Time
|
||||
new_ts.it_interval.tv_sec = posix.Time(timeout div 1000)
|
||||
new_ts.it_interval.tv_nsec = (timeout %% 1_000) * 1_000_000
|
||||
new_ts.it_value.tv_sec = new_ts.it_interval.tv_sec
|
||||
new_ts.it_value.tv_nsec = new_ts.it_interval.tv_nsec
|
||||
|
|
|
|||
|
|
@ -452,10 +452,10 @@ proc selectInto*[T](s: Selector[T], timeout: int,
|
|||
|
||||
if timeout != -1:
|
||||
if timeout >= 1000:
|
||||
tv.tv_sec = (timeout div 1_000).Time
|
||||
tv.tv_sec = posix.Time(timeout div 1_000)
|
||||
tv.tv_nsec = (timeout %% 1_000) * 1_000_000
|
||||
else:
|
||||
tv.tv_sec = 0.Time
|
||||
tv.tv_sec = posix.Time(0)
|
||||
tv.tv_nsec = timeout * 1_000_000
|
||||
else:
|
||||
ptv = nil
|
||||
|
|
|
|||
|
|
@ -291,6 +291,8 @@ when not defined(JS):
|
|||
## echo fmod(-2.5, 0.3) ## -0.1
|
||||
|
||||
else:
|
||||
proc trunc*(x: float32): float32 {.importc: "Math.trunc", nodecl.}
|
||||
proc trunc*(x: float64): float64 {.importc: "Math.trunc", nodecl.}
|
||||
proc floor*(x: float32): float32 {.importc: "Math.floor", nodecl.}
|
||||
proc floor*(x: float64): float64 {.importc: "Math.floor", nodecl.}
|
||||
proc ceil*(x: float32): float32 {.importc: "Math.ceil", nodecl.}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ proc generatedTime*(oid: Oid): Time =
|
|||
var tmp: int32
|
||||
var dummy = oid.time
|
||||
bigEndian32(addr(tmp), addr(dummy))
|
||||
result = Time(tmp)
|
||||
result = fromUnix(tmp)
|
||||
|
||||
when not defined(testing) and isMainModule:
|
||||
let xo = genOid()
|
||||
|
|
|
|||
|
|
@ -173,33 +173,33 @@ proc findExe*(exe: string, followSymlinks: bool = true;
|
|||
return x
|
||||
result = ""
|
||||
|
||||
proc getLastModificationTime*(file: string): Time {.rtl, extern: "nos$1".} =
|
||||
proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
|
||||
## Returns the `file`'s last modification time.
|
||||
when defined(posix):
|
||||
var res: Stat
|
||||
if stat(file, res) < 0'i32: raiseOSError(osLastError())
|
||||
return res.st_mtime
|
||||
return fromUnix(res.st_mtime.int64)
|
||||
else:
|
||||
var f: WIN32_FIND_DATA
|
||||
var h = findFirstFile(file, f)
|
||||
if h == -1'i32: raiseOSError(osLastError())
|
||||
result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
|
||||
result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftLastWriteTime)).int64)
|
||||
findClose(h)
|
||||
|
||||
proc getLastAccessTime*(file: string): Time {.rtl, extern: "nos$1".} =
|
||||
proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
|
||||
## Returns the `file`'s last read or write access time.
|
||||
when defined(posix):
|
||||
var res: Stat
|
||||
if stat(file, res) < 0'i32: raiseOSError(osLastError())
|
||||
return res.st_atime
|
||||
return fromUnix(res.st_atime.int64)
|
||||
else:
|
||||
var f: WIN32_FIND_DATA
|
||||
var h = findFirstFile(file, f)
|
||||
if h == -1'i32: raiseOSError(osLastError())
|
||||
result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
|
||||
result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftLastAccessTime)).int64)
|
||||
findClose(h)
|
||||
|
||||
proc getCreationTime*(file: string): Time {.rtl, extern: "nos$1".} =
|
||||
proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
|
||||
## Returns the `file`'s creation time.
|
||||
##
|
||||
## **Note:** Under POSIX OS's, the returned time may actually be the time at
|
||||
|
|
@ -208,12 +208,12 @@ proc getCreationTime*(file: string): Time {.rtl, extern: "nos$1".} =
|
|||
when defined(posix):
|
||||
var res: Stat
|
||||
if stat(file, res) < 0'i32: raiseOSError(osLastError())
|
||||
return res.st_ctime
|
||||
return fromUnix(res.st_ctime.int64)
|
||||
else:
|
||||
var f: WIN32_FIND_DATA
|
||||
var h = findFirstFile(file, f)
|
||||
if h == -1'i32: raiseOSError(osLastError())
|
||||
result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
|
||||
result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftCreationTime)).int64)
|
||||
findClose(h)
|
||||
|
||||
proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
|
||||
|
|
@ -1443,7 +1443,7 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} =
|
|||
winlean.sleep(int32(milsecs))
|
||||
else:
|
||||
var a, b: Timespec
|
||||
a.tv_sec = Time(milsecs div 1000)
|
||||
a.tv_sec = posix.Time(milsecs div 1000)
|
||||
a.tv_nsec = (milsecs mod 1000) * 1000 * 1000
|
||||
discard posix.nanosleep(a, b)
|
||||
|
||||
|
|
@ -1481,16 +1481,17 @@ type
|
|||
size*: BiggestInt # Size of file.
|
||||
permissions*: set[FilePermission] # File permissions
|
||||
linkCount*: BiggestInt # Number of hard links the file object has.
|
||||
lastAccessTime*: Time # Time file was last accessed.
|
||||
lastWriteTime*: Time # Time file was last modified/written to.
|
||||
creationTime*: Time # Time file was created. Not supported on all systems!
|
||||
lastAccessTime*: times.Time # Time file was last accessed.
|
||||
lastWriteTime*: times.Time # Time file was last modified/written to.
|
||||
creationTime*: times.Time # Time file was created. Not supported on all systems!
|
||||
|
||||
template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
|
||||
## Transforms the native file info structure into the one nim uses.
|
||||
## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
|
||||
## or a 'Stat' structure on posix
|
||||
when defined(Windows):
|
||||
template toTime(e: FILETIME): untyped {.gensym.} = winTimeToUnixTime(rdFileTime(e)) # local templates default to bind semantics
|
||||
template toTime(e: FILETIME): untyped {.gensym.} =
|
||||
fromUnix(winTimeToUnixTime(rdFileTime(e)).int64) # local templates default to bind semantics
|
||||
template merge(a, b): untyped = a or (b shl 32)
|
||||
formalInfo.id.device = rawInfo.dwVolumeSerialNumber
|
||||
formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
|
||||
|
|
@ -1522,9 +1523,9 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
|
|||
formalInfo.id = (rawInfo.st_dev, rawInfo.st_ino)
|
||||
formalInfo.size = rawInfo.st_size
|
||||
formalInfo.linkCount = rawInfo.st_Nlink.BiggestInt
|
||||
formalInfo.lastAccessTime = rawInfo.st_atime
|
||||
formalInfo.lastWriteTime = rawInfo.st_mtime
|
||||
formalInfo.creationTime = rawInfo.st_ctime
|
||||
formalInfo.lastAccessTime = fromUnix(rawInfo.st_atime.int64)
|
||||
formalInfo.lastWriteTime = fromUnix(rawInfo.st_mtime.int64)
|
||||
formalInfo.creationTime = fromUnix(rawInfo.st_ctime.int64)
|
||||
|
||||
result.permissions = {}
|
||||
checkAndIncludeMode(S_IRUSR, fpUserRead)
|
||||
|
|
|
|||
|
|
@ -1060,10 +1060,10 @@ elif not defined(useNimRtl):
|
|||
var tmspec: Timespec
|
||||
|
||||
if timeout >= 1000:
|
||||
tmspec.tv_sec = (timeout div 1_000).Time
|
||||
tmspec.tv_sec = posix.Time(timeout div 1_000)
|
||||
tmspec.tv_nsec = (timeout %% 1_000) * 1_000_000
|
||||
else:
|
||||
tmspec.tv_sec = 0.Time
|
||||
tmspec.tv_sec = posix.Time(0)
|
||||
tmspec.tv_nsec = (timeout * 1_000_000)
|
||||
|
||||
try:
|
||||
|
|
@ -1109,20 +1109,20 @@ elif not defined(useNimRtl):
|
|||
var b: Timespec
|
||||
b.tv_sec = e.tv_sec
|
||||
b.tv_nsec = e.tv_nsec
|
||||
e.tv_sec = (e.tv_sec - s.tv_sec).Time
|
||||
e.tv_sec = e.tv_sec - s.tv_sec
|
||||
if e.tv_nsec >= s.tv_nsec:
|
||||
e.tv_nsec -= s.tv_nsec
|
||||
else:
|
||||
if e.tv_sec == 0.Time:
|
||||
if e.tv_sec == posix.Time(0):
|
||||
raise newException(ValueError, "System time was modified")
|
||||
else:
|
||||
diff = s.tv_nsec - e.tv_nsec
|
||||
e.tv_nsec = 1_000_000_000 - diff
|
||||
t.tv_sec = (t.tv_sec - e.tv_sec).Time
|
||||
t.tv_sec = t.tv_sec - e.tv_sec
|
||||
if t.tv_nsec >= e.tv_nsec:
|
||||
t.tv_nsec -= e.tv_nsec
|
||||
else:
|
||||
t.tv_sec = (int(t.tv_sec) - 1).Time
|
||||
t.tv_sec = t.tv_sec - posix.Time(1)
|
||||
diff = e.tv_nsec - t.tv_nsec
|
||||
t.tv_nsec = 1_000_000_000 - diff
|
||||
s.tv_sec = b.tv_sec
|
||||
|
|
@ -1154,10 +1154,10 @@ elif not defined(useNimRtl):
|
|||
raiseOSError(osLastError())
|
||||
|
||||
if timeout >= 1000:
|
||||
tmspec.tv_sec = (timeout div 1_000).Time
|
||||
tmspec.tv_sec = posix.Time(timeout div 1_000)
|
||||
tmspec.tv_nsec = (timeout %% 1_000) * 1_000_000
|
||||
else:
|
||||
tmspec.tv_sec = 0.Time
|
||||
tmspec.tv_sec = posix.Time(0)
|
||||
tmspec.tv_nsec = (timeout * 1_000_000)
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -190,12 +190,8 @@ when not defined(nimscript):
|
|||
proc randomize*() {.benign.} =
|
||||
## Initializes the random number generator with a "random"
|
||||
## number, i.e. a tickcount. Note: Does not work for NimScript.
|
||||
when defined(JS):
|
||||
proc getMil(t: Time): int {.importcpp: "getTime", nodecl.}
|
||||
randomize(getMil times.getTime())
|
||||
else:
|
||||
let time = int64(times.epochTime() * 1_000_000_000)
|
||||
randomize(time)
|
||||
let time = int64(times.epochTime() * 1_000_000_000)
|
||||
randomize(time)
|
||||
|
||||
{.pop.}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ An expression like ``fmt"{key} is {value:arg} {{z}}"`` is transformed into:
|
|||
format(key, temp)
|
||||
format(" is ", temp)
|
||||
format(value, arg, temp)
|
||||
format("{z}", temp)
|
||||
format(" {z}", temp)
|
||||
temp
|
||||
|
||||
Parts of the string that are enclosed in the curly braces are interpreted
|
||||
|
|
@ -94,7 +94,7 @@ The general form of a standard format specifier is::
|
|||
|
||||
[[fill]align][sign][#][0][minimumwidth][.precision][type]
|
||||
|
||||
The brackets ([]) indicate an optional element.
|
||||
The square brackets ``[]`` indicate an optional element.
|
||||
|
||||
The optional align flag can be one of the following:
|
||||
|
||||
|
|
@ -126,8 +126,9 @@ The 'sign' option is only valid for numeric types, and can be one of the followi
|
|||
positive as well as negative numbers.
|
||||
``-`` Indicates that a sign should be used only for
|
||||
negative numbers (this is the default behavior).
|
||||
`` `` (space) Indicates that a leading space should be used on
|
||||
(space) Indicates that a leading space should be used on
|
||||
positive numbers.
|
||||
================= ====================================================
|
||||
|
||||
If the '#' character is present, integers use the 'alternate form' for formatting.
|
||||
This means that binary, octal, and hexadecimal output will be prefixed
|
||||
|
|
|
|||
1633
lib/pure/times.nim
1633
lib/pure/times.nim
File diff suppressed because it is too large
Load diff
|
|
@ -64,6 +64,8 @@ type
|
|||
|
||||
des_key_schedule* = array[1..16, des_ks_struct]
|
||||
|
||||
pem_password_cb* = proc(buf: cstring, size, rwflag: cint, userdata: pointer): cint {.cdecl.}
|
||||
|
||||
{.deprecated: [PSSL: SslPtr, PSSL_CTX: SslCtx, PBIO: BIO].}
|
||||
|
||||
const
|
||||
|
|
@ -432,6 +434,12 @@ proc ErrClearError*(){.cdecl, dynlib: DLLUtilName, importc: "ERR_clear_error".}
|
|||
proc ErrFreeStrings*(){.cdecl, dynlib: DLLUtilName, importc: "ERR_free_strings".}
|
||||
proc ErrRemoveState*(pid: cInt){.cdecl, dynlib: DLLUtilName, importc: "ERR_remove_state".}
|
||||
|
||||
proc PEM_read_bio_RSA_PUBKEY*(bp: BIO, x: ptr PRSA, pw: pem_password_cb, u: pointer): PRSA {.cdecl,
|
||||
dynlib: DLLSSLName, importc.}
|
||||
|
||||
proc RSA_verify*(kind: cint, origMsg: pointer, origMsgLen: cuint, signature: pointer,
|
||||
signatureLen: cuint, rsa: PRSA): cint {.cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
when true:
|
||||
discard
|
||||
else:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue