< Summary

Information
Line coverage
0%
Covered lines: 0
Uncovered lines: 12
Coverable lines: 12
Total lines: 1393
Line coverage: 0%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
ObjectArray()100%110%
ElementType()100%110%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/BlobEncoders.cs

#LineLine coverage
 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
 4using System.Collections.Immutable;
 5
 6namespace System.Reflection.Metadata.Ecma335
 7{
 8    // TODO: debug metadata blobs
 9    // TODO: revisit ctors (public vs internal vs static factories)?
 10
 11    public readonly struct BlobEncoder
 12    {
 13        public BlobBuilder Builder { get; }
 14
 15        public BlobEncoder(BlobBuilder builder)
 16        {
 17            if (builder is null)
 18            {
 19                Throw.ArgumentNull(nameof(builder));
 20            }
 21
 22            Builder = builder;
 23        }
 24
 25        /// <summary>
 26        /// Encodes Field Signature blob, with additional support for
 27        /// encoding ref fields, custom modifiers and typed references.
 28        /// </summary>
 29        /// <returns>Encoder of the field type.</returns>
 30        public FieldTypeEncoder Field()
 31        {
 32            Builder.WriteByte((byte)SignatureKind.Field);
 33            return new FieldTypeEncoder(Builder);
 34        }
 35
 36        /// <summary>
 37        /// Encodes Field Signature blob.
 38        /// </summary>
 39        /// <returns>Encoder of the field type.</returns>
 40        /// <remarks>To encode byref fields, custom modifiers or typed
 41        /// references use <see cref="Field"/> instead.</remarks>
 42        public SignatureTypeEncoder FieldSignature()
 43        {
 44            return Field().Type(isByRef: false);
 45        }
 46
 47        /// <summary>
 48        /// Encodes Method Specification Signature blob.
 49        /// </summary>
 50        /// <param name="genericArgumentCount">Number of generic arguments.</param>
 51        /// <returns>Encoder of generic arguments.</returns>
 52        /// <exception cref="ArgumentOutOfRangeException"><paramref name="genericArgumentCount"/> is not in range [0, 0x
 53        public GenericTypeArgumentsEncoder MethodSpecificationSignature(int genericArgumentCount)
 54        {
 55            if (unchecked((uint)genericArgumentCount) > ushort.MaxValue)
 56            {
 57                Throw.ArgumentOutOfRange(nameof(genericArgumentCount));
 58            }
 59
 60            Builder.WriteByte((byte)SignatureKind.MethodSpecification);
 61            Builder.WriteCompressedInteger(genericArgumentCount);
 62
 63            return new GenericTypeArgumentsEncoder(Builder);
 64        }
 65
 66        /// <summary>
 67        /// Encodes Method Signature blob.
 68        /// </summary>
 69        /// <param name="convention">Calling convention.</param>
 70        /// <param name="genericParameterCount">Number of generic parameters.</param>
 71        /// <param name="isInstanceMethod">True to encode an instance method signature, false to encode a static method 
 72        /// <returns>An Encoder of the rest of the signature including return value and parameters.</returns>
 73        /// <exception cref="ArgumentOutOfRangeException"><paramref name="genericParameterCount"/> is not in range [0, 0
 74        public MethodSignatureEncoder MethodSignature(
 75            SignatureCallingConvention convention = SignatureCallingConvention.Default,
 76            int genericParameterCount = 0,
 77            bool isInstanceMethod = false)
 78        {
 79            if (unchecked((uint)genericParameterCount) > ushort.MaxValue)
 80            {
 81                Throw.ArgumentOutOfRange(nameof(genericParameterCount));
 82            }
 83
 84            var attributes =
 85                (genericParameterCount != 0 ? SignatureAttributes.Generic : 0) |
 86                (isInstanceMethod ? SignatureAttributes.Instance : 0);
 87
 88            Builder.WriteByte(new SignatureHeader(SignatureKind.Method, convention, attributes).RawValue);
 89
 90            if (genericParameterCount != 0)
 91            {
 92                Builder.WriteCompressedInteger(genericParameterCount);
 93            }
 94
 95            return new MethodSignatureEncoder(Builder, hasVarArgs: convention == SignatureCallingConvention.VarArgs);
 96        }
 97
 98        /// <summary>
 99        /// Encodes Property Signature blob.
 100        /// </summary>
 101        /// <param name="isInstanceProperty">True to encode an instance property signature, false to encode a static pro
 102        /// <returns>An Encoder of the rest of the signature including return value and parameters, which has the same s
 103        public MethodSignatureEncoder PropertySignature(bool isInstanceProperty = false)
 104        {
 105            Builder.WriteByte(new SignatureHeader(SignatureKind.Property, SignatureCallingConvention.Default, (isInstanc
 106            return new MethodSignatureEncoder(Builder, hasVarArgs: false);
 107        }
 108
 109        /// <summary>
 110        /// Encodes Custom Attribute Signature blob.
 111        /// Returns a pair of encoders that must be used in the order they appear in the parameter list.
 112        /// </summary>
 113        /// <param name="fixedArguments">Use first, to encode fixed arguments.</param>
 114        /// <param name="namedArguments">Use second, to encode named arguments.</param>
 115        public void CustomAttributeSignature(out FixedArgumentsEncoder fixedArguments, out CustomAttributeNamedArguments
 116        {
 117            Builder.WriteUInt16(0x0001);
 118
 119            fixedArguments = new FixedArgumentsEncoder(Builder);
 120            namedArguments = new CustomAttributeNamedArgumentsEncoder(Builder);
 121        }
 122
 123        /// <summary>
 124        /// Encodes Custom Attribute Signature blob.
 125        /// </summary>
 126        /// <param name="fixedArguments">Called first, to encode fixed arguments.</param>
 127        /// <param name="namedArguments">Called second, to encode named arguments.</param>
 128        /// <exception cref="ArgumentNullException"><paramref name="fixedArguments"/> or <paramref name="namedArguments"
 129        public void CustomAttributeSignature(Action<FixedArgumentsEncoder> fixedArguments, Action<CustomAttributeNamedAr
 130        {
 131            if (fixedArguments is null)
 132            {
 133                Throw.ArgumentNull(nameof(fixedArguments));
 134            }
 135            if (namedArguments is null)
 136            {
 137                Throw.ArgumentNull(nameof(namedArguments));
 138            }
 139
 140            FixedArgumentsEncoder fixedArgumentsEncoder;
 141            CustomAttributeNamedArgumentsEncoder namedArgumentsEncoder;
 142            CustomAttributeSignature(out fixedArgumentsEncoder, out namedArgumentsEncoder);
 143            fixedArguments(fixedArgumentsEncoder);
 144            namedArguments(namedArgumentsEncoder);
 145        }
 146
 147        /// <summary>
 148        /// Encodes Local Variable Signature.
 149        /// </summary>
 150        /// <param name="variableCount">Number of local variables.</param>
 151        /// <returns>Encoder of a sequence of local variables.</returns>
 152        /// <exception cref="ArgumentOutOfRangeException"><paramref name="variableCount"/> is not in range [0, 0x1ffffff
 153        public LocalVariablesEncoder LocalVariableSignature(int variableCount)
 154        {
 155            if (unchecked((uint)variableCount) > BlobWriterImpl.MaxCompressedIntegerValue)
 156            {
 157                Throw.ArgumentOutOfRange(nameof(variableCount));
 158            }
 159
 160            Builder.WriteByte((byte)SignatureKind.LocalVariables);
 161            Builder.WriteCompressedInteger(variableCount);
 162            return new LocalVariablesEncoder(Builder);
 163        }
 164
 165        /// <summary>
 166        /// Encodes Type Specification Signature.
 167        /// </summary>
 168        /// <returns>
 169        /// Type encoder of the structured type represented by the Type Specification (it shall not encode a primitive t
 170        /// </returns>
 171        public SignatureTypeEncoder TypeSpecificationSignature()
 172        {
 173            return new SignatureTypeEncoder(Builder);
 174        }
 175
 176        /// <summary>
 177        /// Encodes a Permission Set blob.
 178        /// </summary>
 179        /// <param name="attributeCount">Number of attributes in the set.</param>
 180        /// <returns>Permission Set encoder.</returns>
 181        /// <exception cref="ArgumentOutOfRangeException"><paramref name="attributeCount"/> is not in range [0, 0x1fffff
 182        public PermissionSetEncoder PermissionSetBlob(int attributeCount)
 183        {
 184            if (unchecked((uint)attributeCount) > BlobWriterImpl.MaxCompressedIntegerValue)
 185            {
 186                Throw.ArgumentOutOfRange(nameof(attributeCount));
 187            }
 188
 189            Builder.WriteByte((byte)'.');
 190            Builder.WriteCompressedInteger(attributeCount);
 191            return new PermissionSetEncoder(Builder);
 192        }
 193
 194        /// <summary>
 195        /// Encodes Permission Set arguments.
 196        /// </summary>
 197        /// <param name="argumentCount">Number of arguments in the set.</param>
 198        /// <returns>Encoder of the arguments of the set.</returns>
 199        public NamedArgumentsEncoder PermissionSetArguments(int argumentCount)
 200        {
 201            if (unchecked((uint)argumentCount) > BlobWriterImpl.MaxCompressedIntegerValue)
 202            {
 203                Throw.ArgumentOutOfRange(nameof(argumentCount));
 204            }
 205
 206            Builder.WriteCompressedInteger(argumentCount);
 207            return new NamedArgumentsEncoder(Builder);
 208        }
 209    }
 210
 211    public readonly struct MethodSignatureEncoder
 212    {
 213        public BlobBuilder Builder { get; }
 214        public bool HasVarArgs { get; }
 215
 216        public MethodSignatureEncoder(BlobBuilder builder, bool hasVarArgs)
 217        {
 218            Builder = builder;
 219            HasVarArgs = hasVarArgs;
 220        }
 221
 222        /// <summary>
 223        /// Encodes return type and parameters.
 224        /// Returns a pair of encoders that must be used in the order they appear in the parameter list.
 225        /// </summary>
 226        /// <param name="parameterCount">Number of parameters.</param>
 227        /// <param name="returnType">Use first, to encode the return types.</param>
 228        /// <param name="parameters">Use second, to encode the actual parameters.</param>
 229        public void Parameters(int parameterCount, out ReturnTypeEncoder returnType, out ParametersEncoder parameters)
 230        {
 231            if (unchecked((uint)parameterCount) > BlobWriterImpl.MaxCompressedIntegerValue)
 232            {
 233                Throw.ArgumentOutOfRange(nameof(parameterCount));
 234            }
 235
 236            Builder.WriteCompressedInteger(parameterCount);
 237
 238            returnType = new ReturnTypeEncoder(Builder);
 239            parameters = new ParametersEncoder(Builder, hasVarArgs: HasVarArgs);
 240        }
 241
 242        /// <summary>
 243        /// Encodes return type and parameters.
 244        /// </summary>
 245        /// <param name="parameterCount">Number of parameters.</param>
 246        /// <param name="returnType">Called first, to encode the return type.</param>
 247        /// <param name="parameters">Called second, to encode the actual parameters.</param>
 248        /// <exception cref="ArgumentNullException"><paramref name="returnType"/> or <paramref name="parameters"/> is nu
 249        public void Parameters(int parameterCount, Action<ReturnTypeEncoder> returnType, Action<ParametersEncoder> param
 250        {
 251            if (returnType is null)
 252            {
 253                Throw.ArgumentNull(nameof(returnType));
 254            }
 255            if (parameters is null)
 256            {
 257                Throw.ArgumentNull(nameof(parameters));
 258            }
 259
 260            ReturnTypeEncoder returnTypeEncoder;
 261            ParametersEncoder parametersEncoder;
 262            Parameters(parameterCount, out returnTypeEncoder, out parametersEncoder);
 263            returnType(returnTypeEncoder);
 264            parameters(parametersEncoder);
 265        }
 266    }
 267
 268    public readonly struct LocalVariablesEncoder
 269    {
 270        public BlobBuilder Builder { get; }
 271
 272        public LocalVariablesEncoder(BlobBuilder builder)
 273        {
 274            Builder = builder;
 275        }
 276
 277        public LocalVariableTypeEncoder AddVariable()
 278        {
 279            return new LocalVariableTypeEncoder(Builder);
 280        }
 281    }
 282
 283    public readonly struct LocalVariableTypeEncoder
 284    {
 285        public BlobBuilder Builder { get; }
 286
 287        public LocalVariableTypeEncoder(BlobBuilder builder)
 288        {
 289            Builder = builder;
 290        }
 291
 292        public CustomModifiersEncoder CustomModifiers()
 293        {
 294            return new CustomModifiersEncoder(Builder);
 295        }
 296
 297        public SignatureTypeEncoder Type(bool isByRef = false, bool isPinned = false)
 298        {
 299            if (isPinned)
 300            {
 301                Builder.WriteByte((byte)SignatureTypeCode.Pinned);
 302            }
 303
 304            if (isByRef)
 305            {
 306                Builder.WriteByte((byte)SignatureTypeCode.ByReference);
 307            }
 308
 309            return new SignatureTypeEncoder(Builder);
 310        }
 311
 312        public void TypedReference()
 313        {
 314            Builder.WriteByte((byte)SignatureTypeCode.TypedReference);
 315        }
 316    }
 317
 318    public readonly struct ParameterTypeEncoder
 319    {
 320        public BlobBuilder Builder { get; }
 321
 322        public ParameterTypeEncoder(BlobBuilder builder)
 323        {
 324            Builder = builder;
 325        }
 326
 327        public CustomModifiersEncoder CustomModifiers()
 328        {
 329            return new CustomModifiersEncoder(Builder);
 330        }
 331
 332        public SignatureTypeEncoder Type(bool isByRef = false)
 333        {
 334            if (isByRef)
 335            {
 336                Builder.WriteByte((byte)SignatureTypeCode.ByReference);
 337            }
 338
 339            return new SignatureTypeEncoder(Builder);
 340        }
 341
 342        public void TypedReference()
 343        {
 344            Builder.WriteByte((byte)SignatureTypeCode.TypedReference);
 345        }
 346    }
 347
 348    public readonly struct PermissionSetEncoder
 349    {
 350        public BlobBuilder Builder { get; }
 351
 352        public PermissionSetEncoder(BlobBuilder builder)
 353        {
 354            Builder = builder;
 355        }
 356
 357        public PermissionSetEncoder AddPermission(string typeName, ImmutableArray<byte> encodedArguments)
 358        {
 359            if (typeName is null)
 360            {
 361                Throw.ArgumentNull(nameof(typeName));
 362            }
 363
 364            if (encodedArguments.IsDefault)
 365            {
 366                Throw.ArgumentNull(nameof(encodedArguments));
 367            }
 368
 369            if (encodedArguments.Length > BlobWriterImpl.MaxCompressedIntegerValue)
 370            {
 371                Throw.BlobTooLarge(nameof(encodedArguments));
 372            }
 373
 374            Builder.WriteSerializedString(typeName);
 375            Builder.WriteCompressedInteger(encodedArguments.Length);
 376            Builder.WriteBytes(encodedArguments);
 377            return this;
 378        }
 379
 380        public PermissionSetEncoder AddPermission(string typeName, BlobBuilder encodedArguments)
 381        {
 382            if (typeName is null)
 383            {
 384                Throw.ArgumentNull(nameof(typeName));
 385            }
 386            if (encodedArguments is null)
 387            {
 388                Throw.ArgumentNull(nameof(encodedArguments));
 389            }
 390
 391            if (encodedArguments.Count > BlobWriterImpl.MaxCompressedIntegerValue)
 392            {
 393                Throw.BlobTooLarge(nameof(encodedArguments));
 394            }
 395
 396            Builder.WriteSerializedString(typeName);
 397            Builder.WriteCompressedInteger(encodedArguments.Count);
 398            encodedArguments.WriteContentTo(Builder);
 399            return this;
 400        }
 401    }
 402
 403    public readonly struct GenericTypeArgumentsEncoder
 404    {
 405        public BlobBuilder Builder { get; }
 406
 407        public GenericTypeArgumentsEncoder(BlobBuilder builder)
 408        {
 409            Builder = builder;
 410        }
 411
 412        public SignatureTypeEncoder AddArgument()
 413        {
 414            return new SignatureTypeEncoder(Builder);
 415        }
 416    }
 417
 418    public readonly struct FieldTypeEncoder
 419    {
 420        public BlobBuilder Builder { get; }
 421
 422        public FieldTypeEncoder(BlobBuilder builder)
 423        {
 424            Builder = builder;
 425        }
 426
 427        /// <summary>
 428        /// Creates <see cref="CustomModifiersEncoder" /> object that can be used to encode custom modifiers.
 429        /// </summary>
 430        /// <returns>A <see cref="CustomModifiersEncoder"/> instance that can be used to encode custom modifiers.</retur
 431        public CustomModifiersEncoder CustomModifiers()
 432        {
 433            return new CustomModifiersEncoder(Builder);
 434        }
 435
 436        public SignatureTypeEncoder Type(bool isByRef = false)
 437        {
 438            if (isByRef)
 439            {
 440                Builder.WriteByte((byte)SignatureTypeCode.ByReference);
 441            }
 442
 443            return new SignatureTypeEncoder(Builder);
 444        }
 445
 446        public void TypedReference()
 447        {
 448            Builder.WriteByte((byte)SignatureTypeCode.TypedReference);
 449        }
 450    }
 451
 452    public readonly struct FixedArgumentsEncoder
 453    {
 454        public BlobBuilder Builder { get; }
 455
 456        public FixedArgumentsEncoder(BlobBuilder builder)
 457        {
 458            Builder = builder;
 459        }
 460
 461        public LiteralEncoder AddArgument()
 462        {
 463            return new LiteralEncoder(Builder);
 464        }
 465    }
 466
 467    public readonly struct LiteralEncoder
 468    {
 469        public BlobBuilder Builder { get; }
 470
 471        public LiteralEncoder(BlobBuilder builder)
 472        {
 473            Builder = builder;
 474        }
 475
 476        public VectorEncoder Vector()
 477        {
 478            return new VectorEncoder(Builder);
 479        }
 480
 481        /// <summary>
 482        /// Encodes the type and the items of a vector literal.
 483        /// Returns a pair of encoders that must be used in the order they appear in the parameter list.
 484        /// </summary>
 485        /// <param name="arrayType">Use first, to encode the type of the vector.</param>
 486        /// <param name="vector">Use second, to encode the items of the vector.</param>
 487        public void TaggedVector(out CustomAttributeArrayTypeEncoder arrayType, out VectorEncoder vector)
 488        {
 489            arrayType = new CustomAttributeArrayTypeEncoder(Builder);
 490            vector = new VectorEncoder(Builder);
 491        }
 492
 493        /// <summary>
 494        /// Encodes the type and the items of a vector literal.
 495        /// </summary>
 496        /// <param name="arrayType">Called first, to encode the type of the vector.</param>
 497        /// <param name="vector">Called second, to encode the items of the vector.</param>
 498        /// <exception cref="ArgumentNullException"><paramref name="arrayType"/> or <paramref name="vector"/> is null.</
 499        public void TaggedVector(Action<CustomAttributeArrayTypeEncoder> arrayType, Action<VectorEncoder> vector)
 500        {
 501            if (arrayType is null)
 502            {
 503                Throw.ArgumentNull(nameof(arrayType));
 504            }
 505            if (vector is null)
 506            {
 507                Throw.ArgumentNull(nameof(vector));
 508            }
 509
 510            CustomAttributeArrayTypeEncoder arrayTypeEncoder;
 511            VectorEncoder vectorEncoder;
 512            TaggedVector(out arrayTypeEncoder, out vectorEncoder);
 513            arrayType(arrayTypeEncoder);
 514            vector(vectorEncoder);
 515        }
 516
 517        /// <summary>
 518        /// Encodes a scalar literal.
 519        /// </summary>
 520        /// <returns>Encoder of the literal value.</returns>
 521        public ScalarEncoder Scalar()
 522        {
 523            return new ScalarEncoder(Builder);
 524        }
 525
 526        /// <summary>
 527        /// Encodes the type and the value of a literal.
 528        /// Returns a pair of encoders that must be used in the order they appear in the parameter list.
 529        /// </summary>
 530        /// <param name="type">Called first, to encode the type of the literal.</param>
 531        /// <param name="scalar">Called second, to encode the value of the literal.</param>
 532        public void TaggedScalar(out CustomAttributeElementTypeEncoder type, out ScalarEncoder scalar)
 533        {
 534            type = new CustomAttributeElementTypeEncoder(Builder);
 535            scalar = new ScalarEncoder(Builder);
 536        }
 537
 538        /// <summary>
 539        /// Encodes the type and the value of a literal.
 540        /// </summary>
 541        /// <param name="type">Called first, to encode the type of the literal.</param>
 542        /// <param name="scalar">Called second, to encode the value of the literal.</param>
 543        /// <exception cref="ArgumentNullException"><paramref name="type"/> or <paramref name="scalar"/> is null.</excep
 544        public void TaggedScalar(Action<CustomAttributeElementTypeEncoder> type, Action<ScalarEncoder> scalar)
 545        {
 546            if (type is null)
 547            {
 548                Throw.ArgumentNull(nameof(type));
 549            }
 550            if (scalar is null)
 551            {
 552                Throw.ArgumentNull(nameof(scalar));
 553            }
 554
 555            CustomAttributeElementTypeEncoder typeEncoder;
 556            ScalarEncoder scalarEncoder;
 557            TaggedScalar(out typeEncoder, out scalarEncoder);
 558            type(typeEncoder);
 559            scalar(scalarEncoder);
 560        }
 561    }
 562
 563    public readonly struct ScalarEncoder
 564    {
 565        public BlobBuilder Builder { get; }
 566
 567        public ScalarEncoder(BlobBuilder builder)
 568        {
 569            Builder = builder;
 570        }
 571
 572        /// <summary>
 573        /// Encodes <c>null</c> literal of type <see cref="Array"/>.
 574        /// </summary>
 575        public void NullArray()
 576        {
 577            Builder.WriteInt32(-1);
 578        }
 579
 580        /// <summary>
 581        /// Encodes constant literal.
 582        /// </summary>
 583        /// <param name="value">
 584        /// Constant of type
 585        /// <see cref="bool"/>,
 586        /// <see cref="byte"/>,
 587        /// <see cref="sbyte"/>,
 588        /// <see cref="short"/>,
 589        /// <see cref="ushort"/>,
 590        /// <see cref="int"/>,
 591        /// <see cref="uint"/>,
 592        /// <see cref="long"/>,
 593        /// <see cref="ulong"/>,
 594        /// <see cref="float"/>,
 595        /// <see cref="double"/>,
 596        /// <see cref="char"/> (encoded as two-byte Unicode character),
 597        /// <see cref="string"/> (encoded as SerString), or
 598        /// <see cref="Enum"/> (encoded as the underlying integer value).
 599        /// </param>
 600        /// <exception cref="ArgumentException">Unexpected constant type.</exception>
 601        public void Constant(object? value)
 602        {
 603            string? str = value as string;
 604            if (str != null || value == null)
 605            {
 606                String(str);
 607            }
 608            else
 609            {
 610                Builder.WriteConstant(value);
 611            }
 612        }
 613
 614        /// <summary>
 615        /// Encodes literal of type <see cref="Type"/> (possibly null).
 616        /// </summary>
 617        /// <param name="serializedTypeName">The name of the type, or null.</param>
 618        /// <exception cref="ArgumentException"><paramref name="serializedTypeName"/> is empty.</exception>
 619        public void SystemType(string? serializedTypeName)
 620        {
 621            if (serializedTypeName != null && serializedTypeName.Length == 0)
 622            {
 623                Throw.ArgumentEmptyString(nameof(serializedTypeName));
 624            }
 625
 626            String(serializedTypeName);
 627        }
 628
 629        private void String(string? value)
 630        {
 631            Builder.WriteSerializedString(value);
 632        }
 633    }
 634
 635    public readonly struct LiteralsEncoder
 636    {
 637        public BlobBuilder Builder { get; }
 638
 639        public LiteralsEncoder(BlobBuilder builder)
 640        {
 641            Builder = builder;
 642        }
 643
 644        public LiteralEncoder AddLiteral()
 645        {
 646            return new LiteralEncoder(Builder);
 647        }
 648    }
 649
 650    public readonly struct VectorEncoder
 651    {
 652        public BlobBuilder Builder { get; }
 653
 654        public VectorEncoder(BlobBuilder builder)
 655        {
 656            Builder = builder;
 657        }
 658
 659        public LiteralsEncoder Count(int count)
 660        {
 661            if (count < 0)
 662            {
 663                Throw.ArgumentOutOfRange(nameof(count));
 664            }
 665
 666            Builder.WriteUInt32((uint)count);
 667            return new LiteralsEncoder(Builder);
 668        }
 669    }
 670
 671    public readonly struct NameEncoder
 672    {
 673        public BlobBuilder Builder { get; }
 674
 675        public NameEncoder(BlobBuilder builder)
 676        {
 677            Builder = builder;
 678        }
 679
 680        public void Name(string name)
 681        {
 682            if (name is null)
 683            {
 684                Throw.ArgumentNull(nameof(name));
 685            }
 686
 687            if (name.Length == 0) Throw.ArgumentEmptyString(nameof(name));
 688
 689            Builder.WriteSerializedString(name);
 690        }
 691    }
 692
 693    public readonly struct CustomAttributeNamedArgumentsEncoder
 694    {
 695        public BlobBuilder Builder { get; }
 696
 697        public CustomAttributeNamedArgumentsEncoder(BlobBuilder builder)
 698        {
 699            Builder = builder;
 700        }
 701
 702        public NamedArgumentsEncoder Count(int count)
 703        {
 704            if (unchecked((uint)count) > ushort.MaxValue)
 705            {
 706                Throw.ArgumentOutOfRange(nameof(count));
 707            }
 708
 709            Builder.WriteUInt16((ushort)count);
 710            return new NamedArgumentsEncoder(Builder);
 711        }
 712    }
 713
 714    public readonly struct NamedArgumentsEncoder
 715    {
 716        public BlobBuilder Builder { get; }
 717
 718        public NamedArgumentsEncoder(BlobBuilder builder)
 719        {
 720            Builder = builder;
 721        }
 722
 723        /// <summary>
 724        /// Encodes a named argument (field or property).
 725        /// Returns a triplet of encoders that must be used in the order they appear in the parameter list.
 726        /// </summary>
 727        /// <param name="isField">True to encode a field, false to encode a property.</param>
 728        /// <param name="type">Use first, to encode the type of the argument.</param>
 729        /// <param name="name">Use second, to encode the name of the field or property.</param>
 730        /// <param name="literal">Use third, to encode the literal value of the argument.</param>
 731        public void AddArgument(bool isField, out NamedArgumentTypeEncoder type, out NameEncoder name, out LiteralEncode
 732        {
 733            Builder.WriteByte(isField ? (byte)CustomAttributeNamedArgumentKind.Field : (byte)CustomAttributeNamedArgumen
 734            type = new NamedArgumentTypeEncoder(Builder);
 735            name = new NameEncoder(Builder);
 736            literal = new LiteralEncoder(Builder);
 737        }
 738
 739        /// <summary>
 740        /// Encodes a named argument (field or property).
 741        /// </summary>
 742        /// <param name="isField">True to encode a field, false to encode a property.</param>
 743        /// <param name="type">Called first, to encode the type of the argument.</param>
 744        /// <param name="name">Called second, to encode the name of the field or property.</param>
 745        /// <param name="literal">Called third, to encode the literal value of the argument.</param>
 746        /// <exception cref="ArgumentNullException"><paramref name="type"/>, <paramref name="name"/> or <paramref name="
 747        public void AddArgument(bool isField, Action<NamedArgumentTypeEncoder> type, Action<NameEncoder> name, Action<Li
 748        {
 749            if (type is null)
 750            {
 751                Throw.ArgumentNull(nameof(type));
 752            }
 753            if (name is null)
 754            {
 755                Throw.ArgumentNull(nameof(name));
 756            }
 757            if (literal is null)
 758            {
 759                Throw.ArgumentNull(nameof(literal));
 760            }
 761
 762            NamedArgumentTypeEncoder typeEncoder;
 763            NameEncoder nameEncoder;
 764            LiteralEncoder literalEncoder;
 765            AddArgument(isField, out typeEncoder, out nameEncoder, out literalEncoder);
 766            type(typeEncoder);
 767            name(nameEncoder);
 768            literal(literalEncoder);
 769        }
 770    }
 771
 772    public readonly struct NamedArgumentTypeEncoder
 773    {
 774        public BlobBuilder Builder { get; }
 775
 776        public NamedArgumentTypeEncoder(BlobBuilder builder)
 777        {
 778            Builder = builder;
 779        }
 780
 781        public CustomAttributeElementTypeEncoder ScalarType()
 782        {
 783            return new CustomAttributeElementTypeEncoder(Builder);
 784        }
 785
 786        public void Object()
 787        {
 788            Builder.WriteByte((byte)SerializationTypeCode.TaggedObject);
 789        }
 790
 791        public CustomAttributeArrayTypeEncoder SZArray()
 792        {
 793            return new CustomAttributeArrayTypeEncoder(Builder);
 794        }
 795    }
 796
 797    public readonly struct CustomAttributeArrayTypeEncoder
 798    {
 0799        public BlobBuilder Builder { get; }
 800
 801        public CustomAttributeArrayTypeEncoder(BlobBuilder builder)
 0802        {
 0803            Builder = builder;
 0804        }
 805
 806        public void ObjectArray()
 0807        {
 0808            Builder.WriteByte((byte)SerializationTypeCode.SZArray);
 0809            Builder.WriteByte((byte)SerializationTypeCode.TaggedObject);
 0810        }
 811
 812        public CustomAttributeElementTypeEncoder ElementType()
 0813        {
 0814            Builder.WriteByte((byte)SerializationTypeCode.SZArray);
 0815            return new CustomAttributeElementTypeEncoder(Builder);
 0816        }
 817    }
 818
 819    public readonly struct CustomAttributeElementTypeEncoder
 820    {
 821        public BlobBuilder Builder { get; }
 822
 823        public CustomAttributeElementTypeEncoder(BlobBuilder builder)
 824        {
 825            Builder = builder;
 826        }
 827
 828        private void WriteTypeCode(SerializationTypeCode value)
 829        {
 830            Builder.WriteByte((byte)value);
 831        }
 832
 833        public void Boolean() => WriteTypeCode(SerializationTypeCode.Boolean);
 834        public void Char() => WriteTypeCode(SerializationTypeCode.Char);
 835        public void SByte() => WriteTypeCode(SerializationTypeCode.SByte);
 836        public void Byte() => WriteTypeCode(SerializationTypeCode.Byte);
 837        public void Int16() => WriteTypeCode(SerializationTypeCode.Int16);
 838        public void UInt16() => WriteTypeCode(SerializationTypeCode.UInt16);
 839        public void Int32() => WriteTypeCode(SerializationTypeCode.Int32);
 840        public void UInt32() => WriteTypeCode(SerializationTypeCode.UInt32);
 841        public void Int64() => WriteTypeCode(SerializationTypeCode.Int64);
 842        public void UInt64() => WriteTypeCode(SerializationTypeCode.UInt64);
 843        public void Single() => WriteTypeCode(SerializationTypeCode.Single);
 844        public void Double() => WriteTypeCode(SerializationTypeCode.Double);
 845        public void String() => WriteTypeCode(SerializationTypeCode.String);
 846
 847        public void PrimitiveType(PrimitiveSerializationTypeCode type)
 848        {
 849            switch (type)
 850            {
 851                case PrimitiveSerializationTypeCode.Boolean:
 852                case PrimitiveSerializationTypeCode.Byte:
 853                case PrimitiveSerializationTypeCode.SByte:
 854                case PrimitiveSerializationTypeCode.Char:
 855                case PrimitiveSerializationTypeCode.Int16:
 856                case PrimitiveSerializationTypeCode.UInt16:
 857                case PrimitiveSerializationTypeCode.Int32:
 858                case PrimitiveSerializationTypeCode.UInt32:
 859                case PrimitiveSerializationTypeCode.Int64:
 860                case PrimitiveSerializationTypeCode.UInt64:
 861                case PrimitiveSerializationTypeCode.Single:
 862                case PrimitiveSerializationTypeCode.Double:
 863                case PrimitiveSerializationTypeCode.String:
 864                    WriteTypeCode((SerializationTypeCode)type);
 865                    return;
 866
 867                default:
 868                    Throw.ArgumentOutOfRange(nameof(type));
 869                    return;
 870            }
 871        }
 872
 873        public void SystemType()
 874        {
 875            WriteTypeCode(SerializationTypeCode.Type);
 876        }
 877
 878        public void Enum(string enumTypeName)
 879        {
 880            if (enumTypeName is null)
 881            {
 882                Throw.ArgumentNull(nameof(enumTypeName));
 883            }
 884
 885            if (enumTypeName.Length == 0) Throw.ArgumentEmptyString(nameof(enumTypeName));
 886
 887            WriteTypeCode(SerializationTypeCode.Enum);
 888            Builder.WriteSerializedString(enumTypeName);
 889        }
 890    }
 891
 892    /// <summary>
 893    /// Encodes a type in a signature.
 894    /// </summary>
 895    public readonly struct SignatureTypeEncoder
 896    {
 897        /// <summary>
 898        /// The <see cref="BlobBuilder"/> where the signature is written to.
 899        /// </summary>
 900        public BlobBuilder Builder { get; }
 901
 902        /// <summary>
 903        /// Creates a <see cref="SignatureTypeEncoder"/>.
 904        /// </summary>
 905        /// <param name="builder">The <see cref="BlobBuilder"/> where the signature will be written.</param>
 906        public SignatureTypeEncoder(BlobBuilder builder)
 907        {
 908            Builder = builder;
 909        }
 910
 911        private void WriteTypeCode(SignatureTypeCode value)
 912        {
 913            Builder.WriteByte((byte)value);
 914        }
 915
 916        private void ClassOrValue(bool isValueType)
 917        {
 918            Builder.WriteByte(isValueType ? (byte)SignatureTypeKind.ValueType : (byte)SignatureTypeKind.Class);
 919        }
 920
 921        /// <summary>
 922        /// Encodes <see cref="bool"/>.
 923        /// </summary>
 924        public void Boolean() => WriteTypeCode(SignatureTypeCode.Boolean);
 925        /// <summary>
 926        /// Encodes <see cref="char"/>.
 927        /// </summary>
 928        public void Char() => WriteTypeCode(SignatureTypeCode.Char);
 929        /// <summary>
 930        /// Encodes <see cref="sbyte"/>.
 931        /// </summary>
 932        public void SByte() => WriteTypeCode(SignatureTypeCode.SByte);
 933        /// <summary>
 934        /// Encodes <see cref="byte"/>.
 935        /// </summary>
 936        public void Byte() => WriteTypeCode(SignatureTypeCode.Byte);
 937        /// <summary>
 938        /// Encodes <see cref="short"/>.
 939        /// </summary>
 940        public void Int16() => WriteTypeCode(SignatureTypeCode.Int16);
 941        /// <summary>
 942        /// Encodes <see cref="ushort"/>.
 943        /// </summary>
 944        public void UInt16() => WriteTypeCode(SignatureTypeCode.UInt16);
 945        /// <summary>
 946        /// Encodes <see cref="int"/>.
 947        /// </summary>
 948        public void Int32() => WriteTypeCode(SignatureTypeCode.Int32);
 949        /// <summary>
 950        /// Encodes <see cref="uint"/>.
 951        /// </summary>
 952        public void UInt32() => WriteTypeCode(SignatureTypeCode.UInt32);
 953        /// <summary>
 954        /// Encodes <see cref="long"/>.
 955        /// </summary>
 956        public void Int64() => WriteTypeCode(SignatureTypeCode.Int64);
 957        /// <summary>
 958        /// Encodes <see cref="ulong"/>.
 959        /// </summary>
 960        public void UInt64() => WriteTypeCode(SignatureTypeCode.UInt64);
 961        /// <summary>
 962        /// Encodes <see cref="float"/>.
 963        /// </summary>
 964        public void Single() => WriteTypeCode(SignatureTypeCode.Single);
 965        /// <summary>
 966        /// Encodes <see cref="double"/>.
 967        /// </summary>
 968        public void Double() => WriteTypeCode(SignatureTypeCode.Double);
 969        /// <summary>
 970        /// Encodes <see cref="string"/>.
 971        /// </summary>
 972        public void String() => WriteTypeCode(SignatureTypeCode.String);
 973        /// <summary>
 974        /// Encodes <see cref="System.TypedReference"/>.
 975        /// </summary>
 976        public void TypedReference() => WriteTypeCode(SignatureTypeCode.TypedReference);
 977        /// <summary>
 978        /// Encodes <see cref="System.IntPtr"/>.
 979        /// </summary>
 980        public void IntPtr() => WriteTypeCode(SignatureTypeCode.IntPtr);
 981        /// <summary>
 982        /// Encodes <see cref="System.UIntPtr"/>.
 983        /// </summary>
 984        public void UIntPtr() => WriteTypeCode(SignatureTypeCode.UIntPtr);
 985        /// <summary>
 986        /// Encodes <see cref="object"/>.
 987        /// </summary>
 988        public void Object() => WriteTypeCode(SignatureTypeCode.Object);
 989
 990        /// <summary>
 991        /// Encodes a primitive type.
 992        /// </summary>
 993        /// <param name="type">Any primitive type code except for <see cref="PrimitiveTypeCode.Void"/>.</param>
 994        /// <exception cref="ArgumentOutOfRangeException"><paramref name="type"/> is not valid in this context.</excepti
 995        public void PrimitiveType(PrimitiveTypeCode type)
 996        {
 997            switch (type)
 998            {
 999                case PrimitiveTypeCode.Boolean:
 1000                case PrimitiveTypeCode.Byte:
 1001                case PrimitiveTypeCode.SByte:
 1002                case PrimitiveTypeCode.Char:
 1003                case PrimitiveTypeCode.Int16:
 1004                case PrimitiveTypeCode.UInt16:
 1005                case PrimitiveTypeCode.Int32:
 1006                case PrimitiveTypeCode.UInt32:
 1007                case PrimitiveTypeCode.Int64:
 1008                case PrimitiveTypeCode.UInt64:
 1009                case PrimitiveTypeCode.Single:
 1010                case PrimitiveTypeCode.Double:
 1011                case PrimitiveTypeCode.TypedReference:
 1012                case PrimitiveTypeCode.IntPtr:
 1013                case PrimitiveTypeCode.UIntPtr:
 1014                case PrimitiveTypeCode.String:
 1015                case PrimitiveTypeCode.Object:
 1016                    Builder.WriteByte((byte)type);
 1017                    return;
 1018
 1019                case PrimitiveTypeCode.Void:
 1020                default:
 1021                    Throw.ArgumentOutOfRange(nameof(type));
 1022                    return;
 1023            }
 1024        }
 1025
 1026        /// <summary>
 1027        /// Starts encoding an array type.
 1028        /// Returns a pair of encoders that must be used in the order they appear in the parameter list.
 1029        /// </summary>
 1030        /// <param name="elementType">Use first, to encode the type of the element.</param>
 1031        /// <param name="arrayShape">Use second, to encode the shape of the array.</param>
 1032        public void Array(out SignatureTypeEncoder elementType, out ArrayShapeEncoder arrayShape)
 1033        {
 1034            Builder.WriteByte((byte)SignatureTypeCode.Array);
 1035            elementType = this;
 1036            arrayShape = new ArrayShapeEncoder(Builder);
 1037        }
 1038
 1039        /// <summary>
 1040        /// Encodes an array type.
 1041        /// </summary>
 1042        /// <param name="elementType">Called first, to encode the type of the element.</param>
 1043        /// <param name="arrayShape">Called second, to encode the shape of the array.</param>
 1044        /// <exception cref="ArgumentNullException"><paramref name="elementType"/> or <paramref name="arrayShape"/> is n
 1045        public void Array(Action<SignatureTypeEncoder> elementType, Action<ArrayShapeEncoder> arrayShape)
 1046        {
 1047            if (elementType is null)
 1048            {
 1049                Throw.ArgumentNull(nameof(elementType));
 1050            }
 1051            if (arrayShape is null)
 1052            {
 1053                Throw.ArgumentNull(nameof(arrayShape));
 1054            }
 1055
 1056            SignatureTypeEncoder elementTypeEncoder;
 1057            ArrayShapeEncoder arrayShapeEncoder;
 1058            Array(out elementTypeEncoder, out arrayShapeEncoder);
 1059            elementType(elementTypeEncoder);
 1060            arrayShape(arrayShapeEncoder);
 1061        }
 1062
 1063        /// <summary>
 1064        /// Encodes a reference to a type.
 1065        /// </summary>
 1066        /// <param name="type"><see cref="TypeDefinitionHandle"/> or <see cref="TypeReferenceHandle"/>.</param>
 1067        /// <param name="isValueType">True to mark the type as value type, false to mark it as a reference type in the s
 1068        /// <exception cref="ArgumentException"><paramref name="type"/> doesn't have the expected handle kind.</exceptio
 1069        public void Type(EntityHandle type, bool isValueType)
 1070        {
 1071            // Get the coded index before we start writing anything (might throw argument exception):
 1072            // Note: We don't allow TypeSpec as per https://github.com/dotnet/runtime/blob/main/src/libraries/System.Ref
 1073            int codedIndex = CodedIndex.TypeDefOrRef(type);
 1074
 1075            ClassOrValue(isValueType);
 1076            Builder.WriteCompressedInteger(codedIndex);
 1077        }
 1078
 1079        /// <summary>
 1080        /// Starts encoding a function pointer signature.
 1081        /// </summary>
 1082        /// <param name="convention">Calling convention.</param>
 1083        /// <param name="attributes">Function pointer attributes.</param>
 1084        /// <param name="genericParameterCount">Generic parameter count.</param>
 1085        /// <exception cref="ArgumentException"><paramref name="attributes"/> is invalid.</exception>
 1086        /// <exception cref="ArgumentOutOfRangeException"><paramref name="genericParameterCount"/> is not in range [0, 0
 1087        public MethodSignatureEncoder FunctionPointer(
 1088            SignatureCallingConvention convention = SignatureCallingConvention.Default,
 1089            FunctionPointerAttributes attributes = FunctionPointerAttributes.None,
 1090            int genericParameterCount = 0)
 1091        {
 1092            // Spec:
 1093            // The EXPLICITTHIS (0x40) bit can be set only in signatures for function pointers.
 1094            // If EXPLICITTHIS (0x40) in the signature is set, then HASTHIS (0x20) shall also be set.
 1095
 1096            if (attributes != FunctionPointerAttributes.None &&
 1097                attributes != FunctionPointerAttributes.HasThis &&
 1098                attributes != FunctionPointerAttributes.HasExplicitThis)
 1099            {
 1100                throw new ArgumentException(SR.InvalidSignature, nameof(attributes));
 1101            }
 1102
 1103            if (unchecked((uint)genericParameterCount) > ushort.MaxValue)
 1104            {
 1105                Throw.ArgumentOutOfRange(nameof(genericParameterCount));
 1106            }
 1107
 1108            Builder.WriteByte((byte)SignatureTypeCode.FunctionPointer);
 1109            Builder.WriteByte(new SignatureHeader(SignatureKind.Method, convention, (SignatureAttributes)attributes).Raw
 1110
 1111            if (genericParameterCount != 0)
 1112            {
 1113                Builder.WriteCompressedInteger(genericParameterCount);
 1114            }
 1115
 1116            return new MethodSignatureEncoder(Builder, hasVarArgs: convention == SignatureCallingConvention.VarArgs);
 1117        }
 1118
 1119        /// <summary>
 1120        /// Starts encoding a generic instantiation signature.
 1121        /// </summary>
 1122        /// <param name="genericType"><see cref="TypeDefinitionHandle"/> or <see cref="TypeReferenceHandle"/>.</param>
 1123        /// <param name="genericArgumentCount">Generic argument count.</param>
 1124        /// <param name="isValueType">True to mark the type as value type, false to mark it as a reference type in the s
 1125        /// <exception cref="ArgumentException"><paramref name="genericType"/> doesn't have the expected handle kind.</e
 1126        /// <exception cref="ArgumentOutOfRangeException"><paramref name="genericArgumentCount"/> is not in range [1, 0x
 1127        public GenericTypeArgumentsEncoder GenericInstantiation(EntityHandle genericType, int genericArgumentCount, bool
 1128        {
 1129            if (unchecked((uint)(genericArgumentCount - 1)) > ushort.MaxValue - 1)
 1130            {
 1131                Throw.ArgumentOutOfRange(nameof(genericArgumentCount));
 1132            }
 1133
 1134            // Get the coded index before we start writing anything (might throw argument exception):
 1135            // Note: We don't allow TypeSpec as per https://github.com/dotnet/runtime/blob/main/src/libraries/System.Ref
 1136            int codedIndex = CodedIndex.TypeDefOrRef(genericType);
 1137
 1138            Builder.WriteByte((byte)SignatureTypeCode.GenericTypeInstance);
 1139            ClassOrValue(isValueType);
 1140            Builder.WriteCompressedInteger(codedIndex);
 1141            Builder.WriteCompressedInteger(genericArgumentCount);
 1142            return new GenericTypeArgumentsEncoder(Builder);
 1143        }
 1144
 1145        /// <summary>
 1146        /// Encodes a reference to type parameter of a containing generic method.
 1147        /// </summary>
 1148        /// <param name="parameterIndex">Parameter index.</param>
 1149        /// <exception cref="ArgumentOutOfRangeException"><paramref name="parameterIndex"/> is not in range [0, 0xffff].
 1150        public void GenericMethodTypeParameter(int parameterIndex)
 1151        {
 1152            if (unchecked((uint)parameterIndex) > ushort.MaxValue)
 1153            {
 1154                Throw.ArgumentOutOfRange(nameof(parameterIndex));
 1155            }
 1156
 1157            Builder.WriteByte((byte)SignatureTypeCode.GenericMethodParameter);
 1158            Builder.WriteCompressedInteger(parameterIndex);
 1159        }
 1160
 1161        /// <summary>
 1162        /// Encodes a reference to type parameter of a containing generic type.
 1163        /// </summary>
 1164        /// <param name="parameterIndex">Parameter index.</param>
 1165        /// <exception cref="ArgumentOutOfRangeException"><paramref name="parameterIndex"/> is not in range [0, 0xffff].
 1166        public void GenericTypeParameter(int parameterIndex)
 1167        {
 1168            if (unchecked((uint)parameterIndex) > ushort.MaxValue)
 1169            {
 1170                Throw.ArgumentOutOfRange(nameof(parameterIndex));
 1171            }
 1172
 1173            Builder.WriteByte((byte)SignatureTypeCode.GenericTypeParameter);
 1174            Builder.WriteCompressedInteger(parameterIndex);
 1175        }
 1176
 1177        /// <summary>
 1178        /// Starts encoding a pointer signature.
 1179        /// </summary>
 1180        public SignatureTypeEncoder Pointer()
 1181        {
 1182            Builder.WriteByte((byte)SignatureTypeCode.Pointer);
 1183            return this;
 1184        }
 1185
 1186        /// <summary>
 1187        /// Encodes <code>void*</code>.
 1188        /// </summary>
 1189        public void VoidPointer()
 1190        {
 1191            Builder.WriteByte((byte)SignatureTypeCode.Pointer);
 1192            Builder.WriteByte((byte)SignatureTypeCode.Void);
 1193        }
 1194
 1195        /// <summary>
 1196        /// Starts encoding an SZ array (vector) signature.
 1197        /// </summary>
 1198        public SignatureTypeEncoder SZArray()
 1199        {
 1200            Builder.WriteByte((byte)SignatureTypeCode.SZArray);
 1201            return this;
 1202        }
 1203
 1204        /// <summary>
 1205        /// Starts encoding a signature of a type with custom modifiers.
 1206        /// </summary>
 1207        public CustomModifiersEncoder CustomModifiers()
 1208        {
 1209            return new CustomModifiersEncoder(Builder);
 1210        }
 1211    }
 1212
 1213    public readonly struct CustomModifiersEncoder
 1214    {
 1215        public BlobBuilder Builder { get; }
 1216
 1217        public CustomModifiersEncoder(BlobBuilder builder)
 1218        {
 1219            Builder = builder;
 1220        }
 1221
 1222        /// <summary>
 1223        /// Encodes a custom modifier.
 1224        /// </summary>
 1225        /// <param name="type"><see cref="TypeDefinitionHandle"/>, <see cref="TypeReferenceHandle"/> or <see cref="TypeS
 1226        /// <param name="isOptional">Is optional modifier.</param>
 1227        /// <returns>Encoder of subsequent modifiers.</returns>
 1228        /// <exception cref="ArgumentException"><paramref name="type"/> is nil or of an unexpected kind.</exception>
 1229        public CustomModifiersEncoder AddModifier(EntityHandle type, bool isOptional)
 1230        {
 1231            if (type.IsNil)
 1232            {
 1233                Throw.InvalidArgument_Handle(nameof(type));
 1234            }
 1235
 1236            if (isOptional)
 1237            {
 1238                Builder.WriteByte((byte)SignatureTypeCode.OptionalModifier);
 1239            }
 1240            else
 1241            {
 1242                Builder.WriteByte((byte)SignatureTypeCode.RequiredModifier);
 1243            }
 1244
 1245            Builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(type));
 1246            return this;
 1247        }
 1248    }
 1249
 1250    public readonly struct ArrayShapeEncoder
 1251    {
 1252        public BlobBuilder Builder { get; }
 1253
 1254        public ArrayShapeEncoder(BlobBuilder builder)
 1255        {
 1256            Builder = builder;
 1257        }
 1258
 1259        /// <summary>
 1260        /// Encodes array shape.
 1261        /// </summary>
 1262        /// <param name="rank">The number of dimensions in the array (shall be 1 or more).</param>
 1263        /// <param name="sizes">
 1264        /// Dimension sizes. The array may be shorter than <paramref name="rank"/> but not longer.
 1265        /// </param>
 1266        /// <param name="lowerBounds">
 1267        /// Dimension lower bounds, or <c>default(<see cref="ImmutableArray{Int32}"/>)</c> to set all <paramref name="ra
 1268        /// The array may be shorter than <paramref name="rank"/> but not longer.
 1269        /// </param>
 1270        /// <exception cref="ArgumentOutOfRangeException">
 1271        /// <paramref name="rank"/> is outside of range [1, 0xffff],
 1272        /// smaller than <paramref name="sizes"/>.Length, or
 1273        /// smaller than <paramref name="lowerBounds"/>.Length.
 1274        /// </exception>
 1275        /// <exception cref="ArgumentNullException"><paramref name="sizes"/> is null.</exception>
 1276        public void Shape(int rank, ImmutableArray<int> sizes, ImmutableArray<int> lowerBounds)
 1277        {
 1278            // The specification doesn't impose a limit on the max number of array dimensions.
 1279            // The CLR supports <64. More than 0xffff is causing crashes in various tools (ildasm).
 1280            if (unchecked((uint)(rank - 1)) > ushort.MaxValue - 1)
 1281            {
 1282                Throw.ArgumentOutOfRange(nameof(rank));
 1283            }
 1284
 1285            if (sizes.IsDefault)
 1286            {
 1287                Throw.ArgumentNull(nameof(sizes));
 1288            }
 1289
 1290            // rank
 1291            Builder.WriteCompressedInteger(rank);
 1292
 1293            // sizes
 1294            if (sizes.Length > rank)
 1295            {
 1296                Throw.ArgumentOutOfRange(nameof(rank));
 1297            }
 1298
 1299            Builder.WriteCompressedInteger(sizes.Length);
 1300            foreach (int size in sizes)
 1301            {
 1302                Builder.WriteCompressedInteger(size);
 1303            }
 1304
 1305            // lower bounds
 1306            if (lowerBounds.IsDefault) // TODO: remove -- update Roslyn
 1307            {
 1308                Builder.WriteCompressedInteger(rank);
 1309                for (int i = 0; i < rank; i++)
 1310                {
 1311                    Builder.WriteCompressedSignedInteger(0);
 1312                }
 1313            }
 1314            else
 1315            {
 1316                if (lowerBounds.Length > rank)
 1317                {
 1318                    Throw.ArgumentOutOfRange(nameof(rank));
 1319                }
 1320
 1321                Builder.WriteCompressedInteger(lowerBounds.Length);
 1322                foreach (int lowerBound in lowerBounds)
 1323                {
 1324                    Builder.WriteCompressedSignedInteger(lowerBound);
 1325                }
 1326            }
 1327        }
 1328    }
 1329
 1330    public readonly struct ReturnTypeEncoder
 1331    {
 1332        public BlobBuilder Builder { get; }
 1333
 1334        public ReturnTypeEncoder(BlobBuilder builder)
 1335        {
 1336            Builder = builder;
 1337        }
 1338
 1339        public CustomModifiersEncoder CustomModifiers()
 1340        {
 1341            return new CustomModifiersEncoder(Builder);
 1342        }
 1343
 1344        public SignatureTypeEncoder Type(bool isByRef = false)
 1345        {
 1346            if (isByRef)
 1347            {
 1348                Builder.WriteByte((byte)SignatureTypeCode.ByReference);
 1349            }
 1350
 1351            return new SignatureTypeEncoder(Builder);
 1352        }
 1353
 1354        public void TypedReference()
 1355        {
 1356            Builder.WriteByte((byte)SignatureTypeCode.TypedReference);
 1357        }
 1358
 1359        public void Void()
 1360        {
 1361            Builder.WriteByte((byte)SignatureTypeCode.Void);
 1362        }
 1363    }
 1364
 1365    public readonly struct ParametersEncoder
 1366    {
 1367        public BlobBuilder Builder { get; }
 1368        public bool HasVarArgs { get; }
 1369
 1370        public ParametersEncoder(BlobBuilder builder, bool hasVarArgs = false)
 1371        {
 1372            Builder = builder;
 1373            HasVarArgs = hasVarArgs;
 1374        }
 1375
 1376        public ParameterTypeEncoder AddParameter()
 1377        {
 1378            return new ParameterTypeEncoder(Builder);
 1379        }
 1380
 1381        public ParametersEncoder StartVarArgs()
 1382        {
 1383            if (!HasVarArgs)
 1384            {
 1385                Throw.SignatureNotVarArg();
 1386            }
 1387
 1388            Builder.WriteByte((byte)SignatureTypeCode.Sentinel);
 1389            return new ParametersEncoder(Builder, hasVarArgs: false);
 1390        }
 1391    }
 1392}
 1393