1 #Region "Microsoft.VisualBasic::46c34e4ed658057f1dfe9b0ce4525a68, Microsoft.VisualBasic.Core\Language\Value\DefaultValue\Default.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 '     Delegate Function
35
36
37 '     Delegate Function
38
39
40 '     Interface IDefaultValue
41
42 '         Properties: DefaultValue
43
44 '     Interface IsEmpty
45
46 '         Properties: IsEmpty
47
48 '     Structure DefaultValue
49
50 '         Properties: DefaultValue, IsEmpty
51
52 '         Constructor: (+2 OverloadsSub New
53 '         Function: [When], getDefault, ToString
54 '         Operators: (+2 Overloads) +, (+4 OverloadsOr
55
56
57
58
59
60 ' /********************************************************************************/
61
62 #End Region
63
64 Imports System.Linq.Expressions
65 Imports System.Runtime.CompilerServices
66 Imports Microsoft.VisualBasic.Language.Perl
67
68 Namespace Language.Default
69
70     Public Delegate Function Assert(Of T)(obj As T) As Boolean
71
72     ''' <summary>
73     ''' + Test of A eqauls to B?
74     ''' </summary>
75     ''' <typeparam name="T"></typeparam>
76     ''' <param name="x"></param>
77     ''' <param name="y"></param>
78     ''' <returns></returns>
79     Public Delegate Function BinaryAssert(Of T)(x As T, y As T) As Boolean
80
81     Public Interface IDefaultValue(Of T)
82         ReadOnly Property DefaultValue As T
83     End Interface
84
85     ''' <summary>
86     ''' Apply on the structure type that assert the object is null or not.
87     ''' </summary>
88     Public Interface IsEmpty
89         ReadOnly Property IsEmpty As Boolean
90     End Interface
91
92     ''' <summary>
93     ''' The default value
94     ''' </summary>
95     ''' <typeparam name="T"></typeparam>
96     Public Structure DefaultValue(Of T) : Implements IDefaultValue(Of T)
97         Implements IsEmpty
98
99         Public ReadOnly Property DefaultValue As T Implements IDefaultValue(Of T).DefaultValue
100             <MethodImpl(MethodImplOptions.AggressiveInlining)>
101             Get
102                 If LazyValue Is Nothing Then
103                     Return Value
104                 Else
105                     ' using lazy loading, if the default value takes time to creates.
106                     Return LazyValue.Value()
107                 End If
108             End Get
109         End Property
110
111         Public ReadOnly Property IsEmpty As Boolean Implements IsEmpty.IsEmpty
112             <MethodImpl(MethodImplOptions.AggressiveInlining)>
113             Get
114                 Return LazyValue Is Nothing AndAlso assert(Value)
115             End Get
116         End Property
117
118         ''' <summary>
119         ''' The default value for <see cref="DefaultValue"/>
120         ''' </summary>
121         Dim Value As T
122
123         ''' <summary>
124         ''' 假若生成目标值的时间比较久,可以将其申明为Lambda表达式,这样子可以进行惰性加载
125         ''' </summary>
126         Dim LazyValue As Lazy(Of T)
127
128         ''' <summary>
129         ''' asset that if target value is null?
130         ''' </summary>
131         Dim assert As Assert(Of Object)
132
133         Sub New(value As T, Optional assert As Assert(Of Object) = Nothing)
134             Me.Value = value
135             Me.assert = assert Or defaultAssert
136         End Sub
137
138         Sub New(lazy As Func(Of T), Optional assert As Assert(Of Object) = Nothing)
139             Me.LazyValue = lazy.AsLazy
140             Me.assert = assert Or defaultAssert
141         End Sub
142
143         Public Function [When](expression As BooleanAs DefaultValue(Of T)
144             assert = Function(null) expression
145             Return Me
146         End Function
147
148         Public Function [When](assert As Assert(Of T)) As DefaultValue(Of T)
149             Me.assert = Function(o) assert(DirectCast(o, T))
150             Return Me
151         End Function
152
153         Public Overrides Function ToString() As String
154             Return $"default({Value})"
155         End Function
156
157         ''' <summary>
158         ''' Add handler
159         ''' </summary>
160         ''' <param name="[default]"></param>
161         ''' <param name="assert"></param>
162         ''' <returns></returns>
163         ''' 
164         <MethodImpl(MethodImplOptions.AggressiveInlining)>
165         Public Shared Operator +([default] As DefaultValue(Of T), assert As Assert(Of Object)) As DefaultValue(Of T)
166             Return New DefaultValue(Of T) With {
167                 .assert = assert,
168                 .Value = [default].Value
169             }
170         End Operator
171
172         <MethodImpl(MethodImplOptions.AggressiveInlining)>
173         Public Shared Operator +([default] As DefaultValue(Of T), assert As Expression(Of Func(Of Boolean))) As DefaultValue(Of T)
174             Return New DefaultValue(Of T) With {
175                 .assert = Function(null) (assert.Compile())(),
176                 .Value = [default].Value
177             }
178         End Operator
179
180         ''' <summary>
181         ''' if <see cref="assert"/> is true, then will using default <see cref="value"/>, 
182         ''' otherwise, return the source <paramref name="obj"/>.
183         ''' </summary>
184         ''' <param name="obj"></param>
185         ''' <param name="[default]"></param>
186         ''' <returns></returns>
187         ''' 
188         <MethodImpl(MethodImplOptions.AggressiveInlining)>
189         Public Shared Operator Or(obj As T, [default] As DefaultValue(Of T)) As T
190             Return getDefault(obj, [default].DefaultValue, If([default].assert, ExceptionHandler.defaultHandler))
191         End Operator
192
193         <MethodImpl(MethodImplOptions.AggressiveInlining)>
194         Private Shared Function getDefault(value As T, [default] As T, assert As Assert(Of Object))
195             Return If(assert(value), [default], value)
196         End Function
197
198         <MethodImpl(MethodImplOptions.AggressiveInlining)>
199         Public Shared Operator Or([default] As DefaultValue(Of T), obj As T) As T
200             Return getDefault([default].DefaultValue, obj, If([default].assert, ExceptionHandler.defaultHandler))
201         End Operator
202
203         ''' <summary>
204         ''' 这个操作符允许链式计算默认值:
205         ''' 
206         ''' A OR B OR C OR x OR y OR z
207         ''' </summary>
208         ''' <param name="x"></param>
209         ''' <param name="y"></param>
210         ''' <returns></returns>
211         <MethodImpl(MethodImplOptions.AggressiveInlining)>
212         Public Shared Operator Or(x As DefaultValue(Of T), y As DefaultValue(Of T)) As T
213             Return x.DefaultValue Or y
214         End Operator
215
216         <MethodImpl(MethodImplOptions.AggressiveInlining)>
217         Public Shared Widening Operator CType(obj As T) As DefaultValue(Of T)
218             Return New DefaultValue(Of T) With {
219                 .Value = obj,
220                 .assert = AddressOf ExceptionHandler.Default
221             }
222         End Operator
223
224         <MethodImpl(MethodImplOptions.AggressiveInlining)>
225         Public Shared Narrowing Operator CType([default] As DefaultValue(Of T)) As T
226             Return [default].DefaultValue
227         End Operator
228
229         <MethodImpl(MethodImplOptions.AggressiveInlining)>
230         Public Shared Widening Operator CType(lazy As Func(Of T)) As DefaultValue(Of T)
231             Return New DefaultValue(Of T) With {
232                 .LazyValue = lazy.AsLazy,
233                 .assert = AddressOf ExceptionHandler.Default
234             }
235         End Operator
236     End Structure
237 End Namespace