<commit_before>﻿// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Globalization;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Host.Listeners;
using Microsoft.Azure.WebJobs.Host.Protocols;
using Microsoft.Azure.WebJobs.Host.Triggers;

namespace Microsoft.Azure.WebJobs.Host.Bindings
{
    /// <summary>
    /// Helpers for creating bindings to common patterns such as Messaging or Streams.
    /// This will add additional adapters to connect the user's parameter type to an IAsyncCollector. 
    /// It will also see <see cref="IConverterManager"/> to convert 
    /// from the user's type to the underlying IAsyncCollector's message type.
    /// For example, for messaging patterns, if the user is a ICollector, this will add an adapter that implements ICollector and calls IAsyncCollector.  
    /// </summary>
    public static class BindingFactory
    {
        /// <summary>
        /// Bind a  parameter to an IAsyncCollector. Use this for things that have discrete output items (like sending messages or writing table rows)
        /// This will add additional adapters to connect the user's parameter type to an IAsyncCollector. 
        /// </summary>
        /// <typeparam name="TMessage"></typeparam>
        /// <typeparam name="TTriggerValue"></typeparam>
        /// <param name="bindingStrategy">a strategy object that describes how to do the binding</param>
        /// <param name="parameter">the user's parameter being bound to</param>
        /// <param name="converterManager">the converter manager, used to convert between the user parameter's type and the underlying native types used by the trigger strategy</param>
        /// <param name="createListener">a function to create the underlying listener for this parameter</param>
        /// <returns></returns>
        public static ITriggerBinding GetTriggerBinding<TMessage, TTriggerValue>(
            ITriggerBindingStrategy<TMessage, TTriggerValue> bindingStrategy,
            ParameterInfo parameter,
            IConverterManager converterManager,
            Func<ListenerFactoryContext, bool, Task<IListener>> createListener)
        {
            if (bindingStrategy == null)
            {
                throw new ArgumentNullException("bindingStrategy");
            }
            if (parameter == null)
            {
                throw new ArgumentNullException("parameter");
            }

            bool singleDispatch;
            var argumentBinding = BindingFactory.GetTriggerArgumentBinding(bindingStrategy, parameter, converterManager, out singleDispatch);

            var parameterDescriptor = new ParameterDescriptor
            {
                Name = parameter.Name,
                DisplayHints = new ParameterDisplayHints
                {
                    Description = singleDispatch ? "message" : "messages"
                }
            };

            ITriggerBinding binding = new StrategyTriggerBinding<TMessage, TTriggerValue>(
                bindingStrategy, argumentBinding, createListener, parameterDescriptor, singleDispatch);

            return binding;
        }

        // Bind a trigger argument to various parameter types. 
        // Handles either T or T[], 
        private static ITriggerDataArgumentBinding<TTriggerValue> GetTriggerArgumentBinding<TMessage, TTriggerValue>(
            ITriggerBindingStrategy<TMessage, TTriggerValue> bindingStrategy,
            ParameterInfo parameter,
            IConverterManager converterManager,
            out bool singleDispatch)
        {
            ITriggerDataArgumentBinding<TTriggerValue> argumentBinding = null;
            if (parameter.ParameterType.IsArray)
            {
                // dispatch the entire batch in a single call. 
                singleDispatch = false;

                var elementType = parameter.ParameterType.GetElementType();

                var innerArgumentBinding = GetTriggerArgumentElementBinding<TMessage, TTriggerValue>(elementType, bindingStrategy, converterManager);

                argumentBinding = new ArrayTriggerArgumentBinding<TMessage, TTriggerValue>(bindingStrategy, innerArgumentBinding, converterManager);

                return argumentBinding;
            }
            else
            {
                // Dispatch each item one at a time
                singleDispatch = true;

                var elementType = parameter.ParameterType;
                argumentBinding = GetTriggerArgumentElementBinding<TMessage, TTriggerValue>(elementType, bindingStrategy, converterManager);
                return argumentBinding;
            }
        }

        // Bind a T. 
        private static SimpleTriggerArgumentBinding<TMessage, TTriggerValue> GetTriggerArgumentElementBinding<TMessage, TTriggerValue>(
            Type elementType,
            ITriggerBindingStrategy<TMessage, TTriggerValue> bindingStrategy,
            IConverterManager converterManager)
        {
            if (elementType == typeof(TMessage))
            {
                return new SimpleTriggerArgumentBinding<TMessage, TTriggerValue>(bindingStrategy, converterManager);
            }
            if (elementType == typeof(string))
            {
                return new StringTriggerArgumentBinding<TMessage, TTriggerValue>(bindingStrategy, converterManager);
            }
            else
            {
                // Default, assume a Poco
                return new PocoTriggerArgumentBinding<TMessage, TTriggerValue>(bindingStrategy, converterManager, elementType);
            }
        }

        /// <summary>
        /// Creates a binding that binds to an <see cref="IAsyncCollector{T}"/> with the specified argument type. Allows for a binding
        /// to be generated for any POCO type.
        /// </summary>
        /// <param name="parameter">The ParameterInfo for the binding</param>
        /// <param name="collectorGenericType">The generic type that must implement <see cref="IAsyncCollector{T}"/> and have a public constructor with at most one parameter.</param>
        /// <param name="collectorGenericArgumentType">The generic argument type for the <see cref="IAsyncCollector{T}"/></param>
        /// <param name="converterManager">A converter manager to pass along.</param>        
        /// <param name="invokeStringBinder">A <see cref="Func{T, TContext}"/> that returns the TContext to be used by the <see cref="IAsyncCollector{T}"/></param>
        /// <returns></returns>
        public static IBinding BindGenericCollector<TContext>(ParameterInfo parameter, Type collectorGenericType, Type collectorGenericArgumentType,
            IConverterManager converterManager, Func<string, TContext> invokeStringBinder)
        {
            if (collectorGenericType == null)
            {
                throw new ArgumentNullException(nameof(collectorGenericType));
            }
            if (!collectorGenericType.IsGenericTypeDefinition)
            {
                throw new ArgumentException("The parameter 'collectorGenericType' must be a generic type definition.");<commit_msg>Fixing build<commit_after>﻿// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Globalization;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Host.Listeners;
using Microsoft.Azure.WebJobs.Host.Protocols;
using Microsoft.Azure.WebJobs.Host.Triggers;

namespace Microsoft.Azure.WebJobs.Host.Bindings
{
    /// <summary>
    /// Helpers for creating bindings to common patterns such as Messaging or Streams.
    /// This will add additional adapters to connect the user's parameter type to an IAsyncCollector. 
    /// It will also see <see cref="IConverterManager"/> to convert 
    /// from the user's type to the underlying IAsyncCollector's message type.
    /// For example, for messaging patterns, if the user is a ICollector, this will add an adapter that implements ICollector and calls IAsyncCollector.  
    /// </summary>
    public static class BindingFactory
    {
        /// <summary>
        /// Bind a  parameter to an IAsyncCollector. Use this for things that have discrete output items (like sending messages or writing table rows)
        /// This will add additional adapters to connect the user's parameter type to an IAsyncCollector. 
        /// </summary>
        /// <typeparam name="TMessage"></typeparam>
        /// <typeparam name="TTriggerValue"></typeparam>
        /// <param name="bindingStrategy">a strategy object that describes how to do the binding</param>
        /// <param name="parameter">the user's parameter being bound to</param>
        /// <param name="converterManager">the converter manager, used to convert between the user parameter's type and the underlying native types used by the trigger strategy</param>
        /// <param name="createListener">a function to create the underlying listener for this parameter</param>
        /// <returns></returns>
        public static ITriggerBinding GetTriggerBinding<TMessage, TTriggerValue>(
            ITriggerBindingStrategy<TMessage, TTriggerValue> bindingStrategy,
            ParameterInfo parameter,
            IConverterManager converterManager,
            Func<ListenerFactoryContext, bool, Task<IListener>> createListener)
        {
            if (bindingStrategy == null)
            {
                throw new ArgumentNullException("bindingStrategy");
            }
            if (parameter == null)
            {
                throw new ArgumentNullException("parameter");
            }

            bool singleDispatch;
            var argumentBinding = BindingFactory.GetTriggerArgumentBinding(bindingStrategy, parameter, converterManager, out singleDispatch);

            var parameterDescriptor = new ParameterDescriptor
            {
                Name = parameter.Name,
                DisplayHints = new ParameterDisplayHints
                {
                    Description = singleDispatch ? "message" : "messages"
                }
            };

            ITriggerBinding binding = new StrategyTriggerBinding<TMessage, TTriggerValue>(
                bindingStrategy, argumentBinding, createListener, parameterDescriptor, singleDispatch);

            return binding;
        }

        // Bind a trigger argument to various parameter types. 
        // Handles either T or T[], 
        private static ITriggerDataArgumentBinding<TTriggerValue> GetTriggerArgumentBinding<TMessage, TTriggerValue>(
            ITriggerBindingStrategy<TMessage, TTriggerValue> bindingStrategy,
            ParameterInfo parameter,
            IConverterManager converterManager,
            out bool singleDispatch)
        {
            ITriggerDataArgumentBinding<TTriggerValue> argumentBinding = null;
            if (parameter.ParameterType.IsArray)
            {
                // dispatch the entire batch in a single call. 
                singleDispatch = false;

                var elementType = parameter.ParameterType.GetElementType();

                var innerArgumentBinding = GetTriggerArgumentElementBinding<TMessage, TTriggerValue>(elementType, bindingStrategy, converterManager);

                argumentBinding = new ArrayTriggerArgumentBinding<TMessage, TTriggerValue>(bindingStrategy, innerArgumentBinding, converterManager);

                return argumentBinding;
            }
            else
            {
                // Dispatch each item one at a time
                singleDispatch = true;

                var elementType = parameter.ParameterType;
                argumentBinding = GetTriggerArgumentElementBinding<TMessage, TTriggerValue>(elementType, bindingStrategy, converterManager);
                return argumentBinding;
            }
        }

        // Bind a T. 
        private static SimpleTriggerArgumentBinding<TMessage, TTriggerValue> GetTriggerArgumentElementBinding<TMessage, TTriggerValue>(
            Type elementType,
            ITriggerBindingStrategy<TMessage, TTriggerValue> bindingStrategy,
            IConverterManager converterManager)
        {
            if (elementType == typeof(TMessage))
            {
                return new SimpleTriggerArgumentBinding<TMessage, TTriggerValue>(bindingStrategy, converterManager);
            }
            if (elementType == typeof(string))
            {
                return new StringTriggerArgumentBinding<TMessage, TTriggerValue>(bindingStrategy, converterManager);
            }
            else
            {
                // Default, assume a Poco
                return new PocoTriggerArgumentBinding<TMessage, TTriggerValue>(bindingStrategy, converterManager, elementType);
            }
        }

        /// <summary>
        /// Creates a binding that binds to an <see cref="IAsyncCollector{T}"/> with the specified argument type. Allows for a binding
        /// to be generated for any POCO type.
        /// </summary>
        /// <param name="parameter">The ParameterInfo for the binding</param>
        /// <param name="collectorGenericType">The generic type that must implement <see cref="IAsyncCollector{T}"/> and have a public constructor with at most one parameter.</param>
        /// <param name="collectorGenericArgumentType">The generic argument type for the <see cref="IAsyncCollector{T}"/></param>
        /// <param name="converterManager">A converter manager to pass along.</param>        
        /// <param name="invokeStringBinder">A <see cref="Func{T, TContext}"/> that returns the TContext to be used by the <see cref="IAsyncCollector{T}"/></param>
        /// <returns></returns>
        public static IBinding BindGenericCollector<TContext>(ParameterInfo parameter, Type collectorGenericType, Type collectorGenericArgumentType,
            IConverterManager converterManager, Func<string, TContext> invokeStringBinder)
        {
            if (collectorGenericType == null)
            {
                throw new ArgumentNullException("collectorGenericType");
            }
            if (!collectorGenericType.IsGenericTypeDefinition)
            {
                throw new ArgumentException("The parameter 'collectorGenericType' must be a generic type definition.");
{'fraction_non_alphanumeric': 0.07892364241625632, 'fraction_numerical': 0.0, 'mean_word_length': 2.4881470730527333, 'pattern_counts': {'":': 0, '<': 119, '<?xml version=': 0, '>': 119, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2979445', 'n_tokens_mistral': 3294, 'n_tokens_neox': 3165, 'n_words': 1014}