/// <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>()); }
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()); }
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()); } }
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); }
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); }
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; }
/// <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); }
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); }
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> >()); }
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> >()); }
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> >()); }
/// <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>()); }
/// <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>))); }