1 /**
2  * A $(LINK2 http://en.wikipedia.org/wiki/Universally_unique_identifier, UUID), or
3  * $(LINK2 http://en.wikipedia.org/wiki/Universally_unique_identifier, Universally unique identifier),
4  * is intended to uniquely identify information in a distributed environment
5  * without significant central coordination. It can be
6  * used to tag objects with very short lifetimes, or to reliably identify very
7  * persistent objects across a network.
8  *
9 $(SCRIPT inhibitQuickIndex = 1;)
10 
11 $(DIVC quickindex,
12 $(BOOKTABLE ,
13 $(TR $(TH Category) $(TH Functions)
14 )
15 $(TR $(TDNW Parsing UUIDs)
16      $(TD $(MYREF parseUUID)
17           $(MYREF UUID)
18           $(MYREF UUIDParsingException)
19           $(MYREF uuidRegex)
20           )
21      )
22 $(TR $(TDNW Generating UUIDs)
23      $(TD $(MYREF sha1UUID)
24           $(MYREF randomUUID)
25           $(MYREF md5UUID)
26           )
27      )
28 $(TR $(TDNW Using UUIDs)
29      $(TD $(MYREF2 UUID.uuidVersion, uuidVersion)
30           $(MYREF2 UUID.variant, variant)
31           $(MYREF2 UUID.toString, toString)
32           $(MYREF2 UUID.data, data)
33           $(MYREF2 UUID.swap, swap)
34           $(MYREF2 UUID.opEquals, opEquals)
35           $(MYREF2 UUID.opCmp, opCmp)
36           $(MYREF2 UUID.toHash, toHash)
37           )
38      )
39 $(TR $(TDNW UUID namespaces)
40      $(TD $(MYREF dnsNamespace)
41           $(MYREF urlNamespace)
42           $(MYREF oidNamespace)
43           $(MYREF x500Namespace)
44           )
45      )
46 )
47 )
48 
49  * UUIDs have many applications. Some examples follow: Databases may use UUIDs to identify
50  * rows or records in order to ensure that they are unique across different
51  * databases, or for publication/subscription services. Network messages may be
52  * identified with a UUID to ensure that different parts of a message are put back together
53  * again. Distributed computing may use UUIDs to identify a remote procedure call.
54  * Transactions and classes involved in serialization may be identified by UUIDs.
55  * Microsoft's component object model (COM) uses UUIDs to distinguish different software
56  * component interfaces. UUIDs are inserted into documents from Microsoft Office programs.
57  * UUIDs identify audio or video streams in the Advanced Systems Format (ASF). UUIDs are
58  * also a basis for OIDs (object identifiers), and URNs (uniform resource name).
59  *
60  * An attractive feature of UUIDs when compared to alternatives is their relative small size,
61  * of 128 bits, or 16 bytes. Another is that the creation of UUIDs does not require
62  * a centralized authority.
63  *
64  * When UUIDs are generated by one of the defined mechanisms, they are either guaranteed
65  * to be unique, different from all other generated UUIDs (that is, it has never been
66  * generated before and it will never be generated again), or it is extremely likely
67  * to be unique (depending on the mechanism).
68  *
69  * For efficiency, UUID is implemented as a struct. UUIDs are therefore empty if not explicitly
70  * initialized. An UUID is empty if $(MYREF3 UUID.empty, empty) is true. Empty UUIDs are equal to
71  * `UUID.init`, which is a UUID with all 16 bytes set to 0.
72  * Use UUID's constructors or the UUID generator functions to get an initialized UUID.
73  *
74  * This is a port of $(LINK2 http://www.boost.org/doc/libs/1_42_0/libs/uuid/uuid.html,
75  * boost.uuid) from the Boost project with some minor additions and API
76  * changes for a more D-like API.
77  *
78  * Standards:
79  * $(LINK2 http://www.ietf.org/rfc/rfc4122.txt, RFC 4122)
80  *
81  * See_Also:
82  * $(LINK http://en.wikipedia.org/wiki/Universally_unique_identifier)
83  *
84  * Copyright: Copyright Johannes Pfau 2011 - .
85  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
86  * Authors:   Johannes Pfau
87  * Source:    $(PHOBOSSRC std/uuid.d)
88  *
89  * Macros:
90  * MYREF2 = <a href="#$2">$(TT $1)</a>&nbsp;
91  * MYREF3 = <a href="#$2">`$1`</a>
92  */
93 /*          Copyright Johannes Pfau 2011 - 2012.
94  * Distributed under the Boost Software License, Version 1.0.
95  *    (See accompanying file LICENSE_1_0.txt or copy at
96  *          http://www.boost.org/LICENSE_1_0.txt)
97  */
98 module std.uuid;
99 
100 ///
101 @safe unittest
102 {
103     import std.uuid;
104 
105     UUID[] ids;
106     ids ~= randomUUID();
107     ids ~= md5UUID("test.name.123");
108     ids ~= sha1UUID("test.name.123");
109 
110     foreach (entry; ids)
111     {
112         assert(entry.variant == UUID.Variant.rfc4122);
113     }
114     assert(ids[0].uuidVersion == UUID.Version.randomNumberBased);
115     assert(ids[1].toString() == "22390768-cced-325f-8f0f-cfeaa19d0ccd");
116     assert(ids[1].data == [34, 57, 7, 104, 204, 237, 50, 95, 143, 15, 207,
117         234, 161, 157, 12, 205]);
118     UUID id;
119     assert(id.empty);
120 }
121 
122 import std.range.primitives;
123 import std.traits;
124 
125 /**
126  *
127  */
128 public struct UUID
129 {
130     import std.meta : AliasSeq, allSatisfy;
131 
132     private:
133         alias skipSeq = AliasSeq!(8, 13, 18, 23);
134         alias byteSeq = AliasSeq!(0,2,4,6,9,11,14,16,19,21,24,26,28,30,32,34);
135 
136         @safe pure nothrow @nogc Char toChar(Char)(size_t i) const
137         {
138             if (i <= 9)
139                 return cast(Char)('0' + i);
140             else
141                 return cast(Char)('a' + (i-10));
142         }
143 
144         @safe pure nothrow unittest
145         {
146             assert(UUID(cast(ubyte[16])[138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45,
147                 179, 189, 251, 70]).toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
148         }
149 
150         // Reinterpret the UUID as an array of some other primitive.
151         @trusted ref T[16 / T.sizeof] asArrayOf(T)() return
152         if (isIntegral!T)
153         {
154             return *cast(typeof(return)*)&data;
155         }
156 
157     public:
158         /**
159          * RFC 4122 defines different internal data layouts for UUIDs. These are
160          * the UUID formats supported by this module. It's
161          * possible to read, compare and use all these Variants, but
162          * UUIDs generated by this module will always be in rfc4122 format.
163          *
164          * Note: Do not confuse this with $(REF _Variant, std,_variant).
165          */
166         enum Variant
167         {
168             ncs, /// NCS backward compatibility
169             rfc4122, /// Defined in RFC 4122 document
170             microsoft, /// Microsoft Corporation backward compatibility
171             future ///Reserved for future use
172         }
173 
174         /**
175          * RFC 4122 defines different UUID versions. The version shows
176          * how a UUID was generated, e.g. a version 4 UUID was generated
177          * from a random number, a version 3 UUID from an MD5 hash of a name.
178          *
179          * Note:
180          * All of these UUID versions can be read and processed by
181          * `std.uuid`, but only version 3, 4 and 5 UUIDs can be generated.
182          */
183         enum Version
184         {
185             ///Unknown version
186             unknown = -1,
187             ///Version 1
188             timeBased = 1,
189             ///Version 2
190             dceSecurity = 2,
191             ///Version 3 (Name based + MD5)
192             nameBasedMD5 = 3,
193             ///Version 4 (Random)
194             randomNumberBased = 4,
195             ///Version 5 (Name based + SHA-1)
196             nameBasedSHA1 = 5
197         }
198 
199         union
200         {
201             /**
202              * It is sometimes useful to get or set the 16 bytes of a UUID
203              * directly.
204              *
205              * Note:
206              * UUID uses a 16-ubyte representation for the UUID data.
207              * RFC 4122 defines a UUID as a special structure in big-endian
208              * format. These 16-ubytes always equal the big-endian structure
209              * defined in RFC 4122.
210              *
211              * Example:
212              * -----------------------------------------------
213              * auto rawData = uuid.data; //get data
214              * rawData[0] = 1; //modify
215              * uuid.data = rawData; //set data
216              * uuid.data[1] = 2; //modify directly
217              * -----------------------------------------------
218              */
219             ubyte[16] data;
220             private ulong[2] ulongs;
221             static if (size_t.sizeof == 4)
222                 private uint[4] uints;
223         }
224 
225         /*
226          * We could use a union here to also provide access to the
227          * fields specified in RFC 4122, but as we never have to access
228          * those (only necessary for version 1 (and maybe 2) UUIDs),
229          * that is not needed right now.
230          */
231 
232         @safe pure unittest
233         {
234             UUID tmp;
235             tmp.data = cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,12,
236                 13,14,15];
237             assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,
238                 12,13,14,15]);
239             tmp.data[2] = 3;
240             assert(tmp.data == cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11,
241                 12,13,14,15]);
242 
243             auto tmp2 = cast(immutable UUID) tmp;
244             assert(tmp2.data == cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11,
245                 12,13,14,15]);
246         }
247 
248         /**
249          * Construct a UUID struct from the 16 byte representation
250          * of a UUID.
251          */
252         @safe pure nothrow @nogc this(ref const scope ubyte[16] uuidData)
253         {
254             data = uuidData;
255         }
256         /// ditto
257         @safe pure nothrow @nogc this(const ubyte[16] uuidData)
258         {
259             data = uuidData;
260         }
261 
262         ///
263         @safe pure unittest
264         {
265             enum ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
266             auto uuid = UUID(data);
267             enum ctfe = UUID(data);
268             assert(uuid.data == data);
269             assert(ctfe.data == data);
270         }
271 
272         /**
273          * Construct a UUID struct from the 16 byte representation
274          * of a UUID. Variadic constructor to allow a simpler syntax, see examples.
275          * You need to pass exactly 16 ubytes.
276          */
277         @safe pure this(T...)(T uuidData)
278         if (uuidData.length == 16 && allSatisfy!(isIntegral, T))
279         {
280             import std.conv : to;
281 
282             foreach (idx, it; uuidData)
283             {
284                 this.data[idx] = to!ubyte(it);
285             }
286         }
287 
288         ///
289         @safe unittest
290         {
291             auto tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
292             assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,
293                 12,13,14,15]);
294         }
295 
296         @safe unittest
297         {
298             UUID tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
299             assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,
300                 12,13,14,15]);
301 
302             enum UUID ctfeID = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
303             assert(ctfeID == tmp);
304 
305             //Too few arguments
306             assert(!__traits(compiles, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14))));
307 
308             //Too many arguments
309             assert(!__traits(compiles, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1))));
310         }
311 
312         /**
313          * <a name="UUID(string)"></a>
314          * Parse a UUID from its canonical string form. An UUID in its
315          * canonical form looks like this: 8ab3060e-2cba-4f23-b74c-b52db3bdfb46
316          *
317          * Throws:
318          * $(LREF UUIDParsingException) if the input is invalid
319          *
320          * CTFE:
321          * This function is supported in CTFE code. Note that error messages
322          * caused by a malformed UUID parsed at compile time can be cryptic,
323          * but errors are detected and reported at
324          * compile time.
325          *
326          * Note:
327          * This is a strict parser. It only accepts the pattern above.
328          * It doesn't support any leading or trailing characters. It only
329          * accepts characters used for hex numbers and the string must have
330          * hyphens exactly like above.
331          *
332          * For a less strict parser, see $(LREF parseUUID)
333          */
334         this(T)(in T[] uuid)
335         if (isSomeChar!T)
336         {
337             import std.conv : to, parse;
338             if (uuid.length < 36)
339             {
340                 throw new UUIDParsingException(to!string(uuid), 0,
341                     UUIDParsingException.Reason.tooLittle, "Insufficient Input");
342             }
343             if (uuid.length > 36)
344             {
345                 throw new UUIDParsingException(to!string(uuid), 35, UUIDParsingException.Reason.tooMuch,
346                     "Input is too long, need exactly 36 characters");
347             }
348             static immutable skipInd = [skipSeq];
349             foreach (pos; skipInd)
350                 if (uuid[pos] != '-')
351                     throw new UUIDParsingException(to!string(uuid), pos,
352                         UUIDParsingException.Reason.invalidChar, "Expected '-'");
353 
354             ubyte[16] data2; //ctfe bug
355             uint pos = void;
356 
357             foreach (i, p; byteSeq)
358             {
359                 enum uint s = 'a'-10-'0';
360                 uint h = uuid[p];
361                 uint l = uuid[p+1];
362                 pos = p;
363                 if (h < '0') goto Lerr;
364                 if (l < '0') goto Lerr;
365                 if (h > '9')
366                 {
367                     h |= 0x20; //poorman's tolower
368                     if (h < 'a') goto Lerr;
369                     if (h > 'f') goto Lerr;
370                     h -= s;
371                 }
372                 if (l > '9')
373                 {
374                     l |= 0x20; //poorman's tolower
375                     if (l < 'a') goto Lerr;
376                     if (l > 'f') goto Lerr;
377                     l -= s;
378                 }
379                 h -= '0';
380                 l -= '0';
381 
382                 data2[i] = cast(ubyte)((h << 4) ^ l);
383             }
384             this.data = data2;
385             return;
386 
387         Lerr: throw new UUIDParsingException(to!string(uuid), pos,
388                 UUIDParsingException.Reason.invalidChar, "Couldn't parse ubyte");
389         }
390 
391         ///
392         @safe pure unittest
393         {
394             auto id = UUID("8AB3060E-2cba-4f23-b74c-b52db3bdfb46");
395             assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76,
396                181, 45, 179, 189, 251, 70]);
397             assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
398 
399             //Can also be used in CTFE, for example as UUID literals:
400             enum ctfeID = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
401             //here parsing is done at compile time, no runtime overhead!
402         }
403 
404         @safe pure unittest
405         {
406             import std.conv : to;
407             import std.exception;
408             import std.meta : AliasSeq;
409 
410             static foreach (S; AliasSeq!(char[], const(char)[], immutable(char)[],
411                                   wchar[], const(wchar)[], immutable(wchar)[],
412                                   dchar[], const(dchar)[], immutable(dchar)[],
413                                   immutable(char[]), immutable(wchar[]), immutable(dchar[])))
414             {{
415                 //Test valid, working cases
416                 assert(UUID(to!S("00000000-0000-0000-0000-000000000000")).empty);
417 
418                 auto id = UUID(to!S("8AB3060E-2cba-4f23-b74c-b52db3bdfb46"));
419                 assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76,
420                     181, 45, 179, 189, 251, 70]);
421                 assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
422 
423                 enum UUID ctfe = UUID(to!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
424                 assert(ctfe == id);
425 
426                 assert(UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a")).data
427                     == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
428 
429                 //Test too short UUIDS
430                 auto except = collectException!UUIDParsingException(
431                     UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886")));
432                 assert(except && except.reason == UUIDParsingException.Reason.tooLittle);
433 
434                 //Test too long UUIDS
435                 except = collectException!UUIDParsingException(
436                     UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886aa")));
437                 assert(except && except.reason == UUIDParsingException.Reason.tooMuch);
438 
439                 //Test dashes
440                 except = collectException!UUIDParsingException(
441                     UUID(to!S("8ab3060e2cba-4f23-b74c-b52db3bdfb-46")));
442                 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
443 
444                 //Test dashes 2
445                 except = collectException!UUIDParsingException(
446                     UUID(to!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46")));
447                 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
448 
449                 //Test invalid characters
450                 //make sure 36 characters in total or we'll get a 'tooMuch' reason
451                 except = collectException!UUIDParsingException(
452                     UUID(to!S("{8ab3060e-2cba-4f23-b74c-b52db3bdf6}")));
453                 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
454 
455                 //Boost test
456                 assert(UUID(to!S("01234567-89ab-cdef-0123-456789ABCDEF"))
457                     == UUID(cast(ubyte[16])[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0x01,
458                     0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]));
459             }
460         }}
461 
462         /**
463          * Returns true if and only if the UUID is equal
464          * to {00000000-0000-0000-0000-000000000000}
465          */
466         @trusted pure nothrow @nogc @property bool empty() const
467         {
468             if (__ctfe)
469                 return data == (ubyte[16]).init;
470 
471             auto p = cast(const(size_t*))data.ptr;
472             static if (size_t.sizeof == 4)
473                 return p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0;
474             else static if (size_t.sizeof == 8)
475                 return p[0] == 0 && p[1] == 0;
476             else
477                 static assert(false, "nonsense, it's not 32 or 64 bit");
478         }
479 
480         ///
481         @safe pure unittest
482         {
483             UUID id;
484             assert(id.empty);
485             id = UUID("00000000-0000-0000-0000-000000000001");
486             assert(!id.empty);
487         }
488 
489         @safe pure unittest
490         {
491             ubyte[16] getData(size_t i)
492             {
493                 ubyte[16] data;
494                 data[i] = 1;
495                 return data;
496             }
497 
498             for (size_t i = 0; i < 16; i++)
499             {
500                 assert(!UUID(getData(i)).empty);
501             }
502 
503             enum ctfeEmpty = UUID.init.empty;
504             assert(ctfeEmpty);
505 
506             bool ctfeTest()
507             {
508                 for (size_t i = 0; i < 16; i++)
509                 {
510                     auto ctfeEmpty2 = UUID(getData(i)).empty;
511                     assert(!ctfeEmpty2);
512                 }
513                 return true;
514             }
515             enum res = ctfeTest();
516         }
517 
518         /**
519          * RFC 4122 defines different internal data layouts for UUIDs.
520          * Returns the format used by this UUID.
521          *
522          * Note: Do not confuse this with $(REF _Variant, std,_variant).
523          * The type of this property is $(MYREF3 std.uuid.UUID.Variant, _Variant).
524          *
525          * See_Also:
526          * $(MYREF3 UUID.Variant, Variant)
527          */
528         @safe pure nothrow @nogc @property Variant variant() const
529         {
530             //variant is stored in octet 7
531             //which is index 8, since indexes count backwards
532             immutable octet7 = data[8]; //octet 7 is array index 8
533 
534             if ((octet7 & 0x80) == 0x00) //0b0xxxxxxx
535                 return Variant.ncs;
536             else if ((octet7 & 0xC0) == 0x80) //0b10xxxxxx
537                 return Variant.rfc4122;
538             else if ((octet7 & 0xE0) == 0xC0) //0b110xxxxx
539                 return Variant.microsoft;
540             else
541             {
542                 //assert((octet7 & 0xE0) == 0xE0, "Unknown UUID variant!") //0b111xxxx
543                 return Variant.future;
544             }
545         }
546 
547         ///
548         @safe pure unittest
549         {
550             assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").variant
551                == UUID.Variant.rfc4122);
552         }
553         @system pure unittest
554         {
555             // @system due to Variant
556             Variant[ubyte] tests = cast(Variant[ubyte])[0x00 : Variant.ncs,
557                                     0x10 : Variant.ncs,
558                                     0x20 : Variant.ncs,
559                                     0x30 : Variant.ncs,
560                                     0x40 : Variant.ncs,
561                                     0x50 : Variant.ncs,
562                                     0x60 : Variant.ncs,
563                                     0x70 : Variant.ncs,
564                                     0x80 : Variant.rfc4122,
565                                     0x90 : Variant.rfc4122,
566                                     0xa0 : Variant.rfc4122,
567                                     0xb0 : Variant.rfc4122,
568                                     0xc0 : Variant.microsoft,
569                                     0xd0 : Variant.microsoft,
570                                     0xe0 : Variant.future,
571                                     0xf0 : Variant.future];
572             foreach (key, value; tests)
573             {
574                 UUID u;
575                 u.data[8] = key;
576                 assert(u.variant == value);
577             }
578         }
579 
580         /**
581          * RFC 4122 defines different UUID versions. The version shows
582          * how a UUID was generated, e.g. a version 4 UUID was generated
583          * from a random number, a version 3 UUID from an MD5 hash of a name.
584          * Returns the version used by this UUID.
585          *
586          * See_Also:
587          * $(MYREF3 UUID.Version, Version)
588          */
589         @safe pure nothrow @nogc @property Version uuidVersion() const
590         {
591             //version is stored in octet 9
592             //which is index 6, since indexes count backwards
593             immutable octet9 = data[6];
594             if ((octet9 & 0xF0) == 0x10)
595                 return Version.timeBased;
596             else if ((octet9 & 0xF0) == 0x20)
597                 return Version.dceSecurity;
598             else if ((octet9 & 0xF0) == 0x30)
599                 return Version.nameBasedMD5;
600             else if ((octet9 & 0xF0) == 0x40)
601                 return Version.randomNumberBased;
602             else if ((octet9 & 0xF0) == 0x50)
603                 return Version.nameBasedSHA1;
604             else
605                 return Version.unknown;
606         }
607 
608         ///
609         @safe unittest
610         {
611             assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").uuidVersion
612                 == UUID.Version.randomNumberBased);
613         }
614         @system unittest
615         {
616             // @system due to cast
617             Version[ubyte] tests = cast(Version[ubyte]) [
618                 0x00 : UUID.Version.unknown,
619                 0x10 : UUID.Version.timeBased,
620                 0x20 : UUID.Version.dceSecurity,
621                 0x30 : UUID.Version.nameBasedMD5,
622                 0x40 : UUID.Version.randomNumberBased,
623                 0x50 : UUID.Version.nameBasedSHA1,
624                 0x60 : UUID.Version.unknown,
625                 0x70 : UUID.Version.unknown,
626                 0x80 : UUID.Version.unknown,
627                 0x90 : UUID.Version.unknown,
628                 0xa0 : UUID.Version.unknown,
629                 0xb0 : UUID.Version.unknown,
630                 0xc0 : UUID.Version.unknown,
631                 0xd0 : UUID.Version.unknown,
632                 0xe0 : UUID.Version.unknown,
633                 0xf0 : UUID.Version.unknown];
634             foreach (key, value; tests)
635             {
636                 UUID u;
637                 u.data[6] = key;
638                 assert(u.uuidVersion == value);
639             }
640         }
641 
642         /**
643          * Swap the data of this UUID with the data of rhs.
644          */
645         @safe pure nothrow @nogc void swap(ref UUID rhs)
646         {
647             immutable bck = data;
648             data = rhs.data;
649             rhs.data = bck;
650         }
651 
652         ///
653         @safe unittest
654         {
655             immutable ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
656             UUID u1;
657             UUID u2 = UUID(data);
658             u1.swap(u2);
659 
660             assert(u1 == UUID(data));
661             assert(u2 == UUID.init);
662         }
663 
664         /**
665          * All of the standard numeric operators are defined for
666          * the UUID struct.
667          */
668         @safe pure nothrow @nogc bool opEquals(const UUID s) const
669         {
670             return ulongs[0] == s.ulongs[0] && ulongs[1] == s.ulongs[1];
671         }
672 
673         ///
674         @safe pure unittest
675         {
676             //compare UUIDs
677             assert(UUID("00000000-0000-0000-0000-000000000000") == UUID.init);
678 
679             //UUIDs in associative arrays:
680             int[UUID] test = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0") : 1,
681                 UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a") : 2,
682                 UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1") : 3];
683 
684             assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3);
685 
686             //UUIDS can be sorted:
687             import std.algorithm;
688             UUID[] ids = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"),
689                           UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"),
690                           UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")];
691             sort(ids);
692         }
693 
694         /**
695          * ditto
696          */
697         @safe pure nothrow @nogc bool opEquals(ref const scope UUID s) const
698         {
699             return ulongs[0] == s.ulongs[0] && ulongs[1] == s.ulongs[1];
700         }
701 
702         /**
703          * ditto
704          */
705         @safe pure nothrow @nogc int opCmp(const UUID s) const
706         {
707             import std.algorithm.comparison : cmp;
708             return cmp(this.data[], s.data[]);
709         }
710 
711         /**
712          * ditto
713          */
714         @safe pure nothrow @nogc int opCmp(ref const scope UUID s) const
715         {
716             import std.algorithm.comparison : cmp;
717             return cmp(this.data[], s.data[]);
718         }
719 
720         /**
721          * ditto
722          */
723        @safe pure nothrow @nogc UUID opAssign(const UUID s)
724         {
725             ulongs[0] = s.ulongs[0];
726             ulongs[1] = s.ulongs[1];
727             return this;
728         }
729 
730         /**
731          * ditto
732          */
733         @safe pure nothrow @nogc UUID opAssign(ref const scope UUID s)
734         {
735             ulongs[0] = s.ulongs[0];
736             ulongs[1] = s.ulongs[1];
737             return this;
738         }
739 
740         /**
741          * ditto
742          */
743         //MurmurHash2
744         @safe pure nothrow @nogc size_t toHash() const
745         {
746             static if (size_t.sizeof == 4)
747             {
748                 enum uint m = 0x5bd1e995;
749                 enum uint n = 16;
750                 enum uint r = 24;
751 
752                 uint h = n;
753 
754                 uint k = uints[0];
755                 k *= m;
756                 k ^= k >> r;
757                 k *= m;
758 
759                 h ^= k;
760                 h *= m;
761 
762                 k = uints[1];
763                 k *= m;
764                 k ^= k >> r;
765                 k *= m;
766 
767                 h ^= k;
768                 h *= m;
769 
770                 k = uints[2];
771                 k *= m;
772                 k ^= k >> r;
773                 k *= m;
774 
775                 h ^= k;
776                 h *= m;
777 
778                 k = uints[3];
779                 k *= m;
780                 k ^= k >> r;
781                 k *= m;
782 
783                 h ^= k;
784                 h *= m;
785             }
786             else
787             {
788                 enum ulong m = 0xc6a4a7935bd1e995UL;
789                 enum ulong n = m * 16;
790                 enum uint r = 47;
791 
792                 ulong h = n;
793 
794                 ulong k = ulongs[0];
795                 k *= m;
796                 k ^= k >> r;
797                 k *= m;
798 
799                 h ^= k;
800                 h *= m;
801 
802                 k = ulongs[1];
803                 k *= m;
804                 k ^= k >> r;
805                 k *= m;
806 
807                 h ^= k;
808                 h *= m;
809             }
810             return h;
811         }
812         @safe unittest
813         {
814             assert(UUID("00000000-0000-0000-0000-000000000000") == UUID.init);
815             int[UUID] test = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0") : 1,
816                 UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a") : 2,
817                 UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1") : 3];
818 
819             assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3);
820 
821             import std.algorithm;
822             UUID[] ids = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"),
823                           UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"),
824                           UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")];
825             sort(ids);
826             auto id2 = ids.dup;
827 
828             ids = [UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"),
829                    UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"),
830                    UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")];
831             sort(ids);
832             assert(ids == id2);
833 
834             //test comparsion
835             UUID u1;
836             UUID u2 = UUID(cast(ubyte[16])[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
837             UUID u3 = UUID(cast(ubyte[16])[255,255,255,255,255,255,255,255,255,
838                 255,255,255,255,255,255,255]);
839 
840             assert(u1 == u1);
841 
842             assert(u1 != u2);
843 
844             assert(u1 < u2);
845             assert(u2 < u3);
846 
847             assert(u1 <= u1);
848             assert(u1 <= u2);
849             assert(u2 <= u3);
850 
851             assert(u2 >= u2);
852             assert(u3 >= u2);
853 
854             assert(u3 >= u3);
855             assert(u2 >= u1);
856             assert(u3 >= u1);
857 
858             // test hash
859             assert(u1.toHash() != u2.toHash());
860             assert(u2.toHash() != u3.toHash());
861             assert(u3.toHash() != u1.toHash());
862         }
863 
864 
865         /**
866          * Write the UUID into `sink` as an ASCII string in the canonical form,
867          * which is 36 characters in the form "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
868          * Params:
869          *      sink = OutputRange or writeable array at least 36 entries long
870          */
871         void toString(Writer)(scope Writer sink) const
872         {
873             char[36] result = void;
874             foreach (pos; skipSeq)
875                 result[pos] = '-';
876             foreach (i, pos; byteSeq)
877             {
878                 const uint entry = this.data[i];
879                 const uint hi = entry >> 4;
880                 result[pos  ] = toChar!char(hi);
881                 const uint lo = (entry) & 0x0F;
882                 result[pos+1] = toChar!char(lo);
883             }
884             static if (!__traits(compiles, put(sink, result[])) || isSomeString!Writer)
885             {
886                 foreach (i, c; result)
887                     sink[i] = cast(typeof(sink[i]))c;
888             }
889             else
890             {
891                 put(sink, result[]);
892             }
893         }
894 
895         /**
896          * Return the UUID as a string in the canonical form.
897          */
898         @trusted pure nothrow string toString() const
899         {
900             import std.exception : assumeUnique;
901             auto result = new char[36];
902             toString(result);
903             return result.assumeUnique;
904         }
905 
906         ///
907         @safe pure unittest
908         {
909             immutable str = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
910             auto id = UUID(str);
911             assert(id.toString() == str);
912         }
913 
914         @safe pure nothrow @nogc unittest
915         {
916             import std.meta : AliasSeq;
917             static foreach (Char; AliasSeq!(char, wchar, dchar))
918             {{
919                 alias String = immutable(Char)[];
920                 //CTFE
921                 enum String s = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
922                 enum id = UUID(s);
923                 static if (is(Char == char))
924                 {
925                     enum p = id.toString();
926                     static assert(s == p);
927                 }
928                 //nogc
929                 Char[36] str;
930                 id.toString(str[]);
931                 assert(str == s);
932             }}
933         }
934 
935         @system pure nothrow @nogc unittest
936         {
937             // @system due to cast
938             import std.encoding : Char = AsciiChar;
939             enum  utfstr = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
940             alias String = immutable(Char)[];
941             enum String s = cast(String) utfstr;
942             enum id = UUID(utfstr);
943             //nogc
944             Char[36] str;
945             id.toString(str[]);
946             assert(str == s);
947         }
948 
949         @safe unittest
950         {
951             auto u1 = UUID(cast(ubyte[16])[138, 179, 6, 14, 44, 186, 79,
952                 35, 183, 76, 181, 45, 179, 189, 251, 70]);
953             assert(u1.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
954             u1 = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
955             assert(u1.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
956 
957             char[] buf;
958             void sink(scope const(char)[] data)
959             {
960                 buf ~= data;
961             }
962             u1.toString(&sink);
963             assert(buf == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
964         }
965 }
966 
967 ///
968 @safe unittest
969 {
970     UUID id;
971     assert(id.empty);
972 
973     id = randomUUID;
974     assert(!id.empty);
975 
976     id = UUID(cast(ubyte[16]) [138, 179, 6, 14, 44, 186, 79,
977         35, 183, 76, 181, 45, 179, 189, 251, 70]);
978     assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
979 }
980 
981 /**
982  * This function generates a name based (Version 3) UUID from a namespace UUID and a name.
983  * If no namespace UUID was passed, the empty UUID `UUID.init` is used.
984  *
985  * Note:
986  * The default namespaces ($(LREF dnsNamespace), ...) defined by
987  * this module should be used when appropriate.
988  *
989  * RFC 4122 recommends to use Version 5 UUIDs (SHA-1) instead of Version 3
990  * UUIDs (MD5) for new applications.
991  *
992  * CTFE:
993  * CTFE is not supported.
994  *
995  * Note:
996  * RFC 4122 isn't very clear on how UUIDs should be generated from names.
997  * It is possible that different implementations return different UUIDs
998  * for the same input, so be warned. The implementation for UTF-8 strings
999  * and byte arrays used by `std.uuid` is compatible with Boost's implementation.
1000  * `std.uuid` guarantees that the same input to this function will generate
1001  * the same output at any time, on any system (this especially means endianness
1002  * doesn't matter).
1003  *
1004  * Note:
1005  * This function does not provide overloads for wstring and dstring, as
1006  * there's no clear answer on how that should be implemented. It could be
1007  * argued, that string, wstring and dstring input should have the same output,
1008  * but that wouldn't be compatible with Boost, which generates different output
1009  * for strings and wstrings. It's always possible to pass wstrings and dstrings
1010  * by using the ubyte[] function overload (but be aware of endianness issues!).
1011  */
1012 @safe pure nothrow @nogc UUID md5UUID(const(char[]) name, const UUID namespace = UUID.init)
1013 {
1014     return md5UUID(cast(const(ubyte[]))name, namespace);
1015 }
1016 
1017 /// ditto
1018 @safe pure nothrow @nogc UUID md5UUID(const(ubyte[]) data, const UUID namespace = UUID.init)
1019 {
1020     import std.digest.md : MD5;
1021 
1022     MD5 hash;
1023     hash.start();
1024 
1025     /*
1026      * NOTE: RFC 4122 says namespace should be converted to big-endian.
1027      * We always keep the UUID data in big-endian representation, so
1028      * that's fine
1029      */
1030     hash.put(namespace.data[]);
1031     hash.put(data[]);
1032 
1033     UUID u;
1034     u.data = hash.finish();
1035 
1036     //set variant
1037     //must be 0b10xxxxxx
1038     u.data[8] &= 0b10111111;
1039     u.data[8] |= 0b10000000;
1040 
1041     //set version
1042     //must be 0b0011xxxx
1043     u.data[6] &= 0b00111111;
1044     u.data[6] |= 0b00110000;
1045 
1046     return u;
1047 }
1048 
1049 ///
1050 @safe unittest
1051 {
1052     //Use default UUID.init namespace
1053     auto simpleID = md5UUID("test.uuid.any.string");
1054 
1055     //use a name-based id as namespace
1056     auto namespace = md5UUID("my.app");
1057     auto id = md5UUID("some-description", namespace);
1058 }
1059 
1060 @safe pure unittest
1061 {
1062     auto simpleID = md5UUID("test.uuid.any.string");
1063     assert(simpleID.data == cast(ubyte[16])[126, 206, 86, 72, 29, 233, 62, 213, 178, 139, 198, 136,
1064         188, 135, 153, 123]);
1065     auto namespace = md5UUID("my.app");
1066     auto id = md5UUID("some-description", namespace);
1067     assert(id.data == cast(ubyte[16])[166, 138, 167, 79, 48, 219, 55, 166, 170, 103, 39, 73, 216,
1068         150, 144, 164]);
1069 
1070     auto constTest = md5UUID(cast(const(char)[])"test");
1071     constTest = md5UUID(cast(const(char[]))"test");
1072 
1073     char[] mutable = "test".dup;
1074     id = md5UUID(mutable, namespace);
1075 
1076     const(ubyte)[] data = cast(ubyte[])[0,1,2,244,165,222];
1077     id = md5UUID(data);
1078     assert(id.data == cast(ubyte[16])[16, 50, 29, 247, 243, 185, 61, 178, 157, 100, 253, 236, 73,
1079         76, 51, 47]);
1080 
1081     assert(id.variant == UUID.Variant.rfc4122);
1082     assert(id.uuidVersion == UUID.Version.nameBasedMD5);
1083 
1084     auto correct = UUID("3d813cbb-47fb-32ba-91df-831e1593ac29");
1085 
1086     auto u = md5UUID("www.widgets.com", dnsNamespace);
1087     //enum ctfeId = md5UUID("www.widgets.com", dnsNamespace);
1088     //assert(ctfeId == u);
1089     assert(u == correct);
1090     assert(u.variant == UUID.Variant.rfc4122);
1091     assert(u.uuidVersion == UUID.Version.nameBasedMD5);
1092 }
1093 
1094  /**
1095  * This function generates a name based (Version 5) UUID from a namespace
1096  * UUID and a name.
1097  * If no namespace UUID was passed, the empty UUID `UUID.init` is used.
1098  *
1099  * Note:
1100  * The default namespaces ($(LREF dnsNamespace), ...) defined by
1101  * this module should be used when appropriate.
1102  *
1103  * CTFE:
1104  * CTFE is not supported.
1105  *
1106  * Note:
1107  * RFC 4122 isn't very clear on how UUIDs should be generated from names.
1108  * It is possible that different implementations return different UUIDs
1109  * for the same input, so be warned. The implementation for UTF-8 strings
1110  * and byte arrays used by `std.uuid` is compatible with Boost's implementation.
1111  * `std.uuid` guarantees that the same input to this function will generate
1112  * the same output at any time, on any system (this especially means endianness
1113  * doesn't matter).
1114  *
1115  * Note:
1116  * This function does not provide overloads for wstring and dstring, as
1117  * there's no clear answer on how that should be implemented. It could be
1118  * argued, that string, wstring and dstring input should have the same output,
1119  * but that wouldn't be compatible with Boost, which generates different output
1120  * for strings and wstrings. It's always possible to pass wstrings and dstrings
1121  * by using the ubyte[] function overload (but be aware of endianness issues!).
1122  */
1123 @safe pure nothrow @nogc UUID sha1UUID(scope const(char)[] name, scope const UUID namespace = UUID.init)
1124 {
1125     return sha1UUID(cast(const(ubyte[]))name, namespace);
1126 }
1127 
1128 /// ditto
1129 @safe pure nothrow @nogc UUID sha1UUID(scope const(ubyte)[] data, scope const UUID namespace = UUID.init)
1130 {
1131     import std.digest.sha : SHA1;
1132 
1133     SHA1 sha;
1134     sha.start();
1135 
1136     /*
1137      * NOTE: RFC 4122 says namespace should be converted to big-endian.
1138      * We always keep the UUID data in big-endian representation, so
1139      * that's fine
1140      */
1141     sha.put(namespace.data[]);
1142     sha.put(data[]);
1143 
1144     auto hash = sha.finish();
1145     auto u = UUID();
1146     u.data[] = hash[0 .. 16];
1147 
1148     //set variant
1149     //must be 0b10xxxxxx
1150     u.data[8] &= 0b10111111;
1151     u.data[8] |= 0b10000000;
1152 
1153     //set version
1154     //must be 0b0101xxxx
1155     u.data[6] &= 0b01011111;
1156     u.data[6] |= 0b01010000;
1157 
1158     return u;
1159 }
1160 
1161 ///
1162 @safe unittest
1163 {
1164     //Use default UUID.init namespace
1165     auto simpleID = sha1UUID("test.uuid.any.string");
1166 
1167     //use a name-based id as namespace
1168     auto namespace = sha1UUID("my.app");
1169     auto id = sha1UUID("some-description", namespace);
1170 }
1171 
1172 @safe pure unittest
1173 {
1174     auto simpleID = sha1UUID("test.uuid.any.string");
1175     assert(simpleID.data == cast(ubyte[16])[16, 209, 239, 61, 99, 12, 94, 70, 159, 79, 255, 250,
1176         131, 79, 14, 147]);
1177     auto namespace = sha1UUID("my.app");
1178     auto id = sha1UUID("some-description", namespace);
1179     assert(id.data == cast(ubyte[16])[225, 94, 195, 219, 126, 75, 83, 71, 157, 52, 247, 43, 238, 248,
1180         148, 46]);
1181 
1182     auto constTest = sha1UUID(cast(const(char)[])"test");
1183     constTest = sha1UUID(cast(const(char[]))"test");
1184 
1185     char[] mutable = "test".dup;
1186     id = sha1UUID(mutable, namespace);
1187 
1188     const(ubyte)[] data = cast(ubyte[])[0,1,2,244,165,222];
1189     id = sha1UUID(data);
1190     assert(id.data == cast(ubyte[16])[60, 65, 92, 240, 96, 46, 95, 238, 149, 100, 12, 64, 199, 194,
1191         243, 12]);
1192 
1193     auto correct = UUID("21f7f8de-8051-5b89-8680-0195ef798b6a");
1194 
1195     auto u = sha1UUID("www.widgets.com", dnsNamespace);
1196     assert(u == correct);
1197     assert(u.variant == UUID.Variant.rfc4122);
1198     assert(u.uuidVersion == UUID.Version.nameBasedSHA1);
1199 }
1200 
1201 /**
1202  * This function generates a random number based UUID from a random
1203  * number generator.
1204  *
1205  * This function is not supported at compile time.
1206  *
1207  * Params:
1208  *      randomGen = uniform RNG
1209  * See_Also: $(REF isUniformRNG, std,random)
1210  */
1211 @nogc nothrow @safe UUID randomUUID()
1212 {
1213     import std.random : rndGen;
1214     // A PRNG with fewer than `n` bytes of state cannot produce
1215     // every distinct `n` byte sequence.
1216     static if (typeof(rndGen).sizeof >= UUID.sizeof)
1217     {
1218         return randomUUID(rndGen);
1219     }
1220     else
1221     {
1222         import std.random : unpredictableSeed, Xorshift192;
1223         static assert(Xorshift192.sizeof >= UUID.sizeof);
1224         static Xorshift192 rng;
1225         static bool initialized;
1226         if (!initialized)
1227         {
1228             rng.seed(unpredictableSeed);
1229             initialized = true;
1230         }
1231         return randomUUID(rng);
1232     }
1233 }
1234 
1235 /// ditto
1236 UUID randomUUID(RNG)(ref RNG randomGen)
1237 if (isInputRange!RNG && isIntegral!(ElementType!RNG))
1238 {
1239     import std.random : isUniformRNG;
1240     static assert(isUniformRNG!RNG, "randomGen must be a uniform RNG");
1241 
1242     alias E = ElementEncodingType!RNG;
1243     enum size_t elemSize = E.sizeof;
1244     static assert(elemSize <= 16);
1245     static assert(16 % elemSize == 0);
1246 
1247     UUID u;
1248     foreach (ref E e ; u.asArrayOf!E())
1249     {
1250         e = randomGen.front;
1251         randomGen.popFront();
1252     }
1253 
1254     //set variant
1255     //must be 0b10xxxxxx
1256     u.data[8] &= 0b10111111;
1257     u.data[8] |= 0b10000000;
1258 
1259     //set version
1260     //must be 0b0100xxxx
1261     u.data[6] &= 0b01001111;
1262     u.data[6] |= 0b01000000;
1263 
1264     return u;
1265 }
1266 
1267 ///
1268 @safe unittest
1269 {
1270     import std.random : Xorshift192, unpredictableSeed;
1271 
1272     //simple call
1273     auto uuid = randomUUID();
1274 
1275     //provide a custom RNG. Must be seeded manually.
1276     Xorshift192 gen;
1277 
1278     gen.seed(unpredictableSeed);
1279     auto uuid3 = randomUUID(gen);
1280 }
1281 
1282 @safe unittest
1283 {
1284     import std.random : Xorshift192, unpredictableSeed;
1285     //simple call
1286     auto uuid = randomUUID();
1287 
1288     //provide a custom RNG. Must be seeded manually.
1289     Xorshift192 gen;
1290     gen.seed(unpredictableSeed);
1291     auto uuid3 = randomUUID(gen);
1292 
1293     auto u1 = randomUUID();
1294     auto u2 = randomUUID();
1295     assert(u1 != u2);
1296     assert(u1.variant == UUID.Variant.rfc4122);
1297     assert(u1.uuidVersion == UUID.Version.randomNumberBased);
1298 }
1299 
1300 /**
1301  * This is a less strict parser compared to the parser used in the
1302  * UUID constructor. It enforces the following rules:
1303  *
1304  * $(UL
1305  *   $(LI hex numbers are always two hexdigits([0-9a-fA-F]))
1306  *   $(LI there must be exactly 16 such pairs in the input, not less, not more)
1307  *   $(LI there can be exactly one dash between two hex-pairs, but not more)
1308  *   $(LI there can be multiple characters enclosing the 16 hex pairs,
1309  *     as long as these characters do not contain [0-9a-fA-F])
1310  * )
1311  *
1312  * Note:
1313  * Like most parsers, it consumes its argument. This means:
1314  * -------------------------
1315  * string s = "8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46";
1316  * parseUUID(s);
1317  * assert(s == "");
1318  * -------------------------
1319  *
1320  * Throws:
1321  * $(LREF UUIDParsingException) if the input is invalid
1322  *
1323  * CTFE:
1324  * This function is supported in CTFE code. Note that error messages
1325  * caused by a malformed UUID parsed at compile time can be cryptic,
1326  * but errors are detected and reported at compile time.
1327  */
1328 UUID parseUUID(T)(T uuidString)
1329 if (isSomeString!T)
1330 {
1331     return parseUUID(uuidString);
1332 }
1333 
1334 ///ditto
1335 UUID parseUUID(Range)(ref Range uuidRange)
1336 if (isInputRange!Range && isSomeChar!(ElementType!Range))
1337 {
1338     import std.ascii : isHexDigit;
1339     import std.conv : ConvException, parse;
1340 
1341     static if (isForwardRange!Range)
1342         auto errorCopy = uuidRange.save;
1343 
1344     void parserError()(size_t pos, UUIDParsingException.Reason reason, string message, Throwable next = null,
1345         string file = __FILE__, size_t line = __LINE__)
1346     {
1347         static if (isForwardRange!Range)
1348         {
1349             import std.conv : to;
1350             static if (isInfinite!Range)
1351             {
1352                 throw new UUIDParsingException(to!string(take(errorCopy, pos)), pos, reason, message,
1353                     next, file, line);
1354             }
1355             else
1356             {
1357                 throw new UUIDParsingException(to!string(errorCopy), pos, reason, message, next, file,
1358                     line);
1359             }
1360         }
1361         else
1362         {
1363             throw new UUIDParsingException("", pos, reason, message, next, file, line);
1364         }
1365     }
1366 
1367     static if (hasLength!Range)
1368     {
1369         import std.conv : to;
1370         if (uuidRange.length < 32)
1371         {
1372             throw new UUIDParsingException(to!string(uuidRange), 0, UUIDParsingException.Reason.tooLittle,
1373                 "Insufficient Input");
1374         }
1375     }
1376 
1377     UUID result;
1378     size_t consumed;
1379     size_t element = 0;
1380 
1381     //skip garbage
1382     size_t skip()()
1383     {
1384         size_t skipped;
1385         while (!uuidRange.empty && !isHexDigit(uuidRange.front))
1386         {
1387             skipped++;
1388             uuidRange.popFront();
1389         }
1390         return skipped;
1391     }
1392 
1393     consumed += skip();
1394 
1395     if (uuidRange.empty)
1396         parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input");
1397 
1398     bool dashAllowed = false;
1399 
1400     parseLoop: while (!uuidRange.empty)
1401     {
1402         immutable character = uuidRange.front;
1403 
1404         if (character == '-')
1405         {
1406             if (!dashAllowed)
1407                 parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected '-'");
1408             else
1409                 dashAllowed = false;
1410 
1411             consumed++;
1412         }
1413         else if (!isHexDigit(character))
1414         {
1415             parserError(consumed, UUIDParsingException.Reason.invalidChar,
1416                 "Unexpected character (wanted a hexDigit)");
1417         }
1418         else
1419         {
1420             try
1421             {
1422                 consumed += 2;
1423                 static if (isSomeString!Range)
1424                 {
1425                     if (uuidRange.length < 2)
1426                     {
1427                         parserError(consumed, UUIDParsingException.Reason.tooLittle,
1428                             "Insufficient Input");
1429                     }
1430                     auto part = uuidRange[0 .. 2];
1431                     result.data[element++] = parse!ubyte(part, 16);
1432                     uuidRange.popFront();
1433                 }
1434                 else
1435                 {
1436                     dchar[2] copyBuf;
1437                     copyBuf[0] = character;
1438                     uuidRange.popFront();
1439                     if (uuidRange.empty)
1440                     {
1441                         parserError(consumed, UUIDParsingException.Reason.tooLittle,
1442                             "Insufficient Input");
1443                     }
1444                     copyBuf[1] = uuidRange.front;
1445                     auto part = copyBuf[];
1446                     result.data[element++] = parse!ubyte(part, 16);
1447                 }
1448 
1449                 if (element == 16)
1450                 {
1451                     uuidRange.popFront();
1452                     break parseLoop;
1453                 }
1454 
1455                 dashAllowed = true;
1456             }
1457             catch (ConvException e)
1458             {
1459                 parserError(consumed, UUIDParsingException.Reason.invalidChar,
1460                     "Couldn't parse ubyte", e);
1461             }
1462         }
1463         uuidRange.popFront();
1464     }
1465     assert(element <= 16);
1466 
1467     if (element < 16)
1468         parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input");
1469 
1470     consumed += skip();
1471     if (!uuidRange.empty)
1472         parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected character");
1473 
1474     return result;
1475 }
1476 
1477 ///
1478 @safe unittest
1479 {
1480     auto id = parseUUID("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46");
1481     //no dashes
1482     id = parseUUID("8ab3060e2cba4f23b74cb52db3bdfb46");
1483     //dashes at different positions
1484     id = parseUUID("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46");
1485     //leading / trailing characters
1486     id = parseUUID("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}");
1487     //unicode
1488     id = parseUUID("ü8ab3060e2cba4f23b74cb52db3bdfb46ü");
1489     //multiple trailing/leading characters
1490     id = parseUUID("///8ab3060e2cba4f23b74cb52db3bdfb46||");
1491 
1492     //Can also be used in CTFE, for example as UUID literals:
1493     enum ctfeID = parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
1494     //here parsing is done at compile time, no runtime overhead!
1495 }
1496 
1497 @safe pure unittest
1498 {
1499     import std.conv : to;
1500     import std.exception;
1501     import std.meta;
1502 
1503     struct TestRange(bool forward)
1504     {
1505         dstring input;
1506 
1507         @property dchar front()
1508         {
1509             return input.front;
1510         }
1511 
1512         void popFront()
1513         {
1514             input.popFront();
1515         }
1516 
1517         @property bool empty()
1518         {
1519             return input.empty;
1520         }
1521 
1522         static if (forward)
1523         {
1524             @property TestRange!true save()
1525             {
1526                 return this;
1527             }
1528         }
1529     }
1530     alias TestInputRange = TestRange!false;
1531     alias TestForwardRange = TestRange!true;
1532 
1533     assert(isInputRange!TestInputRange);
1534     assert(is(ElementType!TestInputRange == dchar));
1535     assert(isInputRange!TestForwardRange);
1536     assert(isForwardRange!TestForwardRange);
1537     assert(is(ElementType!TestForwardRange == dchar));
1538 
1539     //Helper function for unittests - Need to pass ranges by ref
1540     UUID parseHelper(T)(string input)
1541     {
1542         static if (is(T == TestInputRange) || is(T == TestForwardRange))
1543         {
1544             T range = T(to!dstring(input));
1545             return parseUUID(range);
1546         }
1547         else
1548             return parseUUID(to!T(input));
1549     }
1550 
1551     static foreach (S; AliasSeq!(char[], const(char)[], immutable(char)[],
1552                           wchar[], const(wchar)[], immutable(wchar)[],
1553                           dchar[], const(dchar)[], immutable(dchar)[],
1554                           immutable(char[]), immutable(wchar[]), immutable(dchar[]),
1555                           TestForwardRange, TestInputRange))
1556     {{
1557         //Verify examples.
1558         auto id = parseHelper!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46");
1559         //no dashes
1560         id = parseHelper!S("8ab3060e2cba4f23b74cb52db3bdfb46");
1561         //dashes at different positions
1562         id = parseHelper!S("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46");
1563         //leading / trailing characters
1564         id = parseHelper!S("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}");
1565         //unicode
1566         id = parseHelper!S("ü8ab3060e2cba4f23b74cb52db3bdfb46ü");
1567         //multiple trailing/leading characters
1568         id = parseHelper!S("///8ab3060e2cba4f23b74cb52db3bdfb46||");
1569         enum ctfeId = parseHelper!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
1570         assert(parseHelper!S("8AB3060E-2cba-4f23-b74c-b52db3bdfb46") == ctfeId);
1571 
1572         //Test valid, working cases
1573         assert(parseHelper!S("00000000-0000-0000-0000-000000000000").empty);
1574         assert(parseHelper!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46").data
1575             == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]);
1576 
1577         assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1578             == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1579 
1580         //wstring / dstring
1581         assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1582             == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1583         assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1584             == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1585 
1586         //Test too short UUIDS
1587         auto except = collectException!UUIDParsingException(
1588             parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886"));
1589         assert(except && except.reason == UUIDParsingException.Reason.tooLittle);
1590 
1591         //Test too long UUIDS
1592         except = collectException!UUIDParsingException(
1593             parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886aa"));
1594         assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1595 
1596         //Test too long UUIDS 2
1597         except = collectException!UUIDParsingException(
1598             parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a-aa"));
1599         assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1600 
1601         //Test dashes
1602         assert(parseHelper!S("8ab3060e2cba-4f23-b74c-b52db3bdfb46")
1603             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1604         assert(parseHelper!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46")
1605             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1606         assert(parseHelper!S("8ab3060e2cba4f23b74cb52db3bdfb46")
1607             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1608 
1609         except = collectException!UUIDParsingException(
1610             parseHelper!S("8-ab3060e2cba-4f23-b74c-b52db3bdfb46"));
1611         assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1612 
1613         //Test leading/trailing characters
1614         assert(parseHelper!S("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}")
1615             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1616         assert(parseHelper!S("{8ab3060e2cba4f23b74cb52db3bdfb46}")
1617             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1618 
1619         //Boost test
1620         auto u_increasing = UUID(cast(ubyte[16])[0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
1621             0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
1622         assert(parseHelper!S("0123456789abcdef0123456789ABCDEF") == UUID(cast(ubyte[16])[0x01,
1623             0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]));
1624 
1625         //unicode
1626         assert(parseHelper!S("ü8ab3060e2cba4f23b74cb52db3bdfb46ü")
1627             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1628 
1629         //multiple trailing/leading characters
1630         assert(parseHelper!S("///8ab3060e2cba4f23b74cb52db3bdfb46||")
1631             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1632     }}
1633 
1634     // Test input range with non-dchar element type.
1635     {
1636         import std.utf : byCodeUnit;
1637         auto range = "8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46".byCodeUnit;
1638         assert(parseUUID(range).data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]);
1639     }
1640 }
1641 
1642 /**
1643  * Default namespace from RFC 4122
1644  *
1645  * Name string is a fully-qualified domain name
1646  */
1647 enum dnsNamespace = UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
1648 
1649 /**
1650  * Default namespace from RFC 4122
1651  *
1652  * Name string is a URL
1653  */
1654 enum urlNamespace = UUID("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
1655 
1656 /**
1657  * Default namespace from RFC 4122
1658  *
1659  * Name string is an ISO OID
1660  */
1661 enum oidNamespace = UUID("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
1662 
1663 /**
1664  * Default namespace from RFC 4122
1665  *
1666  * Name string is an X.500 DN (in DER or a text output format)
1667  */
1668 enum x500Namespace = UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8");
1669 
1670 /**
1671  * Regex string to extract UUIDs from text.
1672  */
1673 enum uuidRegex = "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}"~
1674     "-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}";
1675 
1676 ///
1677 @safe unittest
1678 {
1679     import std.algorithm;
1680     import std.regex;
1681 
1682     string test = "Lorem ipsum dolor sit amet, consetetur "~
1683     "6ba7b814-9dad-11d1-80b4-00c04fd430c8 sadipscing \n"~
1684     "elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore \r\n"~
1685     "magna aliquyam erat, sed diam voluptua. "~
1686     "8ab3060e-2cba-4f23-b74c-b52db3bdfb46 At vero eos et accusam et "~
1687     "justo duo dolores et ea rebum.";
1688 
1689     auto r = regex(uuidRegex, "g");
1690     UUID[] found;
1691     foreach (c; match(test, r))
1692     {
1693         found ~= UUID(c.hit);
1694     }
1695     assert(found == [
1696         UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8"),
1697         UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"),
1698     ]);
1699 }
1700 
1701 /**
1702  * This exception is thrown if an error occurs when parsing a UUID
1703  * from a string.
1704  */
1705 public class UUIDParsingException : Exception
1706 {
1707     /**
1708      * The reason why parsing the UUID string failed (if known)
1709      */
1710     enum Reason
1711     {
1712         unknown, ///
1713         tooLittle, ///The passed in input was correct, but more input was expected.
1714         tooMuch, ///The input data is too long (There's no guarantee the first part of the data is valid)
1715         invalidChar, ///Encountered an invalid character
1716 
1717     }
1718     ///ditto
1719     Reason reason;
1720     ///The original input string which should have been parsed.
1721     string input;
1722     ///The position in the input string where the error occurred.
1723     size_t position;
1724 
1725     private this(string input, size_t pos, Reason why = Reason.unknown, string msg = "",
1726         Throwable next = null, string file = __FILE__, size_t line = __LINE__) pure @trusted
1727     {
1728         import std.array : replace;
1729         import std.format : format;
1730         this.input = input;
1731         this.position = pos;
1732         this.reason = why;
1733         string message = format("An error occured in the UUID parser: %s\n" ~
1734           " * Input:\t'%s'\n * Position:\t%s", msg, replace(replace(input,
1735           "\r", "\\r"), "\n", "\\n"), pos);
1736         super(message, file, line, next);
1737     }
1738 }
1739 
1740 ///
1741 @safe unittest
1742 {
1743     import std.exception : collectException;
1744 
1745     const inputUUID = "this-is-an-invalid-uuid";
1746     auto ex = collectException!UUIDParsingException(UUID(inputUUID));
1747     assert(ex !is null); // check that exception was thrown
1748     assert(ex.input == inputUUID);
1749     assert(ex.position == 0);
1750     assert(ex.reason == UUIDParsingException.Reason.tooLittle);
1751 }
1752 
1753 @safe unittest
1754 {
1755     auto ex = new UUIDParsingException("foo", 10, UUIDParsingException.Reason.tooMuch);
1756     assert(ex.input == "foo");
1757     assert(ex.position == 10);
1758     assert(ex.reason == UUIDParsingException.Reason.tooMuch);
1759 }