< Summary

Class:GDX.Collections.Generic.SerializableDictionary[TKey,TValue]
Assembly:GDX
File(s):./Packages/com.dotbunny.gdx/GDX/Collections/Generic/SerializableDictionary.cs
Covered lines:45
Uncovered lines:18
Coverable lines:63
Total lines:203
Line coverage:71.4% (45 of 63)
Covered branches:0
Total branches:0
Covered methods:6
Total methods:8
Method coverage:75% (6 of 8)

Coverage History

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
OnAfterDeserialize()0%2100%
OnBeforeSerialize()0%2100%
GetSerializedDataLength()0%110100%
IsSerializableType(...)0%110100%
LoadSerializedData(...)0%6.896070.83%
OverwriteSerializedData(...)0%2.152066.67%
SaveSerializedData()0%3.013088.89%
SerializableDictionary()0%220100%

File(s)

./Packages/com.dotbunny.gdx/GDX/Collections/Generic/SerializableDictionary.cs

#LineLine coverage
 1// Copyright (c) 2020-2024 dotBunny Inc.
 2// dotBunny licenses this file to you under the BSL-1.0 license.
 3// See the LICENSE file in the project root for more information.
 4
 5#if !UNITY_DOTSRUNTIME
 6
 7using System;
 8using System.Collections.Generic;
 9using UnityEngine;
 10
 11namespace GDX.Collections.Generic
 12{
 13#pragma warning disable IDE0049
 14    /// <summary>
 15    ///     A Unity serializable <see cref="Dictionary{TKey,TValue}" />.
 16    /// </summary>
 17    /// <remarks>
 18    ///     <para>
 19    ///         This will NOT work with <see cref="System.Object" /> based objects, use <see cref="UnityEngine.Object" /
 20    ///         you must. While .NET has solutions for creating custom serialization paths, Unity uses its own system to
 21    ///         serialize data into YAML structures. This also assumes that the types provided can be serialized by Unit
 22    ///     </para>
 23    ///     <para>
 24    ///         The process of serializing and deserializing this dictionary should not be considered performant.
 25    ///     </para>
 26    ///     <para>
 27    ///         The property drawer will not show structs, it will be blank. It does work however if done through code.
 28    ///     </para>
 29    /// </remarks>
 30    /// <typeparam name="TKey">The dictionary's key <see cref="Type" />.</typeparam>
 31    /// <typeparam name="TValue">The dictionary's value <see cref="Type" />.</typeparam>
 32    /// <exception cref="UnsupportedRuntimeException">Not supported on DOTS Runtime.</exception>
 33    [Serializable]
 34#pragma warning restore IDE0049
 35    [VisualScriptingCompatible(1)]
 36    public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
 37    {
 38        /// <summary>
 39        ///     Type constructor.
 40        /// </summary>
 341        public SerializableDictionary()
 342        {
 43#if UNITY_EDITOR
 344            m_IsSerializable = IsSerializableType(typeof(TKey)) && IsSerializableType(typeof(TValue));
 45#endif // UNITY_EDITOR
 346        }
 47
 48        /// <summary>
 49        ///     Rehydrate the serialized data arrays back into a cohesive <see cref="Dictionary{TKey,TValue}" />.
 50        /// </summary>
 51        /// <remarks>Invoked by Unity, calls <see cref="LoadSerializedData" />.</remarks>
 52        public void OnAfterDeserialize()
 053        {
 054            LoadSerializedData();
 055        }
 56
 57        /// <summary>
 58        ///     Build out serialized data arrays and associative data, used to rehydrate during deserialization.
 59        /// </summary>
 60        /// <remarks>Invoked by Unity, calls <see cref="SaveSerializedData" />.</remarks>
 61        public void OnBeforeSerialize()
 062        {
 063            SaveSerializedData();
 064        }
 65
 66        /// <summary>
 67        ///     Get the length of the serialized data arrays.
 68        /// </summary>
 69        /// <returns>An integer value representing the count.</returns>
 70        public int GetSerializedDataLength()
 271        {
 272            return m_SerializedLength;
 273        }
 74
 75        /// <summary>
 76        ///     Is the <paramref name="type" /> capable of being serialized by the
 77        ///     <see cref="SerializableDictionary{TKey,TValue}" />, utilizing Unity's own serialization system?
 78        /// </summary>
 79        /// <returns>true/false if the type is valid.</returns>
 80        public static bool IsSerializableType(Type type)
 881        {
 882            return type != typeof(object);
 883        }
 84
 85        /// <summary>
 86        ///     Load the data into the <see cref="Dictionary{TKey,TValue}" /> cached in the serialized data.
 87        /// </summary>
 88        /// <param name="clearAfterLoad">Should the serialized data be cleared after loading?</param>
 89        public void LoadSerializedData(bool clearAfterLoad = true)
 190        {
 191            Clear();
 92
 93            // If this is not serializable we need to do nothing
 194            if (!m_IsSerializable || m_SerializedLength <= 0)
 095            {
 096                return;
 97            }
 98
 99            // Iterate over all the serialized data and put it back into the dictionary as it once was, in order.
 6100            for (int i = 0; i < m_SerializedLength; i++)
 2101            {
 102#if UNITY_EDITOR
 103                // If the key is already in the dataset what do we do?
 2104                if (ContainsKey(m_SerializedKeys[i]))
 0105                {
 0106                    Debug.LogError(
 107                        "A duplicate key has been detected in the serialized dictionary, the item has been removed.\nYou
 0108                }
 109                else
 2110                {
 111#endif // UNITY_EDITOR
 2112                    Add(m_SerializedKeys[i], m_SerializedValues[i]);
 113#if UNITY_EDITOR
 2114                }
 115#endif // UNITY_EDITOR
 2116            }
 117
 118            // Remove any data cached so that references are not held.
 1119            if (!clearAfterLoad)
 0120            {
 0121                return;
 122            }
 123
 1124            m_SerializedLength = -1;
 1125            m_SerializedKeys = null;
 1126            m_SerializedValues = null;
 1127        }
 128
 129        /// <summary>
 130        ///     Overwrite data in the serialized arrays with the provided data.
 131        /// </summary>
 132        /// <param name="keyArray">An array of keys.</param>
 133        /// <param name="valueArray">An array of values.</param>
 134        public void OverwriteSerializedData(TKey[] keyArray, TValue[] valueArray)
 1135        {
 1136            if (keyArray.Length != valueArray.Length)
 0137            {
 0138                Debug.LogError("The provided array lengths must match.");
 0139                return;
 140            }
 141
 1142            m_SerializedKeys = keyArray;
 1143            m_SerializedValues = valueArray;
 1144            m_SerializedLength = keyArray.Length;
 1145        }
 146
 147        /// <summary>
 148        ///     Fill serializable arrays from dictionary data.
 149        /// </summary>
 150        /// <remarks>We will always create the arrays so the property drawers function nicely.</remarks>
 151        public void SaveSerializedData()
 2152        {
 153            // If this is not serializable we need to do nothing
 2154            if (!m_IsSerializable)
 0155            {
 0156                return;
 157            }
 158
 159            // Stash our length for future usage
 2160            m_SerializedLength = Count;
 161
 162            // Create our serialized data arrays
 2163            m_SerializedKeys = new TKey[m_SerializedLength];
 2164            m_SerializedValues = new TValue[m_SerializedLength];
 165
 166            // Stash our values
 2167            int index = 0;
 10168            foreach (KeyValuePair<TKey, TValue> pair in this)
 2169            {
 2170                m_SerializedKeys[index] = pair.Key;
 2171                m_SerializedValues[index] = pair.Value;
 2172                index++;
 2173            }
 2174        }
 175#pragma warning disable IDE1006
 176        // ReSharper disable InconsistentNaming
 177
 178        /// <summary>
 179        ///     Is the dictionary completely capable of being serialized by Unity?
 180        /// </summary>
 181        /// <remarks>This field is determined/cached in the constructor.</remarks>
 182        [SerializeField] bool m_IsSerializable;
 183
 184        /// <summary>
 185        ///     The length of the serialized data arrays.
 186        /// </summary>
 3187        [SerializeField] int m_SerializedLength = -1;
 188
 189        /// <summary>
 190        ///     An array of all of the keys, in order, used to recreate the base <see cref="Dictionary{TKey,TValue}" />.
 191        /// </summary>
 192        [SerializeField] TKey[] m_SerializedKeys;
 193
 194        /// <summary>
 195        ///     An array of all of the values, in order, used to recreate the base <see cref="Dictionary{TKey,TValue}" /
 196        /// </summary>
 197        [SerializeField] TValue[] m_SerializedValues;
 198
 199        // ReSharper restore InconsistentNaming
 200#pragma warning restore IDE1006
 201    }
 202}
 203#endif // !UNITY_DOTSRUNTIME

Coverage by test methods







Methods/Properties

SerializableDictionary()
OnAfterDeserialize()
OnBeforeSerialize()
GetSerializedDataLength()
IsSerializableType(System.Type)
LoadSerializedData(System.Boolean)
OverwriteSerializedData(, )
SaveSerializedData()