using System; using System.Collections.Generic; using Vellum; namespace Amphora.Vellum { /// /// Saves an OrderedDictionary as a table holding a list of its key and value pairs in order, and its comparer /// unless that's the default. /// public sealed class OrderedDictionaryConverter<[Saveable] KeyType, [Saveable] ValueType> : SaveContainerConverter> { // A list of pairs rather than a map, since a map is written sorted and this order is the point. public const string EntriesKey = "entries"; public const string KeyKey = "key"; public const string ValueKey = "value"; public override SaveNode Write(OrderedDictionary value, SaveSession session) { SaveNode entries = SaveNode.NewList(); foreach (var entry in value) { SaveNode pair = SaveNode.NewTable(); pair.Entries[KeyKey] = session.ToNode(entry.Key); pair.Entries[ValueKey] = session.ToNode(entry.Value); entries.Items.Add(pair); } SaveNode returnMe = SaveNode.NewTable(); SavedComparer.Write(returnMe, value.Comparer); returnMe.Entries[EntriesKey] = entries; return returnMe; } public override OrderedDictionary Allocate(SaveNode node, SaveSession session) { node.RequireEntry(EntriesKey).RequireItems(); return new OrderedDictionary(SavedComparer.Read(node)); } // A pair that can't be loaded whole is left out, and the session's Sandbox records why. public override void Fill(OrderedDictionary blank, SaveNode node, SaveSession session) { SaveNode entries = node.RequireEntry(EntriesKey); IReadOnlyList pairs = entries.RequireItems(); for (int i = 0; i < pairs.Count; ++i) { try { var reader = new SaveReader(pairs[i], session); KeyType key = reader.Require(KeyKey); SavedEntries.RejectRepeatedKey(blank, key, pairs[i].Entries[KeyKey]); blank.Add(key, reader.Require(ValueKey)); } catch (Exception exception) when (LoadSandbox.CanRecover(exception)) { session.RecordFailure(exception, entries, i); } } } public override bool FillNeedsFilledPart(Type partType) { return partType == typeof(KeyType); } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode entries; if (!node.TryGetEntry(EntriesKey, out entries)) { return false; } IReadOnlyList pairs; if (!entries.TryGetItems(out pairs)) { return false; } foreach (SaveNode pair in pairs) { SaveNode key; SaveNode value; if (!pair.TryGetEntry(KeyKey, out key) || !pair.TryGetEntry(ValueKey, out value)) { return false; } children.Add(key, typeof(KeyType)); children.Add(value, typeof(ValueType)); } return true; } } }