diff --git a/changelog.md b/changelog.md index 8b9676a3acaf5..d70a4367d8aac 100644 --- a/changelog.md +++ b/changelog.md @@ -65,8 +65,6 @@ - `strutils.find` now uses and defaults to `last = -1` for whole string searches, making limiting it to just the first char (`last = 0`) valid. - `random.rand` now works with `Ordinal`s. -- `std/oids` now uses `int64` to store time internally (before it was int32), the length of - the string form of `Oid` changes from 24 to 32. [//]: # "Additions:" - Added ISO 8601 week date utilities in `times`: diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index 43eadad27b257..776c046b1556b 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -9,7 +9,8 @@ ## Nim OID support. An OID is a global ID that consists of a timestamp, ## a unique counter and a random value. This combination should suffice to -## produce a globally distributed unique ID. +## produce a globally distributed unique ID. This implementation was extracted +## from the MongoDB interface and is thus binary compatible with a MongoDB OID. ## ## This implementation calls `initRand()` for the first call of ## `genOid`. @@ -19,7 +20,7 @@ from std/private/decode_helpers import handleHexChar type Oid* = object ## An OID. - time: int64 + time: int32 fuzz: int32 count: int32 @@ -43,27 +44,37 @@ proc parseOid*(str: cstring): Oid = ## Parses an OID. var bytes = cast[cstring](addr(result.time)) var i = 0 - while i < 16: + while i < 12: bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1])) inc(i) -proc `$`*(oid: Oid): string = - ## Converts an OID to a string. +template toStringImpl[T: string | cstring](result: var T, oid: Oid) = + ## Stringifies `oid`. const hex = "0123456789abcdef" + const N = 24 - result.setLen 32 + when T is string: + result.setLen N var o = oid var bytes = cast[cstring](addr(o)) var i = 0 - while i < 16: + while i < 12: let b = bytes[i].ord result[2 * i] = hex[(b and 0xF0) shr 4] result[2 * i + 1] = hex[b and 0xF] inc(i) + when T is cstring: + result[N] = '\0' + + +proc `$`*(oid: Oid): string = + ## Converts an OID to a string. + toStringImpl(result, oid) + let - t = getTime().toUnix + t = getTime().toUnix.int32 var seed = initRand(t) @@ -73,24 +84,24 @@ let fuzz = cast[int32](seed.rand(high(int))) template genOid(result: var Oid, incr: var int, fuzz: int32) = - var time = getTime().toUnix + var time = getTime().toUnix.int32 var i = cast[int32](atomicInc(incr)) - bigEndian64(addr result.time, addr(time)) + bigEndian32(addr result.time, addr(time)) result.fuzz = fuzz bigEndian32(addr result.count, addr(i)) proc genOid*(): Oid = ## Generates a new OID. runnableExamples: - doAssert ($genOid()).len == 32 + doAssert ($genOid()).len == 24 runnableExamples("-r:off"): - echo $genOid() # for example, "00000000632c452db08c3d19ee9073e5" + echo $genOid() # for example, "5fc7f546ddbbc84800006aaf" genOid(result, incr, fuzz) proc generatedTime*(oid: Oid): Time = ## Returns the generated timestamp of the OID. - var tmp: int64 + var tmp: int32 var dummy = oid.time - bigEndian64(addr(tmp), addr(dummy)) + bigEndian32(addr(tmp), addr(dummy)) result = fromUnix(tmp) diff --git a/tests/stdlib/toids.nim b/tests/stdlib/toids.nim index 72900d1efb4c9..f162dbe57ccc9 100644 --- a/tests/stdlib/toids.nim +++ b/tests/stdlib/toids.nim @@ -1,15 +1,6 @@ -discard """ - matrix: "--mm:refc; --mm:orc" -""" - import std/oids block: # genOid let x = genOid() - doAssert ($x).len == 32 - -block: - let x = genOid() - let y = parseOid(cstring($x)) - doAssert x == y + doAssert ($x).len == 24