oids.nim 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2013 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Nim OID support. An OID is a global ID that consists of a timestamp,
  10. ## a unique counter and a random value. This combination should suffice to
  11. ## produce a globally distributed unique ID. This implementation was extracted
  12. ## from the Mongodb interface and it thus binary compatible with a Mongo OID.
  13. ##
  14. ## This implementation calls ``math.randomize()`` for the first call of
  15. ## ``genOid``.
  16. import hashes, times, endians
  17. type
  18. Oid* = object ## an OID
  19. time: int32 ##
  20. fuzz: int32 ##
  21. count: int32 ##
  22. proc `==`*(oid1: Oid, oid2: Oid): bool =
  23. ## Compare two Mongo Object IDs for equality
  24. return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and
  25. (oid1.count == oid2.count)
  26. proc hash*(oid: Oid): Hash =
  27. ## Generate hash of Oid for use in hashtables
  28. var h: Hash = 0
  29. h = h !& hash(oid.time)
  30. h = h !& hash(oid.fuzz)
  31. h = h !& hash(oid.count)
  32. result = !$h
  33. proc hexbyte*(hex: char): int =
  34. case hex
  35. of '0'..'9': result = (ord(hex) - ord('0'))
  36. of 'a'..'f': result = (ord(hex) - ord('a') + 10)
  37. of 'A'..'F': result = (ord(hex) - ord('A') + 10)
  38. else: discard
  39. proc parseOid*(str: cstring): Oid =
  40. ## parses an OID.
  41. var bytes = cast[cstring](addr(result.time))
  42. var i = 0
  43. while i < 12:
  44. bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1]))
  45. inc(i)
  46. proc oidToString*(oid: Oid, str: cstring) =
  47. const hex = "0123456789abcdef"
  48. # work around a compiler bug:
  49. var str = str
  50. var o = oid
  51. var bytes = cast[cstring](addr(o))
  52. var i = 0
  53. while i < 12:
  54. let b = bytes[i].ord
  55. str[2 * i] = hex[(b and 0xF0) shr 4]
  56. str[2 * i + 1] = hex[b and 0xF]
  57. inc(i)
  58. str[24] = '\0'
  59. proc `$`*(oid: Oid): string =
  60. result = newString(24)
  61. oidToString(oid, result)
  62. proc rand(): cint {.importc: "rand", header: "<stdlib.h>", nodecl.}
  63. proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>", nodecl.}
  64. var t = getTime().toUnix.int32
  65. srand(t)
  66. var
  67. incr: int = rand()
  68. fuzz: int32 = rand()
  69. proc genOid*(): Oid =
  70. ## generates a new OID.
  71. t = getTime().toUnix.int32
  72. var i = int32(atomicInc(incr))
  73. bigEndian32(addr result.time, addr(t))
  74. result.fuzz = fuzz
  75. bigEndian32(addr result.count, addr(i))
  76. proc generatedTime*(oid: Oid): Time =
  77. ## returns the generated timestamp of the OID.
  78. var tmp: int32
  79. var dummy = oid.time
  80. bigEndian32(addr(tmp), addr(dummy))
  81. result = fromUnix(tmp)
  82. when not defined(testing) and isMainModule:
  83. let xo = genOid()
  84. echo xo.generatedTime