diff --git a/preserves.nimble b/preserves.nimble index 0be8cb9..2e0d4e7 100644 --- a/preserves.nimble +++ b/preserves.nimble @@ -1,6 +1,6 @@ # Package -version = "20240102" +version = "20240103" author = "Emery Hemingway" description = "data model and serialization format" license = "Unlicense" diff --git a/src/preserves.nim b/src/preserves.nim index bf5ae8b..a2ec0a7 100644 --- a/src/preserves.nim +++ b/src/preserves.nim @@ -142,15 +142,6 @@ proc `&`*(x: Value; y: seq[Value]): Value = raise newException(ValueError, "cannot concatenate to non-sequence value") result = Value(kind: pkSequence, sequence: x.sequence & y) -proc getOrDefault(pr, key: Value): Value = - ## Retrieves the value of `pr[key]` if `pr` is a dictionary containing `key` - ## or returns the `#f` Preserves value. - if pr.kind == pkDictionary: - for (k, v) in pr.dict: - if key == k: - result = v - break - proc pop*(pr: var Value; key: Value; val: var Value): bool = ## Deletes the `key` from a Preserves dictionary. ## Returns true, if the key existed, and sets `val` to the mapping @@ -440,9 +431,15 @@ proc toPreserves*[T](x: T): Value {.gcsafe.} = elif T.hasCustomPragma(preservesDictionary): result = initDictionary() for key, val in x.fieldPairs: - var pr = fieldToPreserve(key, val) - applyEmbed(key, pr) - result[toSymbol(key)] = pr + when val is Option: + if val.isSome: + var pr = fieldToPreserve(key, val.get) + applyEmbed(key, pr) + result[key.toSymbol] = pr + else: + var pr = fieldToPreserve(key, val) + applyEmbed(key, pr) + result[key.toSymbol] = pr sortDict(result) else: {.warning: "failed to preserve object " & $T .} @@ -491,6 +488,9 @@ proc toPreservesHook*[A, B](table: Table[A, B]|TableRef[A, B]): Value = result[toPreserves(k)] = toPreserves(v) sortDict(result) +proc toPreservesHook*(o: Option): Value = + o.get.toPreserves + proc fromAtom*[T](v: var T; a: ATom): bool = if T is Atom: v = a @@ -715,12 +715,17 @@ proc fromPreserves*[T](v: var T; pr: Value): bool {.gcsafe.} = if pr.isDictionary: result = true var i: int - for key, _ in fieldPairs(v): - let val = pr.getOrDefault(toSymbol(key)) - result = result and fieldFromPreserve( - key, v.dot(key), val) + for key, field in fieldPairs(v): if not result: break - inc i + let val = step(pr, key.toSymbol) + when field is Option: + if val.isSome: + discard fieldFromPreserve(key, v.dot(key), val.get) + else: + inc i + result = result and val.isSome + if result: + result = result and fieldFromPreserve(key, v.dot(key), val.get) result = result and (i <= pr.len) elif T.hasCustomPragma(preservesOr): for kind in typeof(T.orKind): @@ -740,9 +745,11 @@ proc fromPreserves*[T](v: var T; pr: Value): bool {.gcsafe.} = result = true var i: int for key, _ in fieldPairs(v): - let val = pr.getOrDefault(toSymbol(key)) - result = result and fieldFromPreserve(key, v.dot(key), val) if not result: break + let val = step(pr, key.toSymbol) + result = result and val.isSome + if result: + result = result and fieldFromPreserve(key, v.dot(key), val.get) inc i result = result and (i <= pr.len) else: @@ -811,6 +818,12 @@ proc fromPreservesHook*[A,B](t: var (Table[A,B]|TableRef[A,B]); pr: Value): bool break t[move a] = move b +proc fromPreservesHook*[T](opt: var Option[T]; pr: Value): bool = + opt = some(default T) + result = opt.get.fromPreserves(pr) + if not result: + opt = none(T) + when isMainModule: var t: Table[int, string] var pr = t.toPreservesHook() diff --git a/tests/test_conversions.nim b/tests/test_conversions.nim index ba6c831..00782cb 100644 --- a/tests/test_conversions.nim +++ b/tests/test_conversions.nim @@ -17,11 +17,13 @@ suite "conversions": a: int b: seq[int] c {.preservesEmbedded.}: Bar + d: Option[bool] + e: Option[bool] let - c = Foobar(a: 1, b: @[2], c: ("ku", )) + c = Foobar(a: 1, b: @[2], c: ("ku", ), e: some(true)) b = toPreserves(c) a = preservesTo(b, Foobar) - check($b == """{a: 1 b: [2] c: #!["ku"]}""") + check($b == """{a: 1 b: [2] c: #!["ku"] e: #t}""") check(a.isSome) if a.isSome: check(get(a) == c) check(b.kind == pkDictionary)