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 */
98module 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
122import std.range.primitives;
123import std.traits;
124
125/**
126 *
127 */
128public 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         * $(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
1202UUID randomUUID(RNG)(ref RNG randomGen)
1203if (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 */
1306UUID parseUUID(T)(T uuidString)
1307if (isSomeString!T)
1308{
1309    return parseUUID(uuidString);
1310}
1311
1312///ditto
1313UUID parseUUID(Range)(ref Range uuidRange)
1314if (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 */
1619enum dnsNamespace = UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
1620
1621/**
1622 * Default namespace from RFC 4122
1623 *
1624 * Name string is a URL
1625 */
1626enum urlNamespace = UUID("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
1627
1628/**
1629 * Default namespace from RFC 4122
1630 *
1631 * Name string is an ISO OID
1632 */
1633enum 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 */
1640enum x500Namespace = UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8");
1641
1642/**
1643 * Regex string to extract UUIDs from text.
1644 */
1645enum 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 */
1677public 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