1 #Region "Microsoft.VisualBasic::db6ceb32e039b6697df305bab8374184, 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
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
60 Namespace Scripting.Runtime
61
62     ''' <summary>
63     ''' Methods for convert the <see cref="System.String"/> to some .NET data types.
64     ''' </summary>
65     Public Module Casting
66
67         <MethodImpl(MethodImplOptions.AggressiveInlining)>
68         <Extension>
69         Public Function ScriptValue(size As Size) As String
70             Return $"{size.Width},{size.Height}"
71         End Function
72
73         <Extension>
74         Public Iterator Function [As](Of T)(source As IEnumerable) As IEnumerable(Of T)
75             Dim l As New List(Of Object)
76
77             For Each x In source
78                 l.Add(x)
79
80                 If l.Count > 1 Then
81                     Exit For
82                 End If
83             Next
84
85             If l.Count = 1 AndAlso Not l.First.GetType Is GetType(T) Then
86
87                 Dim x = l.First
88
89                 If x.GetType() Is GetType(IEnumerator) Then
90                 With DirectCast(x, IEnumerator)
91                     Do While .MoveNext
92                         Yield DirectCast(.Current, T)
93                     Loop
94                 End With
95
96                 'Return
97                 'Else
98                 '    source = x
99                 'End If
100             Else
101                 For Each o As Object In source
102                     Yield DirectCast(o, T)
103                 Next
104             End If
105         End Function
106
107         <MethodImpl(MethodImplOptions.AggressiveInlining)>
108         <Extension>
109         Public Function NumericRangeParser(exp As StringAs DoubleRange
110             Return CType(exp, DoubleRange)
111         End Function
112
113         <MethodImpl(MethodImplOptions.AggressiveInlining)>
114         <Extension>
115         Public Function [As](Of T As {IComparable(Of T), Structure})(x As DoubleAs T
116             Return CType(CObj(x), T)
117         End Function
118
119         <MethodImpl(MethodImplOptions.AggressiveInlining)>
120         <Extension>
121         Public Function Expression(size As Size) As String
122             With size
123                 Return $"{ .Width},{ .Height}"
124             End With
125         End Function
126
127         <MethodImpl(MethodImplOptions.AggressiveInlining)>
128         <Extension>
129         Public Function Expression(size As SizeF) As String
130             With size
131                 Return $"{ .Width},{ .Height}"
132             End With
133         End Function
134
135         Public Function PointParser(pt$) As Point
136             Dim x, y As Double
137             Call Ranges.Parser(pt, x, y)
138             Return New Point(x, y)
139         End Function
140
141         Public Function FloatPointParser(pt$) As PointF
142             Dim x, y As Double
143             Call Ranges.Parser(pt, x, y)
144             Return New PointF(x, y)
145         End Function
146
147         <MethodImpl(MethodImplOptions.AggressiveInlining)>
148         <Extension> Public Function SizeParser(pt$) As Size
149             Return pt.FloatSizeParser.ToSize
150         End Function
151
152         <Extension>
153         Public Function FloatSizeParser(pt$) As SizeF
154             If pt.StringEmpty Then
155                 Return Nothing
156             Else
157                 Dim x, y As Double
158                 Call Ranges.Parser(pt, x, y)
159                 Return New SizeF(x, y)
160             End If
161         End Function
162
163         ''' <summary>
164         ''' ``DirectCast(obj, T)``. 这个函数主要是为了解决Class类型之间的继承类型的转换,例如子类型向基础类型转换
165         ''' </summary>
166         ''' <typeparam name="T"></typeparam>
167         ''' <param name="obj"></param>
168         ''' <returns></returns>
169         ''' <remarks>
170         ''' 可能会和向量的As类型转换有冲突
171         ''' </remarks>
172         ''' 
173         <MethodImpl(MethodImplOptions.AggressiveInlining)>
174         <Extension>
175         Public Function AsBaseType(Of TIn As Class, T)(obj As TIn) As T
176             If obj Is Nothing Then
177                 Return Nothing
178             Else
179                 Return DirectCast(CObj(obj), T)
180             End If
181         End Function
182
183         ''' <summary>
184         ''' Cast array type
185         ''' </summary>
186         ''' <typeparam name="T"></typeparam>
187         ''' <typeparam name="TOut"></typeparam>
188         ''' <param name="list">在这里使用向量而非使用通用接口是因为和单个元素的As转换有冲突</param>
189         ''' <returns></returns>
190         <Extension> Public Function [As](Of T, TOut)(list As IEnumerable(Of T)) As TOut()
191             If list Is Nothing Then
192                 Return {}
193             Else
194                 Return list _
195                     .Select(Function(x) CType(CObj(x), TOut)) _
196                     .ToArray
197             End If
198         End Function
199
200         ''' <summary>
201         ''' 用于解析出任意实数的正则表达式
202         ''' </summary>
203         Public Const RegexpDouble As String = "-?\d+(\.\d+)?"
204         Public Const ScientificNotation$ = RegexpDouble & "[Ee][+-]\d+"
205         Public Const RegexpFloat$ = RegexpDouble & "([Ee][+-]\d+)?"
206         Public Const RegexInteger$ = "[-]?\d+"
207
208         ''' <summary>
209         ''' Parsing a real number from the expression text by using the regex expression <see cref="RegexpFloat"/>.
210         ''' (使用正则表达式解析目标字符串对象之中的一个实数)
211         ''' </summary>
212         ''' <param name="s"></param>
213         ''' <returns></returns>
214         ''' <remarks></remarks>
215         <MethodImpl(MethodImplOptions.AggressiveInlining)>
216         <ExportAPI("Double.Match")>
217         <Extension> Public Function RegexParseDouble(s As StringAs Double
218             Return Val(s.Match(RegexpFloat))
219         End Function
220
221         ''' <summary>
222         ''' Will processing value NaN automatically and strip for the comma, percentage expression.
223         ''' </summary>
224         ''' <param name="s">
225         ''' + numeric
226         ''' + NaN
227         ''' + p%
228         ''' + a/b
229         ''' </param>
230         ''' <returns></returns>
231         ''' 
232         <Extension>
233         Public Function ParseNumeric(s As StringAs Double
234             s = Strings.Trim(s)
235
236             If String.IsNullOrEmpty(s) Then
237                 Return 0R
238             ElseIf String.Equals(s, "NaN"StringComparison.Ordinal) OrElse
239                 String.Equals(s, "NA"StringComparison.Ordinal) Then
240
241                 ' R 语言之中是使用NA,.NET语言是使用NaN
242                 Return Double.NaN
243             Else
244                 s = s.Replace(",""")
245             End If
246
247             If s.Last = "%"Then
248                 Return Conversion.Val(Mid(s, 1, s.Length - 1)) / 100  ' 百分比
249             ElseIf InStr(s, "/") > 0 Then
250                 Dim t$() = s.Split("/"c) ' 处理分数
251                 Return Val(t(0)) / Val(t(1))
252             ElseIf InStr(s, "e", CompareMethod.Text) > 0 Then
253                 Dim t = s.ToLower.Split("e"c)
254                 Return Val(t(0)) * (10 ^ Val(t(1)))
255             Else
256                 Return Conversion.Val(s)
257             End If
258         End Function
259
260         ''' <summary>
261         ''' 字符串是空值会返回空字符
262         ''' </summary>
263         ''' <param name="obj"></param>
264         ''' <returns></returns>
265         ''' 
266         <MethodImpl(MethodImplOptions.AggressiveInlining)>
267         Public Function CastChar(obj As StringAs Char
268             Return If(String.IsNullOrEmpty(obj), ASCII.NUL, obj.First)
269         End Function
270
271         ''' <summary>
272         ''' 出错会返回默认是0
273         ''' </summary>
274         ''' <param name="obj"></param>
275         ''' <returns></returns>
276         ''' 
277         <MethodImpl(MethodImplOptions.AggressiveInlining)>
278         Public Function CastInteger(obj As StringAs Integer
279             Return CInt(ParseNumeric(obj))
280         End Function
281
282         <MethodImpl(MethodImplOptions.AggressiveInlining)>
283         Public Function CastLong(obj As StringAs Long
284             Return CLng(ParseNumeric(obj))
285         End Function
286
287         <MethodImpl(MethodImplOptions.AggressiveInlining)>
288         Public Function CastCharArray(obj As StringAs Char()
289             Return obj.ToArray
290         End Function
291
292         <MethodImpl(MethodImplOptions.AggressiveInlining)>
293         Public Function CastDate(obj As StringAs DateTime
294             Return DateTime.Parse(obj)
295         End Function
296
297         <MethodImpl(MethodImplOptions.AggressiveInlining)>
298         Public Function CastStringBuilder(obj As StringAs StringBuilder
299             Return New StringBuilder(obj)
300         End Function
301
302         ''' <summary>
303         ''' <see cref="CommandLine.TryParse"/>
304         ''' </summary>
305         ''' <param name="obj"></param>
306         ''' <returns></returns>
307         ''' 
308         <MethodImpl(MethodImplOptions.AggressiveInlining)>
309         Public Function CastCommandLine(obj As StringAs CommandLine.CommandLine
310             Return CommandLine.TryParse(obj)
311         End Function
312
313         ''' <summary>
314         ''' <see cref="LoadImage"/>
315         ''' </summary>
316         ''' <param name="path"></param>
317         ''' <returns></returns>
318         ''' 
319         <MethodImpl(MethodImplOptions.AggressiveInlining)>
320         Public Function CastImage(path As StringAs Image
321             Return LoadImage(path)
322         End Function
323
324         <MethodImpl(MethodImplOptions.AggressiveInlining)>
325         Public Function CastFileInfo(path As StringAs FileInfo
326             Return FileIO.FileSystem.GetFileInfo(path)
327         End Function
328
329         <MethodImpl(MethodImplOptions.AggressiveInlining)>
330         Public Function CastGDIPlusDeviceHandle(path As StringAs Graphics2D
331             Return GDIPlusDeviceHandleFromImageFile(path)
332         End Function
333
334         <MethodImpl(MethodImplOptions.AggressiveInlining)>
335         Public Function CastFont(face As StringAs Font
336             Return New Font(face, 10)
337         End Function
338
339         <MethodImpl(MethodImplOptions.AggressiveInlining)>
340         Public Function CastIPEndPoint(addr As StringAs System.Net.IPEndPoint
341             Return New Net.IPEndPoint(addr).GetIPEndPoint
342         End Function
343
344         <MethodImpl(MethodImplOptions.AggressiveInlining)>
345         Public Function CastLogFile(path As StringAs LogFile
346             Return New LogFile(path)
347         End Function
348
349         <MethodImpl(MethodImplOptions.AggressiveInlining)>
350         Public Function CastProcess(exe As StringAs Process
351             Return Process.Start(exe)
352         End Function
353
354         <MethodImpl(MethodImplOptions.AggressiveInlining)>
355         Public Function CastSingle(n As StringAs Single
356             Return CSng(ParseNumeric(n))
357         End Function
358
359         Public Function CastRegexOptions(name As StringAs RegexOptions
360             If String.Equals(name, RegexExtensions.NameOf.Compiled, StringComparison.OrdinalIgnoreCase) Then
361                 Return RegexOptions.Compiled
362             ElseIf String.Equals(name, RegexExtensions.NameOf.CultureInvariant, StringComparison.OrdinalIgnoreCase) Then
363                 Return RegexOptions.CultureInvariant
364             ElseIf String.Equals(name, RegexExtensions.NameOf.ECMAScript, StringComparison.OrdinalIgnoreCase) Then
365                 Return RegexOptions.ECMAScript
366             ElseIf String.Equals(name, RegexExtensions.NameOf.ExplicitCapture, StringComparison.OrdinalIgnoreCase) Then
367                 Return RegexOptions.ExplicitCapture
368             ElseIf String.Equals(name, RegexExtensions.NameOf.IgnoreCase, StringComparison.OrdinalIgnoreCase) Then
369                 Return RegexOptions.IgnoreCase
370             ElseIf String.Equals(name, RegexExtensions.NameOf.IgnorePatternWhitespace, StringComparison.OrdinalIgnoreCase) Then
371                 Return RegexOptions.IgnorePatternWhitespace
372             ElseIf String.Equals(name, RegexExtensions.NameOf.Multiline, StringComparison.OrdinalIgnoreCase) Then
373                 Return RegexOptions.Multiline
374             ElseIf String.Equals(name, RegexExtensions.NameOf.RightToLeft, StringComparison.OrdinalIgnoreCase) Then
375                 Return RegexOptions.RightToLeft
376             ElseIf String.Equals(name, RegexExtensions.NameOf.Singleline, StringComparison.OrdinalIgnoreCase) Then
377                 Return RegexOptions.Singleline
378             Else
379                 Return RegexOptions.None
380             End If
381         End Function
382     End Module
383 End Namespace