@@ -21,6 +21,7 @@ internal class AdapterGenerator : SourceGenerator
21
21
22
22
private readonly Dictionary < string , ISymbol > _adaptedMembers = new ( ) ;
23
23
private readonly Dictionary < string , ITypeSymbol > _adaptedStructs = new ( ) ;
24
+ private readonly Dictionary < string , ITypeSymbol > _adaptedArrays = new ( ) ;
24
25
25
26
internal AdapterGenerator ( GeneratorExecutionContext context )
26
27
{
@@ -132,6 +133,19 @@ private string GetStructAdapterName(ITypeSymbol structType, bool toJS)
132
133
return ( getAdapterName , setAdapterName ) ;
133
134
}
134
135
136
+ private string GetArrayAdapterName ( ITypeSymbol elementType , bool toJS )
137
+ {
138
+ string ns = GetNamespace ( elementType ) ;
139
+ string elementName = elementType . Name ;
140
+ string prefix = toJS ? AdapterFromPrefix : AdapterToPrefix ;
141
+ string adapterName = $ "{ prefix } { ns . Replace ( '.' , '_' ) } _{ elementName } _Array";
142
+ if ( ! _adaptedArrays . ContainsKey ( adapterName ) )
143
+ {
144
+ _adaptedArrays . Add ( adapterName , elementType ) ;
145
+ }
146
+ return adapterName ;
147
+ }
148
+
135
149
internal void GenerateAdapters ( SourceBuilder s )
136
150
{
137
151
foreach ( KeyValuePair < string , ISymbol > nameAndSymbol in _adaptedMembers )
@@ -164,6 +178,14 @@ internal void GenerateAdapters(SourceBuilder s)
164
178
ITypeSymbol structSymbol = nameAndSymbol . Value ;
165
179
GenerateStructAdapter ( ref s , adapterName , structSymbol ) ;
166
180
}
181
+
182
+ foreach ( KeyValuePair < string , ITypeSymbol > nameAndSymbol in _adaptedArrays )
183
+ {
184
+ s ++ ;
185
+ string adapterName = nameAndSymbol . Key ;
186
+ ITypeSymbol elementSymbol = nameAndSymbol . Value ;
187
+ GenerateArrayAdapter ( ref s , adapterName , elementSymbol ) ;
188
+ }
167
189
}
168
190
169
191
private void GenerateConstructorAdapter (
@@ -345,6 +367,59 @@ private void GenerateStructAdapter(
345
367
}
346
368
}
347
369
370
+ private void GenerateArrayAdapter (
371
+ ref SourceBuilder s ,
372
+ string adapterName ,
373
+ ITypeSymbol elementType )
374
+ {
375
+ string ns = GetNamespace ( elementType ) ;
376
+ string elementName = elementType . Name ;
377
+
378
+ if ( adapterName . StartsWith ( AdapterFromPrefix ) )
379
+ {
380
+ s += $ "private static JSValue { adapterName } ({ ns } .{ elementName } [] array)";
381
+ s += "{" ;
382
+ s += "JSArray jsArray = new JSArray(array.Length);" ;
383
+ s += "for (int i = 0; i < array.Length; i++)" ;
384
+ s += "{" ;
385
+ s += $ "jsArray[i] = { Convert ( "array[i]" , elementType , null ) } ;";
386
+ s += "}" ;
387
+ s += "return jsArray;" ;
388
+ s += "}" ;
389
+ }
390
+ else
391
+ {
392
+ s += $ "private static { ns } .{ elementName } [] { adapterName } (JSValue value)";
393
+ s += "{" ;
394
+ s += "JSArray jsArray = (JSArray)value;" ;
395
+ s += $ "{ ns } .{ elementName } [] array = new { ns } .{ elementName } [jsArray.Length];";
396
+ s += "for (int i = 0; i < array.Length; i++)" ;
397
+ s += "{" ;
398
+ s += $ "array[i] = { Convert ( "jsArray[i]" , null , elementType ) } ;";
399
+ s += "}" ;
400
+ s += "return array;" ;
401
+ s += "}" ;
402
+ }
403
+ }
404
+
405
+ private bool IsTypedArrayType ( ITypeSymbol elementType )
406
+ {
407
+ return elementType . SpecialType switch
408
+ {
409
+ SpecialType . System_SByte => true ,
410
+ SpecialType . System_Byte => true ,
411
+ SpecialType . System_Int16 => true ,
412
+ SpecialType . System_UInt16 => true ,
413
+ SpecialType . System_Int32 => true ,
414
+ SpecialType . System_UInt32 => true ,
415
+ SpecialType . System_Int64 => true ,
416
+ SpecialType . System_UInt64 => true ,
417
+ SpecialType . System_Single => true ,
418
+ SpecialType . System_Double => true ,
419
+ _ => false ,
420
+ } ;
421
+ }
422
+
348
423
private void AdaptThisArg ( ref SourceBuilder s , ISymbol symbol )
349
424
{
350
425
@@ -425,6 +500,14 @@ private string Convert(string fromExpression, ITypeSymbol? fromType, ITypeSymbol
425
500
}
426
501
else if ( toType . TypeKind == TypeKind . Struct )
427
502
{
503
+ if ( toType is INamedTypeSymbol namedType &&
504
+ namedType . TypeParameters . Length == 1 &&
505
+ namedType . OriginalDefinition . Name == "Memory" &&
506
+ IsTypedArrayType ( namedType . TypeArguments [ 0 ] ) )
507
+ {
508
+ return $ "((JSTypedArray<{ namedType . TypeArguments [ 0 ] } >){ fromExpression } ).AsMemory()";
509
+ }
510
+
428
511
VerifyReferencedTypeIsExported ( toType ) ;
429
512
430
513
string adapterName = GetStructAdapterName ( toType , toJS : false ) ;
@@ -438,6 +521,26 @@ private string Convert(string fromExpression, ITypeSymbol? fromType, ITypeSymbol
438
521
return $ "{ adapterName } ({ fromExpression } )";
439
522
}
440
523
}
524
+ else if ( toType . TypeKind == TypeKind . Array )
525
+ {
526
+ ITypeSymbol elementType = ( ( IArrayTypeSymbol ) toType ) . ElementType ;
527
+ VerifyReferencedTypeIsExported ( elementType ) ;
528
+
529
+ string adapterName = GetArrayAdapterName ( elementType , toJS : false ) ;
530
+ if ( isNullable )
531
+ {
532
+ return $ "({ fromExpression } ).IsNullOrUndefined() ? ({ elementType } []?)null : " +
533
+ $ "{ adapterName } ({ fromExpression } )";
534
+ }
535
+ else
536
+ {
537
+ return $ "{ adapterName } ({ fromExpression } )";
538
+ }
539
+ }
540
+ else if ( toType is INamedTypeSymbol namedType && namedType . TypeParameters . Length > 0 )
541
+ {
542
+ // TODO: Handle generic collections.
543
+ }
441
544
442
545
// TODO: Handle other kinds of conversions from JSValue.
443
546
// TODO: Handle unwrapping external values.
@@ -483,6 +586,14 @@ private string Convert(string fromExpression, ITypeSymbol? fromType, ITypeSymbol
483
586
}
484
587
else if ( fromType . TypeKind == TypeKind . Struct )
485
588
{
589
+ if ( fromType is INamedTypeSymbol namedType &&
590
+ namedType . TypeParameters . Length == 1 &&
591
+ namedType . OriginalDefinition . Name == "Memory" &&
592
+ IsTypedArrayType ( namedType . TypeArguments [ 0 ] ) )
593
+ {
594
+ return $ "new JSTypedArray<{ namedType . TypeArguments [ 0 ] } >({ fromExpression } )";
595
+ }
596
+
486
597
VerifyReferencedTypeIsExported ( fromType ) ;
487
598
488
599
string adapterName = GetStructAdapterName ( fromType , toJS : true ) ;
@@ -496,6 +607,26 @@ private string Convert(string fromExpression, ITypeSymbol? fromType, ITypeSymbol
496
607
return $ "{ adapterName } ({ fromExpression } )";
497
608
}
498
609
}
610
+ else if ( fromType . TypeKind == TypeKind . Array )
611
+ {
612
+ ITypeSymbol elementType = ( ( IArrayTypeSymbol ) fromType ) . ElementType ;
613
+ VerifyReferencedTypeIsExported ( elementType ) ;
614
+
615
+ string adapterName = GetArrayAdapterName ( elementType , toJS : true ) ;
616
+ if ( isNullable )
617
+ {
618
+ return $ "{ fromExpression } == null ? JSValue.Null : " +
619
+ $ "{ adapterName } ({ fromExpression } )";
620
+ }
621
+ else
622
+ {
623
+ return $ "{ adapterName } ({ fromExpression } )";
624
+ }
625
+ }
626
+ else if ( fromType is INamedTypeSymbol namedType && namedType . TypeParameters . Length > 0 )
627
+ {
628
+ // TODO: Handle generic collections.
629
+ }
499
630
500
631
// TODO: Handle other kinds of conversions to JSValue.
501
632
// TODO: Consider wrapping unsupported types in a value of type "external".
@@ -512,6 +643,13 @@ private string Convert(string fromExpression, ITypeSymbol? fromType, ITypeSymbol
512
643
513
644
private void VerifyReferencedTypeIsExported ( ITypeSymbol type )
514
645
{
646
+ switch ( type . SpecialType )
647
+ {
648
+ case SpecialType . System_Object :
649
+ case SpecialType . System_String : return ;
650
+ default : break ;
651
+ }
652
+
515
653
if ( ModuleGenerator . GetJSExportAttribute ( type ) == null )
516
654
{
517
655
// TODO: Consider an option to automatically export referenced classes?
0 commit comments