JsValue.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. using System;
  2. using System.Diagnostics;
  3. using System.Diagnostics.Contracts;
  4. using Jint.Native.Object;
  5. using Jint.Runtime;
  6. namespace Jint.Native
  7. {
  8. [DebuggerTypeProxy(typeof(JsValueDebugView))]
  9. public struct JsValue : IEquatable<JsValue>
  10. {
  11. public static JsValue Undefined = new JsValue(Types.Undefined);
  12. public static JsValue Null = new JsValue(Types.Null);
  13. public static JsValue False = new JsValue(false);
  14. public static JsValue True = new JsValue(true);
  15. public JsValue(bool value)
  16. {
  17. _bool = value;
  18. _double = null;
  19. _object = null;
  20. _string = null;
  21. _type = Types.Boolean;
  22. }
  23. public JsValue(double value)
  24. {
  25. _bool = null;
  26. _double = value;
  27. _object = null;
  28. _string = null;
  29. _type = Types.Number;
  30. }
  31. public JsValue(string value)
  32. {
  33. _bool = null;
  34. _double = null;
  35. _object = null;
  36. _string = value;
  37. _type = Types.String;
  38. }
  39. public JsValue(ObjectInstance value)
  40. {
  41. _bool = null;
  42. _double = null;
  43. _object = value;
  44. _string = null;
  45. _type = Types.Object;
  46. }
  47. private JsValue(Types type)
  48. {
  49. _bool = null;
  50. _double = null;
  51. _object = null;
  52. _string = null;
  53. _type = type;
  54. }
  55. private readonly bool? _bool;
  56. private readonly double? _double;
  57. private readonly ObjectInstance _object;
  58. private readonly string _string;
  59. private readonly Types _type;
  60. [Pure]
  61. public bool IsPrimitive()
  62. {
  63. return _type != Types.Object && _type != Types.None;
  64. }
  65. [Pure]
  66. public bool IsUndefined()
  67. {
  68. return _type == Types.Undefined;
  69. }
  70. [Pure]
  71. public bool IsObject()
  72. {
  73. return _type == Types.Object;
  74. }
  75. [Pure]
  76. public bool IsString()
  77. {
  78. return _type == Types.String;
  79. }
  80. [Pure]
  81. public bool IsNumber()
  82. {
  83. return _type == Types.Number;
  84. }
  85. [Pure]
  86. public bool IsBoolean()
  87. {
  88. return _type == Types.Boolean;
  89. }
  90. [Pure]
  91. public bool IsNull()
  92. {
  93. return _type == Types.Null;
  94. }
  95. [Pure]
  96. public ObjectInstance AsObject()
  97. {
  98. if (_type != Types.Object)
  99. {
  100. throw new ArgumentException("The value is not an object");
  101. }
  102. return _object;
  103. }
  104. public T TryCast<T>(Action<JsValue> fail = null) where T: class
  105. {
  106. if (!this.IsObject())
  107. {
  108. return null;
  109. }
  110. var o = this.AsObject();
  111. var t = o as T;
  112. if (t != null)
  113. {
  114. return t;
  115. }
  116. if (fail != null)
  117. {
  118. fail(this);
  119. }
  120. return null;
  121. }
  122. public bool Is<T>() where T : ObjectInstance
  123. {
  124. return IsObject() && AsObject() is T;
  125. }
  126. public T As<T>() where T : ObjectInstance
  127. {
  128. return _object as T;
  129. }
  130. [Pure]
  131. public bool AsBoolean()
  132. {
  133. if (_type != Types.Boolean)
  134. {
  135. throw new ArgumentException("The value is not a boolean");
  136. }
  137. if (!_bool.HasValue)
  138. {
  139. throw new ArgumentException("The value is not defined");
  140. }
  141. return _bool.Value;
  142. }
  143. [Pure]
  144. public string AsString()
  145. {
  146. if (_type != Types.String)
  147. {
  148. throw new ArgumentException("The value is not a string");
  149. }
  150. if (_string == null)
  151. {
  152. throw new ArgumentException("The value is not defined");
  153. }
  154. return _string;
  155. }
  156. [Pure]
  157. public double AsNumber()
  158. {
  159. if (_type != Types.Number)
  160. {
  161. throw new ArgumentException("The value is not a number");
  162. }
  163. if (!_double.HasValue)
  164. {
  165. throw new ArgumentException("The value is not defined");
  166. }
  167. return _double.Value;
  168. }
  169. public bool Equals(JsValue other)
  170. {
  171. if (_type != other._type)
  172. {
  173. return false;
  174. }
  175. switch (_type)
  176. {
  177. case Types.None:
  178. return false;
  179. case Types.Undefined:
  180. return true;
  181. case Types.Null:
  182. return true;
  183. case Types.Boolean:
  184. return _bool == other._bool;
  185. case Types.String:
  186. return _string == other._string;
  187. case Types.Number:
  188. return _double == other._double;
  189. case Types.Object:
  190. return _object == other._object;
  191. default:
  192. throw new ArgumentOutOfRangeException();
  193. }
  194. }
  195. public Types Type
  196. {
  197. get { return _type; }
  198. }
  199. private static readonly Type[] NumberTypes = { typeof(double), typeof(int), typeof(float), typeof(uint), typeof(byte), typeof(short), typeof(ushort), typeof(long), typeof(ulong) };
  200. public static JsValue FromObject(object value)
  201. {
  202. var s = value as string;
  203. if (s != null)
  204. {
  205. return s;
  206. }
  207. if (System.Array.IndexOf(NumberTypes, value.GetType()) != -1)
  208. {
  209. return (double) value;
  210. }
  211. if (value is bool)
  212. {
  213. return (bool) value;
  214. }
  215. return Undefined;
  216. }
  217. public static bool operator ==(JsValue a, JsValue b)
  218. {
  219. return a.Equals(b);
  220. }
  221. public static bool operator !=(JsValue a, JsValue b)
  222. {
  223. return !a.Equals(b);
  224. }
  225. static public implicit operator JsValue(double value)
  226. {
  227. return new JsValue(value);
  228. }
  229. static public implicit operator JsValue(bool value)
  230. {
  231. return new JsValue(value);
  232. }
  233. static public implicit operator JsValue(string value)
  234. {
  235. return new JsValue(value);
  236. }
  237. static public implicit operator JsValue(ObjectInstance value)
  238. {
  239. return new JsValue(value);
  240. }
  241. internal class JsValueDebugView
  242. {
  243. public string Value;
  244. public JsValueDebugView(JsValue value)
  245. {
  246. switch (value.Type)
  247. {
  248. case Types.None:
  249. Value = "None";
  250. break;
  251. case Types.Undefined:
  252. Value = "undefined";
  253. break;
  254. case Types.Null:
  255. Value = "null";
  256. break;
  257. case Types.Boolean:
  258. Value = value.AsBoolean() + " (bool)";
  259. break;
  260. case Types.String:
  261. Value = value.AsString() + " (string)";
  262. break;
  263. case Types.Number:
  264. Value = value.AsNumber() + " (number)";
  265. break;
  266. case Types.Object:
  267. Value = value.AsObject().GetType().Name;
  268. break;
  269. default:
  270. Value = "Unknown";
  271. break;
  272. }
  273. }
  274. }
  275. }
  276. public static class Undefined
  277. {
  278. public static JsValue Instance = JsValue.Undefined;
  279. public static string Text = "undefined";
  280. }
  281. public static class Null
  282. {
  283. public static JsValue Instance = JsValue.Null;
  284. public static string Text = "null";
  285. }
  286. }