Created
August 28, 2025 20:31
-
-
Save miguelmartin75/c41143c50c7a055d0b8b36e690a5cd56 to your computer and use it in GitHub Desktop.
Compile and run with `nim c -r kvs.nim`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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