1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Diagnostics;
6 using System.Runtime.CompilerServices;
7 using System.Runtime.InteropServices;
8 
9 using Internal.Runtime.CompilerServices;
10 
11 namespace System
12 {
13     // Represents a Globally Unique Identifier.
14     [StructLayout(LayoutKind.Sequential)]
15     [Serializable]
16     [Runtime.Versioning.NonVersionable] // This only applies to field layout
17     [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
18     public partial struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid>, ISpanFormattable
19     {
20         public static readonly Guid Empty = new Guid();
21 
22         ////////////////////////////////////////////////////////////////////////////////
23         //  Member variables
24         ////////////////////////////////////////////////////////////////////////////////
25         private int _a; // Do not rename (binary serialization)
26         private short _b; // Do not rename (binary serialization)
27         private short _c; // Do not rename (binary serialization)
28         private byte _d; // Do not rename (binary serialization)
29         private byte _e; // Do not rename (binary serialization)
30         private byte _f; // Do not rename (binary serialization)
31         private byte _g; // Do not rename (binary serialization)
32         private byte _h; // Do not rename (binary serialization)
33         private byte _i; // Do not rename (binary serialization)
34         private byte _j; // Do not rename (binary serialization)
35         private byte _k; // Do not rename (binary serialization)
36 
37         ////////////////////////////////////////////////////////////////////////////////
38         //  Constructors
39         ////////////////////////////////////////////////////////////////////////////////
40 
41         // Creates a new guid from an array of bytes.
GuidSystem.Guid42         public Guid(byte[] b) :
43             this(new ReadOnlySpan<byte>(b ?? throw new ArgumentNullException(nameof(b))))
44         {
45         }
46 
47         // Creates a new guid from a read-only span.
GuidSystem.Guid48         public Guid(ReadOnlySpan<byte> b)
49         {
50             if (b.Length != 16)
51                 throw new ArgumentException(SR.Format(SR.Arg_GuidArrayCtor, "16"), nameof(b));
52 
53             _a = b[3] << 24 | b[2] << 16 | b[1] << 8 | b[0];
54             _b = (short)(b[5] << 8 | b[4]);
55             _c = (short)(b[7] << 8 | b[6]);
56             _d = b[8];
57             _e = b[9];
58             _f = b[10];
59             _g = b[11];
60             _h = b[12];
61             _i = b[13];
62             _j = b[14];
63             _k = b[15];
64         }
65 
66         [CLSCompliant(false)]
GuidSystem.Guid67         public Guid(uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
68         {
69             _a = (int)a;
70             _b = (short)b;
71             _c = (short)c;
72             _d = d;
73             _e = e;
74             _f = f;
75             _g = g;
76             _h = h;
77             _i = i;
78             _j = j;
79             _k = k;
80         }
81 
82         // Creates a new GUID initialized to the value represented by the arguments.
83         //
GuidSystem.Guid84         public Guid(int a, short b, short c, byte[] d)
85         {
86             if (d == null)
87                 throw new ArgumentNullException(nameof(d));
88             // Check that array is not too big
89             if (d.Length != 8)
90                 throw new ArgumentException(SR.Format(SR.Arg_GuidArrayCtor, "8"), nameof(d));
91 
92             _a = a;
93             _b = b;
94             _c = c;
95             _d = d[0];
96             _e = d[1];
97             _f = d[2];
98             _g = d[3];
99             _h = d[4];
100             _i = d[5];
101             _j = d[6];
102             _k = d[7];
103         }
104 
105         // Creates a new GUID initialized to the value represented by the
106         // arguments.  The bytes are specified like this to avoid endianness issues.
107         //
GuidSystem.Guid108         public Guid(int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
109         {
110             _a = a;
111             _b = b;
112             _c = c;
113             _d = d;
114             _e = e;
115             _f = f;
116             _g = g;
117             _h = h;
118             _i = i;
119             _j = j;
120             _k = k;
121         }
122 
123         [Flags]
124         private enum GuidStyles
125         {
126             None = 0x00000000,
127             AllowParenthesis = 0x00000001, //Allow the guid to be enclosed in parens
128             AllowBraces = 0x00000002, //Allow the guid to be enclosed in braces
129             AllowDashes = 0x00000004, //Allow the guid to contain dash group separators
130             AllowHexPrefix = 0x00000008, //Allow the guid to contain {0xdd,0xdd}
131             RequireParenthesis = 0x00000010, //Require the guid to be enclosed in parens
132             RequireBraces = 0x00000020, //Require the guid to be enclosed in braces
133             RequireDashes = 0x00000040, //Require the guid to contain dash group separators
134             RequireHexPrefix = 0x00000080, //Require the guid to contain {0xdd,0xdd}
135 
136             HexFormat = RequireBraces | RequireHexPrefix,                      /* X */
137             NumberFormat = None,                                                  /* N */
138             DigitFormat = RequireDashes,                                         /* D */
139             BraceFormat = RequireBraces | RequireDashes,                         /* B */
140             ParenthesisFormat = RequireParenthesis | RequireDashes,                    /* P */
141 
142             Any = AllowParenthesis | AllowBraces | AllowDashes | AllowHexPrefix,
143         }
144         private enum GuidParseThrowStyle
145         {
146             None = 0,
147             All = 1,
148             AllButOverflow = 2
149         }
150         private enum ParseFailureKind
151         {
152             None = 0,
153             ArgumentNull = 1,
154             Format = 2,
155             FormatWithParameter = 3,
156             NativeException = 4,
157             FormatWithInnerException = 5
158         }
159 
160         // This will store the result of the parsing.  And it will eventually be used to construct a Guid instance.
161         private struct GuidResult
162         {
163             internal Guid _parsedGuid;
164             internal GuidParseThrowStyle _throwStyle;
165 
166             private ParseFailureKind _failure;
167             private string _failureMessageID;
168             private object _failureMessageFormatArgument;
169             private string _failureArgumentName;
170             private Exception _innerException;
171 
InitSystem.Guid.GuidResult172             internal void Init(GuidParseThrowStyle canThrow)
173             {
174                 _throwStyle = canThrow;
175             }
176 
SetFailureSystem.Guid.GuidResult177             internal void SetFailure(Exception nativeException)
178             {
179                 _failure = ParseFailureKind.NativeException;
180                 _innerException = nativeException;
181             }
182 
SetFailureSystem.Guid.GuidResult183             internal void SetFailure(ParseFailureKind failure, string failureMessageID)
184             {
185                 SetFailure(failure, failureMessageID, null, null, null);
186             }
187 
SetFailureSystem.Guid.GuidResult188             internal void SetFailure(ParseFailureKind failure, string failureMessageID, object failureMessageFormatArgument)
189             {
190                 SetFailure(failure, failureMessageID, failureMessageFormatArgument, null, null);
191             }
192 
SetFailureSystem.Guid.GuidResult193             internal void SetFailure(ParseFailureKind failure, string failureMessageID, object failureMessageFormatArgument,
194                                      string failureArgumentName, Exception innerException)
195             {
196                 Debug.Assert(failure != ParseFailureKind.NativeException, "ParseFailureKind.NativeException should not be used with this overload");
197                 _failure = failure;
198                 _failureMessageID = failureMessageID;
199                 _failureMessageFormatArgument = failureMessageFormatArgument;
200                 _failureArgumentName = failureArgumentName;
201                 _innerException = innerException;
202                 if (_throwStyle != GuidParseThrowStyle.None)
203                 {
204                     throw GetGuidParseException();
205                 }
206             }
207 
GetGuidParseExceptionSystem.Guid.GuidResult208             internal Exception GetGuidParseException()
209             {
210                 switch (_failure)
211                 {
212                     case ParseFailureKind.ArgumentNull:
213                         return new ArgumentNullException(_failureArgumentName, SR.GetResourceString(_failureMessageID));
214 
215                     case ParseFailureKind.FormatWithInnerException:
216                         return new FormatException(SR.GetResourceString(_failureMessageID), _innerException);
217 
218                     case ParseFailureKind.FormatWithParameter:
219                         return new FormatException(SR.Format(SR.GetResourceString(_failureMessageID), _failureMessageFormatArgument));
220 
221                     case ParseFailureKind.Format:
222                         return new FormatException(SR.GetResourceString(_failureMessageID));
223 
224                     case ParseFailureKind.NativeException:
225                         return _innerException;
226 
227                     default:
228                         Debug.Fail("Unknown GuidParseFailure: " + _failure);
229                         return new FormatException(SR.Format_GuidUnrecognized);
230                 }
231             }
232         }
233 
234         // Creates a new guid based on the value in the string.  The value is made up
235         // of hex digits speared by the dash ("-"). The string may begin and end with
236         // brackets ("{", "}").
237         //
238         // The string must be of the form dddddddd-dddd-dddd-dddd-dddddddddddd. where
239         // d is a hex digit. (That is 8 hex digits, followed by 4, then 4, then 4,
240         // then 12) such as: "CA761232-ED42-11CE-BACD-00AA0057B223"
241         //
GuidSystem.Guid242         public Guid(string g)
243         {
244             if (g == null)
245             {
246                 throw new ArgumentNullException(nameof(g));
247             }
248 
249             GuidResult result = new GuidResult();
250             result.Init(GuidParseThrowStyle.All);
251             if (TryParseGuid(g, GuidStyles.Any, ref result))
252             {
253                 this = result._parsedGuid;
254             }
255             else
256             {
257                 throw result.GetGuidParseException();
258             }
259         }
260 
ParseSystem.Guid261         public static Guid Parse(string input) =>
262             Parse(input != null ? (ReadOnlySpan<char>)input : throw new ArgumentNullException(nameof(input)));
263 
ParseSystem.Guid264         public static Guid Parse(ReadOnlySpan<char> input)
265         {
266             GuidResult result = new GuidResult();
267             result.Init(GuidParseThrowStyle.AllButOverflow);
268             if (TryParseGuid(input, GuidStyles.Any, ref result))
269             {
270                 return result._parsedGuid;
271             }
272             else
273             {
274                 throw result.GetGuidParseException();
275             }
276         }
277 
TryParseSystem.Guid278         public static bool TryParse(string input, out Guid result)
279         {
280             if (input == null)
281             {
282                 result = default(Guid);
283                 return false;
284             }
285 
286             return TryParse((ReadOnlySpan<char>)input, out result);
287         }
288 
TryParseSystem.Guid289         public static bool TryParse(ReadOnlySpan<char> input, out Guid result)
290         {
291             GuidResult parseResult = new GuidResult();
292             parseResult.Init(GuidParseThrowStyle.None);
293             if (TryParseGuid(input, GuidStyles.Any, ref parseResult))
294             {
295                 result = parseResult._parsedGuid;
296                 return true;
297             }
298             else
299             {
300                 result = default(Guid);
301                 return false;
302             }
303         }
304 
ParseExactSystem.Guid305         public static Guid ParseExact(string input, string format) =>
306             ParseExact(
307                 input != null ? (ReadOnlySpan<char>)input : throw new ArgumentNullException(nameof(input)),
308                 format != null ? (ReadOnlySpan<char>)format : throw new ArgumentNullException(nameof(format)));
309 
ParseExactSystem.Guid310         public static Guid ParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format)
311         {
312             if (format.Length != 1)
313             {
314                 // all acceptable format strings are of length 1
315                 throw new FormatException(SR.Format_InvalidGuidFormatSpecification);
316             }
317 
318             GuidStyles style;
319             switch (format[0])
320             {
321                 case 'D':
322                 case 'd':
323                     style = GuidStyles.DigitFormat;
324                     break;
325                 case 'N':
326                 case 'n':
327                     style = GuidStyles.NumberFormat;
328                     break;
329                 case 'B':
330                 case 'b':
331                     style = GuidStyles.BraceFormat;
332                     break;
333                 case 'P':
334                 case 'p':
335                     style = GuidStyles.ParenthesisFormat;
336                     break;
337                 case 'X':
338                 case 'x':
339                     style = GuidStyles.HexFormat;
340                     break;
341                 default:
342                     throw new FormatException(SR.Format_InvalidGuidFormatSpecification);
343             }
344 
345             GuidResult result = new GuidResult();
346             result.Init(GuidParseThrowStyle.AllButOverflow);
347             if (TryParseGuid(input, style, ref result))
348             {
349                 return result._parsedGuid;
350             }
351             else
352             {
353                 throw result.GetGuidParseException();
354             }
355         }
356 
TryParseExactSystem.Guid357         public static bool TryParseExact(string input, string format, out Guid result)
358         {
359             if (input == null)
360             {
361                 result = default(Guid);
362                 return false;
363             }
364 
365             return TryParseExact((ReadOnlySpan<char>)input, format, out result);
366         }
367 
TryParseExactSystem.Guid368         public static bool TryParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, out Guid result)
369         {
370             if (format.Length != 1)
371             {
372                 result = default(Guid);
373                 return false;
374             }
375 
376             GuidStyles style;
377             switch (format[0])
378             {
379                 case 'D':
380                 case 'd':
381                     style = GuidStyles.DigitFormat;
382                     break;
383                 case 'N':
384                 case 'n':
385                     style = GuidStyles.NumberFormat;
386                     break;
387                 case 'B':
388                 case 'b':
389                     style = GuidStyles.BraceFormat;
390                     break;
391                 case 'P':
392                 case 'p':
393                     style = GuidStyles.ParenthesisFormat;
394                     break;
395                 case 'X':
396                 case 'x':
397                     style = GuidStyles.HexFormat;
398                     break;
399                 default:
400                     // invalid guid format specification
401                     result = default(Guid);
402                     return false;
403             }
404 
405             GuidResult parseResult = new GuidResult();
406             parseResult.Init(GuidParseThrowStyle.None);
407             if (TryParseGuid(input, style, ref parseResult))
408             {
409                 result = parseResult._parsedGuid;
410                 return true;
411             }
412             else
413             {
414                 result = default(Guid);
415                 return false;
416             }
417         }
418 
TryParseGuidSystem.Guid419         private static bool TryParseGuid(ReadOnlySpan<char> guidString, GuidStyles flags, ref GuidResult result)
420         {
421             guidString = guidString.Trim(); // Remove whitespace from beginning and end
422 
423             if (guidString.Length == 0)
424             {
425                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidUnrecognized));
426                 return false;
427             }
428 
429             // Check for dashes
430             bool dashesExistInString = guidString.IndexOf('-') >= 0;
431 
432             if (dashesExistInString)
433             {
434                 if ((flags & (GuidStyles.AllowDashes | GuidStyles.RequireDashes)) == 0)
435                 {
436                     // dashes are not allowed
437                     result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidUnrecognized));
438                     return false;
439                 }
440             }
441             else
442             {
443                 if ((flags & GuidStyles.RequireDashes) != 0)
444                 {
445                     // dashes are required
446                     result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidUnrecognized));
447                     return false;
448                 }
449             }
450 
451             // Check for braces
452             bool bracesExistInString = (guidString.IndexOf('{', 0) >= 0);
453 
454             if (bracesExistInString)
455             {
456                 if ((flags & (GuidStyles.AllowBraces | GuidStyles.RequireBraces)) == 0)
457                 {
458                     // braces are not allowed
459                     result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidUnrecognized));
460                     return false;
461                 }
462             }
463             else
464             {
465                 if ((flags & GuidStyles.RequireBraces) != 0)
466                 {
467                     // braces are required
468                     result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidUnrecognized));
469                     return false;
470                 }
471             }
472 
473             // Check for parenthesis
474             bool parenthesisExistInString = (guidString.IndexOf('(', 0) >= 0);
475 
476             if (parenthesisExistInString)
477             {
478                 if ((flags & (GuidStyles.AllowParenthesis | GuidStyles.RequireParenthesis)) == 0)
479                 {
480                     // parenthesis are not allowed
481                     result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidUnrecognized));
482                     return false;
483                 }
484             }
485             else
486             {
487                 if ((flags & GuidStyles.RequireParenthesis) != 0)
488                 {
489                     // parenthesis are required
490                     result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidUnrecognized));
491                     return false;
492                 }
493             }
494 
495             try
496             {
497                 // let's get on with the parsing
498                 if (dashesExistInString)
499                 {
500                     // Check if it's of the form [{|(]dddddddd-dddd-dddd-dddd-dddddddddddd[}|)]
501                     return TryParseGuidWithDashes(guidString, ref result);
502                 }
503                 else if (bracesExistInString)
504                 {
505                     // Check if it's of the form {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}}
506                     return TryParseGuidWithHexPrefix(guidString, ref result);
507                 }
508                 else
509                 {
510                     // Check if it's of the form dddddddddddddddddddddddddddddddd
511                     return TryParseGuidWithNoStyle(guidString, ref result);
512                 }
513             }
514             catch (IndexOutOfRangeException ex)
515             {
516                 result.SetFailure(ParseFailureKind.FormatWithInnerException, nameof(SR.Format_GuidUnrecognized), null, null, ex);
517                 return false;
518             }
519             catch (ArgumentException ex)
520             {
521                 result.SetFailure(ParseFailureKind.FormatWithInnerException, nameof(SR.Format_GuidUnrecognized), null, null, ex);
522                 return false;
523             }
524         }
525 
526         // Check if it's of the form {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}}
TryParseGuidWithHexPrefixSystem.Guid527         private static bool TryParseGuidWithHexPrefix(ReadOnlySpan<char> guidString, ref GuidResult result)
528         {
529             int numStart = 0;
530             int numLen = 0;
531 
532             // Eat all of the whitespace
533             guidString = EatAllWhitespace(guidString);
534 
535             // Check for leading '{'
536             if (guidString.Length == 0 || guidString[0] != '{')
537             {
538                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidBrace));
539                 return false;
540             }
541 
542             // Check for '0x'
543             if (!IsHexPrefix(guidString, 1))
544             {
545                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidHexPrefix), "{0xdddddddd, etc}");
546                 return false;
547             }
548 
549             // Find the end of this hex number (since it is not fixed length)
550             numStart = 3;
551             numLen = guidString.IndexOf(',', numStart) - numStart;
552             if (numLen <= 0)
553             {
554                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidComma));
555                 return false;
556             }
557 
558             if (!StringToInt(guidString.Slice(numStart, numLen) /*first DWORD*/, -1, ParseNumbers.IsTight, out result._parsedGuid._a, ref result))
559                 return false;
560 
561             // Check for '0x'
562             if (!IsHexPrefix(guidString, numStart + numLen + 1))
563             {
564                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidHexPrefix), "{0xdddddddd, 0xdddd, etc}");
565                 return false;
566             }
567             // +3 to get by ',0x'
568             numStart = numStart + numLen + 3;
569             numLen = guidString.IndexOf(',', numStart) - numStart;
570             if (numLen <= 0)
571             {
572                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidComma));
573                 return false;
574             }
575 
576             // Read in the number
577             if (!StringToShort(guidString.Slice(numStart, numLen) /*first DWORD*/, -1, ParseNumbers.IsTight, out result._parsedGuid._b, ref result))
578                 return false;
579             // Check for '0x'
580             if (!IsHexPrefix(guidString, numStart + numLen + 1))
581             {
582                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidHexPrefix), "{0xdddddddd, 0xdddd, 0xdddd, etc}");
583                 return false;
584             }
585             // +3 to get by ',0x'
586             numStart = numStart + numLen + 3;
587             numLen = guidString.IndexOf(',', numStart) - numStart;
588             if (numLen <= 0)
589             {
590                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidComma));
591                 return false;
592             }
593 
594             // Read in the number
595             if (!StringToShort(guidString.Slice(numStart, numLen) /*first DWORD*/, -1, ParseNumbers.IsTight, out result._parsedGuid._c, ref result))
596                 return false;
597 
598             // Check for '{'
599             if (guidString.Length <= numStart + numLen + 1 || guidString[numStart + numLen + 1] != '{')
600             {
601                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidBrace));
602                 return false;
603             }
604 
605             // Prepare for loop
606             numLen++;
607             Span<byte> bytes = stackalloc byte[8];
608 
609             for (int i = 0; i < bytes.Length; i++)
610             {
611                 // Check for '0x'
612                 if (!IsHexPrefix(guidString, numStart + numLen + 1))
613                 {
614                     result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidHexPrefix), "{... { ... 0xdd, ...}}");
615                     return false;
616                 }
617 
618                 // +3 to get by ',0x' or '{0x' for first case
619                 numStart = numStart + numLen + 3;
620 
621                 // Calculate number length
622                 if (i < 7)  // first 7 cases
623                 {
624                     numLen = guidString.IndexOf(',', numStart) - numStart;
625                     if (numLen <= 0)
626                     {
627                         result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidComma));
628                         return false;
629                     }
630                 }
631                 else       // last case ends with '}', not ','
632                 {
633                     numLen = guidString.IndexOf('}', numStart) - numStart;
634                     if (numLen <= 0)
635                     {
636                         result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidBraceAfterLastNumber));
637                         return false;
638                     }
639                 }
640 
641                 // Read in the number
642                 int signedNumber;
643                 if (!StringToInt(guidString.Slice(numStart, numLen), -1, ParseNumbers.IsTight, out signedNumber, ref result))
644                 {
645                     return false;
646                 }
647                 uint number = (uint)signedNumber;
648 
649                 // check for overflow
650                 if (number > 255)
651                 {
652                     result.SetFailure(ParseFailureKind.Format, nameof(SR.Overflow_Byte));
653                     return false;
654                 }
655                 bytes[i] = (byte)number;
656             }
657 
658             result._parsedGuid._d = bytes[0];
659             result._parsedGuid._e = bytes[1];
660             result._parsedGuid._f = bytes[2];
661             result._parsedGuid._g = bytes[3];
662             result._parsedGuid._h = bytes[4];
663             result._parsedGuid._i = bytes[5];
664             result._parsedGuid._j = bytes[6];
665             result._parsedGuid._k = bytes[7];
666 
667             // Check for last '}'
668             if (numStart + numLen + 1 >= guidString.Length || guidString[numStart + numLen + 1] != '}')
669             {
670                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidEndBrace));
671                 return false;
672             }
673 
674             // Check if we have extra characters at the end
675             if (numStart + numLen + 1 != guidString.Length - 1)
676             {
677                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_ExtraJunkAtEnd));
678                 return false;
679             }
680 
681             return true;
682         }
683 
684         // Check if it's of the form dddddddddddddddddddddddddddddddd
TryParseGuidWithNoStyleSystem.Guid685         private static bool TryParseGuidWithNoStyle(ReadOnlySpan<char> guidString, ref GuidResult result)
686         {
687             int startPos = 0;
688             int temp;
689             long templ;
690             int currentPos = 0;
691 
692             if (guidString.Length != 32)
693             {
694                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidInvLen));
695                 return false;
696             }
697 
698             for (int i = 0; i < guidString.Length; i++)
699             {
700                 char ch = guidString[i];
701                 if (ch >= '0' && ch <= '9')
702                 {
703                     continue;
704                 }
705                 else
706                 {
707                     char upperCaseCh = char.ToUpperInvariant(ch);
708                     if (upperCaseCh >= 'A' && upperCaseCh <= 'F')
709                     {
710                         continue;
711                     }
712                 }
713 
714                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidInvalidChar));
715                 return false;
716             }
717 
718             if (!StringToInt(guidString.Slice(startPos, 8) /*first DWORD*/, -1, ParseNumbers.IsTight, out result._parsedGuid._a, ref result))
719                 return false;
720 
721             startPos += 8;
722             if (!StringToShort(guidString.Slice(startPos, 4), -1, ParseNumbers.IsTight, out result._parsedGuid._b, ref result))
723                 return false;
724 
725             startPos += 4;
726             if (!StringToShort(guidString.Slice(startPos, 4), -1, ParseNumbers.IsTight, out result._parsedGuid._c, ref result))
727                 return false;
728 
729             startPos += 4;
730             if (!StringToInt(guidString.Slice(startPos, 4), -1, ParseNumbers.IsTight, out temp, ref result))
731                 return false;
732 
733             startPos += 4;
734             currentPos = startPos;
735 
736             if (!StringToLong(guidString, ref currentPos, ParseNumbers.NoSpace, out templ, ref result))
737                 return false;
738 
739             if (currentPos - startPos != 12)
740             {
741                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidInvLen));
742                 return false;
743             }
744 
745             result._parsedGuid._d = (byte)(temp >> 8);
746             result._parsedGuid._e = (byte)(temp);
747             temp = (int)(templ >> 32);
748             result._parsedGuid._f = (byte)(temp >> 8);
749             result._parsedGuid._g = (byte)(temp);
750             temp = (int)(templ);
751             result._parsedGuid._h = (byte)(temp >> 24);
752             result._parsedGuid._i = (byte)(temp >> 16);
753             result._parsedGuid._j = (byte)(temp >> 8);
754             result._parsedGuid._k = (byte)(temp);
755 
756             return true;
757         }
758 
759         // Check if it's of the form [{|(]dddddddd-dddd-dddd-dddd-dddddddddddd[}|)]
TryParseGuidWithDashesSystem.Guid760         private static bool TryParseGuidWithDashes(ReadOnlySpan<char> guidString, ref GuidResult result)
761         {
762             int startPos = 0;
763             int temp;
764             long templ;
765             int currentPos = 0;
766 
767             // check to see that it's the proper length
768             if (guidString[0] == '{')
769             {
770                 if (guidString.Length != 38 || guidString[37] != '}')
771                 {
772                     result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidInvLen));
773                     return false;
774                 }
775                 startPos = 1;
776             }
777             else if (guidString[0] == '(')
778             {
779                 if (guidString.Length != 38 || guidString[37] != ')')
780                 {
781                     result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidInvLen));
782                     return false;
783                 }
784                 startPos = 1;
785             }
786             else if (guidString.Length != 36)
787             {
788                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidInvLen));
789                 return false;
790             }
791 
792             if (guidString[8 + startPos] != '-' ||
793                 guidString[13 + startPos] != '-' ||
794                 guidString[18 + startPos] != '-' ||
795                 guidString[23 + startPos] != '-')
796             {
797                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidDashes));
798                 return false;
799             }
800 
801             currentPos = startPos;
802             if (!StringToInt(guidString, ref currentPos, 8, ParseNumbers.NoSpace, out temp, ref result))
803                 return false;
804             result._parsedGuid._a = temp;
805             ++currentPos; //Increment past the '-';
806 
807             if (!StringToInt(guidString, ref currentPos, 4, ParseNumbers.NoSpace, out temp, ref result))
808                 return false;
809             result._parsedGuid._b = (short)temp;
810             ++currentPos; //Increment past the '-';
811 
812             if (!StringToInt(guidString, ref currentPos, 4, ParseNumbers.NoSpace, out temp, ref result))
813                 return false;
814             result._parsedGuid._c = (short)temp;
815             ++currentPos; //Increment past the '-';
816 
817             if (!StringToInt(guidString, ref currentPos, 4, ParseNumbers.NoSpace, out temp, ref result))
818                 return false;
819             ++currentPos; //Increment past the '-';
820             startPos = currentPos;
821 
822             if (!StringToLong(guidString, ref currentPos, ParseNumbers.NoSpace, out templ, ref result))
823                 return false;
824 
825             if (currentPos - startPos != 12)
826             {
827                 result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidInvLen));
828                 return false;
829             }
830             result._parsedGuid._d = (byte)(temp >> 8);
831             result._parsedGuid._e = (byte)(temp);
832             temp = (int)(templ >> 32);
833             result._parsedGuid._f = (byte)(temp >> 8);
834             result._parsedGuid._g = (byte)(temp);
835             temp = (int)(templ);
836             result._parsedGuid._h = (byte)(temp >> 24);
837             result._parsedGuid._i = (byte)(temp >> 16);
838             result._parsedGuid._j = (byte)(temp >> 8);
839             result._parsedGuid._k = (byte)(temp);
840 
841             return true;
842         }
843 
StringToShortSystem.Guid844         private static bool StringToShort(ReadOnlySpan<char> str, int requiredLength, int flags, out short result, ref GuidResult parseResult)
845         {
846             int parsePos = 0;
847             return StringToShort(str, ref parsePos, requiredLength, flags, out result, ref parseResult);
848         }
849 
StringToShortSystem.Guid850         private static bool StringToShort(ReadOnlySpan<char> str, ref int parsePos, int requiredLength, int flags, out short result, ref GuidResult parseResult)
851         {
852             result = 0;
853             int x;
854             bool retValue = StringToInt(str, ref parsePos, requiredLength, flags, out x, ref parseResult);
855             result = (short)x;
856             return retValue;
857         }
858 
StringToIntSystem.Guid859         private static bool StringToInt(ReadOnlySpan<char> str, int requiredLength, int flags, out int result, ref GuidResult parseResult)
860         {
861             int parsePos = 0;
862             return StringToInt(str, ref parsePos, requiredLength, flags, out result, ref parseResult);
863         }
864 
StringToIntSystem.Guid865         private static bool StringToInt(ReadOnlySpan<char> str, ref int parsePos, int requiredLength, int flags, out int result, ref GuidResult parseResult)
866         {
867             result = 0;
868 
869             int currStart = parsePos;
870             try
871             {
872                 result = ParseNumbers.StringToInt(str, 16, flags, ref parsePos);
873             }
874             catch (OverflowException ex)
875             {
876                 if (parseResult._throwStyle == GuidParseThrowStyle.All)
877                 {
878                     throw;
879                 }
880                 else if (parseResult._throwStyle == GuidParseThrowStyle.AllButOverflow)
881                 {
882                     throw new FormatException(SR.Format_GuidUnrecognized, ex);
883                 }
884                 else
885                 {
886                     parseResult.SetFailure(ex);
887                     return false;
888                 }
889             }
890             catch (Exception ex)
891             {
892                 if (parseResult._throwStyle == GuidParseThrowStyle.None)
893                 {
894                     parseResult.SetFailure(ex);
895                     return false;
896                 }
897                 else
898                 {
899                     throw;
900                 }
901             }
902 
903             //If we didn't parse enough characters, there's clearly an error.
904             if (requiredLength != -1 && parsePos - currStart != requiredLength)
905             {
906                 parseResult.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidInvalidChar));
907                 return false;
908             }
909             return true;
910         }
911 
StringToLongSystem.Guid912         private static unsafe bool StringToLong(ReadOnlySpan<char> str, ref int parsePos, int flags, out long result, ref GuidResult parseResult)
913         {
914             result = 0;
915 
916             try
917             {
918                 result = ParseNumbers.StringToLong(str, 16, flags, ref parsePos);
919             }
920             catch (OverflowException ex)
921             {
922                 if (parseResult._throwStyle == GuidParseThrowStyle.All)
923                 {
924                     throw;
925                 }
926                 else if (parseResult._throwStyle == GuidParseThrowStyle.AllButOverflow)
927                 {
928                     throw new FormatException(SR.Format_GuidUnrecognized, ex);
929                 }
930                 else
931                 {
932                     parseResult.SetFailure(ex);
933                     return false;
934                 }
935             }
936             catch (Exception ex)
937             {
938                 if (parseResult._throwStyle == GuidParseThrowStyle.None)
939                 {
940                     parseResult.SetFailure(ex);
941                     return false;
942                 }
943                 else
944                 {
945                     throw;
946                 }
947             }
948             return true;
949         }
950 
EatAllWhitespaceSystem.Guid951         private static ReadOnlySpan<char> EatAllWhitespace(ReadOnlySpan<char> str)
952         {
953             // Find the first whitespace character.  If there is none, just return the input.
954             int i;
955             for (i = 0; i < str.Length && !char.IsWhiteSpace(str[i]); i++) ;
956             if (i == str.Length)
957             {
958                 return str;
959             }
960 
961             // There was at least one whitespace.  Copy over everything prior to it to a new array.
962             var chArr = new char[str.Length];
963             int newLength = 0;
964             if (i > 0)
965             {
966                 newLength = i;
967                 str.Slice(0, i).CopyTo(chArr);
968             }
969 
970             // Loop through the remaining chars, copying over non-whitespace.
971             for (; i < str.Length; i++)
972             {
973                 char c = str[i];
974                 if (!char.IsWhiteSpace(c))
975                 {
976                     chArr[newLength++] = c;
977                 }
978             }
979 
980             // Return the string with the whitespace removed.
981             return new ReadOnlySpan<char>(chArr, 0, newLength);
982         }
983 
IsHexPrefixSystem.Guid984         private static bool IsHexPrefix(ReadOnlySpan<char> str, int i) =>
985             i + 1 < str.Length &&
986             str[i] == '0' &&
987             (str[i + 1] == 'x' || char.ToLowerInvariant(str[i + 1]) == 'x');
988 
989         [MethodImpl(MethodImplOptions.AggressiveInlining)]
990         private void WriteByteHelper(Span<byte> destination)
991         {
992             destination[0] = (byte)(_a);
993             destination[1] = (byte)(_a >> 8);
994             destination[2] = (byte)(_a >> 16);
995             destination[3] = (byte)(_a >> 24);
996             destination[4] = (byte)(_b);
997             destination[5] = (byte)(_b >> 8);
998             destination[6] = (byte)(_c);
999             destination[7] = (byte)(_c >> 8);
1000             destination[8] = _d;
1001             destination[9] = _e;
1002             destination[10] = _f;
1003             destination[11] = _g;
1004             destination[12] = _h;
1005             destination[13] = _i;
1006             destination[14] = _j;
1007             destination[15] = _k;
1008         }
1009 
1010         // Returns an unsigned byte array containing the GUID.
ToByteArray()1011         public byte[] ToByteArray()
1012         {
1013             var g = new byte[16];
1014             WriteByteHelper(g);
1015             return g;
1016         }
1017 
1018         // Returns whether bytes are sucessfully written to given span.
TryWriteBytes(Span<byte> destination)1019         public bool TryWriteBytes(Span<byte> destination)
1020         {
1021             if (destination.Length < 16)
1022                 return false;
1023 
1024             WriteByteHelper(destination);
1025             return true;
1026         }
1027 
1028         // Returns the guid in "registry" format.
ToString()1029         public override string ToString()
1030         {
1031             return ToString("D", null);
1032         }
1033 
GetHashCode()1034         public override int GetHashCode()
1035         {
1036             // Simply XOR all the bits of the GUID 32 bits at a time.
1037             return _a ^ Unsafe.Add(ref _a, 1) ^ Unsafe.Add(ref _a, 2) ^ Unsafe.Add(ref _a, 3);
1038         }
1039 
1040         // Returns true if and only if the guid represented
1041         //  by o is the same as this instance.
Equals(object o)1042         public override bool Equals(object o)
1043         {
1044             Guid g;
1045             // Check that o is a Guid first
1046             if (o == null || !(o is Guid))
1047                 return false;
1048             else g = (Guid)o;
1049 
1050             // Now compare each of the elements
1051             return g._a == _a &&
1052                 Unsafe.Add(ref g._a, 1) == Unsafe.Add(ref _a, 1) &&
1053                 Unsafe.Add(ref g._a, 2) == Unsafe.Add(ref _a, 2) &&
1054                 Unsafe.Add(ref g._a, 3) == Unsafe.Add(ref _a, 3);
1055         }
1056 
Equals(Guid g)1057         public bool Equals(Guid g)
1058         {
1059             // Now compare each of the elements
1060             return g._a == _a &&
1061                 Unsafe.Add(ref g._a, 1) == Unsafe.Add(ref _a, 1) &&
1062                 Unsafe.Add(ref g._a, 2) == Unsafe.Add(ref _a, 2) &&
1063                 Unsafe.Add(ref g._a, 3) == Unsafe.Add(ref _a, 3);
1064         }
1065 
GetResult(uint me, uint them)1066         private int GetResult(uint me, uint them)
1067         {
1068             if (me < them)
1069             {
1070                 return -1;
1071             }
1072             return 1;
1073         }
1074 
CompareTo(object value)1075         public int CompareTo(object value)
1076         {
1077             if (value == null)
1078             {
1079                 return 1;
1080             }
1081             if (!(value is Guid))
1082             {
1083                 throw new ArgumentException(SR.Arg_MustBeGuid, nameof(value));
1084             }
1085             Guid g = (Guid)value;
1086 
1087             if (g._a != _a)
1088             {
1089                 return GetResult((uint)_a, (uint)g._a);
1090             }
1091 
1092             if (g._b != _b)
1093             {
1094                 return GetResult((uint)_b, (uint)g._b);
1095             }
1096 
1097             if (g._c != _c)
1098             {
1099                 return GetResult((uint)_c, (uint)g._c);
1100             }
1101 
1102             if (g._d != _d)
1103             {
1104                 return GetResult(_d, g._d);
1105             }
1106 
1107             if (g._e != _e)
1108             {
1109                 return GetResult(_e, g._e);
1110             }
1111 
1112             if (g._f != _f)
1113             {
1114                 return GetResult(_f, g._f);
1115             }
1116 
1117             if (g._g != _g)
1118             {
1119                 return GetResult(_g, g._g);
1120             }
1121 
1122             if (g._h != _h)
1123             {
1124                 return GetResult(_h, g._h);
1125             }
1126 
1127             if (g._i != _i)
1128             {
1129                 return GetResult(_i, g._i);
1130             }
1131 
1132             if (g._j != _j)
1133             {
1134                 return GetResult(_j, g._j);
1135             }
1136 
1137             if (g._k != _k)
1138             {
1139                 return GetResult(_k, g._k);
1140             }
1141 
1142             return 0;
1143         }
1144 
CompareTo(Guid value)1145         public int CompareTo(Guid value)
1146         {
1147             if (value._a != _a)
1148             {
1149                 return GetResult((uint)_a, (uint)value._a);
1150             }
1151 
1152             if (value._b != _b)
1153             {
1154                 return GetResult((uint)_b, (uint)value._b);
1155             }
1156 
1157             if (value._c != _c)
1158             {
1159                 return GetResult((uint)_c, (uint)value._c);
1160             }
1161 
1162             if (value._d != _d)
1163             {
1164                 return GetResult(_d, value._d);
1165             }
1166 
1167             if (value._e != _e)
1168             {
1169                 return GetResult(_e, value._e);
1170             }
1171 
1172             if (value._f != _f)
1173             {
1174                 return GetResult(_f, value._f);
1175             }
1176 
1177             if (value._g != _g)
1178             {
1179                 return GetResult(_g, value._g);
1180             }
1181 
1182             if (value._h != _h)
1183             {
1184                 return GetResult(_h, value._h);
1185             }
1186 
1187             if (value._i != _i)
1188             {
1189                 return GetResult(_i, value._i);
1190             }
1191 
1192             if (value._j != _j)
1193             {
1194                 return GetResult(_j, value._j);
1195             }
1196 
1197             if (value._k != _k)
1198             {
1199                 return GetResult(_k, value._k);
1200             }
1201 
1202             return 0;
1203         }
1204 
operator ==(Guid a, Guid b)1205         public static bool operator ==(Guid a, Guid b)
1206         {
1207             // Now compare each of the elements
1208             return a._a == b._a &&
1209                 Unsafe.Add(ref a._a, 1) == Unsafe.Add(ref b._a, 1) &&
1210                 Unsafe.Add(ref a._a, 2) == Unsafe.Add(ref b._a, 2) &&
1211                 Unsafe.Add(ref a._a, 3) == Unsafe.Add(ref b._a, 3);
1212         }
1213 
operator !=(Guid a, Guid b)1214         public static bool operator !=(Guid a, Guid b)
1215         {
1216             // Now compare each of the elements
1217             return a._a != b._a ||
1218                 Unsafe.Add(ref a._a, 1) != Unsafe.Add(ref b._a, 1) ||
1219                 Unsafe.Add(ref a._a, 2) != Unsafe.Add(ref b._a, 2) ||
1220                 Unsafe.Add(ref a._a, 3) != Unsafe.Add(ref b._a, 3);
1221         }
1222 
ToString(string format)1223         public string ToString(string format)
1224         {
1225             return ToString(format, null);
1226         }
1227 
1228         [MethodImpl(MethodImplOptions.AggressiveInlining)]
HexToChar(int a)1229         private static char HexToChar(int a)
1230         {
1231             a = a & 0xf;
1232             return (char)((a > 9) ? a - 10 + 0x61 : a + 0x30);
1233         }
1234 
HexsToChars(char* guidChars, int a, int b)1235         unsafe private static int HexsToChars(char* guidChars, int a, int b)
1236         {
1237             guidChars[0] = HexToChar(a >> 4);
1238             guidChars[1] = HexToChar(a);
1239 
1240             guidChars[2] = HexToChar(b >> 4);
1241             guidChars[3] = HexToChar(b);
1242 
1243             return 4;
1244         }
1245 
HexsToCharsHexOutput(char* guidChars, int a, int b)1246         unsafe private static int HexsToCharsHexOutput(char* guidChars, int a, int b)
1247         {
1248             guidChars[0] = '0';
1249             guidChars[1] = 'x';
1250 
1251             guidChars[2] = HexToChar(a >> 4);
1252             guidChars[3] = HexToChar(a);
1253 
1254             guidChars[4] = ',';
1255             guidChars[5] = '0';
1256             guidChars[6] = 'x';
1257 
1258             guidChars[7] = HexToChar(b >> 4);
1259             guidChars[8] = HexToChar(b);
1260 
1261             return 9;
1262         }
1263 
1264         // IFormattable interface
1265         // We currently ignore provider
ToString(string format, IFormatProvider provider)1266         public string ToString(string format, IFormatProvider provider)
1267         {
1268             if (format == null || format.Length == 0)
1269                 format = "D";
1270 
1271             // all acceptable format strings are of length 1
1272             if (format.Length != 1)
1273                 throw new FormatException(SR.Format_InvalidGuidFormatSpecification);
1274 
1275             int guidSize;
1276             switch (format[0])
1277             {
1278                 case 'D':
1279                 case 'd':
1280                     guidSize = 36;
1281                     break;
1282                 case 'N':
1283                 case 'n':
1284                     guidSize = 32;
1285                     break;
1286                 case 'B':
1287                 case 'b':
1288                 case 'P':
1289                 case 'p':
1290                     guidSize = 38;
1291                     break;
1292                 case 'X':
1293                 case 'x':
1294                     guidSize = 68;
1295                     break;
1296                 default:
1297                     throw new FormatException(SR.Format_InvalidGuidFormatSpecification);
1298             }
1299 
1300             string guidString = string.FastAllocateString(guidSize);
1301 
1302             int bytesWritten;
1303             bool result = TryFormat(new Span<char>(ref guidString.GetRawStringData(), guidString.Length), out bytesWritten, format);
1304             Debug.Assert(result && bytesWritten == guidString.Length, "Formatting guid should have succeeded.");
1305 
1306             return guidString;
1307         }
1308 
1309         // Returns whether the guid is successfully formatted as a span.
TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default)1310         public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default)
1311         {
1312             if (format.Length == 0)
1313                 format = "D";
1314 
1315             // all acceptable format strings are of length 1
1316             if (format.Length != 1)
1317                 throw new FormatException(SR.Format_InvalidGuidFormatSpecification);
1318 
1319             bool dash = true;
1320             bool hex = false;
1321             int braces = 0;
1322 
1323             int guidSize;
1324 
1325             switch (format[0])
1326             {
1327                 case 'D':
1328                 case 'd':
1329                     guidSize = 36;
1330                     break;
1331                 case 'N':
1332                 case 'n':
1333                     dash = false;
1334                     guidSize = 32;
1335                     break;
1336                 case 'B':
1337                 case 'b':
1338                     braces = '{' + ('}' << 16);
1339                     guidSize = 38;
1340                     break;
1341                 case 'P':
1342                 case 'p':
1343                     braces = '(' + (')' << 16);
1344                     guidSize = 38;
1345                     break;
1346                 case 'X':
1347                 case 'x':
1348                     braces = '{' + ('}' << 16);
1349                     dash = false;
1350                     hex = true;
1351                     guidSize = 68;
1352                     break;
1353                 default:
1354                     throw new FormatException(SR.Format_InvalidGuidFormatSpecification);
1355             }
1356 
1357             if (destination.Length < guidSize)
1358             {
1359                 charsWritten = 0;
1360                 return false;
1361             }
1362 
1363             unsafe
1364             {
1365                 fixed (char* guidChars = &MemoryMarshal.GetReference(destination))
1366                 {
1367                     char * p = guidChars;
1368 
1369                     if (braces != 0)
1370                         *p++ = (char)braces;
1371 
1372                     if (hex)
1373                     {
1374                         // {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}}
1375                         *p++ = '0';
1376                         *p++ = 'x';
1377                         p += HexsToChars(p, _a >> 24, _a >> 16);
1378                         p += HexsToChars(p, _a >> 8, _a);
1379                         *p++ = ',';
1380                         *p++ = '0';
1381                         *p++ = 'x';
1382                         p += HexsToChars(p, _b >> 8, _b);
1383                         *p++ = ',';
1384                         *p++ = '0';
1385                         *p++ = 'x';
1386                         p += HexsToChars(p, _c >> 8, _c);
1387                         *p++ = ',';
1388                         *p++ = '{';
1389                         p += HexsToCharsHexOutput(p, _d, _e);
1390                         *p++ = ',';
1391                         p += HexsToCharsHexOutput(p, _f, _g);
1392                         *p++ = ',';
1393                         p += HexsToCharsHexOutput(p, _h, _i);
1394                         *p++ = ',';
1395                         p += HexsToCharsHexOutput(p, _j, _k);
1396                         *p++ = '}';
1397                     }
1398                     else
1399                     {
1400                         // [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)]
1401                         p += HexsToChars(p, _a >> 24, _a >> 16);
1402                         p += HexsToChars(p, _a >> 8, _a);
1403                         if (dash)
1404                             *p++ = '-';
1405                         p += HexsToChars(p, _b >> 8, _b);
1406                         if (dash)
1407                             *p++ = '-';
1408                         p += HexsToChars(p, _c >> 8, _c);
1409                         if (dash)
1410                             *p++ = '-';
1411                         p += HexsToChars(p, _d, _e);
1412                         if (dash)
1413                             *p++ = '-';
1414                         p += HexsToChars(p, _f, _g);
1415                         p += HexsToChars(p, _h, _i);
1416                         p += HexsToChars(p, _j, _k);
1417                     }
1418 
1419                     if (braces != 0)
1420                         *p++ = (char)(braces >> 16);
1421 
1422                     Debug.Assert(p - guidChars == guidSize);
1423                 }
1424             }
1425 
1426             charsWritten = guidSize;
1427             return true;
1428         }
1429 
ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)1430         bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)
1431         {
1432             // Like with the IFormattable implementation, provider is ignored.
1433             return TryFormat(destination, out charsWritten, format);
1434         }
1435     }
1436 }
1437