|
| 1 | +// Copyright (c) Microsoft Corporation. |
| 2 | +// Licensed under the MIT License. |
| 3 | + |
| 4 | +using System.Diagnostics.CodeAnalysis; |
| 5 | +using Microsoft.CodeAnalysis; |
| 6 | + |
| 7 | +namespace Microsoft.Macios.Transformer.Attributes; |
| 8 | + |
| 9 | +readonly struct AsyncData : IEquatable<AsyncData> { |
| 10 | + /// <summary> |
| 11 | + /// Diff the constructor used in the bindings. |
| 12 | + /// </summary> |
| 13 | + internal enum ConstructorType { |
| 14 | + ResultType, |
| 15 | + MethodName |
| 16 | + } |
| 17 | + |
| 18 | + public string? ResultType { get; init; } // this in the attr is a type, but we do not care for the transformation |
| 19 | + public string? MethodName { get; init; } |
| 20 | + public string? ResultTypeName { get; init; } |
| 21 | + public string? PostNonResultSnippet { get; init; } |
| 22 | + |
| 23 | + public AsyncData () { } |
| 24 | + |
| 25 | + public AsyncData (string resultType, ConstructorType constructorType) |
| 26 | + { |
| 27 | + if (constructorType == ConstructorType.ResultType) |
| 28 | + ResultType = resultType; |
| 29 | + else |
| 30 | + MethodName = resultType; |
| 31 | + } |
| 32 | + |
| 33 | + public static bool TryParse (AttributeData attributeData, |
| 34 | + [NotNullWhen (true)] out AsyncData? data) |
| 35 | + { |
| 36 | + data = null; |
| 37 | + var count = attributeData.ConstructorArguments.Length; |
| 38 | + ConstructorType constructorType = ConstructorType.MethodName; |
| 39 | + string? resultType = null; |
| 40 | + string? resultTypeName = null; |
| 41 | + string? methodName = null; |
| 42 | + string? postNonResultSnippet = null; |
| 43 | + |
| 44 | + switch (count) { |
| 45 | + case 0: |
| 46 | + break; |
| 47 | + case 1: |
| 48 | + // we have to diff constructors that take a single parameter, either a string or a type |
| 49 | + if (attributeData.ConstructorArguments [0].Value! is string methodNameValue) { |
| 50 | + constructorType = ConstructorType.MethodName; |
| 51 | + methodName = methodNameValue; |
| 52 | + } else { |
| 53 | + constructorType = ConstructorType.ResultType; |
| 54 | + resultType = ((INamedTypeSymbol) attributeData.ConstructorArguments [0].Value!).ToDisplayString (); |
| 55 | + } |
| 56 | + break; |
| 57 | + default: |
| 58 | + // 0 should not be an option.. |
| 59 | + return false; |
| 60 | + } |
| 61 | + |
| 62 | + if (attributeData.NamedArguments.Length == 0) { |
| 63 | + if (constructorType == ConstructorType.ResultType) |
| 64 | + data = new (resultType!, ConstructorType.ResultType); |
| 65 | + else |
| 66 | + data = new (methodName!, ConstructorType.MethodName); |
| 67 | + return true; |
| 68 | + } |
| 69 | + |
| 70 | + foreach (var (argumentName, value) in attributeData.NamedArguments) { |
| 71 | + switch (argumentName) { |
| 72 | + case "ResultType": |
| 73 | + resultType = ((INamedTypeSymbol) value.Value!).ToDisplayString (); |
| 74 | + break; |
| 75 | + case "MethodName": |
| 76 | + methodName = (string) value.Value!; |
| 77 | + break; |
| 78 | + case "ResultTypeName": |
| 79 | + resultTypeName = (string) value.Value!; |
| 80 | + break; |
| 81 | + case "PostNonResultSnippet": |
| 82 | + postNonResultSnippet = (string) value.Value!; |
| 83 | + break; |
| 84 | + default: |
| 85 | + data = null; |
| 86 | + return false; |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + if (count == 0) { |
| 91 | + // use the default constructor and use the init properties |
| 92 | + data = new () { |
| 93 | + ResultType = resultType, |
| 94 | + MethodName = methodName, |
| 95 | + ResultTypeName = resultTypeName, |
| 96 | + PostNonResultSnippet = postNonResultSnippet |
| 97 | + }; |
| 98 | + return true; |
| 99 | + } |
| 100 | + |
| 101 | + switch (constructorType) { |
| 102 | + case ConstructorType.MethodName: |
| 103 | + data = new (methodName!, ConstructorType.MethodName) { |
| 104 | + ResultType = resultType, |
| 105 | + ResultTypeName = resultTypeName, |
| 106 | + PostNonResultSnippet = postNonResultSnippet |
| 107 | + }; |
| 108 | + break; |
| 109 | + case ConstructorType.ResultType: |
| 110 | + data = new (resultType!, ConstructorType.ResultType) { |
| 111 | + MethodName = methodName, |
| 112 | + ResultTypeName = resultTypeName, |
| 113 | + PostNonResultSnippet = postNonResultSnippet |
| 114 | + }; |
| 115 | + break; |
| 116 | + } |
| 117 | + |
| 118 | + return false; |
| 119 | + } |
| 120 | + |
| 121 | + public bool Equals (AsyncData other) |
| 122 | + { |
| 123 | + if (ResultType != other.ResultType) |
| 124 | + return false; |
| 125 | + if (MethodName != other.MethodName) |
| 126 | + return false; |
| 127 | + if (ResultTypeName != other.ResultTypeName) |
| 128 | + return false; |
| 129 | + return PostNonResultSnippet == other.PostNonResultSnippet; |
| 130 | + } |
| 131 | + |
| 132 | + /// <inheritdoc /> |
| 133 | + public override bool Equals (object? obj) |
| 134 | + { |
| 135 | + return obj is AsyncData other && Equals (other); |
| 136 | + } |
| 137 | + |
| 138 | + /// <inheritdoc /> |
| 139 | + public override int GetHashCode () |
| 140 | + => HashCode.Combine (ResultType, MethodName, ResultTypeName, PostNonResultSnippet); |
| 141 | + |
| 142 | + public static bool operator == (AsyncData x, AsyncData y) |
| 143 | + { |
| 144 | + return x.Equals (y); |
| 145 | + } |
| 146 | + |
| 147 | + public static bool operator != (AsyncData x, AsyncData y) |
| 148 | + { |
| 149 | + return !(x == y); |
| 150 | + } |
| 151 | + |
| 152 | + public override string ToString () |
| 153 | + => $"{{ ResultType: '{ResultType ?? "null"}', MethodName: '{MethodName ?? "null"}', ResultTypeName: '{ResultTypeName ?? "null"}', PostNonResultSnippet: '{PostNonResultSnippet ?? "null"}' }}"; |
| 154 | +} |
0 commit comments