using System.Collections.Generic; namespace Vellum.UnitTests { /// /// A [Saveable] node that can point at others in a loop, to drive loops of generated types. /// [Saveable] public sealed partial class Ring { public string Name; public Ring Next; public Ring Prev; } /// /// A [Saveable] class with each kind of member that can't be assigned outside a constructor, and a member that /// only the constructor sets. /// [Saveable] public sealed partial class Ledger { public readonly string Title; public readonly List Entries = new List(); public int Plain; [NoSave] public string Cache = "built"; public Ledger(string title, int count, string note) { Title = title; Count = count; Note = note; } public int Count { get; } public string Note { get; private set; } } /// /// A [Saveable] class whose own loader reads through the clan it belongs to, which holds it. /// [Saveable] public sealed partial class Clan { public string Name; public List Scouts = new List(); } [Saveable] public sealed partial class Scout { public Clan Clan; public int Rank; [NoSave] public int ClanSize; public Scout() { } private Scout(SaveReader reader) : this(reader, default(AutoLoadEveryField)) { ClanSize = Clan.Scouts.Count; } } /// /// A [Saveable] class that hashes by its name, which a set of its neighbours needs filled in first. /// [Saveable] public sealed partial class Planet { public string Name; public HashSet Neighbors = new HashSet(); public override bool Equals(object other) { var planet = other as Planet; return planet != null && planet.Name == Name; } public override int GetHashCode() { return Name.GetHashCode(); } } /// /// A [Saveable] node that holds a hash set of its neighbours, which hash by identity. /// [Saveable] public sealed partial class Vertex { public string Name; public HashSet Neighbors = new HashSet(); } [Saveable] public sealed partial class Cell { public string Name; public Cell[] Around; } /// /// A class that can be made early and completed, but whose converter writes none of its data before the /// constructor runs. /// public class Mote { public readonly string Name; public readonly HashSet Near; public Mote(string name, HashSet near) { Name = name; Near = near; } } public class MoteConverter : SaveConverter { public override SaveNode Write(Mote value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["name"] = session.ToNode(value.Name); returnMe.Entries["near"] = session.ToNode(value.Near, typeof(HashSet)); return returnMe; } public override Mote Read(SaveNode node, SaveSession session) { return new Mote(session.FromNode(node.RequireEntry("name")), session.FromNode>(node.RequireEntry("near"))); } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode near; if (!node.TryGetEntry("near", out near)) { return false; } children.Add(near, typeof(HashSet)); return true; } public override void Complete(Mote blank, SaveNode node, SaveSession session) { Construct(blank, session.FromNode(node.RequireEntry("name")), session.FromNode>(node.RequireEntry("near"))); } } /// /// An abstract class with a SaveReader constructor, which still can't be made early because it is abstract. /// public abstract class Blueprint { protected Blueprint(SaveReader reader) { } } public class BlueprintConverter : SaveConverter { public override SaveNode Write(Blueprint value, SaveSession session) { return SaveNode.NewTable(); } public override Blueprint Read(SaveNode node, SaveSession session) { throw new System.NotSupportedException(); } } /// /// A class with every kind of field a FieldWriter has to reach. /// public class Bucket { public readonly object Anything; public string Plain; private readonly string secret; public Bucket(string secret, int size) { this.secret = secret; Size = size; } public int Size { get; } public string Secret { get { return secret; } } } /// /// A class whose constructors a ConstructorRunner has to choose between. /// public class Counted { public readonly int Number; public readonly string Text; public Counted(int number) { Number = number; Text = "number"; } public Counted(string text, string other) { Text = text + other; } public Counted(string text, object other) { Text = text + "object"; } } /// /// A class whose constructors a null can't pick between. /// public class Doubtful { public readonly string Text; public Doubtful(string text) { Text = "string"; } public Doubtful(object other) { Text = "object"; } } /// /// A class with readonly fields whose converter fills them before any constructor runs. The constructor reads /// the partner's name, which is only there if the partner was filled. /// public class Spouse { public readonly string Name; public readonly Spouse Partner; public readonly int PairedLength; public Spouse(string name, Spouse partner) { Name = name; Partner = partner; PairedLength = name.Length; if (partner != null) { PairedLength += partner.Name.Length; } } } public class SpouseConverter : SaveConverter { public static readonly FieldWriter NameField = new FieldWriter(nameof(Spouse.Name)); public static readonly FieldWriter PartnerField = new FieldWriter(nameof(Spouse.Partner)); public override SaveNode Write(Spouse value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["name"] = session.ToNode(value.Name); returnMe.Entries["partner"] = session.ToNode(value.Partner, typeof(Spouse)); return returnMe; } public override Spouse Read(SaveNode node, SaveSession session) { return new Spouse(session.FromNode(node.RequireEntry("name")), session.FromNode(node.RequireEntry("partner"))); } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode partner; if (!node.TryGetEntry("partner", out partner)) { return false; } children.Add(partner, typeof(Spouse)); return true; } public override void Fill(Spouse blank, SaveNode node, SaveSession session) { NameField.Set(blank, session.FromNode(node.RequireEntry("name"))); PartnerField.Set(blank, session.FromNode(node.RequireEntry("partner"))); } public override void Complete(Spouse blank, SaveNode node, SaveSession session) { Construct(blank, session.FromNode(node.RequireEntry("name")), session.FromNode(node.RequireEntry("partner"))); } } /// /// A class whose converter builds it in one go, in a loop with a Plate that can be made early. /// public class Knob { public readonly Plate Plate; public Knob(Plate plate) { Plate = plate; } } public class KnobConverter : SaveConverter { public override SaveNode Write(Knob value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["plate"] = session.ToNode(value.Plate, typeof(Plate)); return returnMe; } public override Knob Read(SaveNode node, SaveSession session) { return new Knob(session.FromNode(node.RequireEntry("plate"))); } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode plate; if (!node.TryGetEntry("plate", out plate)) { return false; } children.Add(plate, typeof(Plate)); return true; } } public class Plate { public readonly Knob Knob; public readonly string Label; public Plate(Knob knob, string label) { Knob = knob; Label = label; } } public class PlateConverter : SaveConverter { public static readonly FieldWriter KnobField = new FieldWriter(nameof(Plate.Knob)); public static readonly FieldWriter LabelField = new FieldWriter(nameof(Plate.Label)); public override SaveNode Write(Plate value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["knob"] = session.ToNode(value.Knob, typeof(Knob)); returnMe.Entries["label"] = session.ToNode(value.Label); return returnMe; } public override Plate Read(SaveNode node, SaveSession session) { return new Plate(session.FromNode(node.RequireEntry("knob")), session.FromNode(node.RequireEntry("label"))); } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode knob; if (!node.TryGetEntry("knob", out knob)) { return false; } children.Add(knob, typeof(Knob)); return true; } public override void Fill(Plate blank, SaveNode node, SaveSession session) { KnobField.Set(blank, session.FromNode(node.RequireEntry("knob"))); LabelField.Set(blank, session.FromNode(node.RequireEntry("label"))); } public override void Complete(Plate blank, SaveNode node, SaveSession session) { Construct(blank, session.FromNode(node.RequireEntry("knob")), session.FromNode(node.RequireEntry("label"))); } } /// /// Two classes that point at each other and whose converters only build them in one go, so neither can exist /// before the other. /// public class Gate { public string Name; public Latch Latch; } public class GateConverter : SaveConverter { public override SaveNode Write(Gate value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["name"] = session.ToNode(value.Name); returnMe.Entries["latch"] = session.ToNode(value.Latch, typeof(Latch)); return returnMe; } public override Gate Read(SaveNode node, SaveSession session) { return new Gate { Name = session.FromNode(node.RequireEntry("name")), Latch = session.FromNode(node.RequireEntry("latch")), }; } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode latch; if (!node.TryGetEntry("latch", out latch)) { return false; } children.Add(latch, typeof(Latch)); return true; } } public class Latch { public string Name; public Gate Gate; } public class LatchConverter : SaveConverter { public override SaveNode Write(Latch value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["name"] = session.ToNode(value.Name); returnMe.Entries["gate"] = session.ToNode(value.Gate, typeof(Gate)); return returnMe; } public override Latch Read(SaveNode node, SaveSession session) { return new Latch { Name = session.FromNode(node.RequireEntry("name")), Gate = session.FromNode(node.RequireEntry("gate")), }; } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode gate; if (!node.TryGetEntry("gate", out gate)) { return false; } children.Add(gate, typeof(Gate)); return true; } } /// /// A class that hashes by its name, which its converter fills before any hash set holding it is. /// public class Badge { public readonly string Name; public readonly Hub Hub; public Badge(string name, Hub hub) { Name = name; Hub = hub; } public override bool Equals(object other) { var badge = other as Badge; return badge != null && badge.Name == Name; } public override int GetHashCode() { return Name.GetHashCode(); } } public class BadgeConverter : SaveConverter { public static readonly FieldWriter NameField = new FieldWriter(nameof(Badge.Name)); public static readonly FieldWriter HubField = new FieldWriter(nameof(Badge.Hub)); public override SaveNode Write(Badge value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["name"] = session.ToNode(value.Name); returnMe.Entries["hub"] = session.ToNode(value.Hub, typeof(Hub)); return returnMe; } public override Badge Read(SaveNode node, SaveSession session) { return new Badge(session.FromNode(node.RequireEntry("name")), session.FromNode(node.RequireEntry("hub"))); } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode hub; if (!node.TryGetEntry("hub", out hub)) { return false; } children.Add(hub, typeof(Hub)); return true; } public override void Fill(Badge blank, SaveNode node, SaveSession session) { NameField.Set(blank, session.FromNode(node.RequireEntry("name"))); HubField.Set(blank, session.FromNode(node.RequireEntry("hub"))); } public override void Complete(Badge blank, SaveNode node, SaveSession session) { Construct(blank, session.FromNode(node.RequireEntry("name")), session.FromNode(node.RequireEntry("hub"))); } } public class Hub { public readonly HashSet Badges; public Hub(HashSet badges) { Badges = badges; } } public class HubConverter : SaveConverter { public static readonly FieldWriter> BadgesField = new FieldWriter>(nameof(Hub.Badges)); public override SaveNode Write(Hub value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["badges"] = session.ToNode(value.Badges, typeof(HashSet)); return returnMe; } public override Hub Read(SaveNode node, SaveSession session) { return new Hub(session.FromNode>(node.RequireEntry("badges"))); } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode badges; if (!node.TryGetEntry("badges", out badges)) { return false; } children.Add(badges, typeof(HashSet)); return true; } public override void Fill(Hub blank, SaveNode node, SaveSession session) { BadgesField.Set(blank, session.FromNode>(node.RequireEntry("badges"))); } public override void Complete(Hub blank, SaveNode node, SaveSession session) { Construct(blank, session.FromNode>(node.RequireEntry("badges"))); } } }