protected override void VisitProperty <TContainer, TValue>(Property <TContainer, TValue> property,
                                                                   ref TContainer container, ref TValue value)
        {
            if (!RuntimeTypeInfoCache.IsContainerType(value.GetType()))
            {
                return;
            }

            var isWrapper = typeof(PropertyWrapper <TValue>).IsInstanceOfType(container);

            if (!isWrapper)
            {
                AddToPath(property);
            }

            try
            {
                var path = GetCurrentPath();
                using (var references = VisitorContext.MakeVisitedReferencesScope(this, ref value, path))
                {
                    if (references.VisitedOnCurrentBranch)
                    {
                        VisitorContext.Parent.Add(new CircularReferenceElement <TValue>(VisitorContext.Root, property, value, path, references.GetReferencePath()));
                        return;
                    }

                    var inspector = default(IInspector);
                    if (!path.Empty || EnableRootCustomInspectors)
                    {
                        var visitor = new CustomInspectorVisitor <TValue>();
                        visitor.PropertyPath = path;
                        visitor.Root         = VisitorContext.Root;
                        visitor.Property     = property;
                        PropertyContainer.Visit(ref value, visitor);
                        inspector = visitor.Inspector;
                    }

                    var old = EnableRootCustomInspectors;
                    EnableRootCustomInspectors = true;
                    if (null != inspector)
                    {
                        var customInspector = new CustomInspectorElement(path, inspector, VisitorContext.Root);
                        VisitorContext.Parent.contentContainer.Add(customInspector);
                    }
                    else
                    {
                        RecurseProperty(ref value, property, path);
                    }

                    EnableRootCustomInspectors = old;
                }
            }
            finally
            {
                if (!isWrapper)
                {
                    RemoveFromPath(property);
                }
            }
        }
Esempio n. 2
0
        public override VisualElement Build()
        {
            var root       = new VisualElement();
            var attributes =
                $"[{string.Join(", ", Target.Descriptor.GetAttributes().Select(a => TypeUtility.GetTypeDisplayName(a.GetType())))}]";

            if (attributes.Length > 2)
            {
                var attributesLabel = new Label(attributes);
                Resources.Templates.Explorer.Property.AddStyles(attributesLabel);
                attributesLabel.AddToClassList(UssClasses.Unity.BaseFieldLabel);
                attributesLabel.AddToClassList(k_Attributes);
                root.contentContainer.Add(attributesLabel);
            }

            var descriptor = new AttributeDescriptorElement <string, string, Label, Label>(new AttributeDescriptor <string, string>(Target.Descriptor.Name,
                                                                                                                                    TypeUtility.GetTypeDisplayName(Target.Value)));
            var type = Target.Descriptor.DeclaredValueType();

            if (RuntimeTypeInfoCache.IsContainerType(type) &&
                !type.IsAbstract &&
                !type.IsInterface)
            {
                descriptor.ShowValueAsLink();
            }

            descriptor.RegisterCallback <TypeSelectedEvent <AttributeDescriptor <string, string> > >(evt =>
            {
                GetContext <Explorer.Context>().SelectType(Target.Value);
            });

            root.contentContainer.Add(descriptor);
            return(root);
        }
 public static void Visit <TContainer, TVisitor>(ref TContainer container, TVisitor visitor, ref ChangeTracker changeTracker)
     where TVisitor : IPropertyVisitor
 {
     if (RuntimeTypeInfoCache <TContainer> .IsAbstractOrInterface())
     {
         PropertyBagResolver.Resolve(container.GetType())?.Accept(container, visitor, ref changeTracker);
     }
     else
     {
         PropertyBagResolver.Resolve <TContainer>()?.Accept(ref container, visitor, ref changeTracker);
     }
 }
Esempio n. 4
0
 public static void Visit <TContainer, TVisitor>(ref TContainer container, TVisitor visitor, ref ChangeTracker changeTracker)
     where TVisitor : IPropertyVisitor
 {
     if (!RuntimeTypeInfoCache <TContainer> .IsValueType() && null != container && typeof(TContainer) != container.GetType())
     {
         var boxed = (object)container;
         PropertyBagResolver.Resolve(container.GetType())?.Accept(ref boxed, visitor, ref changeTracker);
         container = (TContainer)boxed;
     }
     else
     {
         PropertyBagResolver.Resolve <TContainer>()?.Accept(ref container, visitor, ref changeTracker);
     }
 }
Esempio n. 5
0
 public static void Transfer <TDestination, TSource>(ref TDestination destination, ref TSource source, ref ChangeTracker changeTracker)
 {
     if (RuntimeTypeInfoCache <TSource> .IsAbstractOrInterface())
     {
         var propertyBag = PropertyBagResolver.Resolve(source.GetType());
         var action      = new TransferAbstractType <TDestination>
         {
             Destination     = destination,
             SourceContainer = (object)source
         };
         propertyBag.Cast(action);
         destination = action.Destination;
     }
     else
     {
         Visit(ref destination, new TransferVisitor <TSource>(source), ref changeTracker);
     }
 }
Esempio n. 6
0
        void VisitWithCustomInspectorOrDefault <TContainer, TDeclaredType>(IProperty property, ref TContainer container, ref TDeclaredType value, DefaultVisitHandler <TDeclaredType> defaultVisit)
        {
            if (!RuntimeTypeInfoCache.IsContainerType(value.GetType()))
            {
                return;
            }

            var isWrapper = typeof(PropertyWrapper <TDeclaredType>).IsInstanceOfType(container);

            if (!isWrapper)
            {
                AddToPath(property);
            }

            try
            {
                var path = GetCurrentPath();
                using (var references = VisitorContext.MakeVisitedReferencesScope(this, ref value, path))
                {
                    if (references.VisitedOnCurrentBranch)
                    {
                        VisitorContext.Parent.Add(new CircularReferenceElement <TDeclaredType>(VisitorContext.Root, property, value, path, references.GetReferencePath()));
                        return;
                    }

                    if (TryVisitWithCustomInspector(ref value, path, property))
                    {
                        return;
                    }

                    defaultVisit(property, ref value, path);
                }
            }
            finally
            {
                if (!isWrapper)
                {
                    RemoveFromPath(property);
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Register a reflected property bag which is compatible with scene serialization for the given type and the
        /// types of its properties, and their properties recursively
        /// </summary>
        /// <param name="type">The type which will used to create the property bags</param>
        public static void RegisterPropertyBagRecursively(Type type)
        {
            if (!RuntimeTypeInfoCache.IsContainerType(type) || type.IsGenericTypeDefinition || type.IsAbstract || type.IsInterface)
            {
                return;
            }

            var propertyBag = ReflectedPropertyBagProvider.Instance.CreatePropertyBag(type);

            if (propertyBag == null)
            {
                return;
            }

            propertyBag.Register();

            var method = SerializationUtils.GetRegisterPropertyBagsForPropertiesMethod(type);

            k_RegisterPropertyBagsArguments[0] = propertyBag;
            method?.Invoke(null, k_RegisterPropertyBagsArguments);
        }
Esempio n. 8
0
        VisitStatus IVisitAdapter.Visit <TProperty, TContainer, TValue>(
            IPropertyVisitor visitor,
            TProperty property,
            ref TContainer container,
            ref TValue value,
            ref ChangeTracker changeTracker)
        {
            if (!typeof(TValue).IsEnum)
            {
                return(VisitStatus.Unhandled);
            }

            if (RuntimeTypeInfoCache <TValue> .IsFlagsEnum())
            {
                GuiFactory.FlagsField(property, ref container, ref value, VisitorContext);
            }
            else
            {
                GuiFactory.EnumField(property, ref container, ref value, VisitorContext);
            }
            return(VisitStatus.Override);
        }
Esempio n. 9
0
        internal static void Construct <TValue>(ref TValue value, ISerializedTypeProvider provider)
        {
            if (RuntimeTypeInfoCache <TValue> .IsValueType)
            {
                if (!(RuntimeTypeInfoCache <TValue> .IsNullable && RuntimeTypeInfoCache.IsContainerType(Nullable.GetUnderlyingType(typeof(TValue)))))
                {
                    return;
                }
            }

            var serializedType = provider.GetSerializedType();

            if (null != serializedType)
            {
                if (!typeof(TValue).IsAssignableFrom(serializedType))
                {
                    throw new ArgumentException($"Type mismatch. DeclaredType=[{typeof(TValue)}] SerializedType=[{serializedType}]");
                }

                ConstructFromSerializedType(ref value, serializedType, provider);
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsObjectType && null == value)
            {
                value = (TValue)provider.GetDefaultObject();
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsAbstractOrInterface)
            {
                throw new ArgumentException();
            }

            ConstructFromDeclaredType(ref value, provider);
        }
        void CloneValue <TValue>(ref TValue dstValue, TValue srcValue)
        {
            // Values types can be copied as-is.
            if (!RuntimeTypeInfoCache <TValue> .IsContainerType)
            {
                dstValue = srcValue;
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .CanBeNull && null == srcValue)
            {
                dstValue = default;
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsValueType)
            {
                dstValue = default;
            }
            else
            {
                var type = srcValue.GetType();

#if !UNITY_DOTSRUNTIME
                // UnityEngine references can be copied as-is.
                if (typeof(UnityEngine.Object).IsAssignableFrom(type))
                {
                    dstValue = srcValue;
                    return;
                }
#endif
                // Boxed value types can be copied as-is.
                if (!RuntimeTypeInfoCache.IsContainerType(type))
                {
                    dstValue = srcValue;
                    return;
                }

                var isReferenceType = !(type.IsValueType || type == typeof(string));

                if (isReferenceType)
                {
                    // If we have already encountered this object before. Use the already created instance.
                    // This is to support things like circular references/graph structures.
                    // The root object is not added to the map so we need to explicitly check for it.
                    if (m_RootSource == (object)srcValue)
                    {
                        dstValue = (TValue)m_RootDestination;
                        return;
                    }

                    // Otherwise let's check the map.
                    if (null != m_References && m_References.TryGetValue(srcValue, out var existingReference))
                    {
                        dstValue = (TValue)existingReference;
                        return;
                    }
                }

                // We are dealing with an arbitrary csharp object.
                // We may or may not need to construct a new instance depending on the default constructor of the container.
                // If we already have a use-able instance we will use that instead of creating a new one.
                // This is both for performance and to handle init-only fields.
                if (type.IsArray)
                {
                    var count = srcValue is IList srcList ? srcList.Count : 0;

                    if (null == dstValue || (dstValue as Array)?.Length != count)
                    {
                        dstValue = (TValue)(object)Array.CreateInstance(type.GetElementType(), count);
                    }
                }
                else
                {
                    if (null == dstValue || dstValue.GetType() != type)
                    {
                        dstValue = (TValue)Activator.CreateInstance(type);
                    }
                }

                // Retain a mapping of references within this object. This is needed to support things like circular references.
                if (isReferenceType)
                {
                    if (null == m_References)
                    {
                        m_References = new Dictionary <object, object>();
                    }
                    m_References.Add(srcValue, dstValue);
                }
            }

            // We now have a properly constructed instance of the dstValue, nest in and copy all members.
            // Unity.Properties will automatically handle collection type from this point.
            var dstContainer = m_Stack;

            m_Stack = dstValue;
            PropertyContainer.Visit(ref srcValue, this, out _);
            dstValue = (TValue)m_Stack;

            m_Stack = dstContainer;
        }
Esempio n. 11
0
        internal void WriteValueWithoutAdapters <TValue>(TValue value, bool isRoot)
        {
            if (RuntimeTypeInfoCache <TValue> .IsEnum)
            {
                BinarySerialization.WritePrimitiveUnsafe(m_Stream, ref value, Enum.GetUnderlyingType(typeof(TValue)));
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .CanBeNull && null == value)
            {
                m_Stream->Add(k_TokenNull);
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsMultidimensionalArray)
            {
                // No support for multidimensional arrays yet. This can be done using adapters for now.
                m_Stream->Add(k_TokenNull);
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsNullable)
            {
                m_Stream->Add(k_TokenNone);

                var underlyingType = Nullable.GetUnderlyingType(typeof(TValue));

                if (RuntimeTypeInfoCache.IsContainerType(underlyingType))
                {
                    // IMPORTANT: Do NOT add a token to the stream since we are triggering a re-entrance on the same object here.
                    // Unpack Nullable<T> as T
                    var underlyingValue = Convert.ChangeType(value, underlyingType);

                    if (!PropertyContainer.TryAccept(this, ref underlyingValue, out var errorCode))
                    {
                        switch (errorCode)
                        {
                        case VisitErrorCode.NullContainer:
                            throw new ArgumentNullException(nameof(value));

                        case VisitErrorCode.InvalidContainerType:
                            throw new InvalidContainerTypeException(value.GetType());

                        case VisitErrorCode.MissingPropertyBag:
                            throw new MissingPropertyBagException(value.GetType());

                        default:
                            throw new Exception($"Unexpected {nameof(VisitErrorCode)}=[{errorCode}]");
                        }
                    }
                }
                else
                {
                    BinarySerialization.WritePrimitiveBoxed(m_Stream, value, underlyingType);
                }

                return;
            }

            if (!RuntimeTypeInfoCache <TValue> .IsValueType)
            {
#if !UNITY_DOTSPLAYER
                if (!(isRoot && m_DisableRootAdapters) && value is UnityEngine.Object unityEngineObject)
                {
                    // Special path for polymorphic unity object references.
                    m_Stream->Add(k_TokenUnityEngineObjectReference);
                    (m_Adapters.Internal as Adapters.Contravariant.IBinaryAdapter <UnityEngine.Object>).Serialize(new BinarySerializationContext <TValue>(this, default, value, isRoot), unityEngineObject);
Esempio n. 12
0
        void WriteValue <TValue>(TValue value, bool isRoot = false)
        {
            var runAdapters = !(isRoot && m_DisableRootAdapters);

            if (runAdapters && m_Adapters.TrySerialize(m_Stream, ref value))
            {
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsEnum)
            {
                BinarySerialization.WritePrimitiveUnsafe(m_Stream, ref value, Enum.GetUnderlyingType(typeof(TValue)));
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .CanBeNull && null == value)
            {
                m_Stream->Add(k_TokenNull);
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsNullable)
            {
                m_Stream->Add(k_TokenNone);
                BinarySerialization.WritePrimitiveBoxed(m_Stream, value, Nullable.GetUnderlyingType(typeof(TValue)));
                return;
            }

            if (!RuntimeTypeInfoCache <TValue> .IsValueType)
            {
#if !UNITY_DOTSPLAYER
                if (runAdapters && value is UnityEngine.Object unityEngineObject)
                {
                    // Special path for polymorphic unity object references.
                    m_Stream->Add(k_TokenUnityEngineObjectReference);
                    m_Adapters.TrySerialize(m_Stream, ref unityEngineObject);
                    return;
                }
#endif

                if (null != m_SerializedReferences && !value.GetType().IsValueType)
                {
                    // At this point we don't know if an object will reference this value.
                    // To avoid a second visitation pass we always create an entry for each managed object reference.
                    var id = m_SerializedReferences.AddSerializedReference(value);

                    if (!m_SerializedReferences.SetSerialized(value))
                    {
                        // This is the second time encountering this object during serialization.
                        // We instead of writing out the object we simply write the id.
                        m_Stream->Add(k_TokenSerializedReference);
                        m_Stream->Add(id);
                        return;
                    }
                }

                // This is a very common case. At serialize time we are serializing something that is polymorphic or an object
                // However at deserialize time the user known the System.Type, we can avoid writing out the fully qualified type name in this case.
                var isRootAndTypeWasGiven = isRoot && null != m_SerializedType;

                if (typeof(TValue) != value.GetType() && !isRootAndTypeWasGiven)
                {
                    m_Stream->Add(k_TokenPolymorphic);
                    m_Stream->Add(value.GetType().AssemblyQualifiedName);
                }
                else
                {
                    m_Stream->Add(k_TokenNone);
                }
            }

            if (RuntimeTypeInfoCache <TValue> .IsObjectType && !RuntimeTypeInfoCache.IsContainerType(value.GetType()))
            {
                BinarySerialization.WritePrimitiveBoxed(m_Stream, value, value.GetType());
                return;
            }

            if (!PropertyContainer.Visit(ref value, this, out var errorCode))
            {
                switch (errorCode)
                {
                case VisitErrorCode.NullContainer:
                    throw new ArgumentNullException(nameof(value));

                case VisitErrorCode.InvalidContainerType:
                    throw new InvalidContainerTypeException(value.GetType());

                case VisitErrorCode.MissingPropertyBag:
                    throw new MissingPropertyBagException(value.GetType());

                default:
                    throw new Exception($"Unexpected {nameof(VisitErrorCode)}=[{errorCode}]");
                }
            }
        }
Esempio n. 13
0
        bool CompareEquality <TValue>(TValue lhs, TValue rhs)
        {
            if (!RuntimeTypeInfoCache <TValue> .IsContainerType)
            {
                return(EqualityComparer <TValue> .Default.Equals(lhs, rhs));
            }

            if (RuntimeTypeInfoCache <TValue> .CanBeNull)
            {
                if (null == lhs)
                {
                    return(null == rhs);
                }
                if (null == rhs)
                {
                    return(false);
                }
            }

            if (!RuntimeTypeInfoCache <TValue> .IsValueType)
            {
                if (ReferenceEquals(lhs, rhs))
                {
                    return(true);
                }

                var type = lhs.GetType();

#if !UNITY_DOTSPLAYER
                // UnityEngine references can be copied as-is.
                if (typeof(UnityEngine.Object).IsAssignableFrom(type))
                {
                    return(EqualityComparer <TValue> .Default.Equals(lhs, rhs));
                }
#endif
                // Boxed value types can be compared as-is using the default comparer (with boxing).
                if (!RuntimeTypeInfoCache.IsContainerType(type))
                {
                    return(EqualityComparer <TValue> .Default.Equals(lhs, rhs));
                }

                var isReferenceType = !(type.IsValueType || type == typeof(string));

                if (isReferenceType)
                {
                    // If this is a reference within the same object. We need to compare against the reference within the other object.
                    // This is to support things like circular references/graph structures.
                    // The root object is not added to the map so we need to explicitly check for it.
                    if (m_LhsObject == (object)lhs)
                    {
                        return(m_RhsObject.Equals(rhs));
                    }

                    // Otherwise let's check the map if it exists.
                    if (null != m_References && m_References.TryGetValue(lhs, out var existingReference))
                    {
                        return(existingReference.Equals(rhs));
                    }

                    // Retain a mapping of references within this object. This is needed to support things like circular references.
                    if (null == m_References)
                    {
                        m_References = new Dictionary <object, object>();
                    }
                    m_References.Add(lhs, rhs);
                }
            }

            // We now have a properly constructed instance of the dstValue, nest in and copy all members.
            // Unity.Properties will automatically handle collection type from this point.
            var dstContainer = m_Stack;

            m_Stack = rhs;
            PropertyContainer.Visit(ref lhs, this, out _);
            m_Stack = dstContainer;

            return(m_Equals);
        }
        void ReadValue <TValue>(ref TValue value, bool isRoot = false)
        {
            var runAdapters = !(isRoot && m_DisableRootAdapters);

            if (runAdapters && m_Adapters.TryDeserialize(m_Stream, ref value))
            {
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsEnum)
            {
                BinarySerialization.ReadPrimitiveUnsafe(m_Stream, ref value, Enum.GetUnderlyingType(typeof(TValue)));
                return;
            }

            var token = default(byte);

            if (RuntimeTypeInfoCache <TValue> .CanBeNull)
            {
                token = m_Stream->ReadNext <byte>();

                switch (token)
                {
                case k_TokenNull:
                    value = default;
                    return;

                case k_TokenSerializedReference:
                    var id = m_Stream->ReadNext <int>();
                    if (null == m_SerializedReferences)
                    {
                        throw new Exception("Deserialization encountered a serialized object reference while running with DisableSerializedReferences.");
                    }
                    value = (TValue)m_SerializedReferences.GetDeserializedReference(id);
                    return;
                }
            }

            if (RuntimeTypeInfoCache <TValue> .IsNullable)
            {
                BinarySerialization.ReadPrimitiveBoxed(m_Stream, ref value, Nullable.GetUnderlyingType(typeof(TValue)));
                return;
            }

#if !UNITY_DOTSPLAYER
            if (runAdapters && token == k_TokenUnityEngineObjectReference)
            {
                var unityEngineObject = default(UnityEngine.Object);
                m_Adapters.TryDeserialize(m_Stream, ref unityEngineObject);
                value = (TValue)(object)unityEngineObject;
                return;
            }
#endif

            if (token == k_TokenPolymorphic)
            {
                m_Stream->ReadNext(out var assemblyQualifiedTypeName);

                if (string.IsNullOrEmpty(assemblyQualifiedTypeName))
                {
                    throw new ArgumentException();
                }

                var concreteType = Type.GetType(assemblyQualifiedTypeName);

                if (null == concreteType)
                {
                    if (FormerNameAttribute.TryGetCurrentTypeName(assemblyQualifiedTypeName, out var currentAssemblyQualifiedTypeName))
                    {
                        concreteType = Type.GetType(currentAssemblyQualifiedTypeName);
                    }

                    if (null == concreteType)
                    {
                        throw new ArgumentException();
                    }
                }

                m_SerializedTypeProviderSerializedType = concreteType;
            }
            else
            {
                // If we have a user provided root type pass it to the type construction.
                m_SerializedTypeProviderSerializedType = isRoot ? m_SerializedType : null;
            }

            DefaultTypeConstruction.Construct(ref value, this);

            if (RuntimeTypeInfoCache <TValue> .IsObjectType && !RuntimeTypeInfoCache.IsContainerType(value.GetType()))
            {
                BinarySerialization.ReadPrimitiveBoxed(m_Stream, ref value, value.GetType());
                return;
            }

            if (!PropertyContainer.Visit(ref value, this, out var errorCode))
            {
                switch (errorCode)
                {
                case VisitErrorCode.NullContainer:
                    throw new ArgumentNullException(nameof(value));

                case VisitErrorCode.InvalidContainerType:
                    throw new InvalidContainerTypeException(value.GetType());

                case VisitErrorCode.MissingPropertyBag:
                    throw new MissingPropertyBagException(value.GetType());

                default:
                    throw new Exception($"Unexpected {nameof(VisitErrorCode)}=[{errorCode}]");
                }
            }
        }
        internal void ReadValueWithoutAdapters <TValue>(ref TValue value, bool isRoot)
        {
            if (RuntimeTypeInfoCache <TValue> .IsEnum)
            {
                BinarySerialization.ReadPrimitiveUnsafe(m_Stream, ref value, Enum.GetUnderlyingType(typeof(TValue)));
                return;
            }

            var token = default(byte);

            if (RuntimeTypeInfoCache <TValue> .CanBeNull)
            {
                token = m_Stream->ReadNext <byte>();

                switch (token)
                {
                case k_TokenNull:
                    value = default;
                    return;

                case k_TokenSerializedReference:
                    var id = m_Stream->ReadNext <int>();
                    if (null == m_SerializedReferences)
                    {
                        throw new Exception("Deserialization encountered a serialized object reference while running with DisableSerializedReferences.");
                    }
                    value = (TValue)m_SerializedReferences.GetDeserializedReference(id);
                    return;
                }
            }

            if (RuntimeTypeInfoCache <TValue> .IsNullable)
            {
                var underlyingType = Nullable.GetUnderlyingType(typeof(TValue));

                if (RuntimeTypeInfoCache.IsContainerType(underlyingType))
                {
                    m_SerializedTypeProviderSerializedType = underlyingType;
                    DefaultTypeConstruction.Construct(ref value, this);

                    var underlyingValue = Convert.ChangeType(value, underlyingType);

                    if (!PropertyContainer.TryAccept(this, ref underlyingValue, out var errorCode))
                    {
                        switch (errorCode)
                        {
                        case VisitErrorCode.NullContainer:
                            throw new ArgumentNullException(nameof(value));

                        case VisitErrorCode.InvalidContainerType:
                            throw new InvalidContainerTypeException(value.GetType());

                        case VisitErrorCode.MissingPropertyBag:
                            throw new MissingPropertyBagException(value.GetType());

                        default:
                            throw new Exception($"Unexpected {nameof(VisitErrorCode)}=[{errorCode}]");
                        }
                    }

                    // Repack the T as Nullable<T>
                    value = (TValue)underlyingValue;
                }
                else
                {
                    BinarySerialization.ReadPrimitiveBoxed(m_Stream, ref value, Nullable.GetUnderlyingType(typeof(TValue)));
                }
                return;
            }

#if !UNITY_DOTSPLAYER
            if (!(isRoot && m_DisableRootAdapters) && token == k_TokenUnityEngineObjectReference)
            {
                value = (TValue)(m_Adapters.Internal as Adapters.Contravariant.IBinaryAdapter <UnityEngine.Object>).Deserialize(new BinaryDeserializationContext <TValue>(this, default, isRoot));;