2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / ComBinderHelpers.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Microsoft Public License. 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  Microsoft Public License, 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 Microsoft Public License.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15 using System; using Microsoft;
16
17
18 #if !SILVERLIGHT
19
20 using System.Diagnostics;
21 #if CODEPLEX_40
22 using System.Dynamic;
23 using System.Dynamic.Utils;
24 using System.Linq.Expressions;
25 using System.Linq.Expressions.Compiler;
26 #else
27 using Microsoft.Scripting;
28 using Microsoft.Scripting.Utils;
29 using Microsoft.Linq.Expressions;
30 using Microsoft.Linq.Expressions.Compiler;
31 #endif
32 using System.Runtime.CompilerServices;
33 #if !CODEPLEX_40
34 using Microsoft.Runtime.CompilerServices;
35 #endif
36
37 using System.Runtime.InteropServices;
38 using System.Collections.Generic;
39
40 #if CODEPLEX_40
41 namespace System.Dynamic {
42 #else
43 namespace Microsoft.Scripting {
44 #endif
45     internal static class ComBinderHelpers {
46
47         internal static bool PreferPut(Type type, bool holdsNull) {
48             Debug.Assert(type != null);
49
50             if (type.IsValueType || type.IsArray) return true;
51
52             if (type == typeof(String) ||
53                 type == typeof(DBNull) ||
54                 holdsNull ||
55                 type == typeof(System.Reflection.Missing) ||
56                 type == typeof(CurrencyWrapper)) {
57
58                 return true;
59             } else {
60                 return false;
61             }
62         }
63
64         internal static bool IsByRef(DynamicMetaObject mo) {
65             ParameterExpression pe = mo.Expression as ParameterExpression;
66             return pe != null && pe.IsByRef;
67         }
68
69         internal static bool IsStrongBoxArg(DynamicMetaObject o) {
70             Type t = o.LimitType;
71             return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(StrongBox<>);
72         }
73
74         // this helper prepares arguments for COM binding by transforming ByVal StongBox arguments
75         // into ByRef expressions that represent the argument's Value fields.
76         internal static bool[] ProcessArgumentsForCom(ref DynamicMetaObject[] args) {
77             Debug.Assert(args != null);
78
79             DynamicMetaObject[] newArgs = new DynamicMetaObject[args.Length];
80             bool[] isByRefArg = new bool[args.Length];
81
82             for (int i = 0; i < args.Length; i++) {
83                 DynamicMetaObject curArgument = args[i];
84
85                 // set new arg infos to their original values or set default ones
86                 // we will do this fixup early so that we can assume we always have
87                 // arginfos in COM binder.
88
89                 if (IsByRef(curArgument)) {
90                     newArgs[i] = curArgument;
91                     isByRefArg[i] = true;
92                 } else {
93                     if (IsStrongBoxArg(curArgument)) {
94                         var restrictions = curArgument.Restrictions.Merge(
95                             GetTypeRestrictionForDynamicMetaObject(curArgument)
96                         );
97
98                         // we have restricted this argument to LimitType so we can convert and conversion will be trivial cast.
99                         Expression boxedValueAccessor = Expression.Field(
100                             Helpers.Convert(
101                                 curArgument.Expression,
102                                 curArgument.LimitType
103                             ),
104                             curArgument.LimitType.GetField("Value")
105                         );
106
107                         IStrongBox value = curArgument.Value as IStrongBox;
108                         object boxedValue = value != null ? value.Value : null;
109
110                         newArgs[i] = new DynamicMetaObject(
111                             boxedValueAccessor,
112                             restrictions,
113                             boxedValue
114                         );
115
116                         isByRefArg[i] = true;
117                     } else {
118                         newArgs[i] = curArgument;
119                         isByRefArg[i] = false;
120                     }
121                 }
122             }
123
124             args = newArgs;
125             return isByRefArg;
126         }
127
128         internal static BindingRestrictions GetTypeRestrictionForDynamicMetaObject(DynamicMetaObject obj) {
129             if (obj.Value == null && obj.HasValue) {
130                 //If the meta object holds a null value, create an instance restriction for checking null
131                 return BindingRestrictions.GetInstanceRestriction(obj.Expression, null);
132             }
133             return BindingRestrictions.GetTypeRestriction(obj.Expression, obj.LimitType);
134         }
135     }
136 }
137
138 #endif