Follow formatting NUI
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Xaml / TypeConversionExtensions.cs
1 //
2 // TypeConversionExtensions.cs
3 //
4 // Author:
5 //       Stephane Delcroix <stephane@mi8.be>
6 //
7 // Copyright (c) 2013 Mobile Inception
8 // Copyright (c) 2014 Xamarin, Inc.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27
28 using System;
29 using System.Collections.Generic;
30 using System.Globalization;
31 using System.Linq;
32 using System.Reflection;
33 // using Tizen.NUI.Binding.Internals;
34 using Tizen.NUI.Xaml.Internals;
35 using Tizen.NUI.Binding;
36
37 namespace Tizen.NUI.Xaml
38 {
39     internal static class TypeConversionExtensions
40     {
41         internal static object ConvertTo(this object value, Type toType, Func<ParameterInfo> pinfoRetriever,
42             IServiceProvider serviceProvider)
43         {
44             Func<TypeConverter> getConverter = () =>
45             {
46                 ParameterInfo pInfo;
47                 if (pinfoRetriever == null || (pInfo = pinfoRetriever()) == null)
48                     return null;
49
50                 var converterTypeName = pInfo.CustomAttributes.GetTypeConverterTypeName();
51                 if (converterTypeName == null)
52                     return null;
53                 var convertertype = Type.GetType(converterTypeName);
54                 return (TypeConverter)Activator.CreateInstance(convertertype);
55             };
56
57             return ConvertTo(value, toType, getConverter, serviceProvider);
58         }
59
60         internal static object ConvertTo(this object value, Type toType, Func<MemberInfo> minfoRetriever,
61             IServiceProvider serviceProvider)
62         {
63             Func<object> getConverter = () =>
64             {
65                 MemberInfo memberInfo;
66                 string converterTypeName = null;
67                 Type realType = toType;
68
69                 if (true == realType.IsGenericType && typeof(Nullable<>) == realType.GetGenericTypeDefinition())
70                 {
71                     realType = realType.GetGenericArguments()[0];
72                 }
73
74                 converterTypeName = realType.CustomAttributes.GetTypeConverterTypeName();
75                 if (minfoRetriever != null && (memberInfo = minfoRetriever()) != null)
76                     converterTypeName = memberInfo.CustomAttributes.GetTypeConverterTypeName() ?? converterTypeName;
77
78                 if (converterTypeName == null)
79                 {
80                     converterTypeName = toType.FullName + "TypeConverter";
81                 }
82
83                 var convertertype = Type.GetType(converterTypeName);
84
85                 if (null == convertertype)
86                 {
87                     return null;
88                 }
89                 else
90                 {
91                     return Activator.CreateInstance(convertertype);
92                 }
93             };
94
95             return ConvertTo(value, toType, getConverter, serviceProvider);
96         }
97
98         static string GetTypeConverterTypeName(this IEnumerable<CustomAttributeData> attributes)
99         {
100             var converterAttribute =
101                 attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName));
102             if (converterAttribute == null)
103                 return null;
104             if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof(string))
105                 return (string)converterAttribute.ConstructorArguments[0].Value;
106             if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof(Type))
107                 return ((Type)converterAttribute.ConstructorArguments[0].Value).AssemblyQualifiedName;
108             return null;
109         }
110
111         //Don't change the name or the signature of this, it's used by XamlC
112         public static object ConvertTo(this object value, Type toType, Type convertertype, IServiceProvider serviceProvider)
113         {
114             if (convertertype == null)
115                 return value.ConvertTo(toType, (Func<object>)null, serviceProvider);
116             Func<object> getConverter = () => Activator.CreateInstance(convertertype);
117             ;
118             return value.ConvertTo(toType, getConverter, serviceProvider);
119         }
120
121         private delegate void ParseValueFunc(string s, IFormatProvider provider);
122
123         static private Dictionary<Type, ParseValueFunc> typeToParseValueFunc = null;
124
125         static private void BuildParseValueFunc()
126         {
127             if (null == typeToParseValueFunc)
128             {
129                 typeToParseValueFunc = new Dictionary<Type, ParseValueFunc>();
130
131             }
132         }
133
134         internal static object ConvertTo(this object value, Type toType, Func<object> getConverter,
135             IServiceProvider serviceProvider)
136         {
137             if (value == null)
138                 return null;
139
140             var str = value as string;
141             if (str != null)
142             {
143                 //If there's a [TypeConverter], use it
144                 object converter = getConverter?.Invoke();
145                 if (null != converter)
146                 {
147                     var xfTypeConverter = converter as TypeConverter;
148                     var xfExtendedTypeConverter = xfTypeConverter as IExtendedTypeConverter;
149                     if (xfExtendedTypeConverter != null)
150                         return value = xfExtendedTypeConverter.ConvertFromInvariantString(str, serviceProvider);
151                     if (xfTypeConverter != null)
152                         return value = xfTypeConverter.ConvertFromInvariantString(str);
153                     var converterType = converter?.GetType();
154                     if (converterType != null)
155                     {
156                         var convertFromStringInvariant = converterType.GetRuntimeMethod("ConvertFromInvariantString",
157                             new[] { typeof(string) });
158                         if (convertFromStringInvariant != null)
159                             return value = convertFromStringInvariant.Invoke(converter, new object[] { str });
160                     }
161                 }
162
163                 var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;
164
165                 //If the type is nullable, as the value is not null, it's safe to assume we want the built-in conversion
166                 if (toType.GetTypeInfo().IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable<>))
167                     toType = Nullable.GetUnderlyingType(toType);
168
169                 //Obvious Built-in conversions
170                 if (toType.GetTypeInfo().IsEnum)
171                     return Enum.Parse(toType, str, ignoreCase);
172
173                 if (toType == typeof(SByte))
174                     return SByte.Parse(str, CultureInfo.InvariantCulture);
175                 if (toType == typeof(Int16))
176                     return Int16.Parse(str, CultureInfo.InvariantCulture);
177                 if (toType == typeof(Int32))
178                     return Int32.Parse(str, CultureInfo.InvariantCulture);
179                 if (toType == typeof(Int64))
180                     return Int64.Parse(str, CultureInfo.InvariantCulture);
181                 if (toType == typeof(Byte))
182                     return Byte.Parse(str, CultureInfo.InvariantCulture);
183                 if (toType == typeof(UInt16))
184                     return UInt16.Parse(str, CultureInfo.InvariantCulture);
185                 if (toType == typeof(UInt32))
186                     return UInt32.Parse(str, CultureInfo.InvariantCulture);
187                 if (toType == typeof(UInt64))
188                     return UInt64.Parse(str, CultureInfo.InvariantCulture);
189                 if (toType == typeof(Single))
190                     return Single.Parse(str, CultureInfo.InvariantCulture);
191                 if (toType == typeof(Double))
192                     return Double.Parse(str, CultureInfo.InvariantCulture);
193                 if (toType == typeof(Boolean))
194                     return Boolean.Parse(str);
195                 if (toType == typeof(TimeSpan))
196                     return TimeSpan.Parse(str, CultureInfo.InvariantCulture);
197                 if (toType == typeof(DateTime))
198                     return DateTime.Parse(str, CultureInfo.InvariantCulture);
199                 if (toType == typeof(Char))
200                 {
201                     char c = '\0';
202                     Char.TryParse(str, out c);
203                     return c;
204                 }
205                 if (toType == typeof(String) && str.StartsWith("{}", StringComparison.Ordinal))
206                     return str.Substring(2);
207                 if (toType == typeof(String))
208                     return value;
209                 if (toType == typeof(Decimal))
210                     return Decimal.Parse(str, CultureInfo.InvariantCulture);
211             }
212
213             //if the value is not assignable and there's an implicit conversion, convert
214             if (value != null && !toType.IsAssignableFrom(value.GetType()))
215             {
216                 var opImplicit = value.GetType().GetImplicitConversionOperator(fromType: value.GetType(), toType: toType)
217                                 ?? toType.GetImplicitConversionOperator(fromType: value.GetType(), toType: toType);
218
219                 if (opImplicit != null)
220                 {
221                     value = opImplicit.Invoke(null, new[] { value });
222                     return value;
223                 }
224             }
225
226             return value;
227         }
228
229         internal static MethodInfo GetImplicitConversionOperator(this Type onType, Type fromType, Type toType)
230         {
231 #if NETSTANDARD1_0
232             var mi = onType.GetRuntimeMethod("op_Implicit", new[] { fromType });
233 #else
234             var bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
235             var mi = onType.GetMethod("op_Implicit", bindingFlags, null, new[] { fromType }, null);
236 #endif
237             if (mi == null) return null;
238             if (!mi.IsSpecialName) return null;
239             if (!mi.IsPublic) return null;
240             if (!mi.IsStatic) return null;
241             if (!toType.IsAssignableFrom(mi.ReturnType)) return null;
242
243             return mi;
244         }
245     }
246 }