/Languages/Ruby/Ruby/Runtime/CustomTypeDescHelpers.cs
C# | 333 lines | 253 code | 59 blank | 21 comment | 30 complexity | ebb4901a585244ef11318503a1d8d1fa MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, MIT, GPL-2.0
1/* ****************************************************************************
2 *
3 * Copyright (c) Microsoft Corporation.
4 *
5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Apache License, Version 2.0, please send an email to
8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Apache License, Version 2.0.
10 *
11 * You must not remove this notice, or any other, from this software.
12 *
13 *
14 * ***************************************************************************/
15
16#if !SILVERLIGHT // ICustomTypeDescriptor
17
18using System;
19using System.Collections.Generic;
20using System.ComponentModel;
21using System.Runtime.CompilerServices;
22using Microsoft.Scripting;
23using Microsoft.Scripting.Actions.Calls;
24using Microsoft.Scripting.Utils;
25using IronRuby.Builtins;
26using IronRuby.Compiler.Generation;
27using IronRuby.Runtime.Calls;
28
29namespace IronRuby.Runtime {
30 /// <summary>
31 /// Helper class that all custom type descriptor implementations call for
32 /// the bulk of their implementation.
33 /// </summary>
34 public static class CustomTypeDescHelpers {
35
36 #region ICustomTypeDescriptor helper functions
37
38 private static RubyClass/*!*/ GetImmediateClass(object self) {
39 IRubyObject rubyObj = self as IRubyObject;
40 ContractUtils.RequiresNotNull(rubyObj, "self");
41 return rubyObj.ImmediateClass;
42 }
43
44 [Emitted]
45 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
46 public static AttributeCollection GetAttributes(object self) {
47 return AttributeCollection.Empty;
48 }
49
50 [Emitted]
51 public static string GetClassName(object self) {
52 return GetImmediateClass(self).NominalClass.Name;
53 }
54
55 [Emitted]
56 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
57 public static string GetComponentName(object self) {
58 return null;
59 }
60
61 [Emitted]
62 public static TypeConverter GetConverter(object self) {
63 return new TypeConverter();
64 }
65
66 [Emitted]
67 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
68 public static EventDescriptor GetDefaultEvent(object self) {
69 return null;
70 }
71
72 [Emitted]
73 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
74 public static PropertyDescriptor GetDefaultProperty(object self) {
75 return null;
76 }
77
78 [Emitted]
79 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "editorBaseType")]
80 public static object GetEditor(object self, Type editorBaseType) {
81 return null;
82 }
83
84 [Emitted]
85 public static EventDescriptorCollection GetEvents(object self, Attribute[] attributes) {
86 // TODO: update when we support attributes on Ruby types
87 if (attributes == null || attributes.Length == 0) {
88 return GetEvents(self);
89 }
90
91 // you want things w/ attributes? we don't have attributes!
92 return EventDescriptorCollection.Empty;
93 }
94
95 [Emitted]
96 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
97 public static EventDescriptorCollection GetEvents(object self) {
98 return EventDescriptorCollection.Empty;
99 }
100
101 [Emitted]
102 public static PropertyDescriptorCollection GetProperties(object self) {
103 return new PropertyDescriptorCollection(GetPropertiesImpl(self, new Attribute[0]));
104 }
105
106 [Emitted]
107 public static PropertyDescriptorCollection GetProperties(object self, Attribute[] attributes) {
108 return new PropertyDescriptorCollection(GetPropertiesImpl(self, attributes));
109 }
110
111 static PropertyDescriptor[] GetPropertiesImpl(object self, Attribute[] attributes) {
112 bool ok = true;
113 foreach (var attr in attributes) {
114 if (attr.GetType() != typeof(BrowsableAttribute)) {
115 ok = false;
116 break;
117 }
118 }
119 if (!ok) {
120 return new PropertyDescriptor[0];
121 }
122
123 RubyClass immediateClass = GetImmediateClass(self);
124 RubyContext context = immediateClass.Context;
125
126 const int readable = 0x01;
127 const int writable = 0x02;
128
129 var properties = new Dictionary<string, int>();
130 using (context.ClassHierarchyLocker()) {
131 immediateClass.ForEachMember(true, RubyMethodAttributes.DefaultVisibility, delegate(string/*!*/ name, RubyModule/*!*/ module, RubyMemberInfo/*!*/ member) {
132 int flag = 0;
133 if (member is RubyAttributeReaderInfo) {
134 flag = readable;
135 } else if (member is RubyAttributeWriterInfo) {
136 flag = writable;
137 } else if (name == "initialize") {
138 // Special case; never a property
139 } else {
140 int arity = member.GetArity();
141 if (arity == 0) {
142 flag = readable;
143 } else if (arity == 1 && name.LastCharacter() == '=') {
144 flag = writable;
145 }
146 }
147 if (flag != 0) {
148 if (flag == writable) {
149 name = name.Substring(0, name.Length - 1);
150 }
151 int oldFlag;
152 properties.TryGetValue(name, out oldFlag);
153 properties[name] = oldFlag | flag;
154 }
155 });
156 }
157
158 var result = new List<PropertyDescriptor>(properties.Count);
159 foreach (var pair in properties) {
160 if (pair.Value == (readable | writable)) {
161 result.Add(new RubyPropertyDescriptor(context, pair.Key, self, immediateClass.GetUnderlyingSystemType()));
162 }
163 }
164 return result.ToArray();
165 }
166
167 [Emitted]
168 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "pd")]
169 public static object GetPropertyOwner(object self, PropertyDescriptor pd) {
170 return self;
171 }
172
173 #endregion
174
175#if EXPOSE_INSTANCE_VARS
176 class RubyInstanceVariableDescriptor : PropertyDescriptor {
177 private readonly string _name;
178 private readonly Type _propertyType;
179 private readonly Type _componentType;
180
181 internal RubyInstanceVariableDescriptor(string name, Type propertyType, Type componentType)
182 : base(name, null) {
183 _name = name;
184 _propertyType = propertyType;
185 _componentType = componentType;
186 }
187
188 public override object GetValue(object component) {
189 object value;
190 GetClass(component).Context.TryGetInstanceVariable(component, _name, out value);
191 return value;
192 }
193 public override void SetValue(object component, object value) {
194 GetClass(component).Context.SetInstanceVariable(component, _name, value);
195 }
196
197 public override bool CanResetValue(object component) {
198 return false;
199 }
200
201 public override Type ComponentType {
202 get { return _componentType; }
203 }
204
205 public override bool IsReadOnly {
206 get { return false; }
207 }
208
209 public override Type PropertyType {
210 get { return _propertyType; }
211 }
212
213 public override void ResetValue(object component) {
214 }
215
216 public override bool ShouldSerializeValue(object component) {
217 return false;
218 }
219 }
220#endif // EXPOSE_INSTANCE_VARS
221
222 class RubyPropertyDescriptor : PropertyDescriptor {
223 private readonly string/*!*/ _name;
224 private readonly Type/*!*/ _propertyType;
225 private readonly Type/*!*/ _componentType;
226 private readonly CallSite<Func<CallSite, object, object>>/*!*/ _getterSite;
227 private readonly CallSite<Func<CallSite, object, object, object>>/*!*/ _setterSite;
228
229 internal RubyPropertyDescriptor(RubyContext/*!*/ context, string/*!*/ name, object testObject, Type/*!*/ componentType)
230 : base(name, null) {
231 _name = name;
232 _componentType = componentType;
233
234 _getterSite = CallSite<Func<CallSite, object, object>>.Create(
235 RubyCallAction.Make(context, _name, RubyCallSignature.WithImplicitSelf(0))
236 );
237
238 _setterSite = CallSite<Func<CallSite, object, object, object>>.Create(
239 RubyCallAction.Make(context, _name + "=", RubyCallSignature.WithImplicitSelf(0))
240 );
241
242 try {
243 _propertyType = GetValue(testObject).GetType();
244 } catch (Exception) {
245 _propertyType = typeof(object);
246 }
247 }
248
249 public override object GetValue(object obj) {
250 return _getterSite.Target.Invoke(_getterSite, obj);
251 }
252
253 public override void SetValue(object obj, object value) {
254 if (_setterSite != null) {
255 _setterSite.Target.Invoke(_setterSite, obj, value);
256 }
257 }
258
259 public override bool CanResetValue(object component) {
260 return false;
261 }
262
263 public override Type ComponentType {
264 get { return _componentType; }
265 }
266
267 public override bool IsReadOnly {
268 get { return (_setterSite == null); }
269 }
270
271 public override Type PropertyType {
272 get { return _propertyType; }
273 }
274
275 public override void ResetValue(object component) {
276 }
277
278 public override bool ShouldSerializeValue(object component) {
279 return false;
280 }
281 }
282
283#if TODO
284 private class TypeConv : TypeConverter {
285 object convObj;
286
287 public TypeConv(object self) {
288 convObj = self;
289 }
290
291 #region TypeConverter overrides
292
293 public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
294 object result;
295 return Converter.TryConvert(convObj, destinationType, out result);
296 }
297
298 public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
299 return Converter.CanConvertFrom(sourceType, convObj.GetType(), NarrowingLevel.All, true);
300 }
301
302 public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
303 return Converter.Convert(value, convObj.GetType());
304 }
305
306 public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
307 return Converter.Convert(convObj, destinationType);
308 }
309
310 public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) {
311 return false;
312 }
313
314 public override bool GetPropertiesSupported(ITypeDescriptorContext context) {
315 return false;
316 }
317
318 public override bool GetStandardValuesSupported(ITypeDescriptorContext context) {
319 return false;
320 }
321
322 public override bool IsValid(ITypeDescriptorContext context, object value) {
323 object result;
324 return Converter.TryConvert(value, convObj.GetType(), out result);
325 }
326
327 #endregion
328 }
329#endif
330 }
331}
332
333#endif