1/**
2 * A $(LINK2 http://en.wikipedia.org/wiki/Universally_unique_identifier, UUID), or
3 * $(LINK2 http://en.wikipedia.org/wiki/Universally_unique_identifier, Universally unique identifier),
4 * is intended to uniquely identify information in a distributed environment
5 * without significant central coordination. It can be
6 * used to tag objects with very short lifetimes, or to reliably identify very
7 * persistent objects across a network.
8 *
9$(SCRIPT inhibitQuickIndex = 1;)
10
11$(DIVC quickindex,
12$(BOOKTABLE ,
13$(TR $(TH Category) $(TH Functions)
14)
15$(TR $(TDNW Parsing UUIDs)
16     $(TD $(MYREF parseUUID)
17          $(MYREF UUID)
18          $(MYREF UUIDParsingException)
19          $(MYREF uuidRegex)
20          )
21     )
22$(TR $(TDNW Generating UUIDs)
23     $(TD $(MYREF sha1UUID)
24          $(MYREF randomUUID)
25          $(MYREF md5UUID)
26          )
27     )
28$(TR $(TDNW Using UUIDs)
29     $(TD $(MYREF2 UUID.uuidVersion, uuidVersion)
30          $(MYREF2 UUID.variant, variant)
31          $(MYREF2 UUID.toString, toString)
32          $(MYREF2 UUID.data, data)
33          $(MYREF2 UUID.swap, swap)
34          $(MYREF2 UUID.opEquals, opEquals)
35          $(MYREF2 UUID.opCmp, opCmp)
36          $(MYREF2 UUID.toHash, toHash)
37          )
38     )
39$(TR $(TDNW UUID namespaces)
40     $(TD $(MYREF dnsNamespace)
41          $(MYREF urlNamespace)
42          $(MYREF oidNamespace)
43          $(MYREF x500Namespace)
44          )
45     )
46)
47)
48
49 * UUIDs have many applications. Some examples follow: Databases may use UUIDs to identify
50 * rows or records in order to ensure that they are unique across different
51 * databases, or for publication/subscription services. Network messages may be
52 * identified with a UUID to ensure that different parts of a message are put back together
53 * again. Distributed computing may use UUIDs to identify a remote procedure call.
54 * Transactions and classes involved in serialization may be identified by UUIDs.
55 * Microsoft's component object model (COM) uses UUIDs to distinguish different software
56 * component interfaces. UUIDs are inserted into documents from Microsoft Office programs.
57 * UUIDs identify audio or video streams in the Advanced Systems Format (ASF). UUIDs are
58 * also a basis for OIDs (object identifiers), and URNs (uniform resource name).
59 *
60 * An attractive feature of UUIDs when compared to alternatives is their relative small size,
61 * of 128 bits, or 16 bytes. Another is that the creation of UUIDs does not require
62 * a centralized authority.
63 *
64 * When UUIDs are generated by one of the defined mechanisms, they are either guaranteed
65 * to be unique, different from all other generated UUIDs (that is, it has never been
66 * generated before and it will never be generated again), or it is extremely likely
67 * to be unique (depending on the mechanism).
68 *
69 * For efficiency, UUID is implemented as a struct. UUIDs are therefore empty if not explicitly
70 * initialized. An UUID is empty if $(MYREF3 UUID.empty, empty) is true. Empty UUIDs are equal to
71 * `UUID.init`, which is a UUID with all 16 bytes set to 0.
72 * Use UUID's constructors or the UUID generator functions to get an initialized UUID.
73 *
74 * This is a port of $(LINK2 http://www.boost.org/doc/libs/1_42_0/libs/uuid/uuid.html,
75 * boost.uuid) from the Boost project with some minor additions and API
76 * changes for a more D-like API.
77 *
78 * Standards:
79 * $(LINK2 http://www.ietf.org/rfc/rfc4122.txt, RFC 4122)
80 *
81 * See_Also:
82 * $(LINK http://en.wikipedia.org/wiki/Universally_unique_identifier)
83 *
84 * Copyright: Copyright Johannes Pfau 2011 - .
85 * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
86 * Authors:   Johannes Pfau
87 * Source:    $(PHOBOSSRC std/uuid.d)
88 *
89 * Macros:
90 * MYREF2 = <a href="#$2">$(TT $1)</a>&nbsp;
91 * MYREF3 = <a href="#$2">`$1`</a>
92 */
93/*          Copyright Johannes Pfau 2011 - 2012.
94 * Distributed under the Boost Software License, Version 1.0.
95 *    (See accompanying file LICENSE_1_0.txt or copy at
96 *          http://www.boost.org/LICENSE_1_0.txt)
97 */
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         * `std.uuid`, but only version 3, 4 and 5 UUIDs can be generated.
182         */
183        enum Version
184        {
185            ///Unknown version
186            unknown = -1,
187            ///Version 1
188            timeBased = 1,
189            ///Version 2
190            dceSecurity = 2,
191            ///Version 3 (Name based + MD5)
192            nameBasedMD5 = 3,
193            ///Version 4 (Random)
194            randomNumberBased = 4,
195            ///Version 5 (Name based + SHA-1)
196            nameBasedSHA1 = 5
197        }
198
199        union
200        {
201            /**
202             * It is sometimes useful to get or set the 16 bytes of a UUID
203             * directly.
204             *
205             * Note:
206             * UUID uses a 16-ubyte representation for the UUID data.
207             * RFC 4122 defines a UUID as a special structure in big-endian
208             * format. These 16-ubytes always equal the big-endian structure
209             * defined in RFC 4122.
210             *
211             * Example:
212             * -----------------------------------------------
213             * auto rawData = uuid.data; //get data
214             * rawData[0] = 1; //modify
215             * uuid.data = rawData; //set data
216             * uuid.data[1] = 2; //modify directly
217             * -----------------------------------------------
218             */
219            ubyte[16] data;
220            private ulong[2] ulongs;
221            static if (size_t.sizeof == 4)
222                private uint[4] uints;
223        }
224
225        /*
226         * We could use a union here to also provide access to the
227         * fields specified in RFC 4122, but as we never have to access
228         * those (only necessary for version 1 (and maybe 2) UUIDs),
229         * that is not needed right now.
230         */
231
232        @safe pure unittest
233        {
234            UUID tmp;
235            tmp.data = cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,12,
236                13,14,15];
237            assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,
238                12,13,14,15]);
239            tmp.data[2] = 3;
240            assert(tmp.data == cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11,
241                12,13,14,15]);
242
243            auto tmp2 = cast(immutable UUID) tmp;
244            assert(tmp2.data == cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11,
245                12,13,14,15]);
246        }
247
248        /**
249         * Construct a UUID struct from the 16 byte representation
250         * of a UUID.
251         */
252        @safe pure nothrow @nogc this(ref const scope ubyte[16] uuidData)
253        {
254            data = uuidData;
255        }
256        /// ditto
257        @safe pure nothrow @nogc this(const ubyte[16] uuidData)
258        {
259            data = uuidData;
260        }
261
262        ///
263        @safe pure unittest
264        {
265            enum ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
266            auto uuid = UUID(data);
267            enum ctfe = UUID(data);
268            assert(uuid.data == data);
269            assert(ctfe.data == data);
270        }
271
272        /**
273         * Construct a UUID struct from the 16 byte representation
274         * of a UUID. Variadic constructor to allow a simpler syntax, see examples.
275         * You need to pass exactly 16 ubytes.
276         */
277        @safe pure this(T...)(T uuidData)
278            if (uuidData.length == 16 && allSatisfy!(isIntegral, T))
279        {
280            import std.conv : to;
281
282            foreach (idx, it; uuidData)
283            {
284                this.data[idx] = to!ubyte(it);
285            }
286        }
287
288        ///
289        @safe unittest
290        {
291            auto tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
292            assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,
293                12,13,14,15]);
294        }
295
296        @safe unittest
297        {
298            UUID tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
299            assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,
300                12,13,14,15]);
301
302            enum UUID ctfeID = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
303            assert(ctfeID == tmp);
304
305            //Too few arguments
306            assert(!__traits(compiles, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14))));
307
308            //Too many arguments
309            assert(!__traits(compiles, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1))));
310        }
311
312        /**
313         * <a name="UUID(string)"></a>
314         * Parse a UUID from its canonical string form. An UUID in its
315         * canonical form looks like this: 8ab3060e-2cba-4f23-b74c-b52db3bdfb46
316         *
317         * Throws:
318         * $(LREF UUIDParsingException) if the input is invalid
319         *
320         * CTFE:
321         * This function is supported in CTFE code. Note that error messages
322         * caused by a malformed UUID parsed at compile time can be cryptic,
323         * but errors are detected and reported at
324         * compile time.
325         *
326         * Note:
327         * This is a strict parser. It only accepts the pattern above.
328         * It doesn't support any leading or trailing characters. It only
329         * accepts characters used for hex numbers and the string must have
330         * hyphens exactly like above.
331         *
332         * For a less strict parser, see $(LREF parseUUID)
333         */
334        this(T)(in T[] uuid) if (isSomeChar!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 : AliasSeq;
408
409            static 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(const 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 const scope 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(const 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 const scope 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(const 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 const scope 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            static if (!__traits(compiles, put(sink, result[])) || isSomeString!Writer)
884            {
885                foreach (i, c; result)
886                    sink[i] = cast(typeof(sink[i]))c;
887            }
888            else
889            {
890                put(sink, result[]);
891            }
892        }
893
894        /**
895         * Return the UUID as a string in the canonical form.
896         */
897        @trusted pure nothrow string toString() const
898        {
899            import std.exception : assumeUnique;
900            auto result = new char[36];
901            toString(result);
902            return result.assumeUnique;
903        }
904
905        ///
906        @safe pure unittest
907        {
908            immutable str = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
909            auto id = UUID(str);
910            assert(id.toString() == str);
911        }
912
913        @safe pure nothrow @nogc unittest
914        {
915            import std.meta : AliasSeq;
916            static foreach (Char; AliasSeq!(char, wchar, dchar))
917            {{
918                alias String = immutable(Char)[];
919                //CTFE
920                enum String s = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
921                enum id = UUID(s);
922                static if (is(Char == char))
923                {
924                    enum p = id.toString();
925                    static assert(s == p);
926                }
927                //nogc
928                Char[36] str;
929                id.toString(str[]);
930                assert(str == s);
931            }}
932        }
933
934        @system pure nothrow @nogc unittest
935        {
936            // @system due to cast
937            import std.encoding : Char = AsciiChar;
938            enum  utfstr = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
939            alias String = immutable(Char)[];
940            enum String s = cast(String) utfstr;
941            enum id = UUID(utfstr);
942            //nogc
943            Char[36] str;
944            id.toString(str[]);
945            assert(str == s);
946        }
947
948        @safe unittest
949        {
950            auto u1 = UUID(cast(ubyte[16])[138, 179, 6, 14, 44, 186, 79,
951                35, 183, 76, 181, 45, 179, 189, 251, 70]);
952            assert(u1.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
953            u1 = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
954            assert(u1.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
955
956            char[] buf;
957            void sink(scope const(char)[] data)
958            {
959                buf ~= data;
960            }
961            u1.toString(&sink);
962            assert(buf == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
963        }
964}
965
966///
967@safe unittest
968{
969    UUID id;
970    assert(id.empty);
971
972    id = randomUUID;
973    assert(!id.empty);
974
975    id = UUID(cast(ubyte[16]) [138, 179, 6, 14, 44, 186, 79,
976        35, 183, 76, 181, 45, 179, 189, 251, 70]);
977    assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
978}
979
980/**
981 * This function generates a name based (Version 3) UUID from a namespace UUID and a name.
982 * If no namespace UUID was passed, the empty UUID `UUID.init` is used.
983 *
984 * Note:
985 * The default namespaces ($(LREF dnsNamespace), ...) defined by
986 * this module should be used when appropriate.
987 *
988 * RFC 4122 recommends to use Version 5 UUIDs (SHA-1) instead of Version 3
989 * UUIDs (MD5) for new applications.
990 *
991 * CTFE:
992 * CTFE is not supported.
993 *
994 * Note:
995 * RFC 4122 isn't very clear on how UUIDs should be generated from names.
996 * It is possible that different implementations return different UUIDs
997 * for the same input, so be warned. The implementation for UTF-8 strings
998 * and byte arrays used by `std.uuid` is compatible with Boost's implementation.
999 * `std.uuid` guarantees that the same input to this function will generate
1000 * the same output at any time, on any system (this especially means endianness
1001 * doesn't matter).
1002 *
1003 * Note:
1004 * This function does not provide overloads for wstring and dstring, as
1005 * there's no clear answer on how that should be implemented. It could be
1006 * argued, that string, wstring and dstring input should have the same output,
1007 * but that wouldn't be compatible with Boost, which generates different output
1008 * for strings and wstrings. It's always possible to pass wstrings and dstrings
1009 * by using the ubyte[] function overload (but be aware of endianness issues!).
1010 */
1011@safe pure nothrow @nogc UUID md5UUID(const(char[]) name, const UUID namespace = UUID.init)
1012{
1013    return md5UUID(cast(const(ubyte[]))name, namespace);
1014}
1015
1016/// ditto
1017@safe pure nothrow @nogc UUID md5UUID(const(ubyte[]) data, const UUID namespace = UUID.init)
1018{
1019    import std.digest.md : MD5;
1020
1021    MD5 hash;
1022    hash.start();
1023
1024    /*
1025     * NOTE: RFC 4122 says namespace should be converted to big-endian.
1026     * We always keep the UUID data in big-endian representation, so
1027     * that's fine
1028     */
1029    hash.put(namespace.data[]);
1030    hash.put(data[]);
1031
1032    UUID u;
1033    u.data = hash.finish();
1034
1035    //set variant
1036    //must be 0b10xxxxxx
1037    u.data[8] &= 0b10111111;
1038    u.data[8] |= 0b10000000;
1039
1040    //set version
1041    //must be 0b0011xxxx
1042    u.data[6] &= 0b00111111;
1043    u.data[6] |= 0b00110000;
1044
1045    return u;
1046}
1047
1048///
1049@safe unittest
1050{
1051    //Use default UUID.init namespace
1052    auto simpleID = md5UUID("test.uuid.any.string");
1053
1054    //use a name-based id as namespace
1055    auto namespace = md5UUID("my.app");
1056    auto id = md5UUID("some-description", namespace);
1057}
1058
1059@safe pure unittest
1060{
1061    auto simpleID = md5UUID("test.uuid.any.string");
1062    assert(simpleID.data == cast(ubyte[16])[126, 206, 86, 72, 29, 233, 62, 213, 178, 139, 198, 136,
1063        188, 135, 153, 123]);
1064    auto namespace = md5UUID("my.app");
1065    auto id = md5UUID("some-description", namespace);
1066    assert(id.data == cast(ubyte[16])[166, 138, 167, 79, 48, 219, 55, 166, 170, 103, 39, 73, 216,
1067        150, 144, 164]);
1068
1069    auto constTest = md5UUID(cast(const(char)[])"test");
1070    constTest = md5UUID(cast(const(char[]))"test");
1071
1072    char[] mutable = "test".dup;
1073    id = md5UUID(mutable, namespace);
1074
1075    const(ubyte)[] data = cast(ubyte[])[0,1,2,244,165,222];
1076    id = md5UUID(data);
1077    assert(id.data == cast(ubyte[16])[16, 50, 29, 247, 243, 185, 61, 178, 157, 100, 253, 236, 73,
1078        76, 51, 47]);
1079
1080    assert(id.variant == UUID.Variant.rfc4122);
1081    assert(id.uuidVersion == UUID.Version.nameBasedMD5);
1082
1083    auto correct = UUID("3d813cbb-47fb-32ba-91df-831e1593ac29");
1084
1085    auto u = md5UUID("www.widgets.com", dnsNamespace);
1086    //enum ctfeId = md5UUID("www.widgets.com", dnsNamespace);
1087    //assert(ctfeId == u);
1088    assert(u == correct);
1089    assert(u.variant == UUID.Variant.rfc4122);
1090    assert(u.uuidVersion == UUID.Version.nameBasedMD5);
1091}
1092
1093 /**
1094 * This function generates a name based (Version 5) UUID from a namespace
1095 * UUID and a name.
1096 * If no namespace UUID was passed, the empty UUID `UUID.init` is used.
1097 *
1098 * Note:
1099 * The default namespaces ($(LREF dnsNamespace), ...) defined by
1100 * this module should be used when appropriate.
1101 *
1102 * CTFE:
1103 * CTFE is not supported.
1104 *
1105 * Note:
1106 * RFC 4122 isn't very clear on how UUIDs should be generated from names.
1107 * It is possible that different implementations return different UUIDs
1108 * for the same input, so be warned. The implementation for UTF-8 strings
1109 * and byte arrays used by `std.uuid` is compatible with Boost's implementation.
1110 * `std.uuid` guarantees that the same input to this function will generate
1111 * the same output at any time, on any system (this especially means endianness
1112 * doesn't matter).
1113 *
1114 * Note:
1115 * This function does not provide overloads for wstring and dstring, as
1116 * there's no clear answer on how that should be implemented. It could be
1117 * argued, that string, wstring and dstring input should have the same output,
1118 * but that wouldn't be compatible with Boost, which generates different output
1119 * for strings and wstrings. It's always possible to pass wstrings and dstrings
1120 * by using the ubyte[] function overload (but be aware of endianness issues!).
1121 */
1122@safe pure nothrow @nogc UUID sha1UUID(scope const(char)[] name, scope const UUID namespace = UUID.init)
1123{
1124    return sha1UUID(cast(const(ubyte[]))name, namespace);
1125}
1126
1127/// ditto
1128@safe pure nothrow @nogc UUID sha1UUID(scope const(ubyte)[] data, scope const UUID namespace = UUID.init)
1129{
1130    import std.digest.sha : SHA1;
1131
1132    SHA1 sha;
1133    sha.start();
1134
1135    /*
1136     * NOTE: RFC 4122 says namespace should be converted to big-endian.
1137     * We always keep the UUID data in big-endian representation, so
1138     * that's fine
1139     */
1140    sha.put(namespace.data[]);
1141    sha.put(data[]);
1142
1143    auto hash = sha.finish();
1144    auto u = UUID();
1145    u.data[] = hash[0 .. 16];
1146
1147    //set variant
1148    //must be 0b10xxxxxx
1149    u.data[8] &= 0b10111111;
1150    u.data[8] |= 0b10000000;
1151
1152    //set version
1153    //must be 0b0101xxxx
1154    u.data[6] &= 0b01011111;
1155    u.data[6] |= 0b01010000;
1156
1157    return u;
1158}
1159
1160///
1161@safe unittest
1162{
1163    //Use default UUID.init namespace
1164    auto simpleID = sha1UUID("test.uuid.any.string");
1165
1166    //use a name-based id as namespace
1167    auto namespace = sha1UUID("my.app");
1168    auto id = sha1UUID("some-description", namespace);
1169}
1170
1171@safe pure unittest
1172{
1173    auto simpleID = sha1UUID("test.uuid.any.string");
1174    assert(simpleID.data == cast(ubyte[16])[16, 209, 239, 61, 99, 12, 94, 70, 159, 79, 255, 250,
1175        131, 79, 14, 147]);
1176    auto namespace = sha1UUID("my.app");
1177    auto id = sha1UUID("some-description", namespace);
1178    assert(id.data == cast(ubyte[16])[225, 94, 195, 219, 126, 75, 83, 71, 157, 52, 247, 43, 238, 248,
1179        148, 46]);
1180
1181    auto constTest = sha1UUID(cast(const(char)[])"test");
1182    constTest = sha1UUID(cast(const(char[]))"test");
1183
1184    char[] mutable = "test".dup;
1185    id = sha1UUID(mutable, namespace);
1186
1187    const(ubyte)[] data = cast(ubyte[])[0,1,2,244,165,222];
1188    id = sha1UUID(data);
1189    assert(id.data == cast(ubyte[16])[60, 65, 92, 240, 96, 46, 95, 238, 149, 100, 12, 64, 199, 194,
1190        243, 12]);
1191
1192    auto correct = UUID("21f7f8de-8051-5b89-8680-0195ef798b6a");
1193
1194    auto u = sha1UUID("www.widgets.com", dnsNamespace);
1195    assert(u == correct);
1196    assert(u.variant == UUID.Variant.rfc4122);
1197    assert(u.uuidVersion == UUID.Version.nameBasedSHA1);
1198}
1199
1200/**
1201 * This function generates a random number based UUID from a random
1202 * number generator.
1203 *
1204 * This function is not supported at compile time.
1205 *
1206 * Params:
1207 *      randomGen = uniform RNG
1208 * See_Also: $(REF isUniformRNG, std,random)
1209 */
1210@safe UUID randomUUID()
1211{
1212    import std.random : rndGen;
1213    // A PRNG with fewer than `n` bytes of state cannot produce
1214    // every distinct `n` byte sequence.
1215    static if (typeof(rndGen).sizeof >= UUID.sizeof)
1216    {
1217        return randomUUID(rndGen);
1218    }
1219    else
1220    {
1221        import std.random : unpredictableSeed, Xorshift192;
1222        static assert(Xorshift192.sizeof >= UUID.sizeof);
1223        static Xorshift192 rng;
1224        static bool initialized;
1225        if (!initialized)
1226        {
1227            rng.seed(unpredictableSeed);
1228            initialized = true;
1229        }
1230        return randomUUID(rng);
1231    }
1232}
1233
1234/// ditto
1235UUID randomUUID(RNG)(ref RNG randomGen)
1236if (isInputRange!RNG && isIntegral!(ElementType!RNG))
1237{
1238    import std.random : isUniformRNG;
1239    static assert(isUniformRNG!RNG, "randomGen must be a uniform RNG");
1240
1241    alias E = ElementEncodingType!RNG;
1242    enum size_t elemSize = E.sizeof;
1243    static assert(elemSize <= 16);
1244    static assert(16 % elemSize == 0);
1245
1246    UUID u;
1247    foreach (ref E e ; u.asArrayOf!E())
1248    {
1249        e = randomGen.front;
1250        randomGen.popFront();
1251    }
1252
1253    //set variant
1254    //must be 0b10xxxxxx
1255    u.data[8] &= 0b10111111;
1256    u.data[8] |= 0b10000000;
1257
1258    //set version
1259    //must be 0b0100xxxx
1260    u.data[6] &= 0b01001111;
1261    u.data[6] |= 0b01000000;
1262
1263    return u;
1264}
1265
1266///
1267@safe unittest
1268{
1269    import std.random : Xorshift192, unpredictableSeed;
1270
1271    //simple call
1272    auto uuid = randomUUID();
1273
1274    //provide a custom RNG. Must be seeded manually.
1275    Xorshift192 gen;
1276
1277    gen.seed(unpredictableSeed);
1278    auto uuid3 = randomUUID(gen);
1279}
1280
1281@safe unittest
1282{
1283    import std.random : Xorshift192, unpredictableSeed;
1284    //simple call
1285    auto uuid = randomUUID();
1286
1287    //provide a custom RNG. Must be seeded manually.
1288    Xorshift192 gen;
1289    gen.seed(unpredictableSeed);
1290    auto uuid3 = randomUUID(gen);
1291
1292    auto u1 = randomUUID();
1293    auto u2 = randomUUID();
1294    assert(u1 != u2);
1295    assert(u1.variant == UUID.Variant.rfc4122);
1296    assert(u1.uuidVersion == UUID.Version.randomNumberBased);
1297}
1298
1299/**
1300 * This is a less strict parser compared to the parser used in the
1301 * UUID constructor. It enforces the following rules:
1302 *
1303 * $(UL
1304 *   $(LI hex numbers are always two hexdigits([0-9a-fA-F]))
1305 *   $(LI there must be exactly 16 such pairs in the input, not less, not more)
1306 *   $(LI there can be exactly one dash between two hex-pairs, but not more)
1307 *   $(LI there can be multiple characters enclosing the 16 hex pairs,
1308 *     as long as these characters do not contain [0-9a-fA-F])
1309 * )
1310 *
1311 * Note:
1312 * Like most parsers, it consumes its argument. This means:
1313 * -------------------------
1314 * string s = "8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46";
1315 * parseUUID(s);
1316 * assert(s == "");
1317 * -------------------------
1318 *
1319 * Throws:
1320 * $(LREF UUIDParsingException) if the input is invalid
1321 *
1322 * CTFE:
1323 * This function is supported in CTFE code. Note that error messages
1324 * caused by a malformed UUID parsed at compile time can be cryptic,
1325 * but errors are detected and reported at compile time.
1326 */
1327UUID parseUUID(T)(T uuidString)
1328if (isSomeString!T)
1329{
1330    return parseUUID(uuidString);
1331}
1332
1333///ditto
1334UUID parseUUID(Range)(ref Range uuidRange)
1335if (isInputRange!Range && isSomeChar!(ElementType!Range))
1336{
1337    import std.ascii : isHexDigit;
1338    import std.conv : ConvException, parse;
1339
1340    static if (isForwardRange!Range)
1341        auto errorCopy = uuidRange.save;
1342
1343    void parserError()(size_t pos, UUIDParsingException.Reason reason, string message, Throwable next = null,
1344        string file = __FILE__, size_t line = __LINE__)
1345    {
1346        static if (isForwardRange!Range)
1347        {
1348            import std.conv : to;
1349            static if (isInfinite!Range)
1350            {
1351                throw new UUIDParsingException(to!string(take(errorCopy, pos)), pos, reason, message,
1352                    next, file, line);
1353            }
1354            else
1355            {
1356                throw new UUIDParsingException(to!string(errorCopy), pos, reason, message, next, file,
1357                    line);
1358            }
1359        }
1360        else
1361        {
1362            throw new UUIDParsingException("", pos, reason, message, next, file, line);
1363        }
1364    }
1365
1366    static if (hasLength!Range)
1367    {
1368        import std.conv : to;
1369        if (uuidRange.length < 32)
1370        {
1371            throw new UUIDParsingException(to!string(uuidRange), 0, UUIDParsingException.Reason.tooLittle,
1372                "Insufficient Input");
1373        }
1374    }
1375
1376    UUID result;
1377    size_t consumed;
1378    size_t element = 0;
1379
1380    //skip garbage
1381    size_t skip()()
1382    {
1383        size_t skipped;
1384        while (!uuidRange.empty && !isHexDigit(uuidRange.front))
1385        {
1386            skipped++;
1387            uuidRange.popFront();
1388        }
1389        return skipped;
1390    }
1391
1392    consumed += skip();
1393
1394    if (uuidRange.empty)
1395        parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input");
1396
1397    bool dashAllowed = false;
1398
1399    parseLoop: while (!uuidRange.empty)
1400    {
1401        immutable character = uuidRange.front;
1402
1403        if (character == '-')
1404        {
1405            if (!dashAllowed)
1406                parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected '-'");
1407            else
1408                dashAllowed = false;
1409
1410            consumed++;
1411        }
1412        else if (!isHexDigit(character))
1413        {
1414            parserError(consumed, UUIDParsingException.Reason.invalidChar,
1415                "Unexpected character (wanted a hexDigit)");
1416        }
1417        else
1418        {
1419            try
1420            {
1421                consumed += 2;
1422                static if (isSomeString!Range)
1423                {
1424                    if (uuidRange.length < 2)
1425                    {
1426                        parserError(consumed, UUIDParsingException.Reason.tooLittle,
1427                            "Insufficient Input");
1428                    }
1429                    auto part = uuidRange[0 .. 2];
1430                    result.data[element++] = parse!ubyte(part, 16);
1431                    uuidRange.popFront();
1432                }
1433                else
1434                {
1435                    dchar[2] copyBuf;
1436                    copyBuf[0] = character;
1437                    uuidRange.popFront();
1438                    if (uuidRange.empty)
1439                    {
1440                        parserError(consumed, UUIDParsingException.Reason.tooLittle,
1441                            "Insufficient Input");
1442                    }
1443                    copyBuf[1] = uuidRange.front;
1444                    auto part = copyBuf[];
1445                    result.data[element++] = parse!ubyte(part, 16);
1446                }
1447
1448                if (element == 16)
1449                {
1450                    uuidRange.popFront();
1451                    break parseLoop;
1452                }
1453
1454                dashAllowed = true;
1455            }
1456            catch (ConvException e)
1457            {
1458                parserError(consumed, UUIDParsingException.Reason.invalidChar,
1459                    "Couldn't parse ubyte", e);
1460            }
1461        }
1462        uuidRange.popFront();
1463    }
1464    assert(element <= 16);
1465
1466    if (element < 16)
1467        parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input");
1468
1469    consumed += skip();
1470    if (!uuidRange.empty)
1471        parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected character");
1472
1473    return result;
1474}
1475
1476///
1477@safe unittest
1478{
1479    auto id = parseUUID("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46");
1480    //no dashes
1481    id = parseUUID("8ab3060e2cba4f23b74cb52db3bdfb46");
1482    //dashes at different positions
1483    id = parseUUID("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46");
1484    //leading / trailing characters
1485    id = parseUUID("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}");
1486    //unicode
1487    id = parseUUID("��8ab3060e2cba4f23b74cb52db3bdfb46��");
1488    //multiple trailing/leading characters
1489    id = parseUUID("///8ab3060e2cba4f23b74cb52db3bdfb46||");
1490
1491    //Can also be used in CTFE, for example as UUID literals:
1492    enum ctfeID = parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
1493    //here parsing is done at compile time, no runtime overhead!
1494}
1495
1496@safe pure unittest
1497{
1498    import std.conv : to;
1499    import std.exception;
1500    import std.meta;
1501
1502    struct TestRange(bool forward)
1503    {
1504        dstring input;
1505
1506        @property dchar front()
1507        {
1508            return input.front;
1509        }
1510
1511        void popFront()
1512        {
1513            input.popFront();
1514        }
1515
1516        @property bool empty()
1517        {
1518            return input.empty;
1519        }
1520
1521        static if (forward)
1522        {
1523            @property TestRange!true save()
1524            {
1525                return this;
1526            }
1527        }
1528    }
1529    alias TestInputRange = TestRange!false;
1530    alias TestForwardRange = TestRange!true;
1531
1532    assert(isInputRange!TestInputRange);
1533    assert(is(ElementType!TestInputRange == dchar));
1534    assert(isInputRange!TestForwardRange);
1535    assert(isForwardRange!TestForwardRange);
1536    assert(is(ElementType!TestForwardRange == dchar));
1537
1538    //Helper function for unittests - Need to pass ranges by ref
1539    UUID parseHelper(T)(string input)
1540    {
1541        static if (is(T == TestInputRange) || is(T == TestForwardRange))
1542        {
1543            T range = T(to!dstring(input));
1544            return parseUUID(range);
1545        }
1546        else
1547            return parseUUID(to!T(input));
1548    }
1549
1550    static foreach (S; AliasSeq!(char[], const(char)[], immutable(char)[],
1551                          wchar[], const(wchar)[], immutable(wchar)[],
1552                          dchar[], const(dchar)[], immutable(dchar)[],
1553                          immutable(char[]), immutable(wchar[]), immutable(dchar[]),
1554                          TestForwardRange, TestInputRange))
1555    {{
1556        //Verify examples.
1557        auto id = parseHelper!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46");
1558        //no dashes
1559        id = parseHelper!S("8ab3060e2cba4f23b74cb52db3bdfb46");
1560        //dashes at different positions
1561        id = parseHelper!S("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46");
1562        //leading / trailing characters
1563        id = parseHelper!S("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}");
1564        //unicode
1565        id = parseHelper!S("��8ab3060e2cba4f23b74cb52db3bdfb46��");
1566        //multiple trailing/leading characters
1567        id = parseHelper!S("///8ab3060e2cba4f23b74cb52db3bdfb46||");
1568        enum ctfeId = parseHelper!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
1569        assert(parseHelper!S("8AB3060E-2cba-4f23-b74c-b52db3bdfb46") == ctfeId);
1570
1571        //Test valid, working cases
1572        assert(parseHelper!S("00000000-0000-0000-0000-000000000000").empty);
1573        assert(parseHelper!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46").data
1574            == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]);
1575
1576        assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1577            == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1578
1579        //wstring / dstring
1580        assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1581            == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1582        assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1583            == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1584
1585        //Test too short UUIDS
1586        auto except = collectException!UUIDParsingException(
1587            parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886"));
1588        assert(except && except.reason == UUIDParsingException.Reason.tooLittle);
1589
1590        //Test too long UUIDS
1591        except = collectException!UUIDParsingException(
1592            parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886aa"));
1593        assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1594
1595        //Test too long UUIDS 2
1596        except = collectException!UUIDParsingException(
1597            parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a-aa"));
1598        assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1599
1600        //Test dashes
1601        assert(parseHelper!S("8ab3060e2cba-4f23-b74c-b52db3bdfb46")
1602            == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1603        assert(parseHelper!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46")
1604            == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1605        assert(parseHelper!S("8ab3060e2cba4f23b74cb52db3bdfb46")
1606            == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1607
1608        except = collectException!UUIDParsingException(
1609            parseHelper!S("8-ab3060e2cba-4f23-b74c-b52db3bdfb46"));
1610        assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1611
1612        //Test leading/trailing characters
1613        assert(parseHelper!S("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}")
1614            == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1615        assert(parseHelper!S("{8ab3060e2cba4f23b74cb52db3bdfb46}")
1616            == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1617
1618        //Boost test
1619        auto u_increasing = UUID(cast(ubyte[16])[0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
1620            0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
1621        assert(parseHelper!S("0123456789abcdef0123456789ABCDEF") == UUID(cast(ubyte[16])[0x01,
1622            0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]));
1623
1624        //unicode
1625        assert(parseHelper!S("��8ab3060e2cba4f23b74cb52db3bdfb46��")
1626            == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1627
1628        //multiple trailing/leading characters
1629        assert(parseHelper!S("///8ab3060e2cba4f23b74cb52db3bdfb46||")
1630            == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1631    }}
1632
1633    // Test input range with non-dchar element type.
1634    {
1635        import std.utf : byCodeUnit;
1636        auto range = "8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46".byCodeUnit;
1637        assert(parseUUID(range).data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]);
1638    }
1639}
1640
1641/**
1642 * Default namespace from RFC 4122
1643 *
1644 * Name string is a fully-qualified domain name
1645 */
1646enum dnsNamespace = UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
1647
1648/**
1649 * Default namespace from RFC 4122
1650 *
1651 * Name string is a URL
1652 */
1653enum urlNamespace = UUID("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
1654
1655/**
1656 * Default namespace from RFC 4122
1657 *
1658 * Name string is an ISO OID
1659 */
1660enum oidNamespace = UUID("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
1661
1662/**
1663 * Default namespace from RFC 4122
1664 *
1665 * Name string is an X.500 DN (in DER or a text output format)
1666 */
1667enum x500Namespace = UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8");
1668
1669/**
1670 * Regex string to extract UUIDs from text.
1671 */
1672enum uuidRegex = "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}"~
1673    "-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}";
1674
1675///
1676@safe unittest
1677{
1678    import std.algorithm;
1679    import std.regex;
1680
1681    string test = "Lorem ipsum dolor sit amet, consetetur "~
1682    "6ba7b814-9dad-11d1-80b4-00c04fd430c8 sadipscing \n"~
1683    "elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore \r\n"~
1684    "magna aliquyam erat, sed diam voluptua. "~
1685    "8ab3060e-2cba-4f23-b74c-b52db3bdfb46 At vero eos et accusam et "~
1686    "justo duo dolores et ea rebum.";
1687
1688    auto r = regex(uuidRegex, "g");
1689    UUID[] found;
1690    foreach (c; match(test, r))
1691    {
1692        found ~= UUID(c.hit);
1693    }
1694    assert(found == [
1695        UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8"),
1696        UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"),
1697    ]);
1698}
1699
1700/**
1701 * This exception is thrown if an error occurs when parsing a UUID
1702 * from a string.
1703 */
1704public class UUIDParsingException : Exception
1705{
1706    /**
1707     * The reason why parsing the UUID string failed (if known)
1708     */
1709    enum Reason
1710    {
1711        unknown, ///
1712        tooLittle, ///The passed in input was correct, but more input was expected.
1713        tooMuch, ///The input data is too long (There's no guarantee the first part of the data is valid)
1714        invalidChar, ///Encountered an invalid character
1715
1716    }
1717    ///ditto
1718    Reason reason;
1719    ///The original input string which should have been parsed.
1720    string input;
1721    ///The position in the input string where the error occurred.
1722    size_t position;
1723
1724    private this(string input, size_t pos, Reason why = Reason.unknown, string msg = "",
1725        Throwable next = null, string file = __FILE__, size_t line = __LINE__) pure @trusted
1726    {
1727        import std.array : replace;
1728        import std.format : format;
1729        this.input = input;
1730        this.position = pos;
1731        this.reason = why;
1732        string message = format("An error occured in the UUID parser: %s\n" ~
1733          " * Input:\t'%s'\n * Position:\t%s", msg, replace(replace(input,
1734          "\r", "\\r"), "\n", "\\n"), pos);
1735        super(message, file, line, next);
1736    }
1737}
1738
1739///
1740@safe unittest
1741{
1742    import std.exception : collectException;
1743
1744    const inputUUID = "this-is-an-invalid-uuid";
1745    auto ex = collectException!UUIDParsingException(UUID(inputUUID));
1746    assert(ex !is null); // check that exception was thrown
1747    assert(ex.input == inputUUID);
1748    assert(ex.position == 0);
1749    assert(ex.reason == UUIDParsingException.Reason.tooLittle);
1750}
1751
1752@safe unittest
1753{
1754    auto ex = new UUIDParsingException("foo", 10, UUIDParsingException.Reason.tooMuch);
1755    assert(ex.input == "foo");
1756    assert(ex.position == 10);
1757    assert(ex.reason == UUIDParsingException.Reason.tooMuch);
1758}
1759