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));;