@@ -54,49 +54,101 @@ namespace OpenQA.Selenium.BiDi.Script;
5454[ JsonConverter ( typeof ( RemoteValueConverter ) ) ]
5555public abstract record RemoteValue
5656{
57- public static implicit operator double ( RemoteValue remoteValue ) => ( double ) ( ( NumberRemoteValue ) remoteValue ) . Value ;
57+ public static implicit operator bool ( RemoteValue remoteValue ) => remoteValue . ConvertTo < bool > ( ) ;
58+ public static implicit operator double ( RemoteValue remoteValue ) => remoteValue . ConvertTo < double > ( ) ;
59+ public static implicit operator float ( RemoteValue remoteValue ) => remoteValue . ConvertTo < float > ( ) ;
60+ public static implicit operator int ( RemoteValue remoteValue ) => remoteValue . ConvertTo < int > ( ) ;
61+ public static implicit operator long ( RemoteValue remoteValue ) => remoteValue . ConvertTo < long > ( ) ;
62+ public static implicit operator string ? ( RemoteValue remoteValue ) => remoteValue . ConvertTo < string > ( ) ;
5863
59- public static implicit operator int ( RemoteValue remoteValue ) => ( int ) ( double ) remoteValue ;
60- public static implicit operator long ( RemoteValue remoteValue ) => ( long ) ( double ) remoteValue ;
61-
62- public static implicit operator string ? ( RemoteValue remoteValue )
63- {
64- return remoteValue switch
64+ public TResult ? ConvertTo < TResult > ( )
65+ => ( this , typeof ( TResult ) ) switch
6566 {
66- StringRemoteValue stringValue => stringValue . Value ,
67- NullRemoteValue => null ,
68- _ => throw new InvalidCastException ( $ "Cannot convert { remoteValue } to string")
67+ ( _, Type t ) when t . IsAssignableFrom ( GetType ( ) )
68+ => ( TResult ) ( object ) this ,
69+ ( BooleanRemoteValue b , Type t ) when t == typeof ( bool )
70+ => ( TResult ) ( object ) b . Value ,
71+ ( NullRemoteValue , Type t ) when ! t . IsValueType || Nullable . GetUnderlyingType ( t ) is not null
72+ => default ,
73+ ( NumberRemoteValue n , Type t ) when t == typeof ( byte )
74+ => ( TResult ) ( object ) Convert . ToByte ( n . Value ) ,
75+ ( NumberRemoteValue n , Type t ) when t == typeof ( sbyte )
76+ => ( TResult ) ( object ) Convert . ToSByte ( n . Value ) ,
77+ ( NumberRemoteValue n , Type t ) when t == typeof ( short )
78+ => ( TResult ) ( object ) Convert . ToInt16 ( n . Value ) ,
79+ ( NumberRemoteValue n , Type t ) when t == typeof ( ushort )
80+ => ( TResult ) ( object ) Convert . ToUInt16 ( n . Value ) ,
81+ ( NumberRemoteValue n , Type t ) when t == typeof ( int )
82+ => ( TResult ) ( object ) Convert . ToInt32 ( n . Value ) ,
83+ ( NumberRemoteValue n , Type t ) when t == typeof ( uint )
84+ => ( TResult ) ( object ) Convert . ToUInt32 ( n . Value ) ,
85+ ( NumberRemoteValue n , Type t ) when t == typeof ( long )
86+ => ( TResult ) ( object ) Convert . ToInt64 ( n . Value ) ,
87+ ( NumberRemoteValue n , Type t ) when t == typeof ( ulong )
88+ => ( TResult ) ( object ) Convert . ToUInt64 ( n . Value ) ,
89+ ( NumberRemoteValue n , Type t ) when t == typeof ( double )
90+ => ( TResult ) ( object ) n . Value ,
91+ ( NumberRemoteValue n , Type t ) when t == typeof ( float )
92+ => ( TResult ) ( object ) Convert . ToSingle ( n . Value ) ,
93+ ( NumberRemoteValue n , Type t ) when t == typeof ( decimal )
94+ => ( TResult ) ( object ) Convert . ToDecimal ( n . Value ) ,
95+ ( StringRemoteValue s , Type t ) when t == typeof ( string )
96+ => ( TResult ) ( object ) s . Value ,
97+ ( ArrayRemoteValue a , Type t ) when t . IsArray
98+ => ConvertRemoteValuesToArray < TResult > ( a . Value , t . GetElementType ( ) ! ) ,
99+ ( ArrayRemoteValue a , Type t ) when t . IsGenericType && t . IsAssignableFrom ( typeof ( List < > ) . MakeGenericType ( t . GetGenericArguments ( ) [ 0 ] ) )
100+ => ConvertRemoteValuesToGenericList < TResult > ( a . Value , typeof ( List < > ) . MakeGenericType ( t . GetGenericArguments ( ) [ 0 ] ) ) ,
101+
102+ ( _, Type t ) when Nullable . GetUnderlyingType ( t ) is { } underlying
103+ => ConvertToNullable < TResult > ( underlying ) ,
104+
105+ _ => throw new InvalidCastException ( $ "Cannot convert { GetType ( ) . Name } to { typeof ( TResult ) . FullName } ")
69106 } ;
70- }
71107
72- // TODO: extend types
73- public TResult ? ConvertTo < TResult > ( )
108+ private TResult ConvertToNullable < TResult > ( Type underlyingType )
74109 {
75- var type = typeof ( TResult ) ;
110+ var convertMethod = typeof ( RemoteValue ) . GetMethod ( nameof ( ConvertTo ) ) ! . MakeGenericMethod ( underlyingType ) ;
111+ var value = convertMethod . Invoke ( this , null ) ;
112+ return ( TResult ) value ! ;
113+ }
76114
77- if ( typeof ( RemoteValue ) . IsAssignableFrom ( type ) ) // handle native derived types
78- {
79- return ( TResult ) ( this as object ) ;
80- }
81- if ( type == typeof ( bool ) )
82- {
83- return ( TResult ) ( Convert . ToBoolean ( ( ( BooleanRemoteValue ) this ) . Value ) as object ) ;
84- }
85- if ( type == typeof ( int ) )
115+ private static TResult ConvertRemoteValuesToArray < TResult > ( IEnumerable < RemoteValue > ? remoteValues , Type elementType )
116+ {
117+ if ( remoteValues is null )
86118 {
87- return ( TResult ) ( Convert . ToInt32 ( ( ( NumberRemoteValue ) this ) . Value ) as object ) ;
119+ return ( TResult ) ( object ) Array . CreateInstance ( elementType , 0 ) ;
88120 }
89- else if ( type == typeof ( string ) )
121+
122+ var convertMethod = typeof ( RemoteValue ) . GetMethod ( nameof ( ConvertTo ) ) ! . MakeGenericMethod ( elementType ) ;
123+ var items = remoteValues . ToList ( ) ;
124+ var array = Array . CreateInstance ( elementType , items . Count ) ;
125+
126+ for ( int i = 0 ; i < items . Count ; i ++ )
90127 {
91- return ( TResult ) ( ( ( StringRemoteValue ) this ) . Value as object ) ;
128+ var convertedItem = convertMethod . Invoke ( items [ i ] , null ) ;
129+ array . SetValue ( convertedItem , i ) ;
92130 }
93- else if ( type is object )
131+
132+ return ( TResult ) ( object ) array ;
133+ }
134+
135+ private static TResult ConvertRemoteValuesToGenericList < TResult > ( IEnumerable < RemoteValue > ? remoteValues , Type listType )
136+ {
137+ var elementType = listType . GetGenericArguments ( ) [ 0 ] ;
138+ var list = ( System . Collections . IList ) Activator . CreateInstance ( listType ) ! ;
139+
140+ if ( remoteValues is not null )
94141 {
95- // :)
96- return ( TResult ) new object ( ) ;
142+ var convertMethod = typeof ( RemoteValue ) . GetMethod ( nameof ( ConvertTo ) ) ! . MakeGenericMethod ( elementType ) ;
143+
144+ foreach ( var item in remoteValues )
145+ {
146+ var convertedItem = convertMethod . Invoke ( item , null ) ;
147+ list . Add ( convertedItem ) ;
148+ }
97149 }
98150
99- throw new BiDiException ( "Cannot convert ....." ) ;
151+ return ( TResult ) list ;
100152 }
101153}
102154
0 commit comments