diff --git a/src/preserves.nim b/src/preserves.nim index 117b56f..a2a46d6 100644 --- a/src/preserves.nim +++ b/src/preserves.nim @@ -3,7 +3,7 @@ import bigints import std/[base64, endians, hashes, macros, sets, streams, tables, typetraits] -import json except `%` +import json except `%`, `%*` type PreserveKind* = enum @@ -470,6 +470,91 @@ proc parsePreserve*(s: Stream): Preserve = else: assertStream(false) +proc initDictionary*(): Preserve = Preserve(kind: pkDictionary) + +proc `%`*(b: bool): Preserve = + Preserve(kind: pkBoolean, bool: b) + +proc `%`*(f: float32): Preserve = + Preserve(kind: pkFloat, float: f) + +proc `%`*(d: float64): Preserve = + Preserve(kind: pkDouble, double: d) + +proc `%`*(n: SomeInteger): Preserve = + Preserve(kind: pkSignedInteger, int: n) + +proc `%`*(b: Bigint): Preserve = + Preserve(kind: pkBigInteger, bigint: b) + +proc `%`*(s: string): Preserve = + Preserve(kind: pkString, string: s) + +proc `%`*(buf: openarray[byte]): Preserve = + Preserve(kind: pkByteString, bytes: @buf) + +proc `%`*(e: enum): Preserve = + ## Initialize a preserves symbol from the string + ## representation of ``e``. + Preserve(kind: pkSymbol, symbol: $e) + +template `%`*(p: Preserve): Preserve = p + +proc `%`*[T](elems: openArray[T]): Preserve = + result = Preserve(kind: pkSequence, + sequence: newSeqOfCap[Preserve](elems.len)) + for e in elems: result.sequence.add(%e) + +proc `%`*[A,B](pairs: openArray[(A, B)]): Preserve = + result = Preserve(kind: pkDictionary) + for (k, v) in pairs: + when A is string: + result.dict[symbol k] = %v + else: + result.dict[%k] = %v + +proc `%`*[T](set: HashSet[T]): Preserve = + result = Preserve(kind: pkSet #[, set: set.map(`%`)]#) + for e in set: + result.set.incl %e + +proc `%`*[A,B](table: Table[A,B]|TableRef[A,B]): Preserve = + result = Preserve(kind: pkDictionary, dict: initTable[Preserve, Preserve](table.len)) + for k, v in table.pairs: result.dict[%k] = %v + +proc `%`*[T: object](o: T): Preserve = + ## Construct JsonNode from tuples and objects. + result = initDictionary() + for k, v in o.fieldPairs: result.dict[symbol(k)] = %v + +proc percentImpl(x: NimNode): NimNode {.compileTime.} = + case x.kind + of nnkBracket: # sequence + result = newNimNode(nnkBracket) + for i in 0 ..< x.len: + result.add(percentImpl(x[i])) + result = newCall(bindSym("%", brOpen), result) + of nnkTableConstr: # dictionary + if x.len == 0: return newCall(bindSym"initDictionary") + result = newNimNode(nnkTableConstr) + for i in 0 ..< x.len: + x[i].expectKind nnkExprColonExpr + result.add newTree(nnkExprColonExpr, x[i][0], percentImpl(x[i][1])) + result = newCall(bindSym("%", brOpen), result) + of nnkCurly: # set + result = newNimNode(nnkCurly) + for i in 0 ..< x.len: + result.add(percentImpl(x[i])) + result = newCall(bindSym("%", brOpen), result) + of nnkPar: + if x.len == 1: result = percentImpl(x[0]) + else: result = newCall(bindSym("%", brOpen), x) + else: + result = newCall(bindSym("%", brOpen), x) + +macro `%*`*(x: untyped): untyped = + result = percentImpl(x) + template record*(label: string) {.pragma.} ## Serialize this object or tuple as a record. ## ``` @@ -521,7 +606,7 @@ proc toPreserve*[T](x: T): Preserve = elif T is SomeInteger: result = Preserve(kind: pkSignedInteger, int: x.BiggestInt) else: - raiseAssert("cannot convert to Preserves: " & $T) + result = %x proc toPreserveHook*[T](set: HashSet[T]): Preserve = Preserve(kind: pkSet, set: set.map(toPreserve)) @@ -642,7 +727,7 @@ proc fromPreserve*[T](result: var T; prs: Preserve) = elif T is string: result = prs.string else: - raiseAssert("cannot convert from Preserves: " & $T) + static: raiseAssert("cannot convert from Preserves: " & $T) proc preserveTo*(prs: Preserve; T: typedesc): T = ## Reverse of `toPreserve`. @@ -663,73 +748,3 @@ proc `[]`*(prs: Preserve; i: int): Preserve = of pkSequence: prs.sequence[i] else: raise newException(ValueError, "`[]` is not valid for " & $prs.kind) - -template `%`*(p: Preserve): Preserve = p - -proc `%`*(b: bool): Preserve = - Preserve(kind: pkBoolean, bool: b) - -proc `%`*(f: float32): Preserve = - Preserve(kind: pkFloat, float: f) - -proc `%`*(d: float64): Preserve = - Preserve(kind: pkDouble, double: d) - -proc `%`*(n: SomeInteger): Preserve = - Preserve(kind: pkSignedInteger, int: n) - -proc `%`*(b: Bigint): Preserve = - Preserve(kind: pkBigInteger, bigint: b) - -proc `%`*(s: string): Preserve = - Preserve(kind: pkString, string: s) - -proc `%`*(buf: seq[byte]): Preserve = - Preserve(kind: pkByteString, bytes: buf) - -proc `%`*(e: enum): Preserve = - ## Initialize a preserves symbol from the string - ## representation of ``e``. - Preserve(kind: pkSymbol, symbol: $e) - -proc `%`*[T](elems: openArray[T]): Preserve = - result = Preserve(kind: pkSequence, - sequence: newSeqOfCap[Preserve](elems.len)) - for e in elems: result.sequence.add(%e) - -proc `%`*[T](set: HashSet[T]): Preserve = - result = Preserve(kind: pkSet #[, set: set.map(`%`)]#) - for e in set: - result.set.incl %e - -proc `%`*[A,B](table: Table[A,B]|TableRef[A,B]): Preserve = - result = Preserve(kind: pkDictionary, dict: initTable[Preserve, Preserve](table.len)) - for k, v in table.pairs: result.dict[%k] = %v - -proc toPreserveImpl(x: NimNode): NimNode {.compileTime.} = - case x.kind - of nnkBracket: # sequence - result = newNimNode(nnkBracket) - for i in 0 ..< x.len: - result.add(toPreserveImpl(x[i])) - result = newCall(bindSym("%", brOpen), result) - of nnkTableConstr: # dictionary - if x.len == 0: return newCall(bindSym"newJObject") - result = newNimNode(nnkTableConstr) - for i in 0 ..< x.len: - x[i].expectKind nnkExprColonExpr - result.add newTree(nnkExprColonExpr, x[i][0], toPreserveImpl(x[i][1])) - result = newCall(bindSym("%", brOpen), result) - of nnkCurly: # set - result = newNimNode(nnkCurly) - for i in 0 ..< x.len: - result.add(toPreserveImpl(x[i])) - result = newCall(bindSym("%", brOpen), result) - of nnkPar: - if x.len == 1: result = toPreserveImpl(x[0]) - else: result = newCall(bindSym("%", brOpen), x) - else: - result = newCall(bindSym("%", brOpen), x) - -macro `%*`*(x: untyped): untyped = - result = toPreserveImpl(x) diff --git a/src/preserves/records.nim b/src/preserves/records.nim index e28766e..3c81536 100644 --- a/src/preserves/records.nim +++ b/src/preserves/records.nim @@ -24,20 +24,6 @@ type RecordClass* = object proc `$`*(rec: RecordClass): string = $rec.label & "/" & $rec.arity -proc `%`*(rec: RecordClass; field: Preserve): Preserve = - ## Initialize a simple record value. - assert(rec.arity == 1) - Preserve(kind: pkRecord, record: @[field, rec.label]) - -proc `%`*[T](rec: RecordClass; field: T): Preserve = - ## Initialize a simple record value. - rec % toPreserve(field) - -proc init*(rec: RecordClass; fields: varargs[Preserve, toPreserve]): Preserve = - ## Initialize a new record value. - assert(fields.len == rec.arity) - result = initRecord(rec.label, fields) - proc isClassOf*(rec: RecordClass; val: Preserve): bool = ## Compare the label and arity of ``val`` to the record type ``rec``. if val.kind == pkRecord: @@ -63,3 +49,28 @@ proc classOf*(T: typedesc[tuple]): RecordClass = RecordClass( label: preserves.symbol(T.getCustomPragmaVal(record)), arity: tupleLen(T)) + +proc init*(rec: RecordClass; fields: varargs[Preserve, toPreserve]): Preserve = + ## Initialize a new record value. + assert(fields.len == rec.arity, $(%fields) & " (arity " & $fields.len & ") is not of arity " & $rec.arity) + result = initRecord(rec.label, fields) + +proc init*(T: typedesc[tuple]; fields: varargs[Preserve, toPreserve]): Preserve = + ## Initialize a new record value. + init(classOf(T), fields) + +proc `%`*(rec: RecordClass; fields: openArray[Preserve]): Preserve = + ## Initialize a simple record value. + init(rec, fields) + +proc `%`*(rec: RecordClass; field: Preserve): Preserve = + ## Initialize a simple record value. + init(rec, [field]) + +proc `%`*[T](rec: RecordClass; field: T): Preserve = + ## Initialize a simple record value. + init(rec, [toPreserve field]) + +proc `%`*(T: typedesc[tuple]; fields: varargs[Preserve, toPreserve]): Preserve = + ## Initialize a new record value. + `%`(classOf(T), fields)