Hi, working with async stuff decided to look at what async way of getting file size and compare it to sync way.
Got no difference in principle, but there is 2 different implementations:
The "sync" version in io.nim:
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.} =
## retrieves the file size (in bytes) of `f`.
let oldPos = getFilePos(f)
discard c_fseek(f, 0, 2) # seek the end of the file
result = getFilePos(f)
setFilePos(f, oldPos)
The "async" version in asyncfile.nim:
proc getFileSize*(f: AsyncFile): int64 =
## Retrieves the specified file's size.
when defined(windows) or defined(nimdoc):
var high: DWORD
let low = getFileSize(f.fd.Handle, addr high)
if low == INVALID_FILE_SIZE:
raiseOSError(osLastError())
result = (high shl 32) or low
else:
let curPos = lseek(f.fd.cint, 0, SEEK_CUR)
result = lseek(f.fd.cint, 0, SEEK_END)
f.offset = lseek(f.fd.cint, curPos, SEEK_SET)
assert(f.offset == curPos)
There also, the 3rd variant exists, but it is a bit different variant, where the argument not file, but string path. But in that variant, we may find another way of getting info for windows platform.
So, the question is: is this organization, intended? Or it is a legacy/historical moment? It is too early for me to judge but willing to better understand std lib design ideas and organization.
OK, but in "async" version, there is nothing async at all (as I can understand).
So that asyncfile can use proc from io module for example.
I've never used async file I/O APIs, but my understanding is that they just cover reading/writing the file itself. The size is metadata that comes from the filesystem's catalog / inodes / whatever, not the file itself, and is very cheap to get.
I suppose you could get the file size asynchronously by spawning the filesystem call onto a background thread, but that seems like overkill...
It's different because AsyncFile keeps its fd field private. The Windows one is using the version from winlean which actually wrapper for GetFileSize from win32.
Also, windows has peculiarity of different handling whether the file handle is synchronous and asynchronous one. That's why it's using the wrapper.