marshal.nim 11 KB

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