I'm trying to make a generic procedure (or template or macro) that takes what's inside a seq[string] and parse its contents into the appropriate fields of any custom object provided.
import std/strutils
type
MyType = object
a: float
b: string
c: int
#This is the "manual way" of doing what I want, by typing out the parsing procedure for
#each field of a specific object
proc mseqToObj(obj:var MyType; sqn: seq[string]) =
obj.a = parseFloat(sqn[0])
obj.b = sqn[1]
obj.c = parseInt(sqn[2])
#My current attempt at trying to make it work for any custom <object>.
proc seqToObj[T](obj: var T; sqn: seq[string]) =
var count: int = 0 #a counter to go through the [sequence]
for fi in fields(obj):
case $fi.typedesc
of $float: fi = parseFloat(sqn[count]) # Error: type mismatch: got 'float' for 'parseFloat(sqn[count])' but expected 'string'
of $string: fi = sqn[count] # Error: type mismatch: got 'string' for 'sqn[count]' but expected 'float'
of $int: fi = parseInt(sqn[count]) # Error: type mismatch: got 'int' for 'parseInt(sqn[count])' but expected 'string'
count += 1
Although the code for seqToObj seems mostly fine, since the case $fi.typedef of... attempts to only let parsing happen for when the field is of said type, the compiler will always fail at the lines where I attempt to parse the values within sqn[count], since it checks for all of the custom object's field types. Even if MyType only had 2 different field types, like float and string, that code would never compile, as it would always point to the parseFloat or the normal sqn[counter]. However, if the object's fields are all of the same type, and the proc only needed to parse said one type, it works, as is the case with the code below:
type
Floater = object
grav, rad, den: float
proc floatParser[T](obj: var T; sqn: seq[string]) =
var count: int = 0 #a counter to go through the sequence
for fi in fields(obj):
fi = parseFloat(sqn[count])
count += 1
var fltr: Floater
floatParser(fltr, @["0.78","3.14","1.677756"])
echo fltr #will correctly print (grav: 0.78, rad: 3.14, den: 1.677756)
So, how should I approach this problem, of parsing strings for an unknown number of fields with a variety of types, within a generic-esque procedure (or macro or template)? Any other recommendations on code cleanup and readability, like a better way to compare field types instead of field.typedesc == $float?
you need to use when. thats a comptime-if
proc seqToObj[T](obj: var T; sqn: seq[string]) =
var count: int = 0
for fi in fields(obj):
when fi is SomeFloat: fi = parseFloat(sqn[count])
elif fi is string: fi = sqn[count]
elif fi is SomeInteger: fi = parseInt(sqn[count])
count += 1
One of the best complete examples for type conversion can be found in MsgPack4Nim: https://github.com/jangko/msgpack4nim/blob/5294022df4de1af2f6bc349488a578d8946f39c2/src/msgpack4nim.nim#L1141
Also, if possible to use your own format, use something like MsgPack. I was getting type conversions from MsgPack counted in the 10's of nanoseconds.
Thanks, that was exactly what I needed to make it work!
@mig I see, overloading via several specific "parseValue" procedures, you can properly treat for all the needed types you use within your own objects
@elcritch I wasn't aware of MessagePack, interesting way to save data. I'll look into it, it sounds super useful
You might be interested in https://github.com/status-im/nim-serialization as well which is a library for writing libraries that convert objects to various formats and back.
It covers the techniques discussed above, along with several other goodies on top, and has several formats to choose from.
If you find msgpack interesting, you might want to consider CBOR instead which is an evolution/upgrade of the former, but standardised, interoperable with JSON and more efficient overall.
See also: https://git.sr.ht/~ehmry/nim_cbor
Documentation is a bit sparse, but I've recently used it successfully to implement a CBOR RPC server/client (not published yet).
CBOR link is broken
Should be fixed - basically, it's a port of json_serialization - and indeed, CDDL is interesting for as a future direction, including for RPC purposes where it would complement https://github.com/status-im/nim-json-rpc/
Should be fixed - basically, it's a port of json_serialization
Thanks! I'll have to check it out and do some benchmarking.
and indeed, CDDL is interesting for as a future direction, including for RPC purposes where it would complement https://github.com/status-im/nim-json-rpc/
Definitely something I've wanted for embedded stuff.
There's CoAP which is essentially a URI based RPC protocol over UDP. There's a streaming portion of the protocol over UDP which I've wanted for a while.