summary refs log blame commit diff stats
path: root/lib/pure/oids.nim
blob: fb70047b6d5c36128a38500da02815a37e9499a9 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                                                                              
                                                                               
  
                                                               
            
 

                                                    

    



                          
 
                                                   
                                    
                                                                    
                                    
 
                            
                                                        





                          

                                          

                                   
                   





                                                                          

                                                                     
                                




                   




                                    

                                           
          



                                                                             
                                                                                 


                               

                             
                                 
                           
 
 
   
                            

   



                                            
 








                                                              
                     


                                  

                                                            
                            

                                     
                                                



                                     
#
#
#            Nim's Runtime Library
#        (c) Copyright 2013 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## 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. 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`.

import std/[hashes, times, endians, random]
from std/private/decode_helpers import handleHexChar

type
  Oid* = object ## An OID.
    time: int32
    fuzz: int32
    count: int32

proc `==`*(oid1: Oid, oid2: Oid): bool {.inline.} =
  ## Compares two OIDs for equality.
  result = (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and
          (oid1.count == oid2.count)

proc hash*(oid: Oid): Hash =
  ## Generates the hash of an OID for use in hashtables.
  var h: Hash = 0
  h = h !& hash(oid.time)
  h = h !& hash(oid.fuzz)
  h = h !& hash(oid.count)
  result = !$h

proc hexbyte*(hex: char): int {.inline.} =
  result = handleHexChar(hex)

proc parseOid*(str: cstring): Oid =
  ## Parses an OID.
  var bytes = cast[cstring](addr(result.time))
  var i = 0
  while i < 12:
    bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1]))
    inc(i)

template toStringImpl[T: string | cstring](result: var T, oid: Oid) =
  ## Stringifies `oid`.
  const hex = "0123456789abcdef"
  const N = 24

  when T is string:
    result.setLen N

  var o = oid
  var bytes = cast[cstring](addr(o))
  var i = 0
  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 oidToString*(oid: Oid, str: cstring) {.deprecated: "unsafe; use `$`".} =
  ## Converts an oid to a string which must have space allocated for 25 elements.
  # work around a compiler bug:
  var str = str
  toStringImpl(str, oid)

proc `$`*(oid: Oid): string =
  ## Converts an OID to a string.
  toStringImpl(result, oid)


let
  t = getTime().toUnix.int32

var
  seed = initRand(t)
  incr: int = seed.rand(int.high)

let fuzz = cast[int32](seed.rand(high(int)))


template genOid(result: var Oid, incr: var int, fuzz: int32) =
  var time = getTime().toUnix.int32
  var i = cast[int32](atomicInc(incr))

  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 == 24
  runnableExamples("-r:off"):
    echo $genOid() # for example, "5fc7f546ddbbc84800006aaf"
  genOid(result, incr, fuzz)

proc generatedTime*(oid: Oid): Time =
  ## Returns the generated timestamp of the OID.
  var tmp: int32
  var dummy = oid.time
  bigEndian32(addr(tmp), addr(dummy))
  result = fromUnix(tmp)