nanoid.go (2305B)
1 package nanoid 2 3 import ( 4 "database/sql/driver" 5 "io" 6 "sync" 7 "unsafe" 8 9 cryptoRand "crypto/rand" 10 ) 11 12 const ( 13 characters = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 14 idSize = 21 15 ) 16 17 type NanoID [idSize]byte 18 19 // Nil is empty id. 20 var Nil = NanoID{} 21 22 // Parse parses the string representation of the id. 23 func Parse(s string) NanoID { 24 var id NanoID 25 copy(id[:], s) 26 return id 27 } 28 29 // Generator generates nanoid. 30 type Generator interface { 31 Generate() NanoID 32 } 33 34 type generator struct { 35 mu sync.Mutex 36 source io.Reader 37 buf []byte 38 bufSize int 39 offset int 40 } 41 42 // New returns a new generator. 43 func New(n int) Generator { 44 return newWithReader(cryptoRand.Reader, n) 45 } 46 47 // NewWithReader returns a new generator with custom source. 48 func NewWithReader(r io.Reader, n int) Generator { 49 return newWithReader(r, n) 50 } 51 52 func newWithReader(source io.Reader, length int) Generator { 53 return &generator{ 54 source: source, 55 buf: make([]byte, length*idSize), 56 bufSize: length * idSize, 57 offset: length * idSize, 58 } 59 } 60 61 func (g *generator) Generate() NanoID { 62 g.mu.Lock() 63 defer g.mu.Unlock() 64 65 if g.offset == g.bufSize { 66 g.source.Read(g.buf) 67 g.offset = 0 68 } 69 70 var id = (*NanoID)(unsafe.Pointer(&g.buf[g.offset])) 71 72 for i, v := range id { 73 id[i] = characters[v&0b00111111] 74 } 75 76 g.offset += idSize 77 78 return *id 79 } 80 81 // Generate generates a new id. 82 func Generate() NanoID { 83 return New(1).Generate() 84 } 85 86 // GenerateN generates n new ids. 87 func GenerateN(n int) []NanoID { 88 gen := New(n) 89 ids := make([]NanoID, n) 90 91 for i := range ids { 92 ids[i] = gen.Generate() 93 } 94 95 return ids 96 } 97 98 // String returns the string representation of the id. 99 func (id NanoID) String() string { 100 return string(id[:]) 101 } 102 103 // GoString returns the string representation of the id. 104 func (id NanoID) GoString() string { 105 return id.String() 106 } 107 108 // Bytes returns the byte slice representation of the id. 109 func (id NanoID) Bytes() []byte { 110 return id[:] 111 } 112 113 // Scan implements the sql.Scanner interface. 114 func (id *NanoID) Scan(src interface{}) error { 115 switch src := src.(type) { 116 case []byte: 117 copy(id[:], src) 118 return nil 119 case string: 120 copy(id[:], src) 121 return nil 122 } 123 124 return nil 125 } 126 127 // Value implements the driver.Valuer interface. 128 func (id NanoID) Value() (driver.Value, error) { 129 return id.String(), nil 130 }