mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 01:14:41 +00:00
split again from #24038, fixes https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102 `var`/pointer types are no longer implicitly convertible to each other if their element types either: * require an int conversion or another conversion operation as long as it's not to `openarray`, * are subtypes with pointer indirection, Previously any conversion below a subrange match would match if the element type wasn't a pointer type, then it would error later in `analyseIfAddressTaken`. Different from #24038 in that the preview define that made subrange matches also fail to match is removed for a simpler diff so that it can be backported.
208 lines
5.7 KiB
Nim
208 lines
5.7 KiB
Nim
discard """
|
|
action: compile
|
|
"""
|
|
|
|
# https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102
|
|
# failed with "for a 'var' type a variable needs to be passed; but 'uint64(result)' is immutable"
|
|
|
|
import
|
|
std/[typetraits, macros]
|
|
|
|
type
|
|
DefaultFlavor = object
|
|
|
|
template serializationFormatImpl(Name: untyped) {.dirty.} =
|
|
type Name = object
|
|
|
|
template serializationFormat(Name: untyped) =
|
|
serializationFormatImpl(Name)
|
|
|
|
template setReader(Format, FormatReader: distinct type) =
|
|
when arity(FormatReader) > 1:
|
|
template Reader(T: type Format, F: distinct type = DefaultFlavor): type = FormatReader[F]
|
|
else:
|
|
template ReaderType(T: type Format): type = FormatReader
|
|
template Reader(T: type Format): type = FormatReader
|
|
|
|
template useDefaultReaderIn(T: untyped, Flavor: type) =
|
|
mixin Reader
|
|
|
|
template readValue(r: var Reader(Flavor), value: var T) =
|
|
mixin readRecordValue
|
|
readRecordValue(r, value)
|
|
|
|
import mvaruintconv
|
|
|
|
type
|
|
FieldTag[RecordType: object; fieldName: static string] = distinct void
|
|
|
|
func declval*(T: type): T {.compileTime.} =
|
|
default(ptr T)[]
|
|
|
|
macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped =
|
|
var typeAst = getType(T)[1]
|
|
var typeImpl: NimNode
|
|
let isSymbol = not typeAst.isTuple
|
|
|
|
if not isSymbol:
|
|
typeImpl = typeAst
|
|
else:
|
|
typeImpl = getImpl(typeAst)
|
|
result = newStmtList()
|
|
|
|
var i = 0
|
|
for field in recordFields(typeImpl):
|
|
let
|
|
fieldIdent = field.name
|
|
realFieldName = newLit($fieldIdent.skipPragma)
|
|
fieldName = realFieldName
|
|
fieldIndex = newLit(i)
|
|
|
|
let fieldNameDefs =
|
|
if isSymbol:
|
|
quote:
|
|
const fieldName {.inject, used.} = `fieldName`
|
|
const realFieldName {.inject, used.} = `realFieldName`
|
|
else:
|
|
quote:
|
|
const fieldName {.inject, used.} = $`fieldIndex`
|
|
const realFieldName {.inject, used.} = $`fieldIndex`
|
|
|
|
let field =
|
|
if isSymbol:
|
|
quote do: declval(`T`).`fieldIdent`
|
|
else:
|
|
quote do: declval(`T`)[`fieldIndex`]
|
|
|
|
result.add quote do:
|
|
block:
|
|
`fieldNameDefs`
|
|
|
|
template FieldType: untyped {.inject, used.} = typeof(`field`)
|
|
|
|
`body`
|
|
|
|
# echo repr(result)
|
|
|
|
template enumAllSerializedFields(T: type, body): untyped =
|
|
enumAllSerializedFieldsImpl(T, body)
|
|
|
|
type
|
|
FieldReader[RecordType, Reader] = tuple[
|
|
fieldName: string,
|
|
reader: proc (rec: var RecordType, reader: var Reader)
|
|
{.gcsafe, nimcall.}
|
|
]
|
|
|
|
proc totalSerializedFieldsImpl(T: type): int =
|
|
mixin enumAllSerializedFields
|
|
enumAllSerializedFields(T): inc result
|
|
|
|
template totalSerializedFields(T: type): int =
|
|
(static(totalSerializedFieldsImpl(T)))
|
|
|
|
template GetFieldType(FT: type FieldTag): type =
|
|
typeof field(declval(FT.RecordType), FT.fieldName)
|
|
|
|
proc makeFieldReadersTable(RecordType, ReaderType: distinct type,
|
|
numFields: static[int]):
|
|
array[numFields, FieldReader[RecordType, ReaderType]] =
|
|
mixin enumAllSerializedFields, handleReadException
|
|
var idx = 0
|
|
|
|
enumAllSerializedFields(RecordType):
|
|
proc readField(obj: var RecordType, reader: var ReaderType)
|
|
{.gcsafe, nimcall.} =
|
|
|
|
mixin readValue
|
|
|
|
type F = FieldTag[RecordType, realFieldName]
|
|
field(obj, realFieldName) = reader.readValue(GetFieldType(F))
|
|
|
|
result[idx] = (fieldName, readField)
|
|
inc idx
|
|
|
|
proc fieldReadersTable(RecordType, ReaderType: distinct type): auto =
|
|
mixin readValue
|
|
type T = RecordType
|
|
const numFields = totalSerializedFields(T)
|
|
var tbl {.threadvar.}: ref array[numFields, FieldReader[RecordType, ReaderType]]
|
|
if tbl == nil:
|
|
tbl = new typeof(tbl)
|
|
tbl[] = makeFieldReadersTable(RecordType, ReaderType, numFields)
|
|
return addr(tbl[])
|
|
|
|
proc readValue(reader: var auto, T: type): T =
|
|
mixin readValue
|
|
reader.readValue(result)
|
|
|
|
template decode(Format: distinct type,
|
|
input: string,
|
|
RecordType: distinct type): auto =
|
|
mixin Reader
|
|
block: # https://github.com/nim-lang/Nim/issues/22874
|
|
var reader: Reader(Format)
|
|
reader.readValue(RecordType)
|
|
|
|
template readValue(Format: type,
|
|
ValueType: type): untyped =
|
|
mixin Reader, init, readValue
|
|
var reader: Reader(Format)
|
|
readValue reader, ValueType
|
|
|
|
template parseArrayImpl(numElem: untyped,
|
|
actionValue: untyped) =
|
|
actionValue
|
|
|
|
serializationFormat Json
|
|
template createJsonFlavor(FlavorName: untyped,
|
|
skipNullFields = false) {.dirty.} =
|
|
type FlavorName = object
|
|
|
|
template Reader(T: type FlavorName): type = Reader(Json, FlavorName)
|
|
type
|
|
JsonReader[Flavor = DefaultFlavor] = object
|
|
|
|
Json.setReader JsonReader
|
|
|
|
template parseArray(r: var JsonReader; body: untyped) =
|
|
parseArrayImpl(idx): body
|
|
|
|
template parseArray(r: var JsonReader; idx: untyped; body: untyped) =
|
|
parseArrayImpl(idx): body
|
|
|
|
proc readRecordValue[T](r: var JsonReader, value: var T) =
|
|
type
|
|
ReaderType {.used.} = type r
|
|
T = type value
|
|
|
|
discard T.fieldReadersTable(ReaderType)
|
|
|
|
proc readValue[T](r: var JsonReader, value: var T) =
|
|
mixin readValue
|
|
|
|
when value is seq:
|
|
r.parseArray:
|
|
readValue(r, value[0])
|
|
|
|
elif value is object:
|
|
readRecordValue(r, value)
|
|
|
|
type
|
|
RemoteSignerInfo = object
|
|
id: uint32
|
|
RemoteKeystore = object
|
|
|
|
proc readValue(reader: var JsonReader, value: var RemoteKeystore) =
|
|
discard reader.readValue(seq[RemoteSignerInfo])
|
|
|
|
createJsonFlavor RestJson
|
|
useDefaultReaderIn(RemoteSignerInfo, RestJson)
|
|
proc readValue(reader: var JsonReader[RestJson], value: var uint64) =
|
|
discard reader.readValue(string)
|
|
|
|
discard Json.decode("", RemoteKeystore)
|
|
block: # https://github.com/nim-lang/Nim/issues/22874
|
|
var reader: Reader(RestJson)
|
|
discard reader.readValue(RemoteSignerInfo)
|