1 #Region "Microsoft.VisualBasic::208fbfa9b3a38cd9b3df433f5066f6db, Microsoft.VisualBasic.Core\Scripting\Runtime\CType\Casting.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Module Casting
35     
36     '         Function: (+3 Overloads) [As], AsBaseType, CastChar, CastCharArray, CastCommandLine
37     '                   CastDate, CastFileInfo, CastFont, CastGDIPlusDeviceHandle, CastImage
38     '                   CastInteger, CastIPEndPoint, CastLogFile, CastLong, CastProcess
39     '                   CastRegexOptions, CastSingle, CastStringBuilder, (+2 Overloads) Expression, FloatPointParser
40     '                   FloatSizeParser, NumericRangeParser, ParseNumeric, PointParser, RegexParseDouble
41     '                   ScriptValue, SizeParser, TryParse
42     
43     
44     ' /********************************************************************************/
45
46 #End Region
47
48 Imports System.Drawing
49 Imports System.IO
50 Imports System.Runtime.CompilerServices
51 Imports System.Text
52 Imports System.Text.RegularExpressions
53 Imports Microsoft.VisualBasic.ApplicationServices.Debugging.Logging
54 Imports Microsoft.VisualBasic.CommandLine.Reflection
55 Imports Microsoft.VisualBasic.ComponentModel
56 Imports Microsoft.VisualBasic.ComponentModel.Ranges.Model
57 Imports Microsoft.VisualBasic.Imaging
58 Imports Microsoft.VisualBasic.Text
59 Imports Microsoft.VisualBasic.ValueTypes
60
61 Namespace Scripting.Runtime
62
63     ''' <summary>
64     ''' Methods for convert the <see cref="String"/> to some .NET data types.
65     ''' </summary>
66     Public Module Casting
67
68         ''' <summary>
69         ''' Try parse of the enum value.
70         ''' </summary>
71         ''' <typeparam name="T">This generic type should be an <see cref="System.Enum"/> type!</typeparam>
72         ''' <param name="expression"></param>
73         ''' <param name="[default]"></param>
74         ''' <returns></returns>
75         <Extension>
76         Public Function TryParse(Of T As Structure)(expression As Match, Optional [default] As T = NothingAs T
77             Dim result As T = Nothing
78
79             If [Enum].TryParse(Of T)(expression.Value, result) Then
80                 Return result
81             Else
82                 Return [default]
83             End If
84         End Function
85
86         ''' <summary>
87         ''' <see cref="Size"/> object to string expression
88         ''' </summary>
89         ''' <param name="size"></param>
90         ''' <returns></returns>
91         <MethodImpl(MethodImplOptions.AggressiveInlining)>
92         <Extension>
93         Public Function ScriptValue(size As Size) As String
94             Return $"{size.Width},{size.Height}"
95         End Function
96
97         <Extension>
98         Public Iterator Function [As](Of T)(source As IEnumerable) As IEnumerable(Of T)
99             Dim l As New List(Of Object)
100
101             For Each x In source
102                 l.Add(x)
103
104                 If l.Count > 1 Then
105                     Exit For
106                 End If
107             Next
108
109             If l.Count = 1 AndAlso Not l.First.GetType Is GetType(T) Then
110
111                 Dim x = l.First
112
113                 If x.GetType() Is GetType(IEnumerator) Then
114                 With DirectCast(x, IEnumerator)
115                     Do While .MoveNext
116                         Yield DirectCast(.Current, T)
117                     Loop
118                 End With
119
120                 'Return
121                 'Else
122                 '    source = x
123                 'End If
124             Else
125                 For Each o As Object In source
126                     Yield DirectCast(o, T)
127                 Next
128             End If
129         End Function
130
131         <MethodImpl(MethodImplOptions.AggressiveInlining)>
132         <Extension>
133         Public Function NumericRangeParser(exp As StringAs DoubleRange
134             Return CType(exp, DoubleRange)
135         End Function
136
137         <MethodImpl(MethodImplOptions.AggressiveInlining)>
138         <Extension>
139         Public Function [As](Of T As {IComparable(Of T), Structure})(x As DoubleAs T
140             Return CType(CObj(x), T)
141         End Function
142
143         <MethodImpl(MethodImplOptions.AggressiveInlining)>
144         <Extension>
145         Public Function Expression(size As Size) As String
146             With size
147                 Return $"{ .Width},{ .Height}"
148             End With
149         End Function
150
151         <MethodImpl(MethodImplOptions.AggressiveInlining)>
152         <Extension>
153         Public Function Expression(size As SizeF) As String
154             With size
155                 Return $"{ .Width},{ .Height}"
156             End With
157         End Function
158
159         ''' <summary>
160         ''' Parse <see cref="Point"/> from a given string expression
161         ''' </summary>
162         ''' <param name="pt$"></param>
163         ''' <returns></returns>
164         Public Function PointParser(pt$) As Point
165             Dim x, y As Double
166             Call Ranges.Parser(pt, x, y)
167             Return New Point(x, y)
168         End Function
169
170         ''' <summary>
171         ''' Parse <see cref="PointF"/> from a given string expression
172         ''' </summary>
173         ''' <param name="pt$"></param>
174         ''' <returns></returns>
175         Public Function FloatPointParser(pt$) As PointF
176             Dim x, y As Double
177             Call Ranges.Parser(pt, x, y)
178             Return New PointF(x, y)
179         End Function
180
181         ''' <summary>
182         ''' Parse <see cref="Size"/> from a given string expression
183         ''' </summary>
184         ''' <param name="pt$"></param>
185         ''' <returns></returns>
186         <MethodImpl(MethodImplOptions.AggressiveInlining)>
187         <Extension> Public Function SizeParser(pt$) As Size
188             Return pt.FloatSizeParser.ToSize
189         End Function
190
191         ''' <summary>
192         ''' Parse <see cref="SizeF"/> from a given string expression
193         ''' </summary>
194         ''' <param name="pt$"></param>
195         ''' <returns></returns>
196         <Extension>
197         Public Function FloatSizeParser(pt$) As SizeF
198             If pt.StringEmpty Then
199                 Return Nothing
200             Else
201                 Dim x, y As Double
202                 Call Ranges.Parser(pt, x, y)
203                 Return New SizeF(x, y)
204             End If
205         End Function
206
207         ''' <summary>
208         ''' ``DirectCast(obj, T)``. 这个函数主要是为了解决Class类型之间的继承类型的转换,例如子类型向基础类型转换
209         ''' </summary>
210         ''' <typeparam name="T"></typeparam>
211         ''' <param name="obj"></param>
212         ''' <returns></returns>
213         ''' <remarks>
214         ''' 可能会和向量的As类型转换有冲突
215         ''' </remarks>
216         ''' 
217         <MethodImpl(MethodImplOptions.AggressiveInlining)>
218         <Extension>
219         Public Function AsBaseType(Of TIn As Class, T)(obj As TIn) As T
220             If obj Is Nothing Then
221                 Return Nothing
222             Else
223                 Return DirectCast(CObj(obj), T)
224             End If
225         End Function
226
227         ''' <summary>
228         ''' Cast array type
229         ''' </summary>
230         ''' <typeparam name="T"></typeparam>
231         ''' <typeparam name="TOut"></typeparam>
232         ''' <param name="list">在这里使用向量而非使用通用接口是因为和单个元素的As转换有冲突</param>
233         ''' <returns></returns>
234         <Extension> Public Function [As](Of T, TOut)(list As IEnumerable(Of T)) As TOut()
235             If list Is Nothing Then
236                 Return {}
237             Else
238                 Return list _
239                     .Select(Function(x) CType(CObj(x), TOut)) _
240                     .ToArray
241             End If
242         End Function
243
244         ''' <summary>
245         ''' 用于解析出任意实数的正则表达式
246         ''' </summary>
247         Public Const RegexpDouble$ = "-?\d+(\.\d+)?"
248         Public Const ScientificNotation$ = RegexpDouble & "[Ee][+-]\d+"
249         Public Const RegexpFloat$ = RegexpDouble & "([Ee][+-]\d+)?"
250         Public Const RegexInteger$ = "[-]?\d+"
251
252         ''' <summary>
253         ''' Parsing a real number from the expression text by using the regex expression <see cref="RegexpFloat"/>.
254         ''' (使用正则表达式解析目标字符串对象之中的一个实数)
255         ''' </summary>
256         ''' <param name="s"></param>
257         ''' <returns></returns>
258         ''' <remarks></remarks>
259         <MethodImpl(MethodImplOptions.AggressiveInlining)>
260         <ExportAPI("Double.Match")>
261         <Extension> Public Function RegexParseDouble(s As StringAs Double
262             Return Val(s.Match(RegexpFloat))
263         End Function
264
265         ''' <summary>
266         ''' Will processing value NaN automatically and strip for the comma, percentage expression.
267         ''' </summary>
268         ''' <param name="s">
269         ''' + numeric
270         ''' + NaN
271         ''' + p%
272         ''' + a/b
273         ''' </param>
274         ''' <returns></returns>
275         ''' 
276         <Extension>
277         Public Function ParseNumeric(s As StringAs Double
278             s = Strings.Trim(s)
279
280             If String.IsNullOrEmpty(s) Then
281                 Return 0R
282             ElseIf String.Equals(s, "NaN"StringComparison.Ordinal) OrElse
283                 String.Equals(s, "NA"StringComparison.Ordinal) Then
284
285                 ' R 语言之中是使用NA,.NET语言是使用NaN
286                 Return Double.NaN
287             Else
288                 s = s.Replace(",""")
289             End If
290
291             If s.Last = "%"Then
292                 Return Conversion.Val(Mid(s, 1, s.Length - 1)) / 100  ' 百分比
293             ElseIf InStr(s, "/") > 0 Then
294                 Dim t$() = s.Split("/"c) ' 处理分数
295                 Return Val(t(0)) / Val(t(1))
296             ElseIf InStr(s, "e", CompareMethod.Text) > 0 Then
297                 Dim t = s.ToLower.Split("e"c)
298                 Return Val(t(0)) * (10 ^ Val(t(1)))
299             Else
300                 Return Conversion.Val(s)
301             End If
302         End Function
303
304         ''' <summary>
305         ''' 字符串是空值会返回空字符
306         ''' </summary>
307         ''' <param name="obj"></param>
308         ''' <returns></returns>
309         ''' 
310         <MethodImpl(MethodImplOptions.AggressiveInlining)>
311         Public Function CastChar(obj As StringAs Char
312             Return If(String.IsNullOrEmpty(obj), ASCII.NUL, obj.First)
313         End Function
314
315         ''' <summary>
316         ''' 出错会返回默认是0
317         ''' </summary>
318         ''' <param name="obj"></param>
319         ''' <returns></returns>
320         ''' 
321         <MethodImpl(MethodImplOptions.AggressiveInlining)>
322         Public Function CastInteger(obj As StringAs Integer
323             Return CInt(ParseNumeric(obj))
324         End Function
325
326         <MethodImpl(MethodImplOptions.AggressiveInlining)>
327         Public Function CastLong(obj As StringAs Long
328             Return CLng(ParseNumeric(obj))
329         End Function
330
331         <MethodImpl(MethodImplOptions.AggressiveInlining)>
332         Public Function CastCharArray(obj As StringAs Char()
333             Return obj.ToArray
334         End Function
335
336         ''' <summary>
337         ''' 支持日期字符串和unix timstamp对<see cref="Date"/>的转换
338         ''' </summary>
339         ''' <param name="obj"></param>
340         ''' <returns></returns>
341         <MethodImpl(MethodImplOptions.AggressiveInlining)>
342         Public Function CastDate(obj As StringAs DateTime
343             If obj.StringEmpty OrElse obj = "0000-00-00 00:00:00" OrElse obj.ToUpper = "NULL" OrElse obj.ToUpper = "NA" Then
344                 Return New Date
345             ElseIf obj.IsPattern("\d+"Then
346                 ' unix timestamp
347                 Return CLng(Val(obj)).FromUnixTimeStamp
348             Else
349                 Return DateTime.Parse(obj)
350             End If
351         End Function
352
353         <MethodImpl(MethodImplOptions.AggressiveInlining)>
354         Public Function CastStringBuilder(obj As StringAs StringBuilder
355             Return New StringBuilder(obj)
356         End Function
357
358         ''' <summary>
359         ''' <see cref="CommandLine.TryParse"/>
360         ''' </summary>
361         ''' <param name="obj"></param>
362         ''' <returns></returns>
363         ''' 
364         <MethodImpl(MethodImplOptions.AggressiveInlining)>
365         Public Function CastCommandLine(obj As StringAs CommandLine.CommandLine
366             Return CommandLine.TryParse(obj)
367         End Function
368
369         ''' <summary>
370         ''' <see cref="LoadImage"/>
371         ''' </summary>
372         ''' <param name="path"></param>
373         ''' <returns></returns>
374         ''' 
375         <MethodImpl(MethodImplOptions.AggressiveInlining)>
376         Public Function CastImage(path As StringAs Image
377             Return LoadImage(path)
378         End Function
379
380         <MethodImpl(MethodImplOptions.AggressiveInlining)>
381         Public Function CastFileInfo(path As StringAs FileInfo
382             Return FileIO.FileSystem.GetFileInfo(path)
383         End Function
384
385         <MethodImpl(MethodImplOptions.AggressiveInlining)>
386         Public Function CastGDIPlusDeviceHandle(path As StringAs Graphics2D
387             Return CanvasCreateFromImageFile(path)
388         End Function
389
390         <MethodImpl(MethodImplOptions.AggressiveInlining)>
391         Public Function CastFont(face As StringAs Font
392             Return New Font(face, 10)
393         End Function
394
395         <MethodImpl(MethodImplOptions.AggressiveInlining)>
396         Public Function CastIPEndPoint(addr As StringAs System.Net.IPEndPoint
397             Return New Net.IPEndPoint(addr).GetIPEndPoint
398         End Function
399
400         <MethodImpl(MethodImplOptions.AggressiveInlining)>
401         Public Function CastLogFile(path As StringAs LogFile
402             Return New LogFile(path)
403         End Function
404
405         <MethodImpl(MethodImplOptions.AggressiveInlining)>
406         Public Function CastProcess(exe As StringAs Process
407             Return Process.Start(exe)
408         End Function
409
410         <MethodImpl(MethodImplOptions.AggressiveInlining)>
411         Public Function CastSingle(n As StringAs Single
412             Return CSng(ParseNumeric(n))
413         End Function
414
415         Public Function CastRegexOptions(name As StringAs RegexOptions
416             If String.Equals(name, RegexExtensions.NameOf.Compiled, StringComparison.OrdinalIgnoreCase) Then
417                 Return RegexOptions.Compiled
418             ElseIf String.Equals(name, RegexExtensions.NameOf.CultureInvariant, StringComparison.OrdinalIgnoreCase) Then
419                 Return RegexOptions.CultureInvariant
420             ElseIf String.Equals(name, RegexExtensions.NameOf.ECMAScript, StringComparison.OrdinalIgnoreCase) Then
421                 Return RegexOptions.ECMAScript
422             ElseIf String.Equals(name, RegexExtensions.NameOf.ExplicitCapture, StringComparison.OrdinalIgnoreCase) Then
423                 Return RegexOptions.ExplicitCapture
424             ElseIf String.Equals(name, RegexExtensions.NameOf.IgnoreCase, StringComparison.OrdinalIgnoreCase) Then
425                 Return RegexOptions.IgnoreCase
426             ElseIf String.Equals(name, RegexExtensions.NameOf.IgnorePatternWhitespace, StringComparison.OrdinalIgnoreCase) Then
427                 Return RegexOptions.IgnorePatternWhitespace
428             ElseIf String.Equals(name, RegexExtensions.NameOf.Multiline, StringComparison.OrdinalIgnoreCase) Then
429                 Return RegexOptions.Multiline
430             ElseIf String.Equals(name, RegexExtensions.NameOf.RightToLeft, StringComparison.OrdinalIgnoreCase) Then
431                 Return RegexOptions.RightToLeft
432             ElseIf String.Equals(name, RegexExtensions.NameOf.Singleline, StringComparison.OrdinalIgnoreCase) Then
433                 Return RegexOptions.Singleline
434             Else
435                 Return RegexOptions.None
436             End If
437         End Function
438     End Module
439 End Namespace