UserData.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Text;
  6. using System.Threading;
  7. using MoonSharp.Interpreter.Interop;
  8. namespace MoonSharp.Interpreter
  9. {
  10. public class UserData : RefIdObject
  11. {
  12. private UserData()
  13. {
  14. // This type can only be instantiated using one of the Create methods
  15. }
  16. public DynValue UserValue { get; set; }
  17. public object Object { get; set; }
  18. internal UserDataDescriptor Descriptor { get; set; }
  19. #if USE_RW_LOCK
  20. private static ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();
  21. #else
  22. private static object m_Lock = new object();
  23. #endif
  24. private static Dictionary<Type, UserDataDescriptor> s_Registry = new Dictionary<Type, UserDataDescriptor>();
  25. private static InteropAccessMode m_DefaultAccessMode;
  26. static UserData()
  27. {
  28. RegisterType<EnumerableWrapper>(InteropAccessMode.HideMembers);
  29. m_DefaultAccessMode = InteropAccessMode.LazyOptimized;
  30. }
  31. public static void RegisterType<T>(InteropAccessMode accessMode = InteropAccessMode.Default, string friendlyName = null)
  32. {
  33. RegisterType_Impl(typeof(T), accessMode, friendlyName);
  34. }
  35. public static void RegisterType(Type type, InteropAccessMode accessMode = InteropAccessMode.Default, string friendlyName = null)
  36. {
  37. RegisterType_Impl(type, accessMode, friendlyName);
  38. }
  39. public static void RegisterAssembly(Assembly asm = null)
  40. {
  41. asm = asm ?? Assembly.GetCallingAssembly();
  42. var userDataTypes = from t in asm.GetTypes()
  43. let attributes = t.GetCustomAttributes(typeof(MoonSharpUserDataAttribute), true)
  44. where attributes != null && attributes.Length > 0
  45. select new { Attributes = attributes, DataType = t };
  46. foreach (var userDataType in userDataTypes)
  47. {
  48. UserData.RegisterType(userDataType.DataType, userDataType.Attributes
  49. .OfType<MoonSharpUserDataAttribute>()
  50. .First()
  51. .AccessMode);
  52. }
  53. }
  54. public static DynValue Create(object o)
  55. {
  56. var descr = GetDescriptorForObject(o);
  57. if (descr == null) return null;
  58. return DynValue.NewUserData(new UserData()
  59. {
  60. Descriptor = descr,
  61. Object = o
  62. });
  63. }
  64. public static DynValue CreateStatic(Type t)
  65. {
  66. var descr = GetDescriptorForType(t, false);
  67. if (descr == null) return null;
  68. return DynValue.NewUserData(new UserData()
  69. {
  70. Descriptor = descr,
  71. Object = null
  72. });
  73. }
  74. public static DynValue CreateStatic<T>()
  75. {
  76. return CreateStatic(typeof(T));
  77. }
  78. public static InteropAccessMode DefaultAccessMode
  79. {
  80. get { return m_DefaultAccessMode; }
  81. set
  82. {
  83. if (value == InteropAccessMode.Default)
  84. throw new ArgumentException("DefaultAccessMode");
  85. m_DefaultAccessMode = value;
  86. }
  87. }
  88. private static void RegisterType_Impl(Type type, InteropAccessMode accessMode, string friendlyName)
  89. {
  90. if (accessMode == InteropAccessMode.Default)
  91. {
  92. MoonSharpUserDataAttribute attr = type.GetCustomAttributes(true).OfType<MoonSharpUserDataAttribute>()
  93. .SingleOrDefault();
  94. if (attr != null)
  95. accessMode = attr.AccessMode;
  96. }
  97. if (accessMode == InteropAccessMode.Default)
  98. accessMode = m_DefaultAccessMode;
  99. #if USE_RW_LOCK
  100. m_Lock.EnterWriteLock();
  101. #else
  102. Monitor.Enter(m_Lock);
  103. #endif
  104. try
  105. {
  106. if (!s_Registry.ContainsKey(type))
  107. {
  108. UserDataDescriptor udd = new UserDataDescriptor(type, accessMode, friendlyName);
  109. s_Registry.Add(udd.Type, udd);
  110. if (accessMode == InteropAccessMode.BackgroundOptimized)
  111. {
  112. ThreadPool.QueueUserWorkItem(o => udd.Optimize());
  113. }
  114. }
  115. }
  116. finally
  117. {
  118. #if USE_RW_LOCK
  119. m_Lock.ExitWriteLock();
  120. #else
  121. Monitor.Exit(m_Lock);
  122. #endif
  123. }
  124. }
  125. private static UserDataDescriptor GetDescriptorForType<T>(bool deepSearch = true)
  126. {
  127. return GetDescriptorForType(typeof(T), deepSearch);
  128. }
  129. private static UserDataDescriptor GetDescriptorForType(Type type, bool deepSearch = true)
  130. {
  131. #if USE_RW_LOCK
  132. m_Lock.EnterReadLock();
  133. #else
  134. Monitor.Enter(m_Lock);
  135. #endif
  136. try
  137. {
  138. if (!deepSearch)
  139. return s_Registry.ContainsKey(type) ? s_Registry[type] : null;
  140. for (Type t = type; t != typeof(object); t = t.BaseType)
  141. {
  142. UserDataDescriptor u;
  143. if (s_Registry.TryGetValue(t, out u))
  144. return u;
  145. }
  146. foreach (Type t in type.GetInterfaces())
  147. {
  148. if (s_Registry.ContainsKey(t))
  149. return s_Registry[t];
  150. }
  151. if (s_Registry.ContainsKey(typeof(object)))
  152. return s_Registry[type];
  153. }
  154. finally
  155. {
  156. #if USE_RW_LOCK
  157. m_Lock.ExitReadLock();
  158. #else
  159. Monitor.Exit(m_Lock);
  160. #endif
  161. }
  162. return null;
  163. }
  164. private static UserDataDescriptor GetDescriptorForObject(object o)
  165. {
  166. return GetDescriptorForType(o.GetType(), true);
  167. }
  168. }
  169. }