using System; using System.Collections.Generic; using System.IO; namespace Vellum.UnitTests { public struct Point { public double X; public double Y; public Point(double x, double y) { X = x; Y = y; } } public class PointConverter : SaveConverter { public override SaveNode Write(Point value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["x"] = session.ToNode(value.X); returnMe.Entries["y"] = session.ToNode(value.Y); return returnMe; } public override Point Read(SaveNode node, SaveSession session) { return new Point(session.FromNode(node.RequireEntry("x")), session.FromNode(node.RequireEntry("y"))); } } /// /// A reference type whose converter saves another converted type inside it. /// public class Waypoint { public string Name; public Point At; } public class WaypointConverter : SaveConverter { public override SaveNode Write(Waypoint value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["name"] = session.ToNode(value.Name); returnMe.Entries["at"] = session.ToNode(value.At); return returnMe; } public override Waypoint Read(SaveNode node, SaveSession session) { return new Waypoint { Name = session.FromNode(node.RequireEntry("name")), At = session.FromNode(node.RequireEntry("at")), }; } } /// /// A type that can contain itself, to drive deep nesting. /// public class Link { public Link Next; } public class LinkConverter : SaveConverter { public override SaveNode Write(Link value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["next"] = session.ToNode(value.Next, typeof(Link)); return returnMe; } public override Link Read(SaveNode node, SaveSession session) { return new Link { Next = (Link)session.FromNode(node.RequireEntry("next"), typeof(Link)) }; } } /// /// A struct that holds a link, to drive deep nesting and cycles through a struct saved on its own. /// public struct LinkHolder { public Link Head; } public class LinkHolderConverter : SaveConverter { public override SaveNode Write(LinkHolder value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["head"] = session.ToNode(value.Head); return returnMe; } public override LinkHolder Read(SaveNode node, SaveSession session) { return new LinkHolder { Head = session.FromNode(node.RequireEntry("head")) }; } } /// /// A struct whose converter always fails, to check what saving one leaves behind. /// public struct FaultyStruct { } public class FaultyStructConverter : SaveConverter { public override SaveNode Write(FaultyStruct value, SaveSession session) { throw new InvalidOperationException("This struct can't be saved."); } public override FaultyStruct Read(SaveNode node, SaveSession session) { throw new InvalidDataException("This struct can't be loaded."); } } /// /// A type whose converter makes up a new one each time, so saving it never ends. /// public class Endless { } public class EndlessConverter : SaveConverter { public override SaveNode Write(Endless value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["next"] = session.ToNode(new Endless(), typeof(Endless)); return returnMe; } public override Endless Read(SaveNode node, SaveSession session) { return new Endless(); } } // Several of the generic converters below are mis-shaped or in conflict on purpose, to test how Vellum treats them. // The generator reports each, and the pragma silences what it says. #pragma warning disable VEL0002, VEL0003, VEL0007 /// /// A generic reference type, to drive converters that are closed over their type argument on first use. /// public class Box { public ItemType Content; } public class BoxConverter : SaveConverter> { public override SaveNode Write(Box value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["content"] = session.ToNode(value.Content, typeof(ItemType)); return returnMe; } public override Box Read(SaveNode node, SaveSession session) { return new Box { Content = (ItemType)session.FromNode(node.RequireEntry("content"), typeof(ItemType)), }; } } public struct Pair { public FirstType First; public SecondType Second; } /// /// Declares its type parameters in the opposite order from the pair it converts, so mixing the two up shows. /// public class PairConverter<[Saveable] SecondType, [Saveable] FirstType> : SaveConverter> { public override SaveNode Write(Pair value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["first"] = session.ToNode(value.First, typeof(FirstType)); returnMe.Entries["second"] = session.ToNode(value.Second, typeof(SecondType)); return returnMe; } public override Pair Read(SaveNode node, SaveSession session) { return new Pair { First = (FirstType)session.FromNode(node.RequireEntry("first"), typeof(FirstType)), Second = (SecondType)session.FromNode(node.RequireEntry("second"), typeof(SecondType)), }; } } /// /// A generic type that can contain itself, to drive the converters' depth limit through a closed converter. /// public class Cell { public Cell Next; } public class CellConverter : SaveConverter> { public override SaveNode Write(Cell value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["next"] = session.ToNode(value.Next, typeof(Cell)); return returnMe; } public override Cell Read(SaveNode node, SaveSession session) { return new Cell { Next = (Cell)session.FromNode(node.RequireEntry("next"), typeof(Cell)), }; } } /// /// A type nested in a generic type, whose converter's type parameters are those of both types. /// public class Holder { public class Slot { public OuterType Outer; public InnerType Inner; } } public class SlotConverter<[Saveable] OuterType, [Saveable] InnerType> : SaveConverter.Slot> { public override SaveNode Write(Holder.Slot value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["outer"] = session.ToNode(value.Outer, typeof(OuterType)); returnMe.Entries["inner"] = session.ToNode(value.Inner, typeof(InnerType)); return returnMe; } public override Holder.Slot Read(SaveNode node, SaveSession session) { return new Holder.Slot { Outer = (OuterType)session.FromNode(node.RequireEntry("outer"), typeof(OuterType)), Inner = (InnerType)session.FromNode(node.RequireEntry("inner"), typeof(InnerType)), }; } } /// /// A generic type that only takes value types, so closing it over anything else fails. /// public class Limited where ItemType : struct { } public enum Mood { Calm, Angry, } public class Palette { public enum Shade : byte { Light, Dark, } } public class Counted { } /// /// Counts the converters made for each closed type, since a static in a generic class is one per closed type. /// public class CountedConverter : SaveConverter> { public static int Made; public CountedConverter() { ++Made; } public override SaveNode Write(Counted value, SaveSession session) { return SaveNode.OfText("counted"); } public override Counted Read(SaveNode node, SaveSession session) { return new Counted(); } } public class StructBoxConverter : SaveConverter> where ItemType : struct { public override SaveNode Write(Box value, SaveSession session) { return SaveNode.OfText("struct box"); } public override Box Read(SaveNode node, SaveSession session) { return new Box(); } } public abstract class AbstractBoxConverter : SaveConverter> { } /// /// Converts only part of a generic type, which would claim every dictionary with string keys. /// public class PartlyClosedConverter : SaveConverter> { public override SaveNode Write(Dictionary value, SaveSession session) { return SaveNode.Null; } public override Dictionary Read(SaveNode node, SaveSession session) { return null; } } public class RepeatedParameterConverter : SaveConverter> { public override SaveNode Write(Pair value, SaveSession session) { return SaveNode.Null; } public override Pair Read(SaveNode node, SaveSession session) { return default(Pair); } } /// /// Derives from the non-generic SaveConverter, so it names no type it converts. /// public class UntypedGenericConverter : SaveConverter { public override Type ValueType { get { return typeof(Box); } } public override SaveNode ToNode(object value, SaveSession session) { return SaveNode.Null; } public override object FromNode(SaveNode node, SaveSession session) { return null; } } public class NestedArgumentConverter : SaveConverter>> { public override SaveNode Write(Box> value, SaveSession session) { return SaveNode.Null; } public override Box> Read(SaveNode node, SaveSession session) { return null; } } public class ExtraParameterConverter : SaveConverter> { public override SaveNode Write(Box value, SaveSession session) { return SaveNode.Null; } public override Box Read(SaveNode node, SaveSession session) { return null; } } public class AnyTypeConverter : SaveConverter { public override SaveNode Write(ItemType value, SaveSession session) { return SaveNode.Null; } public override ItemType Read(SaveNode node, SaveSession session) { return default(ItemType); } } public class NullableOfAnyConverter : SaveConverter where ItemType : struct { public override SaveNode Write(ItemType? value, SaveSession session) { return SaveNode.Null; } public override ItemType? Read(SaveNode node, SaveSession session) { return null; } } public class IntArrayConverter : SaveConverter { public override SaveNode Write(int[] value, SaveSession session) { return SaveNode.Null; } public override int[] Read(SaveNode node, SaveSession session) { return null; } } public class ArrayOfParameterConverter : SaveConverter { public override SaveNode Write(ItemType[] value, SaveSession session) { return SaveNode.Null; } public override ItemType[] Read(SaveNode node, SaveSession session) { return null; } } public class MultiDimensionalConverter : SaveConverter { public override SaveNode Write(ItemType[,] value, SaveSession session) { return SaveNode.Null; } public override ItemType[,] Read(SaveNode node, SaveSession session) { return null; } } /// /// Converts any type, for building converter sets by hand. /// public class StubConverter : SaveConverter { public override SaveNode Write(T value, SaveSession session) { return SaveNode.OfText("stub"); } public override T Read(SaveNode node, SaveSession session) { return default(T); } } #pragma warning restore VEL0002, VEL0003, VEL0007 }