1919
2020using System ;
2121using System . Collections . Generic ;
22+ using System . Dynamic ;
23+ using System . Linq ;
2224using System . Numerics ;
2325using System . Text . Json ;
2426using System . Text . Json . Serialization ;
@@ -55,12 +57,12 @@ namespace OpenQA.Selenium.BiDi.Modules.Script;
5557//[JsonDerivedType(typeof(WindowProxyRemoteValue), "window")]
5658public abstract record RemoteValue
5759{
58- public static implicit operator double ( RemoteValue remoteValue ) => ( double ) ( ( NumberRemoteValue ) remoteValue ) . Value ;
60+ public static explicit operator double ( RemoteValue remoteValue ) => ( double ) ( ( NumberRemoteValue ) remoteValue ) . Value ;
5961
60- public static implicit operator int ( RemoteValue remoteValue ) => ( int ) ( double ) remoteValue ;
61- public static implicit operator long ( RemoteValue remoteValue ) => ( long ) ( double ) remoteValue ;
62+ public static explicit operator int ( RemoteValue remoteValue ) => ( int ) ( double ) remoteValue ;
63+ public static explicit operator long ( RemoteValue remoteValue ) => ( long ) ( double ) remoteValue ;
6264
63- public static implicit operator string ? ( RemoteValue remoteValue )
65+ public static explicit operator string ? ( RemoteValue remoteValue )
6466 {
6567 return remoteValue switch
6668 {
@@ -73,27 +75,237 @@ public abstract record RemoteValue
7375 // TODO: extend types
7476 public TResult ? ConvertTo < TResult > ( )
7577 {
76- var type = typeof ( TResult ) ;
78+ if ( this is UndefinedRemoteValue )
79+ {
80+ throw new BiDiException ( $ "Unable to convert undefined to { typeof ( TResult ) } ") ;
81+ }
82+
83+ if ( this is NullRemoteValue )
84+ {
85+ if ( default ( TResult ) == null )
86+ {
87+ return default ;
88+ }
89+
90+ throw new BiDiException ( $ "Unable to convert null to non-nullable value type { typeof ( TResult ) } ") ;
91+ }
92+
93+ if ( this is BooleanRemoteValue b )
94+ {
95+ if ( typeof ( TResult ) == typeof ( bool ) ||
96+ typeof ( TResult ) == typeof ( bool ? ) ||
97+ typeof ( TResult ) == typeof ( object ) )
98+ {
99+ return ( TResult ) ( object ) b . Value ;
100+ }
101+ }
77102
78- if ( type == typeof ( bool ) )
103+ if ( this is DateRemoteValue date )
79104 {
80- return ( TResult ) ( Convert . ToBoolean ( ( ( BooleanRemoteValue ) this ) . Value ) as object ) ;
105+ if ( typeof ( TResult ) == typeof ( DateTime ) ||
106+ typeof ( TResult ) == typeof ( DateTime ? ) ||
107+ typeof ( TResult ) == typeof ( object ) )
108+ {
109+ return ( TResult ) ( object ) DateTime . Parse ( date . Value ) ;
110+ }
111+
112+ if ( typeof ( TResult ) == typeof ( DateTimeOffset ) ||
113+ typeof ( TResult ) == typeof ( DateTimeOffset ? ) )
114+ {
115+ return ( TResult ) ( object ) DateTimeOffset . Parse ( date . Value ) ;
116+ }
117+
118+ if ( typeof ( TResult ) == typeof ( string ) )
119+ {
120+ return ( TResult ) ( object ) date . Value ;
121+ }
81122 }
82- if ( type == typeof ( int ) )
123+
124+ if ( this is NumberRemoteValue number )
83125 {
84- return ( TResult ) ( Convert . ToInt32 ( ( ( NumberRemoteValue ) this ) . Value ) as object ) ;
126+ if ( typeof ( TResult ) == typeof ( double ) ||
127+ typeof ( TResult ) == typeof ( double ? ) ||
128+ typeof ( TResult ) == typeof ( object ) )
129+ {
130+ return ( TResult ) ( object ) number . Value ;
131+ }
132+
133+ if ( typeof ( TResult ) == typeof ( int ) ||
134+ typeof ( TResult ) == typeof ( int ? ) )
135+ {
136+ if ( double . IsPositiveInfinity ( number . Value ) ||
137+ double . IsNegativeInfinity ( number . Value ) ||
138+ double . IsNaN ( number . Value ) )
139+ {
140+ throw new BiDiException ( $ "Cannot represent { number . Value } as an { nameof ( Int32 ) } ") ;
141+ }
142+
143+ return ( TResult ) ( object ) ( int ) number . Value ;
144+ }
145+
146+ if ( typeof ( TResult ) == typeof ( float ) ||
147+ typeof ( TResult ) == typeof ( float ? ) )
148+ {
149+ return ( TResult ) ( object ) ( float ) number . Value ;
150+ }
151+
152+ if ( typeof ( TResult ) == typeof ( BigInteger ) ||
153+ typeof ( TResult ) == typeof ( BigInteger ? ) )
154+ {
155+ return ( TResult ) ( object ) new BigInteger ( number . Value ) ;
156+ }
85157 }
86- else if ( type == typeof ( string ) )
158+
159+ if ( this is BigIntRemoteValue bigInt )
160+ {
161+ var bigNumber = BigInteger . Parse ( bigInt . Value ) ;
162+ if ( typeof ( TResult ) == typeof ( BigInteger ) ||
163+ typeof ( TResult ) == typeof ( BigInteger ? ) ||
164+ typeof ( TResult ) == typeof ( object ) )
165+ {
166+ return ( TResult ) ( object ) bigNumber ;
167+ }
168+
169+ if ( typeof ( TResult ) == typeof ( double ) ||
170+ typeof ( TResult ) == typeof ( double ? ) ||
171+ typeof ( TResult ) == typeof ( object ) )
172+ {
173+ return ( TResult ) ( object ) ( double ) bigNumber ;
174+ }
175+
176+ if ( typeof ( TResult ) == typeof ( int ) ||
177+ typeof ( TResult ) == typeof ( int ? ) )
178+ {
179+ return ( TResult ) ( object ) ( int ) bigNumber ;
180+ }
181+
182+ if ( typeof ( TResult ) == typeof ( float ) ||
183+ typeof ( TResult ) == typeof ( float ? ) )
184+ {
185+ return ( TResult ) ( object ) ( float ) bigNumber ;
186+ }
187+ }
188+
189+ if ( this is StringRemoteValue str )
87190 {
88- return ( TResult ) ( ( ( StringRemoteValue ) this ) . Value as object ) ;
191+ if ( typeof ( TResult ) == typeof ( string ) ||
192+ typeof ( TResult ) == typeof ( object ) )
193+ {
194+ return ( TResult ) ( object ) str . Value ;
195+ }
89196 }
90- else if ( type is object )
197+
198+ if ( this is RegExpRemoteValue regex )
199+ {
200+ if ( typeof ( TResult ) == typeof ( string ) ||
201+ typeof ( TResult ) == typeof ( object ) )
202+ {
203+ if ( string . IsNullOrEmpty ( regex . Value . Pattern ) )
204+ {
205+ return ( TResult ) ( object ) $ "/{ regex . Value . Pattern } ";
206+ }
207+
208+ return ( TResult ) ( object ) $ "/{ regex . Value . Pattern } /{ regex . Value . Flags } ";
209+ }
210+
211+ if ( typeof ( TResult ) == typeof ( System . Text . RegularExpressions . Regex ) )
212+ {
213+ return ( TResult ) ( object ) new System . Text . RegularExpressions . Regex ( regex . Value . Pattern , RegExpValue . JavaScriptFlagsToRegexOptions ( regex . Value . Flags ) ) ;
214+ }
215+ }
216+
217+ if ( this is ArrayRemoteValue array )
218+ {
219+ if ( typeof ( TResult ) == typeof ( IReadOnlyList < RemoteValue > ) ||
220+ typeof ( TResult ) == typeof ( IEnumerable < RemoteValue > ) ||
221+ typeof ( TResult ) == typeof ( object ) )
222+ {
223+ return ( TResult ) ( object ) array . Value ;
224+ }
225+
226+ if ( typeof ( TResult ) == typeof ( RemoteValue [ ] ) )
227+ {
228+ return ( TResult ) ( object ) array . Value . ToArray ( ) ;
229+ }
230+
231+ if ( typeof ( TResult ) == typeof ( List < RemoteValue > ) )
232+ {
233+ return ( TResult ) ( object ) array . Value . ToList ( ) ;
234+ }
235+ }
236+
237+ if ( this is ObjectRemoteValue obj )
238+ {
239+ if ( typeof ( TResult ) == typeof ( IDictionary < string , RemoteValue > ) ||
240+ typeof ( TResult ) == typeof ( Dictionary < string , RemoteValue > ) )
241+ {
242+ return ( TResult ) ( object ) obj . Value . ToDictionary ( value => ( ( StringRemoteValue ) value [ 0 ] ) . Value , value => value [ 1 ] ) ;
243+ }
244+
245+ if ( typeof ( TResult ) == typeof ( IDictionary < RemoteValue , RemoteValue > ) ||
246+ typeof ( TResult ) == typeof ( Dictionary < RemoteValue , RemoteValue > ) )
247+ {
248+ return ( TResult ) ( object ) obj . Value . ToDictionary ( value => value [ 0 ] , value => value [ 1 ] ) ;
249+ }
250+
251+ if ( typeof ( TResult ) == typeof ( object ) )
252+ {
253+ // Handle dynamic here
254+ IDictionary < string , object ? > values = new ExpandoObject ( ) ;
255+ foreach ( IReadOnlyList < RemoteValue > property in obj . Value )
256+ {
257+ string propertyName = ( ( StringRemoteValue ) property [ 0 ] ) . Value ;
258+ values [ propertyName ] = property [ 1 ] . ConvertTo < dynamic > ( ) ;
259+ }
260+
261+ return ( TResult ) ( object ) values ;
262+ }
263+ }
264+
265+ if ( this is MapRemoteValue map )
266+ {
267+ if ( typeof ( TResult ) == typeof ( IDictionary < RemoteValue , RemoteValue > ) ||
268+ typeof ( TResult ) == typeof ( Dictionary < RemoteValue , RemoteValue > ) )
269+ {
270+ return ( TResult ) ( object ) map . Value . ToDictionary ( value => value [ 0 ] , value => value [ 1 ] ) ;
271+ }
272+ if ( typeof ( TResult ) == typeof ( IDictionary < string , RemoteValue > ) ||
273+ typeof ( TResult ) == typeof ( Dictionary < string , RemoteValue > ) )
274+ {
275+ return ( TResult ) ( object ) map . Value . ToDictionary ( value => ( ( StringRemoteValue ) value [ 0 ] ) . Value , value => value [ 1 ] ) ;
276+ }
277+ }
278+
279+ if ( this is SetRemoteValue set )
91280 {
92- // :)
93- return ( TResult ) new object ( ) ;
281+ if ( typeof ( TResult ) == typeof ( IReadOnlyList < RemoteValue > ) ||
282+ typeof ( TResult ) == typeof ( IEnumerable < RemoteValue > ) ||
283+ typeof ( TResult ) == typeof ( object ) )
284+ {
285+ return ( TResult ) ( object ) set . Value ;
286+ }
287+
288+ if ( typeof ( TResult ) == typeof ( RemoteValue [ ] ) )
289+ {
290+ return ( TResult ) ( object ) set . Value . ToArray ( ) ;
291+ }
292+
293+ if ( typeof ( TResult ) == typeof ( List < RemoteValue > ) )
294+ {
295+ return ( TResult ) ( object ) set . Value . ToList ( ) ;
296+ }
297+
298+ if ( typeof ( TResult ) == typeof ( ISet < RemoteValue > ) ||
299+ #if NET8_0_OR_GREATER
300+ typeof ( TResult ) == typeof ( IReadOnlySet < RemoteValue > ) ||
301+ #endif
302+ typeof ( TResult ) == typeof ( HashSet < RemoteValue > ) )
303+ {
304+ return ( TResult ) ( object ) new HashSet < RemoteValue > ( set . Value ) ;
305+ }
94306 }
95307
96- throw new BiDiException ( "Cannot convert ..... " ) ;
308+ throw new BiDiException ( $ "Cannot convert to type { typeof ( TResult ) } from { this } ") ;
97309 }
98310}
99311
0 commit comments