github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekatyp/ulid.go (about) 1 // Copyright © 2021. All rights reserved. 2 // Author: Ilya Stroy. 3 // Contacts: iyuryevich@pm.me, https://github.com/qioalice 4 // License: https://opensource.org/licenses/MIT 5 6 package ekatyp 7 8 import ( 9 "bytes" 10 "database/sql/driver" 11 12 "github.com/qioalice/ekago/v3/ekarand" 13 14 "github.com/oklog/ulid/v2" 15 ) 16 17 type ( 18 // ULID is a Universally Unique Lexicographically Sortable Identifier. 19 // It's a drop-in replacement of UUID. 20 // Read more: https://github.com/ulid/spec . 21 ULID ulid.ULID 22 ) 23 24 // ---------------------------- UUID COMMON METHODS --------------------------- // 25 // ---------------------------------------------------------------------------- // 26 27 // Equal returns true if both of ULID s are equal, otherwise returns false. 28 func (u ULID) Equal(anotherUlid ULID) bool { 29 return bytes.Equal(u[:], anotherUlid[:]) 30 } 31 32 // IsNil reports whether current ULID is empty (nil). 33 func (u ULID) IsNil() bool { 34 return u == ULID(_UUID_NULL) 35 } 36 37 // SetNil sets the current ULID to zero ULID. Returns modified ULID. 38 func (u *ULID) SetNil() *ULID { 39 *u = ULID(_UUID_NULL) 40 return u 41 } 42 43 // Bytes returns bytes slice representation of ULID. 44 func (u ULID) Bytes() []byte { 45 return u[:] 46 } 47 48 // String returns a lexicographically sortable string encoded ULID 49 // (26 characters, non-standard base 32) e.g. 01AN4Z07BY79KA1307SR9X4MV3 50 // Format: tttttttttteeeeeeeeeeeeeeee where t is time and e is entropy. 51 func (u ULID) String() string { 52 return ulid.ULID(u).String() 53 } 54 55 // --------------------------- UUID CREATION HELPERS -------------------------- // 56 // ---------------------------------------------------------------------------- // 57 58 // ULID_OrPanic is a helper that wraps a call to a function returning (ULID, error) 59 // and panics if the error is non-nil. 60 // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning). 61 func ULID_OrPanic(u ULID, err error) ULID { 62 if err != nil { 63 panic(err) 64 } 65 return u 66 } 67 68 // ULID_OrNil is a helper that wraps a call to a function returning (ULID, error) 69 // and returns zero ULID if the error is non-nil. 70 // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning). 71 func ULID_OrNil(u ULID, err error) ULID { 72 if err != nil { 73 return ULID(_UUID_NULL) 74 } 75 return u 76 } 77 78 // ------------------------------ ULID GENERATORS ----------------------------- // 79 // ---------------------------------------------------------------------------- // 80 81 // ULID_New() returns an new ULID based on the current time and math/rand entropy. 82 // Thread-safety. 83 // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning). 84 func ULID_New() (ULID, error) { 85 u, err := ulid.New(ulid.Now(), (*ekarand.MathRandReader)(nil)) 86 return ULID(u), err 87 } 88 89 // ------------------- ULID GENERATOR'S WRAPPERS OF HELPERS ------------------- // 90 // ---------------------------------------------------------------------------- // 91 92 // Next methods are the same as just generators but it panics 93 // if any error occurred while ULID been generated. 94 95 // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning). 96 func ULID_New_OrPanic() ULID { 97 return ULID_OrPanic(ULID_New()) 98 } 99 100 // Next methods are the same as just generators but it returns 101 // a zero ULID if any error is occurred while UUID been generated. 102 103 // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning). 104 func ULID_New_OrNil() ULID { 105 return ULID_OrNil(ULID_New()) 106 } 107 108 // Next methods are the same as just generators but it returns 109 // only one argument - an error and saves generated ULID as output argument 110 // by the address provided by 'dest' arg. 111 // 112 // It's useful when you awaits only one argument for being returned. 113 // For example in if statement to omit else branch. 114 // 115 // WARNING! 116 // No nil check! 'dest' must be not nil, panic otherwise. 117 118 // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning). 119 func ULID_New_To(dest *ULID) (err error) { 120 *dest, err = ULID_New() 121 return 122 } 123 124 // ------------------------------- ULID PARSERS ------------------------------- // 125 // ---------------------------------------------------------------------------- // 126 127 // ULID_FromString returns ULID parsed from string input. 128 // Input is expected in a form accepted by UnmarshalText. 129 // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning). 130 func ULID_FromString(input string) (ULID, error) { 131 u, err := ulid.ParseStrict(input) 132 return ULID(u), err 133 } 134 135 // -------------------- ULID PARSER'S WRAPPERS OF HELPERS --------------------- // 136 // ---------------------------------------------------------------------------- // 137 138 // ULID_FromString_OrPanic is the same as ULID_OrPanic(ULID_FromString(input)). 139 // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning). 140 func ULID_FromString_OrPanic(input string) ULID { 141 return ULID_OrPanic(ULID_FromString(input)) 142 } 143 144 // ULID_FromString_OrNil is the same as ULID_OrNil(UUID_FromString(input)). 145 // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning). 146 func ULID_FromString_OrNil(input string) ULID { 147 return ULID_OrNil(ULID_FromString(input)) 148 } 149 150 // ------------------------ UUID TEXT ENCODER/DECODER ------------------------- // 151 // ---------------------------------------------------------------------------- // 152 153 // MarshalText implements the encoding.TextMarshaler interface by 154 // returning the string encoded ULID. 155 func (u ULID) MarshalText() ([]byte, error) { 156 return ulid.ULID(u).MarshalText() 157 } 158 159 // MarshalTextTo writes the ULID as a string to the given buffer. 160 // ErrBufferSize is returned when the len(dst) != 26. 161 func (u ULID) MarshalTextTo(dest []byte) error { 162 return ulid.ULID(u).MarshalTextTo(dest) 163 } 164 165 // UnmarshalText implements the encoding.TextUnmarshaler interface by 166 // parsing the data as string encoded ULID. 167 // 168 // ErrDataSize is returned if the len(v) is different from an encoded 169 // ULID's length. Invalid encodings produce undefined ULIDs. 170 func (u *ULID) UnmarshalText(data []byte) error { 171 return (*ulid.ULID)(u).UnmarshalText(data) 172 } 173 174 // ------------------------ UUID JSON ENCODER/DECODER ------------------------- // 175 // ---------------------------------------------------------------------------- // 176 177 // MarshalJSON implements the encoding/json.Marshaler interface. 178 // Returns a JSON string with encoded ULID with the followed format: 179 // "01F58MK33HZR24YGEFXWV619XB". Returns JSON null if ULID is nil. 180 func (u ULID) MarshalJSON() ([]byte, error) { 181 182 if u.IsNil() { 183 return _UUID_JSON_NULL, nil 184 } 185 186 buf := make([]byte, ulid.EncodedSize+2) 187 buf[0], buf[len(buf)-1] = '"', '"' 188 189 if err := ulid.ULID(u).MarshalTextTo(buf[1 : len(buf)-1]); err != nil { 190 return nil, err 191 } 192 193 return buf, nil 194 } 195 196 // UnmarshalJSON implements the encoding/json.Unmarshaler interface. 197 // Decodes data as encoded JSON ULID string and saves the result to u. 198 // Supports JSON null values. 199 func (u *ULID) UnmarshalJSON(data []byte) error { 200 201 if len(data) == 0 || bytes.Compare(data, _UUID_JSON_NULL) == 0 { 202 return nil 203 } 204 205 if len(data) != ulid.EncodedSize+2 { 206 return ulid.ErrDataSize 207 } 208 209 return (*ulid.ULID)(u).UnmarshalText(data[1 : len(data)-1]) 210 } 211 212 // ----------------------- UUID BINARY ENCODER/DECODER ------------------------ // 213 // ---------------------------------------------------------------------------- // 214 215 // MarshalBinary implements the encoding.BinaryMarshaler interface by 216 // returning the ULID as a byte slice. 217 func (u ULID) MarshalBinary() ([]byte, error) { 218 return ulid.ULID(u).MarshalBinary() 219 } 220 221 // MarshalBinaryTo writes the binary encoding of the ULID to the given buffer. 222 // ErrBufferSize is returned when the len(dst) != 16. 223 func (u ULID) MarshalBinaryTo(dst []byte) error { 224 return ulid.ULID(u).MarshalBinaryTo(dst) 225 } 226 227 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface by 228 // copying the passed data and converting it to an ULID. ErrDataSize is 229 // returned if the data length is different from ULID length. 230 func (u *ULID) UnmarshalBinary(data []byte) error { 231 return (*ulid.ULID)(u).UnmarshalBinary(data) 232 } 233 234 // ------------------------- UUID SQL ENCODER/DECODER ------------------------- // 235 // ---------------------------------------------------------------------------- // 236 237 // Value implements the sql/driver.Valuer interface. This returns the value 238 // represented as a string. 239 func (u ULID) Value() (driver.Value, error) { 240 return ulid.ULID(u).MarshalText() 241 } 242 243 // Scan implements the sql.Scanner interface. It supports scanning 244 // a string or byte slice. 245 func (u *ULID) Scan(src any) error { 246 return (*ulid.ULID)(u).Scan(src) 247 }