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.
9 $(SCRIPT inhibitQuickIndex = 1;)
13 $(TR $(TH Category) $(TH Functions)
15 $(TR $(TDNW Parsing UUIDs)
16 $(TD $(MYREF parseUUID)
18 $(MYREF UUIDParsingException)
22 $(TR $(TDNW Generating UUIDs)
23 $(TD $(MYREF sha1UUID)
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)
39 $(TR $(TDNW UUID namespaces)
40 $(TD $(MYREF dnsNamespace)
43 $(MYREF x500Namespace)
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).
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.
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).
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.
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.
79 * $(LINK2 http://www.ietf.org/rfc/rfc4122.txt, RFC 4122)
82 * $(LINK http://en.wikipedia.org/wiki/Universally_unique_identifier)
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)
90 * MYREF2 = <a href="#$2">$(TT $1)</a>
91 * MYREF3 = <a href="#$2">$(D $1)</a>
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)
107 ids
~= md5UUID("test.name.123");
108 ids
~= sha1UUID("test.name.123");
112 assert(entry
.variant
== UUID
.Variant
.rfc4122
);
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]);
122 import std
.range
.primitives
;
130 import std
.meta
: AliasSeq
, allSatisfy
;
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);
136 @safe pure nothrow @nogc Char
toChar(Char
)(size_t i
) const
139 return cast(Char
)('0' + i
);
141 return cast(Char
)('a' + (i
-10));
144 @safe pure nothrow unittest
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");
150 // Reinterpret the UUID as an array of some other primitive.
151 @trusted ref T
[16 / T
.sizeof
] asArrayOf(T
)() return
154 return *cast(typeof(return)*)&data
;
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.
164 * Note: Do not confuse this with $(REF _Variant, std,_variant).
168 ncs
, /// NCS backward compatibility
169 rfc4122
, /// Defined in RFC 4122 document
170 microsoft
, /// Microsoft Corporation backward compatibility
171 future
///Reserved for future use
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.
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.
191 ///Version 3 (Name based + MD5)
193 ///Version 4 (Random)
194 randomNumberBased
= 4,
195 ///Version 5 (Name based + SHA-1)
202 * It is sometimes useful to get or set the 16 bytes of a UUID
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.
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 * -----------------------------------------------
220 private ulong[2] ulongs
;
221 static if (size_t
.sizeof
== 4)
222 private uint[4] uints
;
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.
235 tmp
.data
= cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,12,
237 assert(tmp
.data
== cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,
240 assert(tmp
.data
== cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11,
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,
249 * Construct a UUID struct from the 16 byte representation
252 @safe pure nothrow @nogc this(ref in ubyte[16] uuidData
)
257 @safe pure nothrow @nogc this(in ubyte[16] uuidData
)
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
);
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.
277 @safe pure this(T
...)(T uuidData
)
278 if (uuidData
.length
== 16 && allSatisfy
!(isIntegral
, T
))
280 import std
.conv
: to
;
282 foreach (idx
, it
; uuidData
)
284 this.data
[idx
] = to
!ubyte(it
);
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,
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,
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
);
306 assert(!__traits(compiles
, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14))));
309 assert(!__traits(compiles
, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1))));
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
318 * $(LREF UUIDParsingException) if the input is invalid
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
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.
332 * For a less strict parser, see $(LREF parseUUID)
334 this(T
)(in T
[] uuid
) if (isSomeChar
!(Unqual
!T
))
336 import std
.conv
: to
, parse
;
337 if (uuid
.length
< 36)
339 throw new UUIDParsingException(to
!string(uuid
), 0,
340 UUIDParsingException
.Reason
.tooLittle
, "Insufficient Input");
342 if (uuid
.length
> 36)
344 throw new UUIDParsingException(to
!string(uuid
), 35, UUIDParsingException
.Reason
.tooMuch
,
345 "Input is too long, need exactly 36 characters");
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 '-'");
353 ubyte[16] data2
; //ctfe bug
356 foreach (i
, p
; byteSeq
)
358 enum uint s
= 'a'-10-'0';
362 if (h
< '0') goto Lerr
;
363 if (l
< '0') goto Lerr
;
366 h |
= 0x20; //poorman's tolower
367 if (h
< 'a') goto Lerr
;
368 if (h
> 'f') goto Lerr
;
373 l |
= 0x20; //poorman's tolower
374 if (l
< 'a') goto Lerr
;
375 if (l
> 'f') goto Lerr
;
381 data2
[i
] = cast(ubyte)((h
<< 4) ^ l
);
386 Lerr
: throw new UUIDParsingException(to
!string(uuid
), pos
,
387 UUIDParsingException
.Reason
.invalidChar
, "Couldn't parse ubyte");
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");
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!
405 import std
.conv
: to
;
406 import std
.exception
;
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[])))
414 //Test valid, working cases
415 assert(UUID(to
!S("00000000-0000-0000-0000-000000000000")).empty
);
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");
422 enum UUID ctfe
= UUID(to
!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
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]);
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
);
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
);
439 except
= collectException
!UUIDParsingException(
440 UUID(to
!S("8ab3060e2cba-4f23-b74c-b52db3bdfb-46")));
441 assert(except
&& except
.reason
== UUIDParsingException
.Reason
.invalidChar
);
444 except
= collectException
!UUIDParsingException(
445 UUID(to
!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46")));
446 assert(except
&& except
.reason
== UUIDParsingException
.Reason
.invalidChar
);
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
);
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]));
462 * Returns true if and only if the UUID is equal
463 * to {00000000-0000-0000-0000-000000000000}
465 @trusted pure nothrow @nogc @property bool empty() const
468 return data
== (ubyte[16]).init
;
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;
476 static assert(false, "nonsense, it's not 32 or 64 bit");
484 id
= UUID("00000000-0000-0000-0000-000000000001");
490 ubyte[16] getData(size_t i
)
497 for (size_t i
= 0; i
< 16; i
++)
499 assert(!UUID(getData(i
)).empty
);
502 enum ctfeEmpty
= UUID
.init
.empty
;
507 for (size_t i
= 0; i
< 16; i
++)
509 auto ctfeEmpty2
= UUID(getData(i
)).empty
;
514 enum res
= ctfeTest();
518 * RFC 4122 defines different internal data layouts for UUIDs.
519 * Returns the format used by this UUID.
521 * Note: Do not confuse this with $(REF _Variant, std,_variant).
522 * The type of this property is $(MYREF3 std.uuid.UUID.Variant, _Variant).
525 * $(MYREF3 UUID.Variant, Variant)
527 @safe pure nothrow @nogc @property Variant
variant() const
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
533 if ((octet7
& 0x80) == 0x00) //0b0xxxxxxx
535 else if ((octet7
& 0xC0) == 0x80) //0b10xxxxxx
536 return Variant
.rfc4122
;
537 else if ((octet7
& 0xE0) == 0xC0) //0b110xxxxx
538 return Variant
.microsoft
;
541 //assert((octet7 & 0xE0) == 0xE0, "Unknown UUID variant!") //0b111xxxx
542 return Variant
.future
;
549 assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").variant
550 == UUID
.Variant
.rfc4122
);
552 @system pure unittest
554 // @system due to Variant
555 Variant
[ubyte] tests
= cast(Variant
[ubyte])[0x00 : 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
)
575 assert(u
.variant
== value
);
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.
586 * $(MYREF3 UUID.Version, Version)
588 @safe pure nothrow @nogc @property Version
uuidVersion() const
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
;
604 return Version
.unknown
;
610 assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").uuidVersion
611 == UUID
.Version
.randomNumberBased
);
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
)
637 assert(u
.uuidVersion
== value
);
642 * Swap the data of this UUID with the data of rhs.
644 @safe pure nothrow @nogc void swap(ref UUID rhs
)
646 immutable bck
= data
;
654 immutable ubyte[16] data
= [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
656 UUID u2
= UUID(data
);
659 assert(u1
== UUID(data
));
660 assert(u2
== UUID
.init
);
664 * All of the standard numeric operators are defined for
667 @safe pure nothrow @nogc bool opEquals(in UUID s
) const
669 return ulongs
[0] == s
.ulongs
[0] && ulongs
[1] == s
.ulongs
[1];
676 assert(UUID("00000000-0000-0000-0000-000000000000") == UUID
.init
);
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];
683 assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3);
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")];
696 @safe pure nothrow @nogc bool opEquals(ref in UUID s
) const
698 return ulongs
[0] == s
.ulongs
[0] && ulongs
[1] == s
.ulongs
[1];
704 @safe pure nothrow @nogc int opCmp(in UUID s
) const
706 import std
.algorithm
.comparison
: cmp;
707 return cmp(this.data
[], s
.data
[]);
713 @safe pure nothrow @nogc int opCmp(ref in UUID s
) const
715 import std
.algorithm
.comparison
: cmp;
716 return cmp(this.data
[], s
.data
[]);
722 @safe pure nothrow @nogc UUID
opAssign(in UUID s
)
724 ulongs
[0] = s
.ulongs
[0];
725 ulongs
[1] = s
.ulongs
[1];
732 @safe pure nothrow @nogc UUID
opAssign(ref in UUID s
)
734 ulongs
[0] = s
.ulongs
[0];
735 ulongs
[1] = s
.ulongs
[1];
743 @safe pure nothrow @nogc size_t
toHash() const
745 static if (size_t
.sizeof
== 4)
747 enum uint m
= 0x5bd1e995;
787 enum ulong m
= 0xc6a4a7935bd1e995UL
;
788 enum ulong n
= m
* 16;
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];
818 assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3);
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")];
827 ids
= [UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"),
828 UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"),
829 UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")];
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]);
858 assert(u1
.toHash() != u2
.toHash());
859 assert(u2
.toHash() != u3
.toHash());
860 assert(u3
.toHash() != u1
.toHash());
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"
868 * sink = OutputRange or writeable array at least 36 entries long
870 void toString(Writer
)(scope Writer sink
) const
872 char[36] result
= void;
873 foreach (pos
; skipSeq
)
875 foreach (i
, pos
; byteSeq
)
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
);
883 foreach (i
, c
; result
)
885 static if (__traits(compiles
, put(sink
, c
)))
888 sink
[i
] = cast(typeof(sink
[i
]))c
;
893 * Return the UUID as a string in the canonical form.
895 @trusted pure nothrow string
toString() const
897 import std
.exception
: assumeUnique
;
898 auto result
= new char[36];
900 return result
.assumeUnique
;
906 immutable str = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
908 assert(id
.toString() == str);
911 @safe pure nothrow @nogc unittest
913 import std
.meta
: AliasSeq
;
914 foreach (Char
; AliasSeq
!(char, wchar, dchar))
916 alias String
= immutable(Char
)[];
918 enum String s
= "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
920 static if (is(Char
== char))
922 enum p
= id
.toString();
923 static assert(s
== p
);
932 @system pure nothrow @nogc unittest
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
);
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");
955 void sink(const(char)[] data
)
960 assert(buf
== "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
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.
970 * The default namespaces ($(LREF dnsNamespace), ...) defined by
971 * this module should be used when appropriate.
973 * RFC 4122 recommends to use Version 5 UUIDs (SHA-1) instead of Version 3
974 * UUIDs (MD5) for new applications.
977 * CTFE is not supported.
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
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!).
996 @safe pure nothrow @nogc UUID
md5UUID(const(char[]) name
, const UUID namespace
= UUID
.init
)
998 return md5UUID(cast(const(ubyte[]))name
, namespace
);
1002 @safe pure nothrow @nogc UUID
md5UUID(const(ubyte[]) data
, const UUID namespace
= UUID
.init
)
1004 import std
.digest
.md
: MD5
;
1010 * NOTE: RFC 4122 says namespace should be converted to big-endian.
1011 * We always keep the UUID data in big-endian representation, so
1014 hash
.put(namespace
.data
[]);
1018 u
.data
= hash
.finish();
1021 //must be 0b10xxxxxx
1022 u
.data
[8] &= 0b10111111;
1023 u
.data
[8] |
= 0b10000000;
1026 //must be 0b0011xxxx
1027 u
.data
[6] &= 0b00111111;
1028 u
.data
[6] |
= 0b00110000;
1036 //Use default UUID.init namespace
1037 auto simpleID
= md5UUID("test.uuid.any.string");
1039 //use a name-based id as namespace
1040 auto namespace
= md5UUID("my.app");
1041 auto id
= md5UUID("some-description", namespace
);
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,
1054 auto constTest
= md5UUID(cast(const(char)[])"test");
1055 constTest
= md5UUID(cast(const(char[]))"test");
1057 char[] mutable
= "test".dup
;
1058 id
= md5UUID(mutable
, namespace
);
1060 const(ubyte)[] data
= cast(ubyte[])[0,1,2,244,165,222];
1062 assert(id
.data
== cast(ubyte[16])[16, 50, 29, 247, 243, 185, 61, 178, 157, 100, 253, 236, 73,
1065 assert(id
.variant
== UUID
.Variant
.rfc4122
);
1066 assert(id
.uuidVersion
== UUID
.Version
.nameBasedMD5
);
1068 auto correct
= UUID("3d813cbb-47fb-32ba-91df-831e1593ac29");
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
);
1079 * This function generates a name based (Version 5) UUID from a namespace
1081 * If no namespace UUID was passed, the empty UUID $(D UUID.init) is used.
1084 * The default namespaces ($(LREF dnsNamespace), ...) defined by
1085 * this module should be used when appropriate.
1088 * CTFE is not supported.
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
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!).
1107 @safe pure nothrow @nogc UUID
sha1UUID(in char[] name
, const UUID namespace
= UUID
.init
)
1109 return sha1UUID(cast(const(ubyte[]))name
, namespace
);
1113 @safe pure nothrow @nogc UUID
sha1UUID(in ubyte[] data
, const UUID namespace
= UUID
.init
)
1115 import std
.digest
.sha
: SHA1
;
1121 * NOTE: RFC 4122 says namespace should be converted to big-endian.
1122 * We always keep the UUID data in big-endian representation, so
1125 sha
.put(namespace
.data
[]);
1128 auto hash
= sha
.finish();
1130 u
.data
[] = hash
[0 .. 16];
1133 //must be 0b10xxxxxx
1134 u
.data
[8] &= 0b10111111;
1135 u
.data
[8] |
= 0b10000000;
1138 //must be 0b0101xxxx
1139 u
.data
[6] &= 0b01011111;
1140 u
.data
[6] |
= 0b01010000;
1148 //Use default UUID.init namespace
1149 auto simpleID
= sha1UUID("test.uuid.any.string");
1151 //use a name-based id as namespace
1152 auto namespace
= sha1UUID("my.app");
1153 auto id
= sha1UUID("some-description", namespace
);
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,
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,
1166 auto constTest
= sha1UUID(cast(const(char)[])"test");
1167 constTest
= sha1UUID(cast(const(char[]))"test");
1169 char[] mutable
= "test".dup
;
1170 id
= sha1UUID(mutable
, namespace
);
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,
1177 auto correct
= UUID("21f7f8de-8051-5b89-8680-0195ef798b6a");
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
);
1186 * This function generates a random number based UUID from a random
1189 * This function is not supported at compile time.
1192 * randomGen = uniform RNG
1193 * See_Also: $(REF isUniformRNG, std,random)
1195 @safe UUID
randomUUID()
1197 import std
.random
: rndGen
;
1198 return randomUUID(rndGen
);
1202 UUID
randomUUID(RNG
)(ref RNG randomGen
)
1203 if (isInputRange
!RNG
&& isIntegral
!(ElementType
!RNG
))
1205 import std
.random
: isUniformRNG
;
1206 static assert(isUniformRNG
!RNG
, "randomGen must be a uniform RNG");
1208 alias E
= ElementEncodingType
!RNG
;
1209 enum size_t elemSize
= E
.sizeof
;
1210 static assert(elemSize
<= 16);
1211 static assert(16 % elemSize
== 0);
1214 foreach (ref E e
; u
.asArrayOf
!E())
1216 e
= randomGen
.front
;
1217 randomGen
.popFront();
1221 //must be 0b10xxxxxx
1222 u
.data
[8] &= 0b10111111;
1223 u
.data
[8] |
= 0b10000000;
1226 //must be 0b0100xxxx
1227 u
.data
[6] &= 0b01001111;
1228 u
.data
[6] |
= 0b01000000;
1236 import std
.random
: Xorshift192
, unpredictableSeed
;
1239 auto uuid
= randomUUID();
1241 //provide a custom RNG. Must be seeded manually.
1244 gen
.seed(unpredictableSeed
);
1245 auto uuid3
= randomUUID(gen
);
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.
1256 import std
.random
: rndGen
, Mt19937
;
1257 static assert(is(typeof(rndGen
) == Mt19937
));
1262 import std
.random
: Xorshift192
, unpredictableSeed
;
1264 auto uuid
= randomUUID();
1266 //provide a custom RNG. Must be seeded manually.
1268 gen
.seed(unpredictableSeed
);
1269 auto uuid3
= randomUUID(gen
);
1271 auto u1
= randomUUID();
1272 auto u2
= randomUUID();
1274 assert(u1
.variant
== UUID
.Variant
.rfc4122
);
1275 assert(u1
.uuidVersion
== UUID
.Version
.randomNumberBased
);
1279 * This is a less strict parser compared to the parser used in the
1280 * UUID constructor. It enforces the following rules:
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])
1291 * Like most parsers, it consumes its argument. This means:
1292 * -------------------------
1293 * string s = "8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46";
1296 * -------------------------
1299 * $(LREF UUIDParsingException) if the input is invalid
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.
1306 UUID
parseUUID(T
)(T uuidString
)
1309 return parseUUID(uuidString
);
1313 UUID
parseUUID(Range
)(ref Range uuidRange
)
1314 if (isInputRange
!Range
1315 && is(Unqual
!(ElementType
!Range
) == dchar))
1317 import std
.ascii
: isHexDigit
;
1318 import std
.conv
: ConvException
, parse
;
1320 static if (isForwardRange
!Range
)
1321 auto errorCopy
= uuidRange
.save
;
1323 void parserError()(size_t pos
, UUIDParsingException
.Reason reason
, string message
, Throwable next
= null,
1324 string file
= __FILE__
, size_t line
= __LINE__
)
1326 static if (isForwardRange
!Range
)
1328 import std
.conv
: to
;
1329 static if (isInfinite
!Range
)
1331 throw new UUIDParsingException(to
!string(take(errorCopy
, pos
)), pos
, reason
, message
,
1336 throw new UUIDParsingException(to
!string(errorCopy
), pos
, reason
, message
, next
, file
,
1342 throw new UUIDParsingException("", pos
, reason
, message
, next
, file
, line
);
1346 static if (hasLength
!Range
)
1348 import std
.conv
: to
;
1349 if (uuidRange
.length
< 32)
1351 throw new UUIDParsingException(to
!string(uuidRange
), 0, UUIDParsingException
.Reason
.tooLittle
,
1352 "Insufficient Input");
1364 while (!uuidRange
.empty
&& !isHexDigit(uuidRange
.front
))
1367 uuidRange
.popFront();
1374 if (uuidRange
.empty
)
1375 parserError(consumed
, UUIDParsingException
.Reason
.tooLittle
, "Insufficient Input");
1377 bool dashAllowed
= false;
1379 parseLoop
: while (!uuidRange
.empty
)
1381 immutable character
= uuidRange
.front
;
1383 if (character
== '-')
1386 parserError(consumed
, UUIDParsingException
.Reason
.invalidChar
, "Unexpected '-'");
1388 dashAllowed
= false;
1392 else if (!isHexDigit(character
))
1394 parserError(consumed
, UUIDParsingException
.Reason
.invalidChar
,
1395 "Unexpected character (wanted a hexDigit)");
1402 static if (isSomeString
!Range
)
1404 if (uuidRange
.length
< 2)
1406 parserError(consumed
, UUIDParsingException
.Reason
.tooLittle
,
1407 "Insufficient Input");
1409 auto part
= uuidRange
[0 .. 2];
1410 result
.data
[element
++] = parse
!ubyte(part
, 16);
1411 uuidRange
.popFront();
1416 copyBuf
[0] = character
;
1417 uuidRange
.popFront();
1418 if (uuidRange
.empty
)
1420 parserError(consumed
, UUIDParsingException
.Reason
.tooLittle
,
1421 "Insufficient Input");
1423 copyBuf
[1] = uuidRange
.front
;
1424 auto part
= copyBuf
[];
1425 result
.data
[element
++] = parse
!ubyte(part
, 16);
1430 uuidRange
.popFront();
1436 catch (ConvException e
)
1438 parserError(consumed
, UUIDParsingException
.Reason
.invalidChar
,
1439 "Couldn't parse ubyte", e
);
1442 uuidRange
.popFront();
1444 assert(element
<= 16);
1447 parserError(consumed
, UUIDParsingException
.Reason
.tooLittle
, "Insufficient Input");
1450 if (!uuidRange
.empty
)
1451 parserError(consumed
, UUIDParsingException
.Reason
.invalidChar
, "Unexpected character");
1459 auto id
= parseUUID("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46");
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}");
1467 id
= parseUUID("ü8ab3060e2cba4f23b74cb52db3bdfb46ü");
1468 //multiple trailing/leading characters
1469 id
= parseUUID("///8ab3060e2cba4f23b74cb52db3bdfb46||");
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!
1478 import std
.conv
: to
;
1479 import std
.exception
;
1482 struct TestRange(bool forward
)
1486 @property dchar front()
1496 @property bool empty()
1503 @property TestRange
!true save()
1509 alias TestInputRange
= TestRange
!false;
1510 alias TestForwardRange
= TestRange
!true;
1512 assert(isInputRange
!TestInputRange
);
1513 assert(is(ElementType
!TestInputRange
== dchar));
1514 assert(isInputRange
!TestForwardRange
);
1515 assert(isForwardRange
!TestForwardRange
);
1516 assert(is(ElementType
!TestForwardRange
== dchar));
1518 //Helper function for unittests - Need to pass ranges by ref
1519 UUID
parseHelper(T
)(string input
)
1521 static if (is(T
== TestInputRange
) ||
is(T
== TestForwardRange
))
1523 T range
= T(to
!dstring(input
));
1524 return parseUUID(range
);
1527 return parseUUID(to
!T(input
));
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
))
1537 auto id
= parseHelper
!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46");
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}");
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
);
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]);
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]);
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]);
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
);
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
);
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
);
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"));
1588 except
= collectException
!UUIDParsingException(
1589 parseHelper
!S("8-ab3060e2cba-4f23-b74c-b52db3bdfb46"));
1590 assert(except
&& except
.reason
== UUIDParsingException
.Reason
.invalidChar
);
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"));
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]));
1605 assert(parseHelper
!S("ü8ab3060e2cba4f23b74cb52db3bdfb46ü")
1606 == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1608 //multiple trailing/leading characters
1609 assert(parseHelper
!S("///8ab3060e2cba4f23b74cb52db3bdfb46||")
1610 == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1615 * Default namespace from RFC 4122
1617 * Name string is a fully-qualified domain name
1619 enum dnsNamespace
= UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
1622 * Default namespace from RFC 4122
1624 * Name string is a URL
1626 enum urlNamespace
= UUID("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
1629 * Default namespace from RFC 4122
1631 * Name string is an ISO OID
1633 enum oidNamespace
= UUID("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
1636 * Default namespace from RFC 4122
1638 * Name string is an X.500 DN (in DER or a text output format)
1640 enum x500Namespace
= UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8");
1643 * Regex string to extract UUIDs from text.
1645 enum uuidRegex
= "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}"~
1646 "-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}";
1651 import std
.algorithm
;
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.";
1661 auto r
= regex(uuidRegex
, "g");
1663 foreach (c
; match(test, r
))
1665 found
~= UUID(c
.hit
);
1668 UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8"),
1669 UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"),
1674 * This exception is thrown if an error occurs when parsing a UUID
1677 public class UUIDParsingException
: Exception
1680 * The reason why parsing the UUID string failed (if known)
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
1692 ///The original input string which should have been parsed.
1694 ///The position in the input string where the error occurred.
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
1700 import std
.array
: replace
;
1701 import std
.format
: format
;
1703 this.position
= pos
;
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
);
1715 import std
.exception
: collectException
;
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
);
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
);