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