Esempio n. 1
0
        private static void TestEnumerableListPatterns(TypeModel model, BasicList candidates, Type iType)
        {
#if WINRT
            TypeInfo iTypeInfo = iType.GetTypeInfo();
            if (iTypeInfo.IsGenericType)
            {
                Type typeDef = iTypeInfo.GetGenericTypeDefinition();
                if (typeDef == typeof(System.Collections.Generic.ICollection <>) || typeDef.GetTypeInfo().FullName == "System.Collections.Concurrent.IProducerConsumerCollection`1")
                {
                    Type[] iTypeArgs = iTypeInfo.GenericTypeArguments;
                    if (!candidates.Contains(iTypeArgs[0]))
                    {
                        candidates.Add(iTypeArgs[0]);
                    }
                }
            }
#elif !NO_GENERICS
            if (iType.IsGenericType)
            {
                Type typeDef = iType.GetGenericTypeDefinition();
                if (typeDef == model.MapType(typeof(System.Collections.Generic.IEnumerable <>)) ||
                    typeDef == model.MapType(typeof(System.Collections.Generic.ICollection <>)) ||
                    typeDef.FullName == "System.Collections.Concurrent.IProducerConsumerCollection`1")
                {
                    Type[] iTypeArgs = iType.GetGenericArguments();
                    if (!candidates.Contains(iTypeArgs[0]))
                    {
                        candidates.Add(iTypeArgs[0]);
                    }
                }
            }
#endif
        }
Esempio n. 2
0
        void CscadeDependents_Member(BasicList list, Type type)
        {
            WireType         defaultWireType;
            IProtoSerializer coreSerializer = this.ValueSerializerBuilder.TryGetSimpleCoreSerializer(BinaryDataFormat.Default, type, out defaultWireType);

            if (coreSerializer == null)
            {
                int index = FindOrAddAuto(type, false, false, false);
                if (index >= 0)
                {
                    var tmp = ((MetaType)_types[index]).GetSurrogateOrBaseOrSelf(false);
                    if (!list.Contains(tmp))
                    { // could perhaps also implement as a queue, but this should work OK for sane models
                        list.Add(tmp);
                        CascadeDependents(list, tmp);
                    }
                }
            }
        }
Esempio n. 3
0
        internal static Type GetListItemType(TypeModel model, Type listType)
        {
            Helpers.DebugAssert(listType != null);

#if WINRT
            TypeInfo listTypeInfo = listType.GetTypeInfo();
            if (listType == typeof(string) || listType.IsArray ||
                !typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(listTypeInfo))
            {
                return(null);
            }
#else
            if (listType == model.MapType(typeof(string)) || listType.IsArray ||
                !model.MapType(typeof(IEnumerable)).IsAssignableFrom(listType))
            {
                return(null);
            }
#endif

            BasicList candidates = new BasicList();
#if WINRT
            foreach (MethodInfo method in listType.GetRuntimeMethods())
#else
            foreach (MethodInfo method in listType.GetMethods())
#endif
            {
                if (method.IsStatic || method.Name != "Add")
                {
                    continue;
                }
                ParameterInfo[] parameters = method.GetParameters();
                Type            paramType;
                if (parameters.Length == 1 && !candidates.Contains(paramType = parameters[0].ParameterType))
                {
                    candidates.Add(paramType);
                }
            }

            string name         = listType.Name;
            bool   isQueueStack = name != null && (name.IndexOf("Queue", System.StringComparison.Ordinal) >= 0 || name.IndexOf("Stack", System.StringComparison.Ordinal) >= 0);
#if !NO_GENERICS
            if (!isQueueStack)
            {
                TestEnumerableListPatterns(model, candidates, listType);
#if WINRT
                foreach (Type iType in listTypeInfo.ImplementedInterfaces)
                {
                    TestEnumerableListPatterns(model, candidates, iType);
                }
#else
                foreach (Type iType in listType.GetInterfaces())
                {
                    TestEnumerableListPatterns(model, candidates, iType);
                }
#endif
            }
#endif

#if WINRT
            // more convenient GetProperty overload not supported on all platforms
            foreach (PropertyInfo indexer in listType.GetRuntimeProperties())
            {
                if (indexer.Name != "Item" || candidates.Contains(indexer.PropertyType))
                {
                    continue;
                }
                ParameterInfo[] args = indexer.GetIndexParameters();
                if (args.Length != 1 || args[0].ParameterType != typeof(int))
                {
                    continue;
                }
                MethodInfo getter = indexer.GetMethod;
                if (getter == null || getter.IsStatic)
                {
                    continue;
                }
                candidates.Add(indexer.PropertyType);
            }
#else
            // more convenient GetProperty overload not supported on all platforms
            foreach (PropertyInfo indexer in listType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
            {
                if (indexer.Name != "Item" || candidates.Contains(indexer.PropertyType))
                {
                    continue;
                }
                ParameterInfo[] args = indexer.GetIndexParameters();
                if (args.Length != 1 || args[0].ParameterType != model.MapType(typeof(int)))
                {
                    continue;
                }
                candidates.Add(indexer.PropertyType);
            }
#endif

            switch (candidates.Count)
            {
            case 0:
                return(null);

            case 1:
                return((Type)candidates[0]);

            case 2:
                if (CheckDictionaryAccessors(model, (Type)candidates[0], (Type)candidates[1]))
                {
                    return((Type)candidates[0]);
                }
                if (CheckDictionaryAccessors(model, (Type)candidates[1], (Type)candidates[0]))
                {
                    return((Type)candidates[1]);
                }
                break;
            }

            return(null);
        }
Esempio n. 4
0
        private void CascadeDependents(BasicList list, MetaType metaType)
        {
            MetaType tmp;

            metaType.FinalizeSettingsValue();
            if (metaType.IsList)
            {
                Type             itemType = TypeModel.GetListItemType(this, metaType.Type);
                WireType         defaultWireType;
                IProtoSerializer coreSerializer = this.ValueSerializerBuilder.TryGetSimpleCoreSerializer(BinaryDataFormat.Default, itemType, out defaultWireType);
                if (coreSerializer == null)
                {
                    int index = FindOrAddAuto(itemType, false, false, false);
                    if (index >= 0)
                    {
                        tmp = ((MetaType)_types[index]).GetSurrogateOrBaseOrSelf(false);
                        if (!list.Contains(tmp))
                        { // could perhaps also implement as a queue, but this should work OK for sane models
                            list.Add(tmp);
                            CascadeDependents(list, tmp);
                        }
                    }
                }
            }
            else
            {
                if (metaType.GetFinalSettingsCopy().IsAutoTuple)
                {
                    MemberInfo[] mapping;
                    if (MetaType.ResolveTupleConstructor(metaType.Type, out mapping) != null)
                    {
                        for (int i = 0; i < mapping.Length; i++)
                        {
                            CscadeDependents_Member(list, (mapping[i] as PropertyInfo)?.PropertyType ?? (mapping[i] as FieldInfo)?.FieldType);
                        }
                    }
                }
                else
                {
                    foreach (ValueMember member in metaType.Fields)
                    {
                        member.Serializer.GetHashCode();
                        var  s             = member.GetFinalSettingsCopy(0);
                        Type type          = s.Collection.ItemType ?? member.MemberType;
                        var  fieldMetaType = FindWithoutAdd(type);
                        if (fieldMetaType != null)
                        {
                            type = fieldMetaType.GetSurrogateOrSelf().Type;
                        }

                        CscadeDependents_Member(list, type);
                    }
                }
                if (metaType.HasSubtypes)
                {
                    foreach (SubType subType in metaType.GetSubtypes())
                    {
                        tmp = subType.DerivedType.GetSurrogateOrSelf(); // note: exclude base-types!
                        if (!list.Contains(tmp))
                        {
                            list.Add(tmp);
                            CascadeDependents(list, tmp);
                        }
                    }
                }
                tmp = metaType.BaseType;
                tmp = tmp?.GetSurrogateOrSelf(); // note: already walking base-types; exclude base
                if (tmp != null && !list.Contains(tmp))
                {
                    list.Add(tmp);
                    CascadeDependents(list, tmp);
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Suggest a .proto definition for the given type
        /// </summary>
        /// <param name="type">The type to generate a .proto definition for, or <c>null</c> to generate a .proto that represents the entire model</param>
        /// <returns>The .proto definition as a string</returns>
        public override string GetSchema(Type type)
        {
            BasicList requiredTypes = new BasicList();
            MetaType  primaryType   = null;
            bool      isInbuiltType = false;

            if (type == null)
            { // generate for the entire model
                for (int i = _serviceTypesCount; i < _types.Count; i++)
                {
                    MetaType meta = (MetaType)_types[i];
                    MetaType tmp  = meta.GetSurrogateOrBaseOrSelf(false);
                    if (!requiredTypes.Contains(tmp))
                    {
                        // ^^^ note that the type might have been added as a descendent
                        requiredTypes.Add(tmp);
                        CascadeDependents(requiredTypes, tmp);
                    }
                }
            }
            else
            {
                Type tmp = Helpers.GetNullableUnderlyingType(type);
                if (tmp != null)
                {
                    type = tmp;
                }

                WireType defaultWireType;
                isInbuiltType = (this.ValueSerializerBuilder.TryGetSimpleCoreSerializer(BinaryDataFormat.Default, type, out defaultWireType) != null);
                if (!isInbuiltType)
                {
                    //Agenerate just relative to the supplied type
                    int index = FindOrAddAuto(type, false, false, false);
                    if (index < 0)
                    {
                        throw new ArgumentException("The type specified is not a contract-type", nameof(type));
                    }

                    // get the required types
                    primaryType = ((MetaType)_types[index]).GetSurrogateOrBaseOrSelf(false);
                    requiredTypes.Add(primaryType);
                    CascadeDependents(requiredTypes, primaryType);
                }
            }

            // use the provided type's namespace for the "package"
            StringBuilder headerBuilder = new StringBuilder();
            string        package       = null;

            if (!isInbuiltType)
            {
                IEnumerable typesForNamespace = primaryType == null ? (IEnumerable)MetaTypes : requiredTypes;
                foreach (MetaType meta in typesForNamespace)
                {
                    meta.FinalizeSettingsValue();
                    if (meta.IsList)
                    {
                        continue;
                    }
                    string tmp = meta.Type.Namespace;
                    if (!Helpers.IsNullOrEmpty(tmp))
                    {
                        if (tmp.StartsWith("System.", StringComparison.Ordinal))
                        {
                            continue;
                        }
                        if (package == null)
                        { // haven't seen any suggestions yet
                            package = tmp;
                        }
                        else if (package == tmp)
                        { // that's fine; a repeat of the one we already saw
                        }
                        else
                        { // something else; have confliucting suggestions; abort
                            package = null;
                            break;
                        }
                    }
                }
            }

            if (!Helpers.IsNullOrEmpty(package))
            {
                headerBuilder.Append("package ").Append(package).Append(';');
                Helpers.AppendLine(headerBuilder);
            }

            bool          requiresBclImport = false;
            StringBuilder bodyBuilder       = new StringBuilder();

            // sort them by schema-name
            MetaType[] metaTypesArr = new MetaType[requiredTypes.Count];
            requiredTypes.CopyTo(metaTypesArr, 0);
            Array.Sort(metaTypesArr, MetaType.Comparer.Default);

            // write the messages
            if (isInbuiltType)
            {
                Helpers.AppendLine(bodyBuilder).Append("message ").Append(type.Name).Append(" {");
                MetaType.NewLine(bodyBuilder, 1).Append("optional ").Append(GetSchemaTypeName(type, BinaryDataFormat.Default, false, false, ref requiresBclImport))
                .Append(" value = 1;");
                Helpers.AppendLine(bodyBuilder).Append('}');
            }
            else
            {
                for (int i = 0; i < metaTypesArr.Length; i++)
                {
                    MetaType tmp = metaTypesArr[i];
                    if (tmp.IsList && tmp != primaryType)
                    {
                        continue;
                    }
                    tmp.WriteSchema(bodyBuilder, 0, ref requiresBclImport);
                }
            }
            if (requiresBclImport)
            {
                headerBuilder.Append("import \"bcl.proto\"; // schema for protobuf-net's handling of core .NET types");
                Helpers.AppendLine(headerBuilder);
            }
            return(Helpers.AppendLine(headerBuilder.Append(bodyBuilder)).ToString());
        }
Esempio n. 6
0
        /// <summary>
        /// Adds a known sub-type to the inheritance model
        /// </summary>
        public MetaType AddSubType(int fieldNumber, Type derivedType)
        {
            if (derivedType == null)
            {
                throw new ArgumentNullException(nameof(derivedType));
            }
            if (fieldNumber < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(fieldNumber));
            }

            if (Type.IsArray)
            {
                throw new ArgumentException("An array has inbuilt behaviour and cannot be subclassed");
            }

            if (derivedType.IsArray)
            {
                throw new ArgumentException("An array has inbuilt behaviour and cannot be as used as a subclass");
            }

#if WINRT
            if (!CanHaveSubType(_typeInfo))
            {
#else
            if (!CanHaveSubType(Type))
            {
#endif
                throw new InvalidOperationException("Sub-types can only be added to non-sealed classes");
            }
            if (!IsValidSubType(derivedType))
            {
                throw new ArgumentException(derivedType.Name + " is not a valid sub-type of " + Type.Name, nameof(derivedType));
            }

            if (_subTypesSimple != null && _subTypesSimple.Contains(derivedType))
            {
                return(this);                                                                  // already exists
            }
            if (!IsFieldFree(fieldNumber))
            {
                throw new ArgumentException(string.Format("FieldNumber {0} was already taken in type {1}, can't add sub-type {2}", fieldNumber, Type.Name, derivedType.Name), nameof(fieldNumber));
            }

            if (_subTypesSimple == null)
            {
                _subTypesSimple = new BasicList();
            }
            _subTypesSimple.Add(derivedType);

            MetaType derivedMeta = _model[derivedType];
            ThrowIfFrozen();
            derivedMeta.ThrowIfFrozen();
            SubType subType = new SubType(fieldNumber, derivedMeta);
            ThrowIfFrozen();

            derivedMeta.SetBaseType(this); // includes ThrowIfFrozen
            if (_subTypes == null)
            {
                _subTypes = new BasicList();
            }
            _subTypes.Add(subType);

            return(this);
        }