marshal.nim 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module contains procs for `serialization`:idx: and `deseralization`:idx:
  10. ## of arbitrary Nim data structures. The serialization format uses `JSON`:idx:.
  11. ## Warning: The serialization format could change in future!
  12. ##
  13. ## **Restriction**: For objects their type is **not** serialized. This means
  14. ## essentially that it does not work if the object has some other runtime
  15. ## type than its compiletime type:
  16. ##
  17. ## .. code-block:: nim
  18. ##
  19. ## type
  20. ## A = object of RootObj
  21. ## B = object of A
  22. ## f: int
  23. ##
  24. ## var
  25. ## a: ref A
  26. ## b: ref B
  27. ##
  28. ## new(b)
  29. ## a = b
  30. ## echo($$a[]) # produces "{}", not "{f: 0}"
  31. ##
  32. ## # unmarshal
  33. ## let c = to[B]("""{"f": 2}""")
  34. ##
  35. ## # marshal
  36. ## let s = $$c
  37. ## **Note**: The ``to`` and ``$$`` operations are available at compile-time!
  38. import streams, typeinfo, json, intsets, tables, unicode
  39. proc ptrToInt(x: pointer): int {.inline.} =
  40. result = cast[int](x) # don't skip alignment
  41. proc storeAny(s: Stream, a: Any, stored: var IntSet) =
  42. case a.kind
  43. of akNone: assert false
  44. of akBool: s.write($getBool(a))
  45. of akChar:
  46. let ch = getChar(a)
  47. if ch < '\128':
  48. s.write(escapeJson($ch))
  49. else:
  50. s.write($int(ch))
  51. of akArray, akSequence:
  52. s.write("[")
  53. for i in 0 .. a.len-1:
  54. if i > 0: s.write(", ")
  55. storeAny(s, a[i], stored)
  56. s.write("]")
  57. of akObject, akTuple:
  58. s.write("{")
  59. var i = 0
  60. for key, val in fields(a):
  61. if i > 0: s.write(", ")
  62. s.write(escapeJson(key))
  63. s.write(": ")
  64. storeAny(s, val, stored)
  65. inc(i)
  66. s.write("}")
  67. of akSet:
  68. s.write("[")
  69. var i = 0
  70. for e in elements(a):
  71. if i > 0: s.write(", ")
  72. s.write($e)
  73. inc(i)
  74. s.write("]")
  75. of akRange: storeAny(s, skipRange(a), stored)
  76. of akEnum: s.write(getEnumField(a).escapeJson)
  77. of akPtr, akRef:
  78. var x = a.getPointer
  79. if isNil(x): s.write("null")
  80. elif stored.containsOrIncl(x.ptrToInt):
  81. # already stored, so we simply write out the pointer as an int:
  82. s.write($x.ptrToInt)
  83. else:
  84. # else as a [value, key] pair:
  85. # (reversed order for convenient x[0] access!)
  86. s.write("[")
  87. s.write($x.ptrToInt)
  88. s.write(", ")
  89. storeAny(s, a[], stored)
  90. s.write("]")
  91. of akProc, akPointer, akCString: s.write($a.getPointer.ptrToInt)
  92. of akString:
  93. var x = getString(a)
  94. if x.validateUtf8() == -1: s.write(escapeJson(x))
  95. else:
  96. s.write("[")
  97. var i = 0
  98. for c in x:
  99. if i > 0: s.write(", ")
  100. s.write($ord(c))
  101. inc(i)
  102. s.write("]")
  103. of akInt..akInt64, akUInt..akUInt64: s.write($getBiggestInt(a))
  104. of akFloat..akFloat128: s.write($getBiggestFloat(a))
  105. proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) =
  106. case a.kind
  107. of akNone: assert false
  108. of akBool:
  109. case p.kind
  110. of jsonFalse: setBiggestInt(a, 0)
  111. of jsonTrue: setBiggestInt(a, 1)
  112. else: raiseParseErr(p, "'true' or 'false' expected for a bool")
  113. next(p)
  114. of akChar:
  115. if p.kind == jsonString:
  116. var x = p.str
  117. if x.len == 1:
  118. setBiggestInt(a, ord(x[0]))
  119. next(p)
  120. return
  121. elif p.kind == jsonInt:
  122. setBiggestInt(a, getInt(p))
  123. next(p)
  124. return
  125. raiseParseErr(p, "string of length 1 expected for a char")
  126. of akEnum:
  127. if p.kind == jsonString:
  128. setBiggestInt(a, getEnumOrdinal(a, p.str))
  129. next(p)
  130. return
  131. raiseParseErr(p, "string expected for an enum")
  132. of akArray:
  133. if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for an array")
  134. next(p)
  135. var i = 0
  136. while p.kind != jsonArrayEnd and p.kind != jsonEof:
  137. loadAny(p, a[i], t)
  138. inc(i)
  139. if p.kind == jsonArrayEnd: next(p)
  140. else: raiseParseErr(p, "']' end of array expected")
  141. of akSequence:
  142. case p.kind
  143. of jsonNull:
  144. setPointer(a, nil)
  145. next(p)
  146. of jsonArrayStart:
  147. next(p)
  148. invokeNewSeq(a, 0)
  149. var i = 0
  150. while p.kind != jsonArrayEnd and p.kind != jsonEof:
  151. extendSeq(a)
  152. loadAny(p, a[i], t)
  153. inc(i)
  154. if p.kind == jsonArrayEnd: next(p)
  155. else: raiseParseErr(p, "")
  156. else:
  157. raiseParseErr(p, "'[' expected for a seq")
  158. of akObject, akTuple:
  159. if a.kind == akObject: setObjectRuntimeType(a)
  160. if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
  161. next(p)
  162. while p.kind != jsonObjectEnd and p.kind != jsonEof:
  163. if p.kind != jsonString:
  164. raiseParseErr(p, "string expected for a field name")
  165. var fieldName = p.str
  166. next(p)
  167. loadAny(p, a[fieldName], t)
  168. if p.kind == jsonObjectEnd: next(p)
  169. else: raiseParseErr(p, "'}' end of object expected")
  170. of akSet:
  171. if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for a set")
  172. next(p)
  173. while p.kind != jsonArrayEnd and p.kind != jsonEof:
  174. if p.kind != jsonInt: raiseParseErr(p, "int expected for a set")
  175. inclSetElement(a, p.getInt.int)
  176. next(p)
  177. if p.kind == jsonArrayEnd: next(p)
  178. else: raiseParseErr(p, "']' end of array expected")
  179. of akPtr, akRef:
  180. case p.kind
  181. of jsonNull:
  182. setPointer(a, nil)
  183. next(p)
  184. of jsonInt:
  185. setPointer(a, t.getOrDefault(p.getInt))
  186. next(p)
  187. of jsonArrayStart:
  188. next(p)
  189. if a.kind == akRef: invokeNew(a)
  190. else: setPointer(a, alloc0(a.baseTypeSize))
  191. if p.kind == jsonInt:
  192. t[p.getInt] = getPointer(a)
  193. next(p)
  194. else: raiseParseErr(p, "index for ref type expected")
  195. loadAny(p, a[], t)
  196. if p.kind == jsonArrayEnd: next(p)
  197. else: raiseParseErr(p, "']' end of ref-address pair expected")
  198. else: raiseParseErr(p, "int for pointer type expected")
  199. of akProc, akPointer, akCString:
  200. case p.kind
  201. of jsonNull:
  202. setPointer(a, nil)
  203. next(p)
  204. of jsonInt:
  205. setPointer(a, cast[pointer](p.getInt.int))
  206. next(p)
  207. else: raiseParseErr(p, "int for pointer type expected")
  208. of akString:
  209. case p.kind
  210. of jsonNull:
  211. setPointer(a, nil)
  212. next(p)
  213. of jsonString:
  214. setString(a, p.str)
  215. next(p)
  216. of jsonArrayStart:
  217. next(p)
  218. var str = ""
  219. while p.kind == jsonInt:
  220. let code = p.getInt()
  221. if code < 0 or code > 255:
  222. raiseParseErr(p, "invalid charcode: " & $code)
  223. str.add(chr(code))
  224. next(p)
  225. if p.kind == jsonArrayEnd: next(p)
  226. else: raiseParseErr(p, "an array of charcodes expected for string")
  227. setString(a, str)
  228. else: raiseParseErr(p, "string expected")
  229. of akInt..akInt64, akUInt..akUInt64:
  230. if p.kind == jsonInt:
  231. setBiggestInt(a, getInt(p))
  232. next(p)
  233. return
  234. raiseParseErr(p, "int expected")
  235. of akFloat..akFloat128:
  236. if p.kind == jsonFloat:
  237. setBiggestFloat(a, getFloat(p))
  238. next(p)
  239. return
  240. raiseParseErr(p, "float expected")
  241. of akRange: loadAny(p, a.skipRange, t)
  242. proc loadAny(s: Stream, a: Any, t: var Table[BiggestInt, pointer]) =
  243. var p: JsonParser
  244. open(p, s, "unknown file")
  245. next(p)
  246. loadAny(p, a, t)
  247. close(p)
  248. proc load*[T](s: Stream, data: var T) =
  249. ## loads `data` from the stream `s`. Raises `IOError` in case of an error.
  250. var tab = initTable[BiggestInt, pointer]()
  251. loadAny(s, toAny(data), tab)
  252. proc store*[T](s: Stream, data: T) =
  253. ## stores `data` into the stream `s`. Raises `IOError` in case of an error.
  254. var stored = initIntSet()
  255. var d: T
  256. shallowCopy(d, data)
  257. storeAny(s, toAny(d), stored)
  258. proc `$$`*[T](x: T): string =
  259. ## returns a string representation of `x`.
  260. ##
  261. ## Note: to serialize `x` to JSON use $(%x) from the ``json`` module
  262. var stored = initIntSet()
  263. var d: T
  264. shallowCopy(d, x)
  265. var s = newStringStream()
  266. storeAny(s, toAny(d), stored)
  267. result = s.data
  268. proc to*[T](data: string): T =
  269. ## reads data and transforms it to a ``T``.
  270. runnableExamples:
  271. type
  272. Foo = object
  273. id: int
  274. bar: string
  275. let x = Foo(id: 1, bar: "baz")
  276. # serialize
  277. let y = ($$x)
  278. # deserialize back to type 'Foo':
  279. let z = y.to[:Foo]
  280. var tab = initTable[BiggestInt, pointer]()
  281. loadAny(newStringStream(data), toAny(result), tab)
  282. when not defined(testing) and isMainModule:
  283. template testit(x: untyped) = echo($$to[type(x)]($$x))
  284. var x: array[0..4, array[0..4, string]] = [
  285. ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
  286. ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
  287. ["test", "1", "2", "3", "4"]]
  288. testit(x)
  289. var test2: tuple[name: string, s: uint] = ("tuple test", 56u)
  290. testit(test2)
  291. type
  292. TE = enum
  293. blah, blah2
  294. TestObj = object
  295. test, asd: int
  296. case test2: TE
  297. of blah:
  298. help: string
  299. else:
  300. nil
  301. PNode = ref Node
  302. Node = object
  303. next, prev: PNode
  304. data: string
  305. proc buildList(): PNode =
  306. new(result)
  307. new(result.next)
  308. new(result.prev)
  309. result.data = "middle"
  310. result.next.data = "next"
  311. result.prev.data = "prev"
  312. result.next.next = result.prev
  313. result.next.prev = result
  314. result.prev.next = result
  315. result.prev.prev = result.next
  316. var test3: TestObj
  317. test3.test = 42
  318. test3.test2 = blah
  319. testit(test3)
  320. var test4: ref tuple[a, b: string]
  321. new(test4)
  322. test4.a = "ref string test: A"
  323. test4.b = "ref string test: B"
  324. testit(test4)
  325. var test5 = @[(0,1),(2,3),(4,5)]
  326. testit(test5)
  327. var test6: set[char] = {'A'..'Z', '_'}
  328. testit(test6)
  329. var test7 = buildList()
  330. echo($$test7)
  331. testit(test7)
  332. type
  333. A {.inheritable.} = object
  334. B = object of A
  335. f: int
  336. var
  337. a: ref A
  338. b: ref B
  339. new(b)
  340. a = b
  341. echo($$a[]) # produces "{}", not "{f: 0}"