SchemaTypes.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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. /// <summary>
  32. /// Represents a <see cref="String"/> type.
  33. /// </summary>
  34. [System.Diagnostics.DebuggerDisplay("{PersistentName}")]
  35. public sealed class StringType : SchemaType
  36. {
  37. #region constructor
  38. internal StringType(Context ctx) : base(ctx) { }
  39. #endregion
  40. #region properties
  41. public override string PersistentName => typeof(String).Name;
  42. #endregion
  43. }
  44. [System.Diagnostics.DebuggerDisplay("{PersistentName}")]
  45. public sealed class ObjectType : SchemaType
  46. {
  47. #region constructor
  48. internal ObjectType(Context ctx) : base(ctx) { }
  49. #endregion
  50. #region properties
  51. public override string PersistentName => typeof(Object).Name;
  52. #endregion
  53. }
  54. /// <summary>
  55. /// Represents a "by value" type <see cref="Boolean"/>, <see cref="Int32"/>, <see cref="Single"/>, etc
  56. /// </summary>
  57. /// <remarks>
  58. /// This type can optionally be set as nullable.
  59. /// </remarks>
  60. [System.Diagnostics.DebuggerDisplay("{PersistentName}")]
  61. public sealed class BlittableType : SchemaType
  62. {
  63. #region constructor
  64. internal BlittableType(Context ctx, TypeInfo t, bool isNullable) : base(ctx)
  65. {
  66. if (t == typeof(String).GetTypeInfo()) isNullable = false;
  67. _Type = t;
  68. _IsNullable = isNullable;
  69. }
  70. #endregion
  71. #region data
  72. // https://en.wikipedia.org/wiki/Blittable_types
  73. private readonly TypeInfo _Type;
  74. private readonly Boolean _IsNullable;
  75. #endregion
  76. #region properties
  77. public TypeInfo DataType => _Type;
  78. public bool IsNullable => _IsNullable;
  79. public override string PersistentName => _IsNullable ? $"{_Type.Name}?" : _Type.Name;
  80. #endregion
  81. }
  82. [System.Diagnostics.DebuggerDisplay("enum {PersistentName}")]
  83. public sealed class EnumType : SchemaType
  84. {
  85. #region constructor
  86. internal EnumType(Context ctx, string name, bool isNullable) : base(ctx)
  87. {
  88. _PersistentName = name;
  89. _IsNullable = isNullable;
  90. }
  91. #endregion
  92. #region data
  93. private readonly String _PersistentName;
  94. private readonly Boolean _IsNullable;
  95. private bool _UseIntegers;
  96. private readonly Dictionary<string, int> _Values = new Dictionary<string, int>();
  97. #endregion
  98. #region properties
  99. public bool IsNullable => _IsNullable;
  100. public override string PersistentName => _PersistentName;
  101. public bool UseIntegers { get => _UseIntegers; set => _UseIntegers = value; }
  102. public SchemaType ItemType => UseIntegers ? (SchemaType)Owner.UseBlittable(typeof(int).GetTypeInfo()) : Owner.UseString();
  103. public IEnumerable<KeyValuePair<string, int>> Values => _Values;
  104. #endregion
  105. #region API
  106. public void SetValue(string key, int val) { _Values[key] = val; }
  107. #endregion
  108. }
  109. [System.Diagnostics.DebuggerDisplay("{PersistentName}")]
  110. public sealed class ArrayType : SchemaType
  111. {
  112. #region constructor
  113. internal ArrayType(Context ctx, SchemaType element) : base(ctx)
  114. {
  115. _ItemType = element;
  116. }
  117. #endregion
  118. #region data
  119. private readonly SchemaType _ItemType;
  120. public SchemaType ItemType => _ItemType;
  121. #endregion
  122. #region properties
  123. public override string PersistentName => $"{_ItemType.PersistentName}[]";
  124. #endregion
  125. }
  126. [System.Diagnostics.DebuggerDisplay("{PersistentName}")]
  127. public sealed class DictionaryType : SchemaType
  128. {
  129. #region lifecycle
  130. internal DictionaryType(Context ctx, SchemaType key,SchemaType val) : base(ctx)
  131. {
  132. _KeyType = key;
  133. _ValueType = val;
  134. }
  135. #endregion
  136. #region data
  137. private readonly SchemaType _KeyType;
  138. private readonly SchemaType _ValueType;
  139. #endregion
  140. #region properties
  141. public SchemaType KeyType => _KeyType;
  142. public SchemaType ValueType => _ValueType;
  143. public override string PersistentName => $"<{_KeyType.PersistentName},{_ValueType.PersistentName}>[]";
  144. #endregion
  145. }
  146. [System.Diagnostics.DebuggerDisplay("{FieldType.PersistentName} {PersistentName}")]
  147. public sealed class FieldInfo
  148. {
  149. #region lifecycle
  150. internal FieldInfo(ClassType owner, string name)
  151. {
  152. _Owner = owner;
  153. _PersistentName = name;
  154. }
  155. #endregion
  156. #region data
  157. private readonly ClassType _Owner;
  158. private readonly String _PersistentName;
  159. private SchemaType _FieldType;
  160. private Object _ExclusiveMinimumValue;
  161. private Object _InclusiveMinimumValue;
  162. private Object _DefaultValue;
  163. private Object _InclusiveMaximumValue;
  164. private Object _ExclusiveMaximumValue;
  165. private int _MinItems;
  166. private int _MaxItems;
  167. #endregion
  168. #region properties
  169. public ClassType DeclaringClass => _Owner;
  170. public String Description { get; set; }
  171. public String PersistentName => _PersistentName;
  172. public SchemaType FieldType { get => _FieldType; set => _FieldType = value; }
  173. public Object ExclusiveMinimumValue { get => _ExclusiveMinimumValue; set => _ExclusiveMinimumValue = value; }
  174. public Object InclusiveMinimumValue { get => _InclusiveMinimumValue; set => _InclusiveMinimumValue = value; }
  175. public Object DefaultValue { get => _DefaultValue; set => _DefaultValue = value; }
  176. public Object InclusiveMaximumValue { get => _InclusiveMaximumValue; set => _InclusiveMaximumValue = value; }
  177. public Object ExclusiveMaximumValue { get => _ExclusiveMaximumValue; set => _ExclusiveMaximumValue = value; }
  178. public int MinItems { get => _MinItems; set => _MinItems = value; }
  179. public int MaxItems { get => _MaxItems; set => _MaxItems = value; }
  180. #endregion
  181. #region fluent api
  182. public FieldInfo SetDataType(SchemaType type) { _FieldType = type; return this; }
  183. public FieldInfo SetDataType(Type type, bool isNullable)
  184. {
  185. if (type == typeof(string)) { _FieldType = DeclaringClass.Owner.UseString(); return this; }
  186. _FieldType = DeclaringClass.Owner.UseBlittable(type.GetTypeInfo(), isNullable);
  187. return this;
  188. }
  189. public FieldInfo RemoveDefaultValue() { _DefaultValue = null; return this; }
  190. public FieldInfo SetDefaultValue(string defval) { _DefaultValue = defval; return this; }
  191. public FieldInfo SetLimits(Decimal? min, Decimal? max) { _InclusiveMinimumValue = min; _InclusiveMaximumValue = max; return this; }
  192. public FieldInfo SetItemsRange(int min, int max = int.MaxValue) { _MinItems = min; _MaxItems = max; return this; }
  193. #endregion
  194. #region comparer helper
  195. private sealed class _Comparer : IEqualityComparer<FieldInfo> , IComparer<FieldInfo>
  196. {
  197. public int Compare(FieldInfo x, FieldInfo y)
  198. {
  199. var xx = _Adjust(x._PersistentName);
  200. var yy = _Adjust(y._PersistentName);
  201. return string.CompareOrdinal(xx, yy);
  202. }
  203. private static string _Adjust(string name)
  204. {
  205. if (name.StartsWith("asset")) return "____" + name;
  206. if (name.StartsWith("extensions")) return "___" + name;
  207. return name;
  208. }
  209. public bool Equals(FieldInfo x, FieldInfo y) { return Compare(x,y) == 0; }
  210. public int GetHashCode(FieldInfo obj) { return obj._PersistentName.GetHashCode(); }
  211. }
  212. private static readonly _Comparer _DefaultComparer = new _Comparer();
  213. public static IEqualityComparer<FieldInfo> EqualityComparer => _DefaultComparer;
  214. public static IComparer<FieldInfo> Comparer => _DefaultComparer;
  215. #endregion
  216. }
  217. [System.Diagnostics.DebuggerDisplay("class {PersistentName} : {BaseClass.PersistentName}")]
  218. public sealed class ClassType : SchemaType
  219. {
  220. #region constructor
  221. internal ClassType(Context ctx, string name) : base(ctx)
  222. {
  223. _PersistentName = name;
  224. }
  225. #endregion
  226. #region data
  227. private readonly String _PersistentName;
  228. private readonly SortedSet<FieldInfo> _Fields = new SortedSet<FieldInfo>(FieldInfo.Comparer);
  229. private ClassType _BaseClass;
  230. public override string PersistentName => _PersistentName;
  231. public ClassType BaseClass { get => _BaseClass; set => _BaseClass = value; }
  232. public IEnumerable<FieldInfo> Fields => _Fields;
  233. /// <summary>
  234. /// True to prevent to codegen emitter to emit this class
  235. /// </summary>
  236. public bool IgnoredByEmitter { get; set; }
  237. #endregion
  238. #region API
  239. public FieldInfo GetField(string name)
  240. {
  241. return _Fields.First(item => item.PersistentName == name);
  242. }
  243. public FieldInfo UseField(string name)
  244. {
  245. var f = new FieldInfo(this, name);
  246. _Fields.Add(f);
  247. return GetField(name);
  248. }
  249. #endregion
  250. }
  251. /// <summary>
  252. /// not used
  253. /// </summary>
  254. public sealed class ReferenceType : SchemaType
  255. {
  256. #region constructor
  257. internal ReferenceType(Context ctx, SchemaType refType) : base(ctx)
  258. {
  259. _ReferencedType = refType;
  260. }
  261. #endregion
  262. #region data
  263. // In code it has the representation List<Node>();
  264. // In serialization, it has the representation List<int>();
  265. private readonly SchemaType _ReferencedType;
  266. public override string PersistentName => throw new NotImplementedException();
  267. #endregion
  268. }
  269. }