File: Marshalling\BlittableMarshaller.cs
Web Access
Project: Microsoft.Interop.SourceGeneration.csproj (Microsoft.Interop.SourceGeneration)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.Interop
{
    public sealed class BlittableMarshaller : IUnboundMarshallingGenerator
    {
        public ManagedTypeInfo AsNativeType(TypePositionInfo info)
        {
            return info.ManagedType;
        }

        public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info)
        {
            return info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType;
        }

        public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context)
        {
            if (!info.IsByRef)
            {
                return ValueBoundaryBehavior.ManagedIdentifier;
            }
            else if (context.SingleFrameSpansNativeContext && !context.IsInStubReturnPosition(info))
            {
                return ValueBoundaryBehavior.NativeIdentifier;
            }
            return ValueBoundaryBehavior.AddressOfNativeIdentifier;
        }

        public void Generate(IndentedTextWriter writer, TypePositionInfo info, StubCodeContext codeContext, StubIdentifierContext context)
        {
            if (!info.IsByRef || codeContext.IsInStubReturnPosition(info))
                return;

            (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);

            if (codeContext.SingleFrameSpansNativeContext)
            {
                if (context.CurrentStage == StubIdentifierContext.Stage.Pin)
                {
                    writer.WriteLine($"fixed ({AsNativeType(info).FullTypeName}* {nativeIdentifier} = &{managedIdentifier})");
                }
                return;
            }

            MarshalDirection direction = MarshallerHelpers.GetMarshalDirection(info, codeContext);

            switch (context.CurrentStage)
            {
                case StubIdentifierContext.Stage.Setup:
                    break;
                case StubIdentifierContext.Stage.Marshal:
                    if (direction is MarshalDirection.ManagedToUnmanaged or MarshalDirection.Bidirectional && info.IsByRef)
                    {
                        writer.WriteLine($"{nativeIdentifier} = {managedIdentifier};");
                    }

                    break;
                case StubIdentifierContext.Stage.Unmarshal:
                    if (direction is MarshalDirection.UnmanagedToManaged or MarshalDirection.Bidirectional && info.IsByRef)
                    {
                        writer.WriteLine($"{managedIdentifier} = {nativeIdentifier};");
                    }
                    break;
                default:
                    break;
            }
        }

        public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context)
        {
            return info.IsByRef && !context.IsInStubReturnPosition(info) && !context.SingleFrameSpansNativeContext;
        }

        public ByValueMarshalKindSupport SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, TypePositionInfo info, out GeneratorDiagnostic? diagnostic)
            => ByValueMarshalKindSupportDescriptor.Default.GetSupport(marshalKind, info, out diagnostic);
    }
}