nim-confutils/confutils/winreg/reader.nim

84 lines
2.5 KiB
Nim
Raw Normal View History

2020-10-21 05:01:48 +00:00
import
tables, strutils, typetraits, options,
serialization/[object_serialization, errors],
./utils
type
WinregReader* = object
hKey: HKEY
path: string
2020-10-21 09:07:25 +00:00
key: seq[string]
2020-10-21 05:01:48 +00:00
WinregReaderError* = object of WinregError
GenericWinregReaderError* = object of WinregReaderError
deserializedField*: string
innerException*: ref CatchableError
proc handleReadException*(r: WinregReader,
Record: type,
fieldName: string,
field: auto,
err: ref CatchableError) =
var ex = new GenericWinregReaderError
ex.deserializedField = fieldName
ex.innerException = err
raise ex
proc init*(T: type WinregReader,
hKey: HKEY, path: string): T =
result.hKey = hKey
result.path = path
2020-10-21 09:07:25 +00:00
template getUnderlyingType*[T](_: Option[T]): untyped = T
2020-10-21 05:01:48 +00:00
proc readValue*[T](r: var WinregReader, value: var T)
{.raises: [SerializationError, IOError, Defect].} =
mixin readValue
2020-10-21 09:07:25 +00:00
# TODO: reduce allocation
2020-10-21 05:01:48 +00:00
2020-10-21 09:07:25 +00:00
when T is (SomePrimitives or range or string):
let path = constructPath(r.path, r.key)
discard getValue(r.hKey, path, r.key[^1], value)
elif T is Option:
let path = constructPath(r.path, r.key)
var outVal: getUnderlyingType(value)
if getValue(r.hKey, path, r.key[^1], outVal):
value = some(outVal)
2020-10-21 05:01:48 +00:00
elif T is (seq or array):
when uTypeIsPrimitives(T):
2020-10-21 09:07:25 +00:00
let path = constructPath(r.path, r.key)
discard getValue(r.hKey, path, r.key[^1], value)
2020-10-21 05:01:48 +00:00
elif uTypeIsRecord(T):
2020-10-21 09:07:25 +00:00
let key = r.key[^1]
for i in 0..<value.len:
r.key[^1] = key & $i
r.readValue(value[i])
2020-10-21 05:01:48 +00:00
else:
const typeName = typetraits.name(T)
{.fatal: "Failed to convert from Winreg array an unsupported type: " & typeName.}
elif T is (object or tuple):
2020-10-21 09:07:25 +00:00
type T = type(value)
when T.totalSerializedFields > 0:
let fields = T.fieldReadersTable(WinregReader)
var expectedFieldPos = 0
r.key.add ""
value.enumInstanceSerializedFields(fieldName, field):
type FieldType = type field
when T is tuple:
r.key[^1] = $expectedFieldPos
var reader = fields[][expectedFieldPos].reader
expectedFieldPos += 1
else:
r.key[^1] = fieldName
var reader = findFieldReader(fields[], fieldName, expectedFieldPos)
if reader != nil:
reader(value, r)
discard r.key.pop()
2020-10-21 05:01:48 +00:00
else:
const typeName = typetraits.name(T)
{.fatal: "Failed to convert from Winreg an unsupported type: " & typeName.}