├── LICENSE ├── README.md ├── haxelib.json └── src └── uuid ├── FlakeId.hx └── Uuid.hx /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # uuid 2 | 3 | Cross-platform generation of UUID based on [RFC-4122](https://tools.ietf.org/html/rfc4122) . 4 | 5 | Support for 1, 3, 4 and 5 versions of UUID. 6 | Port from [node-uuid](https://github.com/kelektiv/node-uuid) and using built-in Xorshift128+ for random generator. 7 | 8 | Version 3 use Md5 for hash and version 5 use Sha1. 9 | 10 | # short-uuid 11 | 12 | Generate and translate standard UUIDs into shorter - or just different - formats and back ( [based on short-uuid](https://github.com/oculus42/short-uuid) ). 13 | 14 | It also provides translators to convert back and forth from RFC compliant UUIDs to the shorter formats. 15 | 16 | # nanoid 17 | 18 | A tiny, secure, URL-friendly, unique string ID generator ( [based on nanoid](https://github.com/ai/nanoid) ). 19 | 20 | * **Small.** 108 bytes (minified and gzipped). [Size Limit] controls the size. 21 | * **Fast.** It is 40% faster than UUID. 22 | * **Safe.** It uses Xorshift128+ RNG and can use any cryptographically strong RNG. 23 | * **Compact.** It uses a larger alphabet than UUID (`A-Za-z0-9_-`). So ID size was reduced from 36 to 21 symbols. 24 | * **Portable.** Nano ID was ported to many programming languages. 25 | 26 | # FlakeId 27 | 28 | FlakeId is a distributed ID generation algorithm based on [Twitter Snowflake](https://en.wikipedia.org/wiki/Snowflake_ID) . 29 | 30 | Advantages of FlakeID over UUID : 31 | 32 | * Flake IDs are 64-bits, half the size of a UUID 33 | * Can use time as first component and remain sortable 34 | 35 | Each Flake ID is 64 bits long, consisting of: 36 | 37 | * **Timestamp** - a 42 bit long number of milliseconds elapsed since 1 January 1970 00:00:00 UTC 38 | * **Datacenter Id** - a 5 bit long datacenter identifier. It can take up to 32 unique values (including 0) 39 | * **Machine Id** - a 5 bit long machine identifier. It can take up to 32 unique values (including 0) 40 | * **Counter** - a 12 bit long counter of a self-increasing sequence. It can take up to 4096 unique values in a millisecond. 41 | 42 | Breakdown of bits for an id e.g. `6848815309908238345` (counter is `9`, datacenter is `11` and worker `6`) is as follows: 43 | ``` 44 | 010111110000101111100001001111001101111101 01011 00110 000000001001 45 | |------------| 12 bit counter 46 | |-----| 5 bit machine id 47 | |-----| 5 bit datacenter id 48 | |----- -----| 10 bit generator identifier 49 | |------------------------------------------| 42 bit timestamp 50 | ``` 51 | 52 | ## Convert from/to one type to another 53 | Here is an example of usage, where we store **nanoId** in the database ( it's much more compact) , but it is shown to the user as **uuid** , for readability and security reasons. 54 | 55 | ```haxe 56 | var uniqueId = Uuid.nanoId(); // Generate unique id and store in database 57 | var uuid = Uuid.fromNano(uniqueId); // Convert NanoId to Uuid and show on user screen 58 | var searchUid = Uuid.toNano(uuid); // Server receive uuid and convert to NanoId. Use nanoId to search in database. 59 | 60 | var shortUuid = Uuid.short(); 61 | var uuid = Uuid.fromShort(shortUuid); 62 | ``` 63 | Convert from any base to another base ( binary, hex, decimal, octal and many others) . 64 | ```haxe 65 | var vBinary = Uuid.convert("273247893827239437",Uuid.NUMBERS_DEC,Uuid.NUMBERS_BIN); //convert decimal to binary format 66 | var vHex = Uuid.convert(vBinary, Uuid.NUMBERS_BIN, Uuid.NUMBERS_HEX); //convert bunary to hex format 67 | var vBase58 = Uuid.convert(vHex, Uuid.NUMBERS_HEX, Uuid.FLICKR_BASE58); // convert hex to Base58 format 68 | var vOctal = Uuid.convert(vBase58, Uuid.FLICKR_BASE58, Uuid.NUMBERS_OCT ); // convert from Base58 to octal format 69 | ``` 70 | 71 | ## Random generator 72 | For Uuid.v1() and Uuid.v4() you can pass any random function which return value between 0 and 255 . The default random generator is Xorshift128+ . Here is example for custom random function using Std.random 73 | ```haxe 74 | public function secureRandom():Int 75 | { 76 | return Std.random(256); 77 | } 78 | 79 | var uuid = Uuid.v1(secureRandom); 80 | 81 | ``` 82 | You can use Uuid to get any random number between some range, based on Xorshift128+ RNG, using the following code: 83 | ```haxe 84 | var dice:Int = Uuid.randomFromRange(1,6); 85 | ``` 86 | ## API Summary 87 | 88 | | | | 89 | | --- | --- | 90 | | [`Uuid.nanoId()`](#uuidnanoidlen-alphabet-randomfunc-string) | Create a tiny, secure, URL-friendly, unique string ID | 91 | | [`Uuid.short()`](#uuidshorttoalphabet-randomfunc-string) | Generate shorter UUIDs based on v4 | 92 | | [`Uuid.v1()`](#uuidv1node-optclocksequence-msecs-optnsecs-randomfunc-separator-shortuuid-toalphabetstring) | Create a version 1 (timestamp) UUID | 93 | | [`Uuid.v3()`](#uuidv3name-namespaceseparatorshortuuidtoalphabetstring) | Create a version 3 (namespace with MD5) UUID | 94 | | [`Uuid.v4()`](#uuidv4randbytesrandomfuncseparatorshortuuidtoalphabetstring) | Create a version 4 (random) UUID | 95 | | [`Uuid.v5()`](#uuidv5name-namespaceseparatorshortuuidtoalphabetstring) | Create a version 5 (namespace with SHA-1) UUID | 96 | | [`Uuid.NIL`](#uuidnil) | The nil UUID string (all zeros) | 97 | | [`Uuid.parse()`](#uuidparseuuid-separatorbytes) | Convert UUID string to bytes | 98 | | [`Uuid.stringify()`](#uuidstringifydata-separatorstring) | Convert bytes to UUID string | 99 | | [`Uuid.randomFromRange()`](#uuidrandomfromrangemin-maxint) | Return random number between range | 100 | | [`Uuid.randomByte()`](#uuidrandombyteint) | Return random value between 0 and 255 (included) | 101 | | [`Uuid.fromShort()`](#uuidfromshortshortuuid-separatorfromalphabetstring) | Convert short uuid to Uuid based on the alphabet | 102 | | [`Uuid.toShort()`](#uuidtoshortuuid-separatortoalphabetstring) | Convert Uuid to short uuid based on the alphabet | 103 | | [`Uuid.fromNano()`](#uuidfromnanonanouuid-separatorfromalphabetstring) | Convert nanoId to Uuid | 104 | | [`Uuid.toNano()`](#uuidtonanouuid-separatortoalphabetstring) | Convert Uuid to nanoId | 105 | | [`Uuid.convert()`](#uuidconvertnumber-fromalphabettoalphabetstring) | Convert any string from one alphabet to another | 106 | | [`Uuid.validate()`](#uuidvalidateuuid-separatorbool) | Test a string to see if it is a valid UUID | 107 | | [`Uuid.version()`](#uuidversionuuid-separatorint) | Detect RFC version of a UUID | 108 | | | | 109 | | [`flakeId.nextId()`](#flakeidnextidint64) | Return generated id | 110 | | [`flakeId.setMachineId()`](#flakeidsetmachineidmachineidvoid) | Set unique machine id, default is random between 0 and 31 | 111 | | [`flakeId.setDatacenterId()`](#flakeidsetdatacenteriddatacenteridvoid) | Set unique datecenter id, default is random between 0 and 31| 112 | | [`flakeId.setCustomEpoch()`](#flakeidsetcustomepochcustomepochvoid) | Set custom Epoch time , default is 1420070400 | 113 | | [`flakeId.timestamp()`](#flakeidtimestampint64) | Get the current Unix time in milliseconds | 114 | 115 | ## API Constants 116 | 117 | | | | 118 | | --- | --- | 119 | | `Uuid.DNS` | Returns the [RFC 4122](https://tools.ietf.org/html/rfc4122) identifier of the DNS namespace | 120 | | `Uuid.URL` | Returns the [RFC 4122](https://tools.ietf.org/html/rfc4122) identifier of the URL namespace | 121 | | `Uuid.ISO_OID` | Returns the [RFC 4122](https://tools.ietf.org/html/rfc4122) identifier of the ISO OID namespace | 122 | | `Uuid.X500_DN` | Returns the [RFC 4122](https://tools.ietf.org/html/rfc4122) identifier of the X.500 namespace | 123 | | `Uuid.LOWERCASE_BASE26` | Lowercase English letters | 124 | | `Uuid.UPPERCASE_BASE26` | Uppercase English letters. | 125 | | `Uuid.NO_LOOK_ALIKES_BASE51` | Numbers and english alphabet without lookalikes: `1`, `l`, `I`, `0`, `O`, `o`, `u`, `v`, `5`, `S`, `s` | 126 | | `Uuid.FLICKR_BASE58` | Avoid similar characters 0/O, 1/I/l | 127 | | `Uuid.BASE_70` | Numbers, English letters and special character | 128 | | `Uuid.BASE_85` | Numbers, English letters and special character (ZeroMQ (Z85) alphabet) | 129 | | `Uuid.COOKIE_BASE90` | Safe for HTTP cookies values | 130 | | `Uuid.NANO_ID_ALPHABET` | Alphabet used to create NanoId string | 131 | | `Uuid.NUMBERS_BIN` | Binary numbers | 132 | | `Uuid.NUMBERS_OCT` | Octal numbers | 133 | | `Uuid.NUMBERS_DEC` | Decimal numbers | 134 | | `Uuid.NUMBERS_HEX` | Hex numbers | 135 | 136 | ## API 137 | 138 | ### Uuid.nanoId(len, alphabet, randomFunc ):String 139 | 140 | Create unique string ID 141 | 142 | NanoId is 40% faster than UUID and uses a larger alphabet than UUID (A-Za-z0-9_-), so default size is reduced from 36 to 21 symbols. 143 | It is comparable to UUID v4. 144 | 145 | | | | 146 | | -------------- | ---------------------------------------------------------------------------- | 147 | | `len` | `Int` Size of the NanoId string ( default is `21`) | 148 | | `alphabet` | `String` Alphabet used to generate NanoId | 149 | | `randomFunc` | `Void->Int` Any random function that returns a random bytes (0-255) | 150 | | _returns_ | `String` | 151 | 152 | Example: 153 | 154 | ```haxe 155 | trace("Uuid: "+Uuid.nanoId()); // 6OxUkLI4bGmR_JlVMX9fQ 156 | ``` 157 | 158 | ### Uuid.short(toAlphabet, randomFunc ):String 159 | 160 | Create shorter version for UUID based UUID v4. 161 | 162 | 163 | | | | 164 | | -------------- | ---------------------------------------------------------------------------- | 165 | | `toAlphabet` | `String` Alphabet used to generate short-uuid | 166 | | `randomFunc` | `Void->Int` Any random function that returns a random bytes (0-255) | 167 | | _returns_ | `String` | 168 | 169 | Example: 170 | 171 | ```haxe 172 | trace("Uuid: "+Uuid.short()); // mhvXdrZT4jP5T8vBxuvm75 173 | ``` 174 | 175 | ### Uuid.NIL 176 | 177 | The nil UUID string (all zeros). 178 | 179 | Example: 180 | ```haxe 181 | trace("Uuid:" +Uuid.NIL); // ⇨ '00000000-0000-0000-0000-000000000000' 182 | ``` 183 | 184 | ### Uuid.parse(uuid, separator):Bytes 185 | 186 | Convert UUID string to Bytes 187 | 188 | | | | 189 | | -------------- | ---------------------------------------------------------------------------- | 190 | | `uuid` | `String` A valid UUID | 191 | | `separator` | `String` Set different divider ( default is `-`) | 192 | | _returns_ | `Bytes` | 193 | 194 | Example: 195 | ```haxe 196 | // Parse a UUID 197 | var b = Uuid.parse('6ae99955-2a0d-5dca-94d6-2e2bc8b764d3'); 198 | trace("Hex: "+b.toHex()); // 6ae999552a0d5dca94d62e2bc8b764d3 199 | 200 | // Hex representation on the byte order (for documentation purposes) 201 | // [ 202 | // '6a', 'e9', '99', '55', 203 | // '2a', '0d', '5d', 'ca', 204 | // '94', 'd6', '2e', '2b', 205 | // 'c8', 'b7', '64', 'd3' 206 | // ] 207 | ``` 208 | 209 | ### Uuid.stringify(data, separator):String 210 | 211 | Convert Bytes to UUID string using separator 212 | 213 | | | | 214 | | -------------- | ---------------------------------------------------------------------------- | 215 | | `data` | `Bytes` Should be 16 bytes | 216 | | `separator` | `String` Set different divider ( default is `-`) | 217 | | _returns_ | `String` | 218 | 219 | Example: 220 | 221 | ```haxe 222 | var b = Bytes.ofHex("6ae999552a0d5dca94d62e2bc8b764d3"); 223 | trace("Uuid: "+Uuid.stringify(b)); //6ae99955-2a0d-5dca-94d6-2e2bc8b764d3 224 | ``` 225 | 226 | 227 | ### Uuid.validate(uuid, separator):Bool 228 | 229 | Test a string to see if it is a valid UUID 230 | 231 | | | | 232 | | --------- | --------------------------------------------------- | 233 | | `uuid` | `String` to validate | 234 | | `separator` | `String` Set different divider ( default is `-`) | 235 | | _returns_ | `true` if string is a valid UUID, `false` otherwise | 236 | 237 | Example: 238 | 239 | ```haxe 240 | Uuid.validate('not a UUID'); // ⇨ false 241 | Uuid.validate('6ae99955-2a0d-5dca-94d6-2e2bc8b764d3'); // ⇨ true 242 | ``` 243 | 244 | ### Uuid.version(uuid, separator):Int 245 | 246 | Detect RFC version of a UUID 247 | 248 | | | | 249 | | --------- | ---------------------------------------- | 250 | | `uuid` | `String` A valid UUID | 251 | | `separator` | `String` Set different divider ( default is `-`) | 252 | | _returns_ | `Int` The RFC version of the UUID | 253 | 254 | Example: 255 | 256 | ```haxe 257 | Uuid.version('45637ec4-c85f-11ea-87d0-0242ac130003'); // ⇨ 1 258 | Uuid.version('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ 4 259 | ``` 260 | 261 | ### Uuid.randomFromRange(min, max):Int 262 | 263 | Return random number between min and max (included) values 264 | 265 | | | | 266 | | --------- | ---------------------------------------- | 267 | | `min` | `Int` Start number | 268 | | `max` | `Int` End number | 269 | | _returns_ | `Int` | 270 | 271 | Example: 272 | 273 | ```haxe 274 | Uuid.randomFromRange(1,6); // return a number in range [1,6] 275 | ``` 276 | 277 | ### Uuid.randomByte():Int 278 | 279 | Return a random number between 0 and 255 (included) 280 | 281 | | | | 282 | | --------- | ---------------------------------------- | 283 | | _returns_ | `Int` 284 | 285 | Example: 286 | 287 | ```haxe 288 | Uuid.randomByte(); // return a number in range [0,255] 289 | ``` 290 | 291 | ### Uuid.fromShort(shortUuid, separator,fromAlphabet):String 292 | 293 | Translate shorter UUID format to standard UUID 294 | 295 | | | | 296 | | --------- | ---------------------------------------- | 297 | | `shortUuid` | `String` short uuid string | 298 | | `separator` | `String` Set divider ( default is `-`) | 299 | | `fromAlphabet` | `String` Alphabet to use for translation ( default `FLICKR_BASE58`) | 300 | | _returns_ | `String` | 301 | 302 | ⚠️ Note: Alphabets can be a custom ones or one of predefined : `COOKIE_BASE90` , `FLICKR_BASE58` , `BASE_70` , `BASE_85` , `LOWERCASE_BASE26` , `UPPERCASE_BASE26`, `NO_LOOK_ALIKES_BASE51` , `NUMBERS_BIN` , `NUMBERS_OCT` , `NUMBERS_DEC` , `NUMBERS_HEX` 303 | 304 | Example: 305 | 306 | ```haxe 307 | Uuid.fromShort("ecHyJhpvZANyZY6k1L5EYK"); // 6ae99955-2a0d-5dca-94d6-2e2bc8b764d3 308 | ``` 309 | 310 | 311 | ### Uuid.toShort(uuid, separator,toAlphabet):String 312 | 313 | Translate standard UUIDs into shorter format 314 | 315 | | | | 316 | | --------- | ---------------------------------------- | 317 | | `uuid` | `String` A valid UUID | 318 | | `separator` | `String` Set divider ( default is `-`) | 319 | | `toAlphabet` | `String` Alphabet to use for translation ( default `FLICKR_BASE58`) | 320 | | _returns_ | `String` | 321 | 322 | ⚠️ Note: Alphabets can be a custom ones or one of predefined : `COOKIE_BASE90` , `FLICKR_BASE58` , `BASE_70` , `BASE_85` , `LOWERCASE_BASE26` , `UPPERCASE_BASE26`, `NO_LOOK_ALIKES_BASE51` , `NUMBERS_BIN` , `NUMBERS_OCT` , `NUMBERS_DEC` , `NUMBERS_HEX` 323 | 324 | Example: 325 | 326 | ```haxe 327 | Uuid.toShort('6ae99955-2a0d-5dca-94d6-2e2bc8b764d3'); // ecHyJhpvZANyZY6k1L5EYK 328 | ``` 329 | 330 | 331 | ### Uuid.fromNano(nanoUuid, separator,fromAlphabet):String 332 | 333 | Translate shorter UUID format to standard UUID 334 | 335 | | | | 336 | | --------- | ---------------------------------------- | 337 | | `nanoUuid` | `String` A valid nanoId string | 338 | | `separator` | `String` Set divider ( default is `-`) | 339 | | `fromAlphabet` | `String` Alphabet to use for translation ( default `FLICKR_BASE58`) | 340 | | _returns_ | `String` | 341 | 342 | ⚠️ Note: Alphabets can be a custom ones or one of predefined : `COOKIE_BASE90` , `FLICKR_BASE58` , `BASE_70` , `BASE_85` , `LOWERCASE_BASE26` , `UPPERCASE_BASE26`, `NO_LOOK_ALIKES_BASE51` , `NUMBERS_BIN` , `NUMBERS_OCT` , `NUMBERS_DEC` , `NUMBERS_HEX` 343 | 344 | Example: 345 | 346 | ```haxe 347 | Uuid.fromShort("ecHyJhpvZANyZY6k1L5EYK"); // 6ae99955-2a0d-5dca-94d6-2e2bc8b764d3 348 | ``` 349 | 350 | 351 | ### Uuid.toNano(uuid, separator,toAlphabet):String 352 | 353 | Translate standard UUIDs into shorter format 354 | 355 | | | | 356 | | --------- | ---------------------------------------- | 357 | | `uuid` | `String` A valid UUID | 358 | | `separator` | `String` Set divider ( default is `-`) | 359 | | `toAlphabet` | `String` Alphabet to use for translation ( default `FLICKR_BASE58`) | 360 | | _returns_ | `String` | 361 | 362 | ⚠️ Note: Alphabets can be a custom ones or one of predefined : `COOKIE_BASE90` , `FLICKR_BASE58` , `BASE_70` , `BASE_85` , `LOWERCASE_BASE26` , `UPPERCASE_BASE26`, `NO_LOOK_ALIKES_BASE51` , `NUMBERS_BIN` , `NUMBERS_OCT` , `NUMBERS_DEC` , `NUMBERS_HEX` 363 | 364 | Example: 365 | 366 | ```haxe 367 | Uuid.toShort('6ae99955-2a0d-5dca-94d6-2e2bc8b764d3'); // ecHyJhpvZANyZY6k1L5EYK 368 | ``` 369 | 370 | ### Uuid.convert(number, fromAlphabet,toAlphabet):String 371 | 372 | Convert any string from one alphabet to another 373 | 374 | | | | 375 | | --------- | ---------------------------------------- | 376 | | `number` | `String` Any number or string | 377 | | `fromAlphabet` | `String` Alphabet source ( for `number`) | 378 | | `toAlphabet` | `String` Alphabet destination | 379 | | _returns_ | `String` | 380 | 381 | Example: 382 | 383 | ```haxe 384 | Uuid.convert('12345',Uuid.NUMBERS_DEC,Uuid.NUMBERS_BIN); // 11000000111001 385 | Uuid.convert('12345678',Uuid.NUMBERS_DEC,Uuid.NUMBERS_HEX); // ⇨ bc614e 386 | Uuid.convert('1234567890',Uuid.NUMBERS_DEC,Uuid.BASE_70); // ⇨ PtmIa 387 | ``` 388 | 389 | ### Uuid.v1(node, optClockSequence, msecs, optNsecs, randomFunc, separator, shortUuid, toAlphabet):String 390 | 391 | Create an RFC version 1 (timestamp) UUID 392 | 393 | | | | 394 | | --- | --- | 395 | | `node` | `Bytes` RFC "node" field as 6 bytes | 396 | | `optClockSequence` | RFC "clock sequence" as a `Int` between 0 - 0x3fff | 397 | | `msecs` | RFC "timestamp" field (`Float` of milliseconds, unix epoch) | 398 | | `optNsecs` | RFC "timestamp" field (`Int` of nanseconds to add to `msecs`, should be 0-10,000) | 399 | | `randomFunc` | `Void->Int` Any random function that returns a random bytes (0-255) | 400 | | `separator` | `String` Set divider ( default is `-`)| 401 | | `shortUuid` | `Bool` If `true` UUID will be exported as short UUID | 402 | | `toAlphabet`| `String` Alphabet used for export on short UUID | 403 | | _returns_ | UUID `String` | 404 | | _throws_ | `Error` if more than 10M UUIDs/sec are requested | 405 | 406 | 407 | Example: 408 | 409 | ```haxe 410 | Uuid.v1(); // ⇨ '2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d' 411 | ``` 412 | 413 | Example using with options: 414 | 415 | ```haxe 416 | var node = Bytes.ofHex("010207090506"); 417 | var optClockSequence = 0x1a7f; 418 | var msecs = 1556526368; 419 | var optNsecs = 6200; 420 | uuid = Uuid.v1(node,optClockSequence,msecs,optNsecs); // ⇨ '25848a38-1cd0-11b2-9a7f-010207090506' 421 | ``` 422 | 423 | ### Uuid.v3(name, namespace,separator,shortUuid,toAlphabet):String 424 | 425 | Create an RFC version 3 (namespace w/ MD5) UUID 426 | 427 | API is identical to `v5()`, but uses "v3" instead. 428 | 429 | ⚠️ Note: Per the RFC, "_If backward compatibility is not an issue, SHA-1 [Version 5] is preferred_." 430 | 431 | ### Uuid.v4(randBytes,randomFunc,separator,shortUuid,toAlphabet):String 432 | 433 | Create an RFC version 4 (random) UUID 434 | 435 | | | | 436 | | --- | --- | 437 | | `randBytes`| `Bytes` 16 random bytes (0-255) | 438 | | `randomFunc` | `Void->Int` Any random function that returns a random bytes (0-255) | 439 | | `separator` | `String` Set divider ( default is `-`)| 440 | | `shortUuid` | `Bool` If `true` UUID will be exported as short UUID | 441 | | `toAlphabet`| `String` Alphabet used for export on short UUID | 442 | | _returns_ | UUID `String` | 443 | 444 | Example: 445 | 446 | ```haxe 447 | Uuid.v4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed' 448 | ``` 449 | 450 | Example using predefined `random` values: 451 | 452 | ```haxe 453 | var randomValues= Bytes.ofHex("109156bec4fbc1ea71b4efe1671c5836"); 454 | Uuid.v4(randomValues); // ⇨ '109156be-c4fb-41ea-b1b4-efe1671c5836' 455 | ``` 456 | 457 | ### Uuid.v5(name, namespace,separator,shortUuid,toAlphabet):String 458 | 459 | Create an RFC version 5 (namespace w/ SHA-1) UUID 460 | 461 | | | | 462 | | --- | --- | 463 | | `name` | `String` | 464 | | `namespace` | `String` Namespace UUID | 465 | | `separator` | `String` Set divider ( default is `-`)| 466 | | `shortUuid` | `Bool` If `true` UUID will be exported as short UUID | 467 | | `toAlphabet`| `String` Alphabet used for export on short UUID | 468 | | _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` | 469 | 470 | Note: The RFC `DNS` and `URL` namespaces are available as `Uuid.DNS` and `Uuid.URL`. 471 | 472 | Example with custom namespace: 473 | 474 | ```haxe 475 | // Define a custom namespace. Readers, create your own using something like 476 | // https://www.uuidgenerator.net/ 477 | var MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341'; 478 | 479 | Uuid.v5('Hello, World!', MY_NAMESPACE); // ⇨ '630eb68f-e0fa-5ecc-887a-7c7a62614681' 480 | ``` 481 | 482 | Example with RFC `URL` namespace: 483 | 484 | ```haxe 485 | Uuid.v5('https://www.w3.org/', Uuid.URL); // ⇨ 'c106a26a-21bb-5538-8bf2-57095d1976c1' 486 | ``` 487 | 488 | ### flakeid.nextId():Int64 489 | 490 | Return a unique 64-bit number 491 | 492 | | | | 493 | | --------- | ---------------------------------------- | 494 | | _returns_ | `Int64` 495 | 496 | Example: 497 | 498 | ```haxe 499 | var flakeId = new FlakeId(); 500 | flakeId.nextId(); // return a unique identifier 501 | ``` 502 | 503 | ### flakeid.setMachineId(machineId):Void 504 | 505 | Set machine identifier ( could be 0 to 31) 506 | 507 | | | | 508 | | --- | --- | 509 | | `machineId`| `Int` A 5 bit long machine identifier | 510 | | _returns_ | | 511 | 512 | Example: 513 | 514 | ```haxe 515 | var flakeId = new FlakeId(); 516 | flakeId.setMachineId(4); 517 | ``` 518 | 519 | ### flakeid.setDatacenterId(datacenterId):Void 520 | 521 | Set machine identifier ( could be 0 to 31) 522 | 523 | | | | 524 | | --- | --- | 525 | | `datacenterId`| `Int` A 5 bit long datacenter identifier | 526 | | _returns_ | | 527 | 528 | Example: 529 | 530 | ```haxe 531 | var flakeId = new FlakeId(); 532 | flakeId.setDatacenterId(9); 533 | ``` 534 | 535 | ### flakeid.setCustomEpoch(customEpoch):Void 536 | 537 | Set time in milliseconds elapsed since 1 January 1970 00:00:00 UTC 538 | 539 | | | | 540 | | --- | --- | 541 | | `customEpoch`| `Int64` Unix time in milliseconds | 542 | | _returns_ | | 543 | 544 | Example: 545 | 546 | ```haxe 547 | var flakeId = new FlakeId(); 548 | flakeId.setCustomEpoch(Int64.make(0x0000015F,0x2064AA48)); 549 | ``` 550 | 551 | ### flakeid.timestamp():Int64 552 | 553 | Return the current Unix time in milliseconds 554 | 555 | | | | 556 | | --------- | ---------------------------------------- | 557 | | _returns_ | `Int64` 558 | 559 | Example: 560 | 561 | ```haxe 562 | var flakeId = new FlakeId(); 563 | flakeId.timestamp(); //Current time in milliseconds 564 | ``` 565 | 566 | ## Usage 567 | Version 1 (timestamp): 568 | ```haxe 569 | var uuid = Uuid.v1(); 570 | trace("UUID: " + uuid); 571 | 572 | // Using custom separator 573 | var uuid = Uuid.v1("_"); 574 | trace("UUID: " + uuid); 575 | 576 | //Using predefined values 577 | var node = Bytes.ofHex("010203040506"); // Array of 6 bytes, by default is random generated 578 | var optClockSequence = 0x1a7f; // clock sequence (0 - 0x3fff) 579 | var msecs = 1556526368; // Time in milliseconds since unix Epoch 580 | var optNsecs = 4500; // Additional time in nanoseconds (0-9999) 581 | uuid = Uuid.v1(node,optClockSequence,msecs,optNsecs); 582 | trace("UUID: " + uuid); 583 | ``` 584 | Version 3 (namespace): 585 | ```haxe 586 | var uuid = Uuid.v3("https://example.com/haxe",Uuid.URL); //namespace should be valid Uuid 587 | trace("UUID: " + uuid); 588 | 589 | uuid = Uuid.v3("The Cross-platform Toolkit"); 590 | trace("UUID: " + uuid); 591 | 592 | uuid = Uuid.v3("The Cross-platform Toolkit",'7e9606ce-8af4-435b-89d6-66d6d885b97a'); 593 | trace("UUID: " + uuid); 594 | ``` 595 | Version 4 (random): 596 | ```haxe 597 | var uuid = Uuid.v4(); 598 | trace("UUID: " + uuid); 599 | 600 | //Using custom separator - empty position 601 | var uuid = Uuid.v4(""); 602 | trace("UUID: " + uuid); 603 | ``` 604 | Version 5 (namespace): 605 | ```haxe 606 | var uuid = Uuid.v5("https://example.com/haxe",Uuid.URL); 607 | trace("UUID: " + uuid); 608 | 609 | uuid = Uuid.v5("The Cross-platform Toolkit"); 610 | trace("UUID: " + uuid); 611 | 612 | uuid = Uuid.v5("The Cross-platform Toolkit",'7e9606ce-8af4-435b-89d6-66d6d885b97a'); 613 | trace("UUID: " + uuid); 614 | ``` 615 | 616 | Flake ID 617 | ```haxe 618 | var flakeId = new FlakeId(11,6); // datecenterid is `11` and machineid id `6` 619 | var uniqueId = flakeId.nextId(); // create one unique id 620 | for (i in 0...10) { 621 | trace(flakeId.nextId()); //generate ten unique ids 622 | } 623 | ``` 624 | -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uuid", 3 | "url": "https://github.com/flashultra/uuid", 4 | "license": "MIT", 5 | "tags": ["cross","haxe","uuid","game","binary","nanoid","short-uuid","flakeid","snowflake","flake"], 6 | "description": "Cross platform, simple Uuid , Short-Uuid , NanoId and FlakeId generator. Uuid generation is based on RFC4122 . Support versions are v1, v3, v4 and v5", 7 | "version": "2.4.1", 8 | "releasenote": "Fix datetime bug (flash target)", 9 | "contributors": [ "flashultra" ], 10 | "classPath": "src" 11 | } -------------------------------------------------------------------------------- /src/uuid/FlakeId.hx: -------------------------------------------------------------------------------- 1 | package uuid; 2 | 3 | import haxe.Int64; 4 | import haxe.Exception; 5 | 6 | class FlakeId { 7 | // Custom Epoch (January 1, 2015 Midnight UTC = 2015-01-01T00:00:00Z) 8 | public static final DEFAULT_CUSTOM_EPOCH :Int64 = Int64.make(0x00000000,0x54A48E00); 9 | 10 | private static final SEQUENCE_BIT:Int = 12; 11 | private static final MACHINE_BIT:Int = 5; 12 | private static final DATACENTER_BIT:Int = 5; 13 | 14 | private static final MAX_DATACENTER_NUM:Int = -1 ^ (-1 << DATACENTER_BIT); 15 | private static final MAX_MACHINE_NUM:Int = -1 ^ (-1 << MACHINE_BIT); 16 | private static final MAX_SEQUENCE:Int = -1 ^ (-1 << SEQUENCE_BIT); 17 | 18 | private static final MACHINE_LEFT:Int = SEQUENCE_BIT ; 19 | private static final DATACENTER_LEFT:Int = SEQUENCE_BIT + MACHINE_BIT; 20 | private static final TIMESTMP_LEFT:Int = DATACENTER_LEFT + DATACENTER_BIT ; 21 | 22 | private var datacenterId:Int; 23 | private var machineId:Int; 24 | private var sequence:Int = 0; 25 | private var lastTimestamp:Int64 = -1; 26 | private var customEpoch:Int64 = DEFAULT_CUSTOM_EPOCH; 27 | 28 | 29 | public function new(?datacenterId:Int,?machineId:Int,?epochTime:Int64) 30 | { 31 | if ( datacenterId == null ) datacenterId = Uuid.randomFromRange(0,MAX_DATACENTER_NUM); 32 | if ( machineId == null ) machineId = Uuid.randomFromRange(0,MAX_MACHINE_NUM); 33 | if ( epochTime == null ) epochTime = DEFAULT_CUSTOM_EPOCH; 34 | 35 | if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) 36 | { 37 | throw new Exception('datacenterId can\'t be greater than $MAX_DATACENTER_NUM or less than 0'); 38 | } 39 | if (machineId > MAX_MACHINE_NUM || machineId < 0) 40 | { 41 | throw new Exception('machineId can\'t be greater than $MAX_MACHINE_NUM or less than 0'); 42 | } 43 | this.datacenterId = datacenterId; 44 | this.machineId = machineId; 45 | } 46 | 47 | public function nextId():Int64 48 | { 49 | var currentTimestamp:Int64 = baseId(); 50 | 51 | var id:Int64 = ( currentTimestamp << TIMESTMP_LEFT) 52 | | (datacenterId << DATACENTER_LEFT) 53 | | (machineId << MACHINE_LEFT) 54 | | sequence; 55 | 56 | return id; 57 | } 58 | 59 | public function nextRandom():Int64 60 | { 61 | var currentTimestamp:Int64 = baseId(); 62 | 63 | var id:Int64 = ( currentTimestamp << TIMESTMP_LEFT) 64 | | (Uuid.randomFromRange(0,1023) << DATACENTER_LEFT) 65 | | sequence; 66 | 67 | return id; 68 | } 69 | 70 | private function baseId():Int64 71 | { 72 | var currentTimestamp :Int64 = timestamp(); 73 | 74 | if (currentTimestamp < lastTimestamp) { 75 | currentTimestamp = lastTimestamp; 76 | } 77 | 78 | if (currentTimestamp == lastTimestamp) { 79 | sequence = (sequence + 1) & MAX_SEQUENCE; 80 | if (sequence == 0) { 81 | currentTimestamp = waitNextMillis(); 82 | } 83 | } else { 84 | sequence = Uuid.randomFromRange(0,9) & MAX_SEQUENCE; 85 | } 86 | 87 | lastTimestamp = currentTimestamp; 88 | 89 | return (currentTimestamp - customEpoch); 90 | } 91 | 92 | private function waitNextMillis():Int64 93 | { 94 | var mill:Int64 = timestamp(); 95 | while (mill <= lastTimestamp) 96 | { 97 | mill = timestamp(); 98 | } 99 | return mill; 100 | } 101 | 102 | public function setMachineId( machineId:Int):Void 103 | { 104 | if (machineId > MAX_MACHINE_NUM || machineId < 0) 105 | { 106 | throw new Exception('machineId can\'t be greater than $MAX_MACHINE_NUM or less than 0'); 107 | } 108 | this.machineId = machineId; 109 | } 110 | 111 | public function setDatacenterId( datacenterId:Int):Void 112 | { 113 | if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) 114 | { 115 | throw new Exception('datacenterId can\'t be greater than $MAX_DATACENTER_NUM or less than 0'); 116 | } 117 | this.datacenterId = datacenterId; 118 | } 119 | 120 | public function setCustomEpoch(customEpoch:Int64):Void 121 | { 122 | if ( customEpoch < 0 ) 123 | { 124 | throw new Exception('customEpoch can\'t be less than 0'); 125 | } 126 | this.customEpoch = customEpoch; 127 | } 128 | 129 | public function timestamp():Int64 130 | { 131 | return Int64.fromFloat(#if js js.lib.Date.now() #elseif sys Sys.time() * 1000 #else Date.now().getTime() #end); 132 | } 133 | } -------------------------------------------------------------------------------- /src/uuid/Uuid.hx: -------------------------------------------------------------------------------- 1 | package uuid; 2 | 3 | import haxe.ds.Vector; 4 | import haxe.Int64; 5 | import haxe.io.Bytes; 6 | import haxe.crypto.Md5; 7 | import haxe.crypto.Sha1; 8 | 9 | class Uuid { 10 | public inline static var DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; 11 | public inline static var URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; 12 | public inline static var ISO_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8'; 13 | public inline static var X500_DN = '6ba7b814-9dad-11d1-80b4-00c04fd430c8'; 14 | public inline static var NIL = '00000000-0000-0000-0000-000000000000'; 15 | 16 | public inline static var LOWERCASE_BASE26 = "abcdefghijklmnopqrstuvwxyz"; 17 | public inline static var UPPERCASE_BASE26 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 18 | public inline static var NO_LOOK_ALIKES_BASE51 = "2346789ABCDEFGHJKLMNPQRTUVWXYZabcdefghijkmnpqrtwxyz"; // without 1, l, I, 0, O, o, u, v, 5, S, s 19 | public inline static var FLICKR_BASE58 = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; // without similar characters 0/O, 1/I/l 20 | public inline static var BASE_70 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+!@#$^"; 21 | public inline static var BASE_85 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#"; 22 | public inline static var COOKIE_BASE90 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+-./:<=>?@[]^_`{|}~"; 23 | public inline static var NANO_ID_ALPHABET = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 24 | 25 | public inline static var NUMBERS_BIN = "01"; 26 | public inline static var NUMBERS_OCT = "01234567"; 27 | public inline static var NUMBERS_DEC = "0123456789"; 28 | public inline static var NUMBERS_HEX = "0123456789abcdef"; 29 | 30 | 31 | static var lastMSecs:Float = 0; 32 | static var lastNSecs = 0; 33 | static var clockSequenceBuffer:Int = -1; 34 | static var regexp:EReg = ~/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; 35 | 36 | static var rndSeed:Int64 = Int64.fromFloat(#if js js.lib.Date.now() #elseif sys Sys.time()*1000 #else Date.now().getTime() #end); 37 | static var state0 = splitmix64_seed(rndSeed); 38 | static var state1 = splitmix64_seed(rndSeed + Std.random(10000) + 1); 39 | private static var DVS:Int64 = Int64.make(0x00000001, 0x00000000); 40 | 41 | private static function splitmix64_seed(index:Int64):Int64 { 42 | var result:Int64 = (index + Int64.make(0x9E3779B9, 0x7F4A7C15)); 43 | result = (result ^ (result >> 30)) * Int64.make(0xBF58476D, 0x1CE4E5B9); 44 | result = (result ^ (result >> 27)) * Int64.make(0x94D049BB, 0x133111EB); 45 | return result ^ (result >> 31); 46 | } 47 | 48 | public static function randomFromRange(min:Int, max:Int):Int { 49 | var s1:Int64 = state0; 50 | var s0:Int64 = state1; 51 | state0 = s0; 52 | s1 ^= s1 << 23; 53 | state1 = s1 ^ s0 ^ (s1 >>> 18) ^ (s0 >>> 5); 54 | var result:Int = ((state1 + s0) % (max - min + 1)).low; 55 | result = (result < 0) ? -result : result; 56 | return result + min; 57 | } 58 | 59 | public static function randomByte():Int { 60 | return randomFromRange(0, 255); 61 | } 62 | 63 | public static function fromShort(shortUuid:String, separator:String = '-', fromAlphabet:String = FLICKR_BASE58):String { 64 | var uuid = Uuid.convert(shortUuid,fromAlphabet,NUMBERS_HEX); 65 | return hexToUuid(uuid,separator); 66 | } 67 | 68 | public static function toShort(uuid:String, separator:String = '-',toAlphabet:String = FLICKR_BASE58):String { 69 | uuid = StringTools.replace(uuid, separator, '').toLowerCase(); 70 | return Uuid.convert(uuid,NUMBERS_HEX,toAlphabet); 71 | } 72 | 73 | public static function fromNano(nanoUuid:String, separator:String = '-', fromAlphabet:String = NANO_ID_ALPHABET):String { 74 | var uuid = Uuid.convert(nanoUuid,fromAlphabet,NUMBERS_HEX); 75 | return hexToUuid(uuid,separator); 76 | } 77 | 78 | public static function toNano(uuid:String, separator:String = '-',toAlphabet:String = NANO_ID_ALPHABET):String { 79 | uuid = StringTools.replace(uuid, separator, '').toLowerCase(); 80 | return Uuid.convert(uuid,NUMBERS_HEX,toAlphabet); 81 | } 82 | 83 | public static function v1(node:Bytes = null, optClockSequence:Int = -1, msecs:Float = -1, optNsecs:Int = -1, ?randomFunc:Void->Int, separator:String = "-", shortUuid:Bool = false, toAlphabet:String = FLICKR_BASE58):String { 84 | if ( randomFunc == null) randomFunc = randomByte; 85 | var buffer:Bytes = Bytes.alloc(16); 86 | if (node == null) { 87 | node = Bytes.alloc(6); 88 | for (i in 0...6) 89 | node.set(i, randomFunc()); 90 | node.set(0, node.get(0) | 0x01); 91 | } 92 | if (clockSequenceBuffer == -1) { 93 | clockSequenceBuffer = (randomFunc() << 8 | randomFunc()) & 0x3fff; 94 | } 95 | var clockSeq = optClockSequence; 96 | if (optClockSequence == -1) { 97 | clockSeq = clockSequenceBuffer; 98 | } 99 | if (msecs == -1) { 100 | msecs = Math.fround(#if js js.lib.Date.now() #elseif sys Sys.time()*1000 #else Date.now().getTime() #end); 101 | } 102 | var nsecs = optNsecs; 103 | if (optNsecs == -1) { 104 | nsecs = lastNSecs + 1; 105 | } 106 | var dt = (msecs - lastMSecs) + (nsecs - lastNSecs) / 10000; 107 | if (dt < 0 && (optClockSequence == -1)) { 108 | clockSeq = (clockSeq + 1) & 0x3fff; 109 | } 110 | if ((dt < 0 || msecs > lastMSecs) && optNsecs == -1) { 111 | nsecs = 0; 112 | } 113 | if (nsecs >= 10000) { 114 | throw "Can't create more than 10M uuids/sec"; 115 | } 116 | lastMSecs = msecs; 117 | lastNSecs = nsecs; 118 | clockSequenceBuffer = clockSeq; 119 | 120 | msecs += 12219292800000; 121 | var imsecs:Int64 = Int64.fromFloat(msecs); 122 | var tl:Int = (((imsecs & 0xfffffff) * 10000 + nsecs) % DVS).low; 123 | buffer.set(0, tl >>> 24 & 0xff); 124 | buffer.set(1, tl >>> 16 & 0xff); 125 | buffer.set(2, tl >>> 8 & 0xff); 126 | buffer.set(3, tl & 0xff); 127 | 128 | var tmh:Int = ((imsecs / DVS * 10000) & 0xfffffff).low; 129 | buffer.set(4, tmh >>> 8 & 0xff); 130 | buffer.set(5, tmh & 0xff); 131 | 132 | buffer.set(6, tmh >>> 24 & 0xf | 0x10); 133 | buffer.set(7, tmh >>> 16 & 0xff); 134 | 135 | buffer.set(8, clockSeq >>> 8 | 0x80); 136 | buffer.set(9, clockSeq & 0xff); 137 | 138 | for (i in 0...6) 139 | buffer.set(i + 10, node.get(i)); 140 | 141 | var uuid = stringify(buffer,separator); 142 | if ( shortUuid ) uuid = Uuid.toShort(uuid,separator,toAlphabet); 143 | 144 | return uuid; 145 | } 146 | 147 | public static function v3(name:String, namespace:String = "", separator:String = "-", shortUuid:Bool = false, toAlphabet:String = FLICKR_BASE58):String { 148 | namespace = StringTools.replace(namespace, '-', ''); 149 | var buffer = Md5.make(Bytes.ofHex(namespace + Bytes.ofString(name).toHex())); 150 | buffer.set(6, (buffer.get(6) & 0x0f) | 0x30); 151 | buffer.set(8, (buffer.get(8) & 0x3f) | 0x80); 152 | var uuid = stringify(buffer,separator); 153 | if ( shortUuid ) uuid = Uuid.toShort(uuid,separator,toAlphabet); 154 | return uuid; 155 | } 156 | 157 | public static function v4(randBytes:Bytes = null, ?randomFunc:Void->Int, separator:String = "-", shortUuid:Bool = false, toAlphabet:String = FLICKR_BASE58):String { 158 | if ( randomFunc == null) randomFunc = randomByte; 159 | var buffer:Bytes = randBytes; 160 | if ( buffer == null ) { 161 | buffer = Bytes.alloc(16); 162 | for (i in 0...16) { 163 | buffer.set(i, randomFunc()); 164 | } 165 | } else { 166 | if ( buffer.length < 16) throw "Random bytes should be at least 16 bytes"; 167 | } 168 | buffer.set(6, (buffer.get(6) & 0x0f) | 0x40); 169 | buffer.set(8, (buffer.get(8) & 0x3f) | 0x80); 170 | var uuid = stringify(buffer,separator); 171 | if ( shortUuid ) uuid = Uuid.toShort(uuid,separator,toAlphabet); 172 | return uuid; 173 | } 174 | 175 | public static function v5(name:String, namespace:String = "", separator:String = "-", shortUuid:Bool = false, toAlphabet:String = FLICKR_BASE58):String { 176 | namespace = StringTools.replace(namespace, '-', ''); 177 | var buffer = Sha1.make(Bytes.ofHex(namespace + Bytes.ofString(name).toHex())); 178 | buffer.set(6, (buffer.get(6) & 0x0f) | 0x50); 179 | buffer.set(8, (buffer.get(8) & 0x3f) | 0x80); 180 | var uuid = stringify(buffer,separator); 181 | if ( shortUuid ) uuid = Uuid.toShort(uuid,separator,toAlphabet); 182 | return uuid; 183 | } 184 | 185 | public static function stringify(data:Bytes,separator:String = "-"):String { 186 | return hexToUuid(data.toHex(),separator); 187 | } 188 | 189 | public static function parse(uuid:String, separator:String = "-"):Bytes { 190 | return Bytes.ofHex(StringTools.replace(uuid, separator, '')); 191 | } 192 | 193 | public static function validate(uuid:String,separator:String = "-"):Bool { 194 | if ( separator == "") { 195 | uuid = uuid.substr(0, 8) + "-" + uuid.substr(8, 4) + "-" + uuid.substr(12, 4) + "-" + uuid.substr(16, 4) + "-" + uuid.substr(20, 12); 196 | } else if ( separator != "-") { 197 | uuid = StringTools.replace(uuid, separator, '-'); 198 | } 199 | return regexp.match(uuid); 200 | } 201 | 202 | public static function version(uuid:String,separator:String = "-"):Int { 203 | uuid = StringTools.replace(uuid, separator, ''); 204 | return Std.parseInt("0x"+uuid.substr(12,1)); 205 | } 206 | 207 | public static function hexToUuid( hex:String , separator:String):String { 208 | return ( hex.substr(0, 8) + separator + hex.substr(8, 4) + separator + hex.substr(12, 4) + separator + hex.substr(16, 4) + separator + hex.substr(20, 12)); 209 | } 210 | 211 | public static function convert(number:String, fromAlphabet:String, toAlphabet:String ):String { 212 | var fromBase:Int = fromAlphabet.length; 213 | var toBase:Int = toAlphabet.length; 214 | var len = number.length; 215 | var buf:String = ""; 216 | var numberMap:Vector = new Vector(len); 217 | var divide:Int = 0, newlen:Int = 0; 218 | for(i in 0...len) { 219 | numberMap[i] = fromAlphabet.indexOf(number.charAt(i)); 220 | } 221 | do { 222 | divide = 0; 223 | newlen = 0; 224 | for(i in 0...len) { 225 | divide = divide * fromBase + numberMap[i]; 226 | if (divide >= toBase) { 227 | numberMap[newlen++] = Math.floor( divide / toBase); 228 | divide = divide % toBase; 229 | } else if (newlen > 0) { 230 | numberMap[newlen++] = 0; 231 | } 232 | } 233 | len = newlen; 234 | buf = toAlphabet.charAt(divide) + buf; 235 | } while (newlen !=0 ); 236 | 237 | return buf; 238 | } 239 | 240 | public static function nanoId(len:Int=21,alphabet:String=NANO_ID_ALPHABET,?randomFunc:Void->Int):String { 241 | if ( randomFunc == null ) randomFunc = randomByte; 242 | if ( alphabet == null ) throw "Alphabet cannot be null"; 243 | if ( alphabet.length == 0 || alphabet.length >= 256 ) throw "Alphabet must contain between 1 and 255 symbols"; 244 | if ( len <= 0 ) throw "Length must be greater than zero"; 245 | var mask:Int = (2 << Math.floor(Math.log(alphabet.length - 1) / Math.log(2))) - 1; 246 | var step:Int = Math.ceil(1.6 * mask * len / alphabet.length); 247 | var sb = new StringBuf(); 248 | while (sb.length != len) { 249 | for(i in 0...step) { 250 | var rnd = randomFunc(); 251 | var aIndex:Int = rnd & mask; 252 | if (aIndex < alphabet.length) { 253 | sb.add(alphabet.charAt(aIndex)); 254 | if (sb.length == len) break; 255 | } 256 | } 257 | } 258 | return sb.toString(); 259 | } 260 | 261 | public static function short(toAlphabet:String = FLICKR_BASE58, ?randomFunc:Void->Int):String { 262 | return Uuid.v4(randomFunc,true,toAlphabet); 263 | } 264 | } --------------------------------------------------------------------------------