FSharpUtils
                    class FSharpUtils
                
                using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Newtonsoft.Json.Utilities
{
    [System.Runtime.CompilerServices.NullableContext(1)]
    [System.Runtime.CompilerServices.Nullable(0)]
    internal class FSharpUtils
    {
        private static readonly object Lock = new object();
        [System.Runtime.CompilerServices.Nullable(2)]
        private static FSharpUtils _instance;
        private MethodInfo _ofSeq;
        private Type _mapType;
        public const string FSharpSetTypeName = "FSharpSet`1";
        public const string FSharpListTypeName = "FSharpList`1";
        public const string FSharpMapTypeName = "FSharpMap`2";
        public static FSharpUtils Instance => _instance;
        public Assembly FSharpCoreAssembly { get; set; }
        [System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        [field: System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        public MethodCall<object, object> IsUnion {
            [return: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                2,
                1
            })]
            get;
            [param: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                2,
                1
            })]
            private set;
        }
        [System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        [field: System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        public MethodCall<object, object> GetUnionCases {
            [return: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                2,
                1
            })]
            get;
            [param: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                2,
                1
            })]
            private set;
        }
        [System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        [field: System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        public MethodCall<object, object> PreComputeUnionTagReader {
            [return: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                2,
                1
            })]
            get;
            [param: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                2,
                1
            })]
            private set;
        }
        [System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        [field: System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        public MethodCall<object, object> PreComputeUnionReader {
            [return: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                2,
                1
            })]
            get;
            [param: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                2,
                1
            })]
            private set;
        }
        [System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        [field: System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        public MethodCall<object, object> PreComputeUnionConstructor {
            [return: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                2,
                1
            })]
            get;
            [param: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                2,
                1
            })]
            private set;
        }
        public Func<object, object> GetUnionCaseInfoDeclaringType { get; set; }
        public Func<object, object> GetUnionCaseInfoName { get; set; }
        public Func<object, object> GetUnionCaseInfoTag { get; set; }
        [System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            1,
            2
        })]
        [field: System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            1,
            2
        })]
        public MethodCall<object, object> GetUnionCaseInfoFields {
            [return: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                1,
                2
            })]
            get;
            [param: System.Runtime.CompilerServices.Nullable(new byte[] {
                1,
                1,
                2
            })]
            private set;
        }
        private FSharpUtils(Assembly fsharpCoreAssembly)
        {
            FSharpCoreAssembly = fsharpCoreAssembly;
            Type type = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpType");
            MethodInfo methodWithNonPublicFallback = GetMethodWithNonPublicFallback(type, "IsUnion", BindingFlags.Static | BindingFlags.Public);
            IsUnion = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(methodWithNonPublicFallback);
            MethodInfo methodWithNonPublicFallback2 = GetMethodWithNonPublicFallback(type, "GetUnionCases", BindingFlags.Static | BindingFlags.Public);
            GetUnionCases = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(methodWithNonPublicFallback2);
            Type type2 = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpValue");
            PreComputeUnionTagReader = CreateFSharpFuncCall(type2, "PreComputeUnionTagReader");
            PreComputeUnionReader = CreateFSharpFuncCall(type2, "PreComputeUnionReader");
            PreComputeUnionConstructor = CreateFSharpFuncCall(type2, "PreComputeUnionConstructor");
            Type type3 = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.UnionCaseInfo");
            GetUnionCaseInfoName = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(TypeExtensions.GetProperty(type3, "Name"));
            GetUnionCaseInfoTag = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(TypeExtensions.GetProperty(type3, "Tag"));
            GetUnionCaseInfoDeclaringType = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(TypeExtensions.GetProperty(type3, "DeclaringType"));
            GetUnionCaseInfoFields = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(TypeExtensions.GetMethod(type3, "GetFields"));
            Type type4 = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule");
            _ofSeq = TypeExtensions.GetMethod(type4, "OfSeq");
            _mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2");
        }
        public static void EnsureInitialized(Assembly fsharpCoreAssembly)
        {
            if (_instance == null) {
                lock (Lock) {
                    if (_instance == null)
                        _instance = new FSharpUtils(fsharpCoreAssembly);
                }
            }
        }
        private static MethodInfo GetMethodWithNonPublicFallback(Type type, string methodName, BindingFlags bindingFlags)
        {
            MethodInfo method = type.GetMethod(methodName, bindingFlags);
            if ((object)method == null && (bindingFlags & BindingFlags.NonPublic) != BindingFlags.NonPublic)
                method = type.GetMethod(methodName, bindingFlags | BindingFlags.NonPublic);
            return method;
        }
        [return: System.Runtime.CompilerServices.Nullable(new byte[] {
            1,
            2,
            1
        })]
        private static MethodCall<object, object> CreateFSharpFuncCall(Type type, string methodName)
        {
            MethodInfo methodWithNonPublicFallback = GetMethodWithNonPublicFallback(type, methodName, BindingFlags.Static | BindingFlags.Public);
            MethodInfo method = methodWithNonPublicFallback.ReturnType.GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public);
            MethodCall<object, object> call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(methodWithNonPublicFallback);
            MethodCall<object, object> invoke = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(method);
            return (object target, object[] args) => new FSharpFunction(call(target, args), invoke);
        }
        public ObjectConstructor<object> CreateSeq(Type t)
        {
            MethodInfo method = _ofSeq.MakeGenericMethod(t);
            return JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(method);
        }
        public ObjectConstructor<object> CreateMap(Type keyType, Type valueType)
        {
            return (ObjectConstructor<object>)typeof(FSharpUtils).GetMethod("BuildMapCreator").MakeGenericMethod(keyType, valueType).Invoke(this, null);
        }
        [System.Runtime.CompilerServices.NullableContext(2)]
        [return: System.Runtime.CompilerServices.Nullable(1)]
        public ObjectConstructor<object> BuildMapCreator<TKey, TValue>()
        {
            ConstructorInfo constructor = TypeExtensions.GetConstructor(_mapType.MakeGenericType(typeof(TKey), typeof(TValue)), new Type[1] {
                typeof(IEnumerable<Tuple<TKey, TValue>>)
            });
            ObjectConstructor<object> ctorDelegate = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructor);
            return delegate(object[] args) {
                IEnumerable<Tuple<TKey, TValue>> enumerable = Enumerable.Select<KeyValuePair<TKey, TValue>, Tuple<TKey, TValue>>((IEnumerable<KeyValuePair<TKey, TValue>>)args[0], (Func<KeyValuePair<TKey, TValue>, Tuple<TKey, TValue>>)((KeyValuePair<TKey, TValue> kv) => new Tuple<TKey, TValue>(kv.Key, kv.Value)));
                return ctorDelegate(new object[1] {
                    enumerable
                });
            };
        }
    }
}