private (MessageDescription RequestType, int[] DataIndexes, MessageDescription?HeaderType, int[] HeaderIndexes) GetRequestType()
        {
            if (Method.Parameters.Length == 0)
            {
                return(MessageDescription.Empty(), Array.Empty <int>(), null, Array.Empty <int>());
            }

            var dataParameters       = new List <ITypeSymbol>();
            var dataParameterIndexes = new List <int>();
            var streamingIndex       = -1;

            for (var i = 0; i < Method.Parameters.Length; i++)
            {
                var parameter = Method.Parameters[i];
                if (IsDataParameter(parameter.TypeSymbol))
                {
                    if (SyntaxTools.IsAsyncEnumerable(parameter.TypeSymbol))
                    {
                        streamingIndex = i;
                    }
                    else
                    {
                        dataParameters.Add(parameter.TypeSymbol);
                        dataParameterIndexes.Add(i);
                    }
                }
            }

            if (streamingIndex >= 0)
            {
                var requestType = CreateMessage(Method.Parameters[streamingIndex].TypeSymbol.GenericTypeArguments()[0]);
                MessageDescription?headerType = null;
                if (dataParameters.Count > 0)
                {
                    headerType = CreateMessage(dataParameters.ToArray());
                }

                return(
                    requestType,
                    new[] { streamingIndex },
                    headerType,
                    dataParameterIndexes.ToArray());
            }

            return(
                CreateMessage(dataParameters.ToArray()),
                dataParameterIndexes.ToArray(),
                null,
                Array.Empty <int>());
        }
        private MethodType GetOperationType()
        {
            var returnType = Method.ReturnTypeSymbol;

            if (SyntaxTools.IsTask(Method.ReturnTypeSymbol))
            {
                var args = returnType.GenericTypeArguments();
                returnType = args.IsEmpty ? returnType : args[0];
            }

            var responseIsStreaming = SyntaxTools.IsAsyncEnumerable(returnType) ||
                                      (SyntaxTools.IsValueTuple(returnType) && returnType.GenericTypeArguments().Any(SyntaxTools.IsAsyncEnumerable));

            var requestIsStreaming = Method.Parameters.Select(i => i.TypeSymbol).Any(SyntaxTools.IsAsyncEnumerable);

            if (responseIsStreaming)
            {
                return(requestIsStreaming ? MethodType.DuplexStreaming : MethodType.ServerStreaming);
            }

            return(requestIsStreaming ? MethodType.ClientStreaming : MethodType.Unary);
        }
        private void ValidateSignature()
        {
            if (Method.TypeArguments.Length != 0)
            {
                ThrowInvalidSignature();
            }

            var hasInputStreaming = false;

            for (var i = 0; i < Method.Parameters.Length; i++)
            {
                var parameter = Method.Parameters[i];

                if (parameter.IsOut || parameter.IsRef)
                {
                    ThrowInvalidSignature();
                }

                if (IsDataParameter(parameter.TypeSymbol))
                {
                    if (SyntaxTools.IsAsyncEnumerable(parameter.TypeSymbol))
                    {
                        if (hasInputStreaming)
                        {
                            ThrowInvalidSignature();
                        }

                        hasInputStreaming = true;
                    }
                }
                else if (!IsContextParameter(parameter.TypeSymbol))
                {
                    ThrowInvalidSignature();
                }
            }
        }
        private (MessageDescription ResponseType, int Index, MessageDescription?HeaderType, int[] HeaderIndexes) CreateResponseType(ITypeSymbol returnType)
        {
            if (SyntaxTools.IsVoid(returnType))
            {
                return(MessageDescription.Empty(), 0, null, Array.Empty <int>());
            }

            var responseType = returnType;

            if (SyntaxTools.IsTask(returnType))
            {
                var genericArguments = responseType.GenericTypeArguments();
                if (genericArguments.IsEmpty)
                {
                    return(MessageDescription.Empty(), 0, null, Array.Empty <int>());
                }

                responseType = genericArguments[0];
            }

            if (SyntaxTools.IsValueTuple(responseType) && responseType.GenericTypeArguments().Any(SyntaxTools.IsAsyncEnumerable))
            {
                if (!SyntaxTools.IsTask(returnType))
                {
                    ThrowInvalidSignature("Wrap return type with Task<> or ValueTask<>.");
                }

                var genericArguments = responseType.GenericTypeArguments();
                if (genericArguments.Length == 1)
                {
                    ThrowInvalidSignature("Unwrap return type from ValueTuple<>.");
                }

                var streamIndex   = -1;
                var headerIndexes = new List <int>();
                var headerTypes   = new List <ITypeSymbol>();
                for (var i = 0; i < genericArguments.Length; i++)
                {
                    var genericArgument = genericArguments[i];
                    if (SyntaxTools.IsAsyncEnumerable(genericArgument))
                    {
                        responseType = genericArgument.GenericTypeArguments()[0];
                        if (streamIndex >= 0 || IsContextParameter(responseType) || !IsDataParameter(responseType))
                        {
                            ThrowInvalidSignature();
                        }

                        streamIndex = i;
                    }
                    else if (IsContextParameter(genericArgument) || !IsDataParameter(genericArgument))
                    {
                        ThrowInvalidSignature();
                    }
                    else
                    {
                        headerIndexes.Add(i);
                        headerTypes.Add(genericArgument);
                    }
                }

                return(
                    CreateMessage(responseType),
                    streamIndex,
                    CreateMessage(headerTypes.ToArray()),
                    headerIndexes.ToArray());
            }

            if (SyntaxTools.IsAsyncEnumerable(responseType))
            {
                responseType = responseType.GenericTypeArguments()[0];
            }

            if (IsContextParameter(responseType) || !IsDataParameter(responseType))
            {
                ThrowInvalidSignature();
            }

            return(CreateMessage(responseType), 0, null, Array.Empty <int>());
        }
Exemplo n.º 5
0
        public void IsAsyncEnumerable(Type type, bool expected)
        {
            var symbol = Compilation.GetTypeByMetadataName(type);

            SyntaxTools.IsAsyncEnumerable(symbol).ShouldBe(expected);
        }