oids.nim 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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.
  12. ##
  13. ## This implementation calls `initRand()` for the first call of
  14. ## `genOid`.
  15. import hashes, times, endians, random
  16. from std/private/decode_helpers import handleHexChar
  17. type
  18. Oid* = object ## An OID.
  19. time: int64
  20. fuzz: int32
  21. count: int32
  22. proc `==`*(oid1: Oid, oid2: Oid): bool {.inline.} =
  23. ## Compares two OIDs for equality.
  24. result = (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and
  25. (oid1.count == oid2.count)
  26. proc hash*(oid: Oid): Hash =
  27. ## Generates the hash of an 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 {.inline.} =
  34. result = handleHexChar(hex)
  35. proc parseOid*(str: cstring): Oid =
  36. ## Parses an OID.
  37. var bytes = cast[cstring](addr(result.time))
  38. var i = 0
  39. while i < 16:
  40. bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1]))
  41. inc(i)
  42. proc `$`*(oid: Oid): string =
  43. ## Converts an OID to a string.
  44. const hex = "0123456789abcdef"
  45. result.setLen 32
  46. var o = oid
  47. var bytes = cast[cstring](addr(o))
  48. var i = 0
  49. while i < 16:
  50. let b = bytes[i].ord
  51. result[2 * i] = hex[(b and 0xF0) shr 4]
  52. result[2 * i + 1] = hex[b and 0xF]
  53. inc(i)
  54. let
  55. t = getTime().toUnix
  56. var
  57. seed = initRand(t)
  58. incr: int = seed.rand(int.high)
  59. let fuzz = cast[int32](seed.rand(high(int)))
  60. template genOid(result: var Oid, incr: var int, fuzz: int32) =
  61. var time = getTime().toUnix
  62. var i = cast[int32](atomicInc(incr))
  63. bigEndian64(addr result.time, addr(time))
  64. result.fuzz = fuzz
  65. bigEndian32(addr result.count, addr(i))
  66. proc genOid*(): Oid =
  67. ## Generates a new OID.
  68. runnableExamples:
  69. doAssert ($genOid()).len == 32
  70. runnableExamples("-r:off"):
  71. echo $genOid() # for example, "00000000632c452db08c3d19ee9073e5"
  72. genOid(result, incr, fuzz)
  73. proc generatedTime*(oid: Oid): Time =
  74. ## Returns the generated timestamp of the OID.
  75. var tmp: int64
  76. var dummy = oid.time
  77. bigEndian64(addr(tmp), addr(dummy))
  78. result = fromUnix(tmp)