// Returns: Whether the sub-type was converted in here and we should return now. void SerializeActualType(object obj, SaveInheritanceAttribute info, Type baseType, Type actualType, ref BitTarget header) { switch (info.Mode) { case SaveInheritanceMode.Index: if (!TryWriteListInheritance(info, actualType, false, ref header)) { throw new UnsupportedSubTypeException(baseType, actualType); } break; case SaveInheritanceMode.Key: WriteKeyInheritance(info, baseType, actualType, ref header); break; case SaveInheritanceMode.IndexOrKey: if (!TryWriteListInheritance(info, actualType, true, ref header)) { header.WriteBitOff(); WriteKeyInheritance(info, baseType, actualType, ref header); } break; } // Serialize the actual type now. SerializeItemNoSetup(obj, GetRuntimeMapItem(actualType), ref header, true); }
public static void EnsureHasAllTypeCache(Type type, SaveInheritanceAttribute info) { lock (info) { // Just use one of them to see if the cache is valid or not. if (info.HasGeneratedFullKeyCache) { return; } KeyedSubTypeInfo[]? keyedInfo = GetKeyedSubTypesFor(type); // We'll also fill in the serialize cache since we've now gone through all the types. info.KeySerializeCache = new Dictionary <Type, string>(keyedInfo.Length); info.KeyDeserializeCache = new Dictionary <string, Type>(keyedInfo.Length); for (int i = 0; i < keyedInfo.Length; i++) { KeyedSubTypeInfo currentInfo = keyedInfo[i]; info.KeySerializeCache.Add(currentInfo.Type, currentInfo.Key); info.KeyDeserializeCache.Add(currentInfo.Key, currentInfo.Type); } info.HasGeneratedFullKeyCache = true; } }
public static string GetOrAddTypeKeyFromCache(Type baseType, Type type, SaveInheritanceAttribute info) { lock (info) { // Try to get it from the cache. if (info.KeySerializeCache != null && info.KeySerializeCache.TryGetValue(type, out string?val)) { return(val); } Debug.Assert(!info.HasGeneratedFullKeyCache); // If it's not in the cache, get and add it now. SaveInheritanceKeyAttribute?attribute = type.GetCustomAttribute <SaveInheritanceKeyAttribute>(false); if (attribute == null) { throw new UnsupportedSubTypeException(baseType, type); } info.KeySerializeCache ??= new Dictionary <Type, string>(1); info.KeySerializeCache.Add(type, attribute.Key); info.KeyDeserializeCache ??= new Dictionary <string, Type>(1); info.KeyDeserializeCache.Add(attribute.Key, type); return(attribute.Key); } }
public void EnsureHasAllTypeCache_Existing() { SaveInheritanceAttribute attribute = typeof(KeyBase).GetCustomAttribute <SaveInheritanceAttribute>(); // Simulate it having already been done. attribute.HasGeneratedFullKeyCache = true; KeyInheritanceHandler.EnsureHasAllTypeCache(typeof(KeyBase), attribute); // Since nothing has actually been done these will just be null. Assert.IsNull(attribute.KeySerializeCache); Assert.IsNull(attribute.KeyDeserializeCache); }
bool TryWriteListInheritance(SaveInheritanceAttribute info, Type actualType, bool writeOnIfSuccessful, ref BitTarget header) { if (info.IndexSerializeCache !.TryGetValue(actualType, out uint pos)) { if (writeOnIfSuccessful) { header.WriteBitOn(); } WriteCompressedInt(pos, ref header); return(true); } return(false); }
public void GetOrAddTypeKeyFromCache_New() { SaveInheritanceAttribute attribute = typeof(KeyBase).GetCustomAttribute <SaveInheritanceAttribute>(); string key = KeyInheritanceHandler.GetOrAddTypeKeyFromCache(typeof(KeyBase), typeof(KeySubFirst), attribute); Assert.AreEqual("First", key); Assert.AreEqual(1, attribute.KeySerializeCache.Count); Assert.AreEqual(1, attribute.KeyDeserializeCache.Count); Assert.AreEqual("First", attribute.KeySerializeCache[typeof(KeySubFirst)]); Assert.AreEqual(typeof(KeySubFirst), attribute.KeyDeserializeCache["First"]); }
// Returns: Whether the sub-type was converted in here and we should return now. object DeserializeActualType(SaveInheritanceAttribute info, Type baseType) { Type?actualType = info.Mode switch { SaveInheritanceMode.Index => TryReadListInheritance(info, baseType), SaveInheritanceMode.Key => TryReadKeyInheritance(info, baseType), SaveInheritanceMode.IndexOrKey => _currentHeader.ReadBit() ? TryReadListInheritance(info, baseType) : TryReadKeyInheritance(info, baseType), _ => throw new Exception("Invalid save inheritance mode") }; if (actualType == null) { throw new InvalidSubTypeInfoException(baseType); } // Deserialize the actual type. return(DeserializeItemNoSetup(GetRuntimeMapItem(actualType), true)); } Type?TryReadListInheritance(SaveInheritanceAttribute info, Type baseType) { uint key = ReadCompressedInt(ref _currentHeader); return(info.IndexDeserializeCache.GetValueOrDefault(key)); } Type?TryReadKeyInheritance(SaveInheritanceAttribute info, Type baseType) { // Make sure the info is initialized for deserialization. KeyInheritanceHandler.EnsureHasAllTypeCache(baseType, info); // Read in the key from the source. string key = ReadString(ref _currentHeader); // See if there's an item with that key. return(info.KeyDeserializeCache !.GetValueOrDefault(key)); } void EnsureReadHeader() { if (!_readHeader) { _currentHeader = new BitSource(this, 8); _readHeader = true; } } }
public void EnsureHasAllTypeCache_New_CrossAssembly() { SaveInheritanceAttribute attribute = typeof(KeyBase).GetCustomAttribute <SaveInheritanceAttribute>(); KeyInheritanceHandler.EnsureHasAllTypeCache(typeof(OtherAssemblyBase), attribute); Assert.AreEqual(2, attribute.KeySerializeCache.Count); Assert.AreEqual(2, attribute.KeyDeserializeCache.Count); Assert.AreEqual("First", attribute.KeySerializeCache[typeof(OtherAssemblySub)]); Assert.AreEqual(typeof(OtherAssemblySub), attribute.KeyDeserializeCache["First"]); Assert.AreEqual("Second", attribute.KeySerializeCache[typeof(CrossAssemblySub)]); Assert.AreEqual(typeof(CrossAssemblySub), attribute.KeyDeserializeCache["Second"]); Assert.IsTrue(attribute.HasGeneratedFullKeyCache); }
public void GetOrAddTypeKeyFromCache_Exists() { SaveInheritanceAttribute attribute = typeof(KeyBase).GetCustomAttribute <SaveInheritanceAttribute>(); // Fill the cache up. var oldSerializeCache = attribute.KeySerializeCache = new Dictionary <Type, string>(); var oldDeserializeCache = attribute.KeyDeserializeCache = new Dictionary <string, Type>(); oldSerializeCache.Add(typeof(KeySubFirst), "First"); oldDeserializeCache.Add("First", typeof(KeySubFirst)); string key = KeyInheritanceHandler.GetOrAddTypeKeyFromCache(typeof(KeyBase), typeof(KeySubFirst), attribute); Assert.AreEqual("First", key); // Ensure it didn't add to the cache. Assert.AreEqual(oldSerializeCache, attribute.KeySerializeCache); Assert.AreEqual(oldDeserializeCache, attribute.KeyDeserializeCache); Assert.AreEqual(1, attribute.KeySerializeCache.Count); Assert.AreEqual(1, attribute.KeyDeserializeCache.Count); }
void WriteKeyInheritance(SaveInheritanceAttribute info, Type baseType, Type actualType, ref BitTarget header) { string key = KeyInheritanceHandler.GetOrAddTypeKeyFromCache(baseType, actualType, info); WriteString(key, ref header); }