SchemaTypes.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Text;
  6. namespace SharpGLTF.SchemaReflection
  7. {
  8. /// <summary>
  9. /// Base class for all schema Types
  10. /// </summary>
  11. public abstract partial class SchemaType
  12. {
  13. #region constructor
  14. protected SchemaType(Context ctx) { _Owner = ctx; }
  15. #endregion
  16. #region data
  17. /// <summary>
  18. /// context where this type is stored
  19. /// </summary>
  20. private readonly Context _Owner;
  21. /// <summary>
  22. /// identifier used for serialization and deserialization
  23. /// </summary>
  24. public abstract string PersistentName { get; }
  25. #endregion
  26. #region properties
  27. public String Description { get; set; }
  28. public Context Owner => _Owner;
  29. #endregion
  30. }
  31. [System.Diagnostics.DebuggerDisplay("{PersistentName}")]
  32. public sealed class StringType : SchemaType
  33. {
  34. #region constructor
  35. internal StringType(Context ctx) : base(ctx) { }
  36. #endregion
  37. #region properties
  38. public override string PersistentName => typeof(String).Name;
  39. #endregion
  40. }
  41. [System.Diagnostics.DebuggerDisplay("{PersistentName}")]
  42. public sealed class ObjectType : SchemaType
  43. {
  44. #region constructor
  45. internal ObjectType(Context ctx) : base(ctx) { }
  46. #endregion
  47. #region properties
  48. public override string PersistentName => typeof(Object).Name;
  49. #endregion
  50. }
  51. [System.Diagnostics.DebuggerDisplay("{PersistentName}")]
  52. public sealed class BlittableType : SchemaType
  53. {
  54. #region constructor
  55. internal BlittableType(Context ctx, TypeInfo t, bool isNullable) : base(ctx)
  56. {
  57. if (t == typeof(String).GetTypeInfo()) isNullable = false;
  58. _Type = t;
  59. _IsNullable = isNullable;
  60. }
  61. #endregion
  62. #region data
  63. // https://en.wikipedia.org/wiki/Blittable_types
  64. private readonly TypeInfo _Type;
  65. private readonly Boolean _IsNullable;
  66. #endregion
  67. #region properties
  68. public TypeInfo DataType => _Type;
  69. public bool IsNullable => _IsNullable;
  70. public override string PersistentName => _IsNullable ? $"{_Type.Name}?" : _Type.Name;
  71. #endregion
  72. }
  73. [System.Diagnostics.DebuggerDisplay("enum {PersistentName}")]
  74. public sealed class EnumType : SchemaType
  75. {
  76. #region constructor
  77. internal EnumType(Context ctx, string name, bool isNullable) : base(ctx)
  78. {
  79. _PersistentName = name;
  80. _IsNullable = isNullable;
  81. }
  82. #endregion
  83. #region data
  84. private readonly String _PersistentName;
  85. private readonly Boolean _IsNullable;
  86. private bool _UseIntegers;
  87. private readonly Dictionary<string, int> _Values = new Dictionary<string, int>();
  88. #endregion
  89. #region properties
  90. public bool IsNullable => _IsNullable;
  91. public override string PersistentName => _PersistentName;
  92. public bool UseIntegers { get => _UseIntegers; set => _UseIntegers = value; }
  93. public SchemaType ItemType => UseIntegers ? (SchemaType)Owner.UseBlittable(typeof(int).GetTypeInfo()) : Owner.UseString();
  94. public IEnumerable<KeyValuePair<string, int>> Values => _Values;
  95. #endregion
  96. #region API
  97. public void SetValue(string key, int val) { _Values[key] = val; }
  98. #endregion
  99. }
  100. [System.Diagnostics.DebuggerDisplay("{PersistentName}")]
  101. public sealed class ArrayType : SchemaType
  102. {
  103. #region constructor
  104. internal ArrayType(Context ctx, SchemaType element) : base(ctx)
  105. {
  106. _ItemType = element;
  107. }
  108. #endregion
  109. #region data
  110. private readonly SchemaType _ItemType;
  111. public SchemaType ItemType => _ItemType;
  112. #endregion
  113. #region properties
  114. public override string PersistentName => $"{_ItemType.PersistentName}[]";
  115. #endregion
  116. }
  117. [System.Diagnostics.DebuggerDisplay("{PersistentName}")]
  118. public sealed class DictionaryType : SchemaType
  119. {
  120. #region lifecycle
  121. internal DictionaryType(Context ctx, SchemaType key,SchemaType val) : base(ctx)
  122. {
  123. _KeyType = key;
  124. _ValueType = val;
  125. }
  126. #endregion
  127. #region data
  128. private readonly SchemaType _KeyType;
  129. private readonly SchemaType _ValueType;
  130. #endregion
  131. #region properties
  132. public SchemaType KeyType => _KeyType;
  133. public SchemaType ValueType => _ValueType;
  134. public override string PersistentName => $"<{_KeyType.PersistentName},{_ValueType.PersistentName}>[]";
  135. #endregion
  136. }
  137. [System.Diagnostics.DebuggerDisplay("{FieldType.PersistentName} {PersistentName}")]
  138. public sealed class FieldInfo
  139. {
  140. #region lifecycle
  141. internal FieldInfo(ClassType owner, string name)
  142. {
  143. _Owner = owner;
  144. _PersistentName = name;
  145. }
  146. #endregion
  147. #region data
  148. private readonly ClassType _Owner;
  149. private readonly String _PersistentName;
  150. private SchemaType _FieldType;
  151. private Object _DefaultValue;
  152. private Object _MinimumValue;
  153. private Object _MaximumValue;
  154. private int _MinItems;
  155. private int _MaxItems;
  156. #endregion
  157. #region properties
  158. public ClassType DeclaringClass => _Owner;
  159. public String Description { get; set; }
  160. public string PersistentName => _PersistentName;
  161. public SchemaType FieldType { get => _FieldType; set => _FieldType = value; }
  162. public Object DefaultValue { get => _DefaultValue; set => _DefaultValue = value; }
  163. public Object MinimumValue { get => _MinimumValue; set => _MinimumValue = value; }
  164. public Object MaximumValue { get => _MaximumValue; set => _MaximumValue = value; }
  165. public int MinItems { get => _MinItems; set => _MinItems = value; }
  166. public int MaxItems { get => _MaxItems; set => _MaxItems = value; }
  167. #endregion
  168. #region fluent api
  169. public FieldInfo SetDataType(SchemaType type) { _FieldType = type; return this; }
  170. public FieldInfo SetDataType(Type type, bool isNullable)
  171. {
  172. _FieldType = DeclaringClass.Owner.UseBlittable(type.GetTypeInfo(), isNullable);
  173. return this;
  174. }
  175. public FieldInfo RemoveDefaultValue() { _DefaultValue = null; return this; }
  176. public FieldInfo SetDefaultValue(string defval) { _DefaultValue = defval; return this; }
  177. public FieldInfo SetLimits(Decimal? min, Decimal? max) { _MinimumValue = min; _MaximumValue = max; return this; }
  178. public FieldInfo SetItemsRange(int min, int max = int.MaxValue) { _MinItems = min; _MaxItems = max; return this; }
  179. #endregion
  180. #region comparer helper
  181. private sealed class _Comparer : IEqualityComparer<FieldInfo> , IComparer<FieldInfo>
  182. {
  183. public int Compare(FieldInfo x, FieldInfo y)
  184. {
  185. var xx = _Adjust(x._PersistentName);
  186. var yy = _Adjust(y._PersistentName);
  187. return string.CompareOrdinal(xx, yy);
  188. }
  189. private static string _Adjust(string name)
  190. {
  191. if (name.StartsWith("asset")) return "____" + name;
  192. if (name.StartsWith("extensions")) return "___" + name;
  193. return name;
  194. }
  195. public bool Equals(FieldInfo x, FieldInfo y) { return Compare(x,y) == 0; }
  196. public int GetHashCode(FieldInfo obj) { return obj._PersistentName.GetHashCode(); }
  197. }
  198. private static readonly _Comparer _DefaultComparer = new _Comparer();
  199. public static IEqualityComparer<FieldInfo> EqualityComparer => _DefaultComparer;
  200. public static IComparer<FieldInfo> Comparer => _DefaultComparer;
  201. #endregion
  202. }
  203. [System.Diagnostics.DebuggerDisplay("class {PersistentName} : {BaseClass.PersistentName}")]
  204. public sealed class ClassType : SchemaType
  205. {
  206. #region constructor
  207. internal ClassType(Context ctx, string name) : base(ctx)
  208. {
  209. _PersistentName = name;
  210. }
  211. #endregion
  212. #region data
  213. private readonly String _PersistentName;
  214. private readonly SortedSet<FieldInfo> _Fields = new SortedSet<FieldInfo>(FieldInfo.Comparer);
  215. private ClassType _BaseClass;
  216. public override string PersistentName => _PersistentName;
  217. public ClassType BaseClass { get => _BaseClass; set => _BaseClass = value; }
  218. public IEnumerable<FieldInfo> Fields => _Fields;
  219. #endregion
  220. #region API
  221. public FieldInfo UseField(string name)
  222. {
  223. var f = new FieldInfo(this, name);
  224. _Fields.Add(f);
  225. return _Fields.FirstOrDefault(item => item.PersistentName == name);
  226. }
  227. #endregion
  228. }
  229. /// <summary>
  230. /// not used
  231. /// </summary>
  232. public sealed class ReferenceType : SchemaType
  233. {
  234. #region constructor
  235. internal ReferenceType(Context ctx, SchemaType refType) : base(ctx)
  236. {
  237. _ReferencedType = refType;
  238. }
  239. #endregion
  240. #region data
  241. // In code it has the representation List<Node>();
  242. // In serialization, it has the representation List<int>();
  243. private readonly SchemaType _ReferencedType;
  244. public override string PersistentName => throw new NotImplementedException();
  245. #endregion
  246. }
  247. }