public OperationDescription(IMethodSymbol method, string serviceName)
        {
            ServiceName = serviceName;
            Method      = new MethodDescription(method);
            ValidateSignature();

            OperationName = ServiceContract.GetServiceOperationName(method);
            (ResponseType, ResponseTypeIndex, HeaderResponseType, HeaderResponseTypeInput) = CreateResponseType(method.ReturnType);
            (RequestType, RequestTypeInput, HeaderRequestType, HeaderRequestTypeInput)     = GetRequestType();
            OperationType              = GetOperationType();
            ContextInput               = GetContextInput();
            IsAsync                    = SyntaxTools.IsTask(method.ReturnType);
            GrpcMethodName             = "Method" + OperationName;
            GrpcMethodInputHeaderName  = "MethodInputHeader" + OperationName;
            GrpcMethodOutputHeaderName = "MethodOutputHeader" + OperationName;
        }
        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 static bool IsDataParameter(ITypeSymbol type)
 {
     return(!SyntaxTools.IsTask(type) &&
            !IsContextParameter(type) &&
            !SyntaxTools.IsStream(type));
 }
        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>());
        }
Esempio n. 5
0
        public void IsTask(Type type, bool expected)
        {
            var symbol = Compilation.GetTypeByMetadataName(type);

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