Skip to content

Instantly share code, notes, and snippets.

@miguelmartin75
Created August 28, 2025 20:31
Show Gist options
  • Select an option

  • Save miguelmartin75/c41143c50c7a055d0b8b36e690a5cd56 to your computer and use it in GitHub Desktop.

Select an option

Save miguelmartin75/c41143c50c7a055d0b8b36e690a5cd56 to your computer and use it in GitHub Desktop.
Compile and run with `nim c -r kvs.nim`
import std/[parseutils, strformat, strutils, tables, sugar, enumerate]
type ParseError* = object of CatchableError
proc parseValue*(x: var int, value: string): bool = parseInt(value, x) > 0
proc parseValue*(x: var float, value: string): bool = parseFloat(value, x) > 0
proc parseValue*(x: var string, value: string): bool =
x = value
return true
proc loadFromData*[T: object](content: string, sep: string = "="): T =
let
kvs = collect:
for i, line in enumerate(content.splitLines):
if line.len == 0:
continue
let kv = line.split(sep)
doAssert kv.len == 2, (
&"line: {i}, expected a key and value pair seperated by {sep}" &
&"got instead {kv.len} seperations, line content: {line}"
)
{kv[0]: kv[1]}
for name, value in result.fieldPairs:
if name in kvs:
if not parseValue(value, kvs[name]):
raise newException(ParseError,
"could not parse field: '" &
$name &
"' with specified value: " &
kvs[name] &
" (expected type is: " & $typeof(value) & ")"
)
# NOTE: the below line wont work as `name` & `value` are mangled, as this loop is unrolled inline
# raise newException(CatchableError, &"could not parse '{name}' ...")
proc load*[T: object](fp: string, sep: string = "="): T =
let content = readFile(fp)
return loadFromData[T](content, sep)
proc parseValue*[T](xs: var seq[T], value: string): bool =
doAssert value.startsWith("["), "expected seq to start with character '['"
doAssert value.endsWith("]"), "expected seq to start with character ']'"
for value in value[1..^2].split(","):
var tmp: T
doAssert parseValue(tmp, value.strip(trailing=false)), &"could not parse {value} as type {$T}"
xs.add tmp
return true
type
Config = object
name: string
lr: float
betas: seq[float]
# placing config.txt in a const, as the Nim playground doesn't support files
const configData = """
name=my experiment
lr=0.001
betas=[0.99, 0.999]
"""
# let config = load[Config]("config.txt")
let config = loadFromData[Config](configData)
echo config
# const configAtCt = load[Config]("config.txt")
const configAtCt = loadFromData[Config](configData)
static: # a static block executes each statement at complie time
echo "Configuration at compile time:"
echo configAtCt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment