1+ using System ;
2+
3+ namespace Assimalign . Extensions ;
4+
5+ public record Either < T1 , T2 > : IEither
6+ {
7+ #region Implicit Conversion From Value
8+ public static implicit operator Either < T1 , T2 > ( T1 value ) => new Either < T1 , T2 > ( value ) ;
9+ public static implicit operator Either < T1 , T2 > ( T2 value ) => new Either < T1 , T2 > ( value ) ;
10+ #endregion Implicit Conversion From Value
11+
12+ #region Implicit Conversion By Type Swap
13+ public static implicit operator Either < T1 , T2 > ( Either < T2 , T1 > other )
14+ {
15+ int [ ] map = new [ ] { 2 , 1 } ;
16+ return new Either < T1 , T2 > ( map [ other . _typeIndex - 1 ] , other . _value ) ;
17+ }
18+ #endregion Implicit Conversion By Type Swap
19+
20+ #region Implicit Widening Conversions
21+ #endregion Implicit Widening Conversions
22+
23+ #region Constructors
24+ public Either ( T1 value ) { _value = value ; _typeIndex = 1 ; }
25+ public Either ( T2 value ) { _value = value ; _typeIndex = 2 ; }
26+ #endregion Constructors
27+
28+ #region Or methods
29+ public Either < T1 , T2 , T3 > Or < T3 > ( ) => this
30+ . Match ( ( T1 v1 ) => new Either < T1 , T2 , T3 > ( v1 ) )
31+ . Match ( ( T2 v2 ) => new Either < T1 , T2 , T3 > ( v2 ) ) ;
32+ public Either < T1 , T2 , T3 , T4 > Or < T3 , T4 > ( ) => this
33+ . Match ( ( T1 v1 ) => new Either < T1 , T2 , T3 , T4 > ( v1 ) )
34+ . Match ( ( T2 v2 ) => new Either < T1 , T2 , T3 , T4 > ( v2 ) ) ;
35+ public Either < T1 , T2 , T3 , T4 , T5 > Or < T3 , T4 , T5 > ( ) => this
36+ . Match ( ( T1 v1 ) => new Either < T1 , T2 , T3 , T4 , T5 > ( v1 ) )
37+ . Match ( ( T2 v2 ) => new Either < T1 , T2 , T3 , T4 , T5 > ( v2 ) ) ;
38+ #endregion Or methods
39+
40+ #region IEither Implementation
41+ int _typeIndex ;
42+ object _value ;
43+
44+ int IEither . TypeIndex => _typeIndex ;
45+
46+ Type IEither . Type => _typeIndex switch
47+ {
48+ 1 => typeof ( T1 ) ,
49+ 2 => typeof ( T2 ) ,
50+ _ => throw new InvalidOperationException ( )
51+ } ;
52+
53+ object IEither . Value => _value ;
54+
55+ Either ( int typeIndex , object value ) => ( _typeIndex , _value ) = ( typeIndex , value ) ;
56+ #endregion IEither Implementation
57+
58+ #region Value Casts
59+ T1 AsT1 => ( T1 ) _value ;
60+ T2 AsT2 => ( T2 ) _value ;
61+ #endregion Value Casts
62+
63+ #region Explicit Casts
64+ public static explicit operator T1 ( Either < T1 , T2 > either ) => either . AsT1 ;
65+ public static explicit operator T2 ( Either < T1 , T2 > either ) => either . AsT2 ;
66+ #endregion Explicit Casts
67+
68+ #region Switch method
69+ public void Switch ( Action < T1 > ifT1 , Action < T2 > ifT2 )
70+ {
71+ switch ( _typeIndex )
72+ {
73+ case 1 : ifT1 ( AsT1 ) ; break ;
74+ case 2 : ifT2 ( AsT2 ) ; break ;
75+ default : throw new InvalidOperationException ( ) ;
76+ }
77+ }
78+ #endregion Switch method
79+
80+ #region Nonreductive Match
81+ public Either < TResult1 , T2 > Match < TResult1 > ( Func < T1 , TResult1 > ifT1 ) => _typeIndex switch
82+ {
83+ 1 => ifT1 ( AsT1 ) ,
84+ 2 => AsT2 ,
85+ _ => throw new InvalidOperationException ( )
86+ } ;
87+ public Either < T1 , T2 , TResult1 > Match < TResult1 >
88+ ( Func < T1 , TResult1 > ifT1 , Func < T1 , bool > when ) => _typeIndex switch
89+ {
90+ 1 when ( when ( AsT1 ) ) => ifT1 ( AsT1 ) ,
91+ 2 => AsT2 ,
92+ 1 => AsT1 ,
93+ _ => throw new InvalidOperationException ( )
94+ } ;
95+ public Either < T1 , TResult2 > Match < TResult2 > ( Func < T2 , TResult2 > ifT2 ) => _typeIndex switch
96+ {
97+ 1 => AsT1 ,
98+ 2 => ifT2 ( AsT2 ) ,
99+ _ => throw new InvalidOperationException ( )
100+ } ;
101+ public Either < T1 , T2 , TResult2 > Match < TResult2 >
102+ ( Func < T2 , TResult2 > ifT2 , Func < T2 , bool > when ) => _typeIndex switch
103+ {
104+ 1 => AsT1 ,
105+ 2 when ( when ( AsT2 ) ) => ifT2 ( AsT2 ) ,
106+ 2 => AsT2 ,
107+ _ => throw new InvalidOperationException ( )
108+ } ;
109+ #endregion Nonreductive Match
110+
111+ #region Nonreductive Match - Compositional
112+ public Either < TResult1 , T2 > Match < TResult1 > ( Func < T1 , Either < TResult1 , T2 > > ifT1 ) => _typeIndex switch
113+ {
114+ 1 => ifT1 ( AsT1 ) ,
115+ 2 => AsT2 ,
116+ _ => throw new InvalidOperationException ( )
117+ } ;
118+ public Either < T1 , T2 , TResult1 > Match < TResult1 >
119+ ( Func < T1 , Either < T1 , T2 , TResult1 > > ifT1 , Func < T1 , bool > when ) => _typeIndex switch
120+ {
121+ 1 when ( when ( AsT1 ) ) => ifT1 ( AsT1 ) ,
122+ 2 => AsT2 ,
123+ 1 => AsT1 ,
124+ _ => throw new InvalidOperationException ( )
125+ } ;
126+ public Either < T1 , TResult2 > Match < TResult2 > ( Func < T2 , Either < T1 , TResult2 > > ifT2 ) => _typeIndex switch
127+ {
128+ 1 => AsT1 ,
129+ 2 => ifT2 ( AsT2 ) ,
130+ _ => throw new InvalidOperationException ( )
131+ } ;
132+ public Either < T1 , T2 , TResult2 > Match < TResult2 >
133+ ( Func < T2 , Either < T1 , T2 , TResult2 > > ifT2 , Func < T2 , bool > when ) => _typeIndex switch
134+ {
135+ 1 => AsT1 ,
136+ 2 when ( when ( AsT2 ) ) => ifT2 ( AsT2 ) ,
137+ 2 => AsT2 ,
138+ _ => throw new InvalidOperationException ( )
139+ } ;
140+ #endregion Nonreductive Match - Compositional
141+
142+ #region Reductive Match
143+ public T2 Match
144+ ( Func < T1 , T2 > ifT1 ) => _typeIndex switch
145+ {
146+ 1 => ifT1 ( AsT1 ) ,
147+ 2 => AsT2 ,
148+ _ => throw new InvalidOperationException ( )
149+ } ;
150+ public Either < T1 , T2 > Match
151+ ( Func < T1 , T2 > ifT1 , Func < T1 , bool > when ) => _typeIndex switch
152+ {
153+ 1 when ( when ( AsT1 ) ) => ifT1 ( AsT1 ) ,
154+ 2 => AsT2 ,
155+ 1 => AsT1 ,
156+ _ => throw new InvalidOperationException ( )
157+ } ;
158+ public T1 Match
159+ ( Func < T2 , T1 > ifT2 ) => _typeIndex switch
160+ {
161+ 1 => AsT1 ,
162+ 2 => ifT2 ( AsT2 ) ,
163+ _ => throw new InvalidOperationException ( )
164+ } ;
165+ public Either < T1 , T2 > Match
166+ ( Func < T2 , T1 > ifT2 , Func < T2 , bool > when ) => _typeIndex switch
167+ {
168+ 1 => AsT1 ,
169+ 2 when ( when ( AsT2 ) ) => ifT2 ( AsT2 ) ,
170+ 2 => AsT2 ,
171+ _ => throw new InvalidOperationException ( )
172+ } ;
173+ #endregion Reductive Match
174+
175+ #region Throw Methods
176+ public T2 ThrowIf
177+ ( Func < T1 , Exception > ifT1 ) => _typeIndex switch
178+ {
179+ 1 => throw ifT1 ( AsT1 ) ,
180+ 2 => AsT2 ,
181+ _ => throw new InvalidOperationException ( )
182+ } ;
183+ public Either < T1 , T2 > ThrowIf
184+ ( Func < T1 , Exception > ifT1 , Func < T1 , bool > when ) => _typeIndex switch
185+ {
186+ 1 when ( when ( AsT1 ) ) => throw ifT1 ( AsT1 ) ,
187+ 2 => AsT2 ,
188+ 1 => AsT1 ,
189+ _ => throw new InvalidOperationException ( )
190+ } ;
191+ public T1 ThrowIf
192+ ( Func < T2 , Exception > ifT2 ) => _typeIndex switch
193+ {
194+ 1 => AsT1 ,
195+ 2 => throw ifT2 ( AsT2 ) ,
196+ _ => throw new InvalidOperationException ( )
197+ } ;
198+ public Either < T1 , T2 > ThrowIf
199+ ( Func < T2 , Exception > ifT2 , Func < T2 , bool > when ) => _typeIndex switch
200+ {
201+ 1 => AsT1 ,
202+ 2 when ( when ( AsT2 ) ) => throw ifT2 ( AsT2 ) ,
203+ 2 => AsT2 ,
204+ _ => throw new InvalidOperationException ( )
205+ } ;
206+ #endregion Throw Methods
207+
208+ #region If (methods)
209+ public bool If ( out T1 @if ) => If ( out @if , out _ ) ;
210+ public bool If ( out T1 @if , out T2 @else )
211+ {
212+ switch ( _typeIndex )
213+ {
214+ case 1 :
215+ @if = AsT1 ;
216+ @else = default ;
217+ return true ;
218+ case 2 :
219+ @if = default ;
220+ @else = AsT2 ;
221+ return false ;
222+ default :
223+ throw new InvalidOperationException ( ) ;
224+ }
225+ }
226+ public bool If ( out T2 @if ) => If ( out @if , out _ ) ;
227+ public bool If ( out T2 @if , out T1 @else )
228+ {
229+ switch ( _typeIndex )
230+ {
231+ case 1 :
232+ @if = default ;
233+ @else = AsT1 ;
234+ return false ;
235+ case 2 :
236+ @if = AsT2 ;
237+ @else = default ;
238+ return true ;
239+ default :
240+ throw new InvalidOperationException ( ) ;
241+ }
242+ }
243+ #endregion If (methods)
244+
245+ #region ToString
246+ public override string ToString ( ) => $ "{ ( ( IEither ) this ) . Type . Name } :{ _value } ";
247+
248+ // For LINQPad:
249+ object ToDump ( ) => new { Type = ( ( IEither ) this ) . Type , Value = ( ( IEither ) this ) . Value } ;
250+ #endregion ToString
251+ }
0 commit comments