using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; namespace SharpGLTF.SchemaReflection { /// /// Base class for all schema Types /// public abstract partial class SchemaType { #region constructor protected SchemaType(Context ctx) { _Owner = ctx; } #endregion #region data /// /// context where this type is stored /// private readonly Context _Owner; /// /// identifier used for serialization and deserialization /// public abstract string PersistentName { get; } #endregion #region properties public Context Owner => _Owner; #endregion } [System.Diagnostics.DebuggerDisplay("{PersistentName}")] public sealed class StringType : SchemaType { #region constructor internal StringType(Context ctx) : base(ctx) { } #endregion #region properties public override string PersistentName => typeof(String).Name; #endregion } [System.Diagnostics.DebuggerDisplay("{PersistentName}")] public sealed class ObjectType : SchemaType { #region constructor internal ObjectType(Context ctx) : base(ctx) { } #endregion #region properties public override string PersistentName => typeof(Object).Name; #endregion } [System.Diagnostics.DebuggerDisplay("{PersistentName}")] public sealed class BlittableType : SchemaType { #region constructor internal BlittableType(Context ctx, TypeInfo t, bool isNullable) : base(ctx) { if (t == typeof(String).GetTypeInfo()) isNullable = false; _Type = t; _IsNullable = isNullable; } #endregion #region data // https://en.wikipedia.org/wiki/Blittable_types private readonly TypeInfo _Type; private readonly Boolean _IsNullable; #endregion #region properties public TypeInfo DataType => _Type; public bool IsNullable => _IsNullable; public override string PersistentName => _IsNullable ? $"{_Type.Name}?" : _Type.Name; #endregion } [System.Diagnostics.DebuggerDisplay("enum {PersistentName}")] public sealed class EnumType : SchemaType { #region constructor internal EnumType(Context ctx, string name, bool isNullable) : base(ctx) { _PersistentName = name; _IsNullable = isNullable; } #endregion #region data private readonly String _PersistentName; private readonly Boolean _IsNullable; private bool _UseIntegers; private readonly Dictionary _Values = new Dictionary(); #endregion #region properties public bool IsNullable => _IsNullable; public override string PersistentName => _PersistentName; public bool UseIntegers { get => _UseIntegers; set => _UseIntegers = value; } public SchemaType ItemType => UseIntegers ? (SchemaType)Owner.UseBlittable(typeof(int).GetTypeInfo()) : Owner.UseString(); public IEnumerable> Values => _Values; #endregion #region API public void SetValue(string key, int val) { _Values[key] = val; } #endregion } [System.Diagnostics.DebuggerDisplay("{PersistentName}")] public sealed class ArrayType : SchemaType { #region constructor internal ArrayType(Context ctx, SchemaType element) : base(ctx) { _ItemType = element; } #endregion #region data private readonly SchemaType _ItemType; public SchemaType ItemType => _ItemType; #endregion #region properties public override string PersistentName => $"{_ItemType.PersistentName}[]"; #endregion } [System.Diagnostics.DebuggerDisplay("{PersistentName}")] public sealed class DictionaryType : SchemaType { #region lifecycle internal DictionaryType(Context ctx, SchemaType key,SchemaType val) : base(ctx) { _KeyType = key; _ValueType = val; } #endregion #region data private readonly SchemaType _KeyType; private readonly SchemaType _ValueType; #endregion #region properties public SchemaType KeyType => _KeyType; public SchemaType ValueType => _ValueType; public override string PersistentName => $"<{_KeyType.PersistentName},{_ValueType.PersistentName}>[]"; #endregion } [System.Diagnostics.DebuggerDisplay("{FieldType.PersistentName} {PersistentName}")] public sealed class FieldInfo { #region lifecycle internal FieldInfo(ClassType owner, string name) { _Owner = owner; _PersistentName = name; } #endregion #region data private readonly ClassType _Owner; private readonly String _PersistentName; private SchemaType _FieldType; private Object _DefaultValue; private Object _MinimumValue; private Object _MaximumValue; private int _MinItems; private int _MaxItems; #endregion #region properties public ClassType DeclaringClass => _Owner; public string PersistentName => _PersistentName; public SchemaType FieldType { get => _FieldType; set => _FieldType = value; } public Object DefaultValue { get => _DefaultValue; set => _DefaultValue = value; } public Object MinimumValue { get => _MinimumValue; set => _MinimumValue = value; } public Object MaximumValue { get => _MaximumValue; set => _MaximumValue = value; } public int MinItems { get => _MinItems; set => _MinItems = value; } public int MaxItems { get => _MaxItems; set => _MaxItems = value; } #endregion #region fluent api public FieldInfo SetDataType(SchemaType type) { _FieldType = type; return this; } public FieldInfo SetDataType(Type type, bool isNullable) { _FieldType = DeclaringClass.Owner.UseBlittable(type.GetTypeInfo(), isNullable); return this; } public FieldInfo RemoveDefaultValue() { _DefaultValue = null; return this; } public FieldInfo SetDefaultValue(string defval) { _DefaultValue = defval; return this; } public FieldInfo SetLimits(Decimal? min, Decimal? max) { _MinimumValue = min; _MaximumValue = max; return this; } public FieldInfo SetItemsRange(int min, int max = int.MaxValue) { _MinItems = min; _MaxItems = max; return this; } #endregion #region comparer helper private sealed class _Comparer : IEqualityComparer { public bool Equals(FieldInfo x, FieldInfo y) { return x._PersistentName == y._PersistentName; } public int GetHashCode(FieldInfo obj) { return obj._PersistentName.GetHashCode(); } } private static readonly _Comparer _DefaultComparer = new _Comparer(); public static IEqualityComparer Comparer => _DefaultComparer; #endregion } [System.Diagnostics.DebuggerDisplay("class {PersistentName} : {BaseClass.PersistentName}")] public sealed class ClassType : SchemaType { #region constructor internal ClassType(Context ctx, string name) : base(ctx) { _PersistentName = name; } #endregion #region data private readonly String _PersistentName; private readonly HashSet _Fields = new HashSet(FieldInfo.Comparer); private ClassType _BaseClass; public override string PersistentName => _PersistentName; public ClassType BaseClass { get => _BaseClass; set => _BaseClass = value; } public IEnumerable Fields => _Fields; #endregion #region API public FieldInfo UseField(string name) { var f = new FieldInfo(this, name); _Fields.Add(f); return _Fields.FirstOrDefault(item => item.PersistentName == name); } #endregion } /// /// not used /// public sealed class ReferenceType : SchemaType { #region constructor internal ReferenceType(Context ctx, SchemaType refType) : base(ctx) { _ReferencedType = refType; } #endregion #region data // In code it has the representation List(); // In serialization, it has the representation List(); private readonly SchemaType _ReferencedType; public override string PersistentName => throw new NotImplementedException(); #endregion } }