예제 #1
0
        /// <summary>
        /// Determines whether two object instances are equal using a deep comparison.
        /// </summary>
        /// <param name="lhs">The first object to compare.</param>
        /// <param name="rhs">The second object to compare.</param>
        /// <returns><see langword="true"/> if the objects are considered equal; otherwise, <see langword="false"/>.</returns>
        public bool CompareEqual(object lhs, object rhs)
        {
            if (lhs == null)
            {
                return(rhs == null);
            }
            if (rhs == null)
            {
                return(false);
            }

            var type = lhs.GetType();

#if !UNITY_DOTSPLAYER
            if (typeof(UnityEngine.Object).IsAssignableFrom(type))
            {
                return(lhs.Equals(rhs));
            }
#endif
            var properties = PropertyBagStore.GetPropertyBag(type);

            if (null == properties)
            {
                throw new MissingPropertyBagException(type);
            }

            m_References?.Clear();
            m_LhsObject = lhs;
            m_RhsObject = rhs;
            m_Equals    = true;

            m_Stack = rhs;
            properties.Accept(this, ref lhs);
            return(m_Equals);
        }
        public void ClassWithAnonymousType_HasPropertyBagGenerated()
        {
            // Check properties are generated for anonymous field types.
            {
                var propertyBag = PropertyBagStore.GetPropertyBag(typeof(ClassWithAnonymousType));

                Assert.That(propertyBag, Is.InstanceOf(typeof(ContainerPropertyBag <ClassWithAnonymousType>)));

                var typed      = propertyBag as ContainerPropertyBag <ClassWithAnonymousType>;
                var container  = default(ClassWithAnonymousType);
                var properties = typed.GetProperties(ref container);

                Assert.That(properties.Count(), Is.EqualTo(1));
                Assert.That(properties.ElementAt(0), Is.InstanceOf(typeof(Property <ClassWithAnonymousType, (int IntValue, float FloatValue)>)));
            }

            // Check that the anonymous type has a property bag generated
            {
                var propertyBag = PropertyBagStore.GetPropertyBag(typeof((int IntValue, float FloatValue)));
                Assert.That(propertyBag, Is.InstanceOf(typeof(ContainerPropertyBag <(int IntValue, float FloatValue)>)));

                var typed      = propertyBag as ContainerPropertyBag <(int IntValue, float FloatValue)>;
                var container  = default((int IntValue, float FloatValue));
                var properties = typed.GetProperties(ref container);

                Assert.That(properties.Count(), Is.EqualTo(2));
                Assert.That(properties.ElementAt(0), Is.InstanceOf(typeof(Property <(int IntValue, float FloatValue), int>)));
                Assert.That(properties.ElementAt(1), Is.InstanceOf(typeof(Property <(int IntValue, float FloatValue), float>)));
            }
        }
        public void ClassWithPointerTypes_HasHasPropertyBagGenerated()
        {
            var propertyBag = PropertyBagStore.GetPropertyBag(typeof(ClassWithPointerTypes)) as ContainerPropertyBag <ClassWithPointerTypes>;

            Assert.That(propertyBag, Is.Not.Null);
            Assert.That(propertyBag.GetProperties().Count(), Is.EqualTo(1));
        }
        public void ClassThatInheritsClassWithAttributes_HasPropertyBagGenerated()
        {
            var container  = default(SuperClassWithAttributeOnPrivateField);
            var properties = (PropertyBagStore.GetPropertyBag(typeof(SuperClassWithAttributeOnPrivateField)) as IPropertyBag <SuperClassWithAttributeOnPrivateField>).GetProperties(ref container);

            Assert.That(properties.Count(), Is.EqualTo(1));
            Assert.That(properties.First().HasAttribute <CustomAttribute>());
        }
예제 #5
0
        public void ClassWithMultidimensionalGeneric_HasPropertyBagGenerated()
        {
            var propertyBag = PropertyBagStore.GetPropertyBag(typeof(ClassWithMultidimensionalGeneric)) as ContainerPropertyBag <ClassWithMultidimensionalGeneric>;

            Assert.That(propertyBag, Is.Not.Null);
            var container = new ClassWithMultidimensionalGeneric();

            Assert.That(propertyBag.GetProperties(ref container).Count(), Is.EqualTo(0));
        }
        /// <summary>
        /// Tries to visit the specified <paramref name="container"/> by ref using the specified <paramref name="visitor"/>.
        /// </summary>
        /// <param name="visitor">The visitor.</param>
        /// <param name="container">The container to visit.</param>
        /// <param name="errorCode">When this method returns, contains the error code.</param>
        /// <typeparam name="TContainer">The declared container type.</typeparam>
        /// <returns><see langword="true"/> if the visitation succeeded; <see langword="false"/> otherwise.</returns>
        public static bool TryAccept <TContainer>(IPropertyBagVisitor visitor, ref TContainer container, out VisitErrorCode errorCode)
        {
            if (!RuntimeTypeInfoCache <TContainer> .IsContainerType)
            {
                errorCode = VisitErrorCode.InvalidContainerType;
                return(false);
            }

            // Can not visit a null container.
            if (RuntimeTypeInfoCache <TContainer> .CanBeNull)
            {
                if (EqualityComparer <TContainer> .Default.Equals(container, default))
                {
                    errorCode = VisitErrorCode.NullContainer;
                    return(false);
                }
            }

            if (!RuntimeTypeInfoCache <TContainer> .IsValueType && typeof(TContainer) != container.GetType())
            {
                if (!RuntimeTypeInfoCache.IsContainerType(container.GetType()))
                {
                    errorCode = VisitErrorCode.InvalidContainerType;
                    return(false);
                }

                var properties = PropertyBagStore.GetPropertyBag(container.GetType());

                if (null == properties)
                {
                    errorCode = VisitErrorCode.MissingPropertyBag;
                    return(false);
                }

                // At this point the generic parameter is useless to us since it's not the correct type.
                // Instead we need to retrieve the untyped property bag and accept on that. Since we don't know the type
                // We need to box the container and let the property bag cast it internally.
                var boxed = (object)container;
                properties.Accept(visitor, ref boxed);
                container = (TContainer)boxed;
            }
            else
            {
                var properties = PropertyBagStore.GetPropertyBag <TContainer>();

                if (null == properties)
                {
                    errorCode = VisitErrorCode.MissingPropertyBag;
                    return(false);
                }

                PropertyBag.AcceptWithSpecializedVisitor(properties, visitor, ref container);
            }

            errorCode = VisitErrorCode.Ok;
            return(true);
        }
        public void ClassWithMultidimensionalGeneric_HasPropertyBagGenerated()
        {
            var propertyBag = PropertyBagStore.GetPropertyBag(typeof(ClassWithMultidimensionalGeneric)) as ContainerPropertyBag <ClassWithMultidimensionalGeneric>;

            Assert.That(propertyBag, Is.Not.Null);
            var container = new ClassWithMultidimensionalGeneric();

            // @TODO ILPP should support this case
            // Assert.That(propertyBag.GetProperties(ref container).Count(), Is.EqualTo(2));
            Assert.Pass(); // Test is inconclusive on CI
        }
        /// <summary>
        /// Constructs a new instance of the given <see cref="TContainer"/> type.
        /// </summary>
        /// <typeparam name="TContainer">The container type to construct.</typeparam>
        /// <returns>A new instance of <see cref="TContainer"/>.</returns>
        public static TContainer CreateInstance <TContainer>()
        {
            var propertyBag = PropertyBagStore.GetPropertyBag <TContainer>();

            if (null == propertyBag)
            {
                throw new MissingPropertyBagException(typeof(TContainer));
            }

            return(propertyBag.CreateInstance());
        }
예제 #9
0
        public void ClassWithSomeResolvedGenerics_HasPropertyBagGenerated()
        {
            Assert.That(PropertyBagStore.GetPropertyBag(typeof(ClassWithGenericParameterAndGenericBase <int>)), Is.InstanceOf(typeof(ContainerPropertyBag <ClassWithGenericParameterAndGenericBase <int> >)));

            var container = new ClassWithGenericParameterAndGenericBase <int>
            {
                Value0 = 1,
                Value1 = 4.2f
            };

            PropertyContainer.Visit(ref container, new DebugVisitor());
        }
 protected override void VisitPath <TContainer, TValue>(Property <TContainer, TValue> property, ref TContainer container, ref TValue value)
 {
     if (PropertyBagStore.GetPropertyBag <TValue>() is ICollectionPropertyBagAccept <TValue> collectionPropertyBagAccept)
     {
         m_CollectionSearchDataVisitor.SearchData = SearchData;
         collectionPropertyBagAccept.Accept(m_CollectionSearchDataVisitor, ref value);
     }
     else
     {
         SearchData.Add(value?.ToString());
     }
 }
예제 #11
0
        IComponentProperty GetOrCreatePropertyForType(int typeIndex, bool isReadOnly)
        {
            var cache = isReadOnly ? m_ReadOnlyPropertyCache : m_ReadWritePropertyCache;

            if (cache.TryGetValue(typeIndex, out var property))
            {
                return(property);
            }

            m_ComponentPropertyConstructor.TypeIndex  = typeIndex;
            m_ComponentPropertyConstructor.IsReadOnly = isReadOnly;
            PropertyBagStore.GetPropertyBag(TypeManager.GetType(typeIndex)).Accept(m_ComponentPropertyConstructor);
            cache.Add(typeIndex, m_ComponentPropertyConstructor.Property);
            return(m_ComponentPropertyConstructor.Property);
        }
예제 #12
0
        public void ClassWithGenericBaseClass_HasPropertyBagGenerated()
        {
            Assert.That(PropertyBagStore.GetPropertyBag(typeof(Baz)), Is.InstanceOf(typeof(ContainerPropertyBag <Baz>)));

            var container = new Baz
            {
                Root           = 1,
                Value          = "Hello",
                Value0         = 1.23f,
                Value1         = 42,
                Value0Property = 1.4f
            };

            PropertyContainer.Visit(ref container, new DebugVisitor());
        }
        /// <summary>
        /// Creates a new object that is a copy of the given instance.
        /// </summary>
        /// <param name="obj">The object to clone.</param>
        /// <returns>A new object that is a copy of the given instance.</returns>
        public object Clone(object obj)
        {
            switch (obj)
            {
            case null:
                return(null);

            case ICloneable cloneable:
                return(cloneable.Clone());
            }

            var type = obj.GetType();

#if !UNITY_DOTSRUNTIME
            // UnityEngine references are always by reference.
            if (typeof(UnityEngine.Object).IsAssignableFrom(type))
            {
                return(obj);
            }
#endif
            var instance = type.IsArray
                ? Array.CreateInstance(type.GetElementType(), obj is IList srcList ? srcList.Count : 0)
                : Activator.CreateInstance(type);

            // Visit the source container and write to the dst.
            var properties = PropertyBagStore.GetPropertyBag(type);

            if (null == properties)
            {
                throw new MissingPropertyBagException(type);
            }

            m_References?.Clear();

            m_RootSource      = obj;
            m_RootDestination = instance;

            // Push the instance on the stack.
            m_Stack = instance;
            properties.Accept(this, ref obj);
            return(m_Stack);
        }
예제 #14
0
        static PropertyBagDebugInfoStore()
        {
            s_AllDebugInfos    = new List <PropertyBagDebugInfo>();
            s_DebugInfoPerType = new Dictionary <Type, PropertyBagDebugInfo>();
            s_Indices          = new Dictionary <Type, int>();

            foreach (var type in PropertyBagStore.AllTypes)
            {
                var info = new PropertyBagDebugInfo(type, PropertyBagStore.GetPropertyBag(type));
                s_AllDebugInfos.Add(info);
                s_DebugInfoPerType[type] = info;
            }

            s_AllDebugInfos.Sort((lhs, rhs) => string.Compare(lhs.Name, rhs.Name, StringComparison.Ordinal));
            for (var i = 0; i < s_AllDebugInfos.Count; ++i)
            {
                var info = AllDebugInfos[i];
                s_Indices[info.Type] = i;
            }
            PropertyBagStore.NewTypeRegistered += OnPropertyBagRegistered;
        }
예제 #15
0
        /// <summary>
        /// Gathers all blob asset references within the specified object.
        /// </summary>
        /// <param name="obj">The object to extract all blob asset references from.</param>
        /// <param name="blobAssets">The array where new blob asset references are added.</param>
        /// <param name="blobAssetMap">Mapping to track existing blob asset references encountered.</param>
        /// <exception cref="ArgumentNullException">The given object was null.</exception>
        /// <exception cref="MissingPropertyBagException">The given object has no property bag associated with it.</exception>
        public void GatherBlobAssetReferences(object obj, NativeList <SerializeUtility.BlobAssetPtr> blobAssets, NativeHashMap <SerializeUtility.BlobAssetPtr, int> blobAssetMap)
        {
            if (null == obj)
            {
                throw new ArgumentNullException(nameof(obj));
            }

            var type       = obj.GetType();
            var properties = PropertyBagStore.GetPropertyBag(type);

            if (null == properties)
            {
                throw new MissingPropertyBagException(type);
            }

            m_References?.Clear();

            m_BlobAssets   = blobAssets;
            m_BlobAssetMap = blobAssetMap;

            properties.Accept(this, ref obj);
        }
예제 #16
0
        IPropertyBag GetPropertyBag(object obj)
        {
            if (null == obj)
            {
                throw new ArgumentNullException(nameof(obj));
            }

            var type     = obj.GetType();
            var typeInfo = TypeManager.GetTypeInfo(TypeManager.GetTypeIndex(type));

            if (typeInfo.Category == TypeManager.TypeCategory.UnityEngineObject)
            {
                throw new ArgumentException("Cannot remap hybrid components", nameof(obj));
            }

            var properties = PropertyBagStore.GetPropertyBag(type);

            if (null == properties)
            {
                throw new MissingPropertyBagException(type);
            }

            return(properties);
        }
예제 #17
0
 public void ClassWithGenericNestedGeneric_HasPropertyBagGenerated()
 {
     Assert.That(PropertyBagStore.GetPropertyBag(typeof(ClassWithGeneric <NestedClass <float> >)), Is.InstanceOf(typeof(ContainerPropertyBag <ClassWithGeneric <NestedClass <float> > >)));
     Assert.That(PropertyBagStore.GetPropertyBag(typeof(NestedClass <float>)), Is.InstanceOf(typeof(ContainerPropertyBag <NestedClass <float> >)));
 }
 public void ClassWithNestedNamespacesAndTypes_HasPropertyBagGenerated()
 {
     Assert.That(PropertyBagStore.GetPropertyBag <Test.Foo.Bar.ClassWithNestedNamespacesAndTypes>(), Is.InstanceOf <ContainerPropertyBag <Test.Foo.Bar.ClassWithNestedNamespacesAndTypes> >());
 }
예제 #19
0
 public void ClassWithOpenGenericInterface_DoesNotHavePropertyBagGenerated()
 {
     Assert.That(PropertyBagStore.GetPropertyBag(typeof(ClassWithOpenGenericInterface <>)), Is.Null);
 }
 public void ClassWithMultipleNamespaceScopes_HasPropertyBagGenerated()
 {
     Assert.That(PropertyBagStore.GetPropertyBag <NestedNamespace.ClassWithMultipleNamespaceScopes>(), Is.InstanceOf <ContainerPropertyBag <NestedNamespace.ClassWithMultipleNamespaceScopes> >());
 }
            public object Construct(Type type, UnsafeValueView view)
            {
                if (type != typeof(Component) || m_GameObject == null)
                {
                    return(null);
                }

                try
                {
                    var componentType = m_GenericConstructor.GetSerializedType();
                    if (componentType == null)
                    {
                        return(null);
                    }

#if !NET_DOTS && !ENABLE_IL2CPP
                    SceneSerialization.RegisterPropertyBag(componentType);
#endif

                    var properties = PropertyBagStore.GetPropertyBag(componentType);
                    if (properties == null)
                    {
                        Debug.LogWarning($"Could not resolve component type {componentType} deserializing {m_GameObject.name}. Will preserve serialized contents as JSON string");
                        return(CreateMissingComponent(view));
                    }

                    if (componentType == typeof(MissingComponent))
                    {
                        try
                        {
                            var value   = new JsonObject();
                            var visitor = new JsonSceneReader(m_SerializationMetadata);
                            visitor.SetView(view);
                            PropertyContainer.Visit(ref value, visitor);
                            var jsonString = value[nameof(MissingComponent.JsonString)].ToString();

                            // For some reason, newlines are read as null characters which break parsing
                            jsonString = jsonString.Replace('\0', '\n');

                            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
                            {
                                using (var reader = new SerializedObjectReader(stream))
                                {
                                    reader.Read(out var document);
                                    var componentVisitor = new ComponentVisitor(m_GameObject, document.AsUnsafe(),
                                                                                null, m_SerializationMetadata);

                                    Component missingComponent = null;
                                    componentVisitor.ReadValue(ref missingComponent, document.AsUnsafe());
                                    return(missingComponent);
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            Debug.Log($"Encountered an exception trying to deserialize MissingComponent. Preserving it as-is. Exception follows:\n{e}");
                        }
                    }

                    return(componentType == typeof(Transform) ? m_GameObject.GetComponent <Transform>() : m_GameObject.AddComponent(componentType));
                }
                catch (ArgumentException)
                {
                    Debug.LogWarning($"Could not resolve component type deserializing {m_GameObject.name}. Will preserve serialized contents as JSON string");
                    return(CreateMissingComponent(view));
                }
            }
 public void ClassWithNestedCollections_HasCollectionPropertyBagsGenerated()
 {
     Assert.That(PropertyBagStore.GetPropertyBag(typeof(ClassWithNestedCollections)), Is.InstanceOf <ContainerPropertyBag <ClassWithNestedCollections> >());
     Assert.That(PropertyBagStore.GetPropertyBag(typeof(List <List <ClassWithNestedCollections.NestedClass> >)), Is.InstanceOf <ListPropertyBag <List <ClassWithNestedCollections.NestedClass> > >());
     Assert.That(PropertyBagStore.GetPropertyBag(typeof(List <ClassWithNestedCollections.NestedClass>)), Is.InstanceOf <ListPropertyBag <ClassWithNestedCollections.NestedClass> >());
 }
예제 #23
0
 public void ClassInGlobalNamespace_HasPropertyBagsGenerated()
 {
     Assert.That(PropertyBagStore.GetPropertyBag(typeof(ClassInGlobalNamespace)), Is.InstanceOf <ContainerPropertyBag <ClassInGlobalNamespace> >());
 }
 public void ClassWithCollections_HasCollectionPropertyBagsGenerated()
 {
     Assert.That(PropertyBagStore.GetPropertyBag(typeof(List <int>)), Is.InstanceOf <ListPropertyBag <int> >());
     Assert.That(PropertyBagStore.GetPropertyBag(typeof(Dictionary <string, int>)), Is.InstanceOf <DictionaryPropertyBag <string, int> >());
 }
예제 #25
0
 /// <summary>
 /// Gets the strongly typed <see cref="PropertyBag{TContainer}"/> for the given <typeparamref name="TContainer"/>.
 /// </summary>
 /// <typeparam name="TContainer">The container type to resolve the property bag for.</typeparam>
 /// <returns>The resolved property bag, strongly typed.</returns>
 public static IPropertyBag <TContainer> GetPropertyBag <TContainer>()
 {
     return(PropertyBagStore.GetPropertyBag <TContainer>());
 }
예제 #26
0
 /// <summary>
 /// Gets an interface to the <see cref="PropertyBag{TContainer}"/> for the given type.
 /// </summary>
 /// <remarks>
 /// The returned <see cref="IPropertyBag"/> can be used to get the strongly typed generic using the <see cref="IPropertyBagAccept"/> interface method.
 /// </remarks>
 /// <param name="type">The container type to resolve the property bag for.</param>
 /// <returns>The resolved property bag.</returns>
 public static IPropertyBag GetPropertyBag(Type type)
 {
     return(PropertyBagStore.GetPropertyBag(type));
 }
        public void ClassQualifiedWithTypeFromAnotherAssembly_HasPropertyBagGenerated()
        {
            var propertyBag = PropertyBagStore.GetPropertyBag(typeof(ClassQualifiedWithTypeFromAnotherAssemblyWithGeneratePropertyBag));

            Assert.That(propertyBag, Is.InstanceOf(typeof(ContainerPropertyBag <ClassQualifiedWithTypeFromAnotherAssemblyWithGeneratePropertyBag>)));
        }