@@ -25,6 +25,62 @@ private void GenerateTrivialCode(SourceProductionContext spc, HashSet<ITypeSymbo
2525 if ( ! generatedTypeNames . Add ( ninoType . TypeSymbol . GetDisplayString ( ) ) )
2626 continue ;
2727
28+
29+ if ( ! ninoType . TypeSymbol . IsSealedOrStruct ( ) )
30+ {
31+ sb . AppendLine ( ) ;
32+ sb . AppendLine ( $$ """
33+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
34+ public static void SerializePolymorphic({{ ninoType . TypeSymbol . GetTypeFullName ( ) }} value, ref Writer writer)
35+ {
36+ switch(value)
37+ {
38+ case null:
39+ {
40+ writer.Write(TypeCollector.Null);
41+ return;
42+ }
43+ """ ) ;
44+ if ( NinoGraph . SubTypes . TryGetValue ( ninoType , out var subTypes ) )
45+ {
46+ foreach ( var subType in subTypes )
47+ {
48+ if ( ! subType . TypeSymbol . IsInstanceType ( ) )
49+ continue ;
50+
51+ var valName = subType . TypeSymbol . GetCachedVariableName ( "val_" ) ;
52+ sb . AppendLine ( $$ """
53+ case {{ subType . TypeSymbol . GetTypeFullName ( ) }} {{ valName }} :
54+ {
55+ """ ) ;
56+
57+ sb . AppendLine (
58+ $ " writer.Write(NinoTypeConst.{ subType . TypeSymbol . GetTypeFullName ( ) . GetTypeConstName ( ) } );") ;
59+
60+ // Optimized write path - direct write for unmanaged types
61+ if ( subType . TypeSymbol . IsUnmanagedType )
62+ {
63+ sb . AppendLine ( $ " writer.Write({ valName } );") ;
64+ }
65+ else
66+ {
67+ WriteMembers ( subType , valName , sb , " " ) ;
68+ }
69+
70+ sb . AppendLine ( " return;" ) ;
71+ sb . AppendLine ( " }" ) ;
72+ }
73+ }
74+
75+ sb . AppendLine ( " default:" ) ;
76+ sb . AppendLine (
77+ $ " CachedSerializer<{ ninoType . TypeSymbol . GetTypeFullName ( ) } >.SerializePolymorphic(value, ref writer);") ;
78+ sb . AppendLine ( " break;" ) ;
79+ sb . AppendLine ( " }" ) ;
80+ sb . AppendLine ( " }" ) ;
81+ sb . AppendLine ( ) ;
82+ }
83+
2884 if ( ! ninoType . TypeSymbol . IsInstanceType ( ) ||
2985 ! string . IsNullOrEmpty ( ninoType . CustomSerializer ) )
3086 continue ;
@@ -206,7 +262,7 @@ private bool TryGetInlineSerializeCall(ITypeSymbol type, string valueExpression,
206262 return true ;
207263 }
208264
209- private void WriteMembers ( NinoType type , string valName , StringBuilder sb )
265+ private void WriteMembers ( NinoType type , string valName , StringBuilder sb , string indent = "" )
210266 {
211267 // First pass: collect all types that need serializers or custom formatters
212268 HashSet < ITypeSymbol > typesNeedingSerializers = new ( SymbolEqualityComparer . Default ) ;
@@ -320,7 +376,7 @@ string GetSerializerVarName(ITypeSymbol serializerType)
320376 // PRIORITY 1: Custom formatter (highest priority)
321377 if ( customFormatterVarsByMember . TryGetValue ( member , out var formatterVar ) )
322378 {
323- sb . AppendLine ( $ " { formatterVar } .Serialize({ val } , ref writer);") ;
379+ sb . AppendLine ( $ "{ indent } { formatterVar } .Serialize({ val } , ref writer);") ;
324380 }
325381 }
326382 else
@@ -331,13 +387,13 @@ string GetSerializerVarName(ITypeSymbol serializerType)
331387 {
332388 case NinoTypeHelper . NinoTypeKind . Unmanaged :
333389 // PRIORITY 2: Unmanaged types - write directly
334- sb . AppendLine ( $ " writer.Write({ val } );") ;
390+ sb . AppendLine ( $ "{ indent } writer.Write({ val } );") ;
335391 break ;
336392
337393 case NinoTypeHelper . NinoTypeKind . Boxed :
338394 // PRIORITY 3: Object type - call boxed API in NinoSerializer directly
339395 sb . AppendLine (
340- $ " NinoSerializer.SerializeBoxed({ val } , ref writer, { val } ?.GetType());") ;
396+ $ "{ indent } NinoSerializer.SerializeBoxed({ val } , ref writer, { val } ?.GetType());") ;
341397 break ;
342398
343399 case NinoTypeHelper . NinoTypeKind . BuiltIn :
@@ -346,16 +402,16 @@ string GetSerializerVarName(ITypeSymbol serializerType)
346402 {
347403 if ( member . IsUtf8String )
348404 {
349- sb . AppendLine ( $ " writer.WriteUtf8({ val } );") ;
405+ sb . AppendLine ( $ "{ indent } writer.WriteUtf8({ val } );") ;
350406 }
351407 else
352408 {
353- sb . AppendLine ( $ " writer.Write({ val } );") ;
409+ sb . AppendLine ( $ "{ indent } writer.Write({ val } );") ;
354410 }
355411 }
356412 else
357413 {
358- sb . AppendLine ( $ " Serializer.Serialize({ val } , ref writer);") ;
414+ sb . AppendLine ( $ "{ indent } Serializer.Serialize({ val } , ref writer);") ;
359415 }
360416
361417 break ;
@@ -364,30 +420,36 @@ string GetSerializerVarName(ITypeSymbol serializerType)
364420 // PRIORITY 5: NinoType - use CachedSerializer
365421 if ( TryGetInlineSerializeCall ( declaredType , val , out var inlineCall ) )
366422 {
367- sb . AppendLine ( $ " { inlineCall } ;") ;
423+ sb . AppendLine ( $ "{ indent } { inlineCall } ;") ;
424+ }
425+ else if ( ! declaredType . IsSealedOrStruct ( ) )
426+ {
427+ sb . AppendLine (
428+ $ "{ indent } Serializer.SerializePolymorphic({ val } , ref writer);") ;
368429 }
369430 else
370431 {
371432 var serializerVar = GetSerializerVarName ( declaredType ) ;
372- sb . AppendLine ( $ " { serializerVar } .Serialize({ val } , ref writer);") ;
433+ sb . AppendLine ( $ "{ indent } { serializerVar } .Serialize({ val } , ref writer);") ;
373434 }
435+
374436 break ;
375437 }
376438 }
377439 }
378440 else
379441 {
380442 // Standard path with version tolerance support
381- sb . AppendLine ( $ "#if { NinoTypeHelper . WeakVersionToleranceSymbol } ") ;
443+ sb . AppendLine ( $ "{ indent } #if { NinoTypeHelper . WeakVersionToleranceSymbol } ") ;
382444 foreach ( var val in valNames )
383445 {
384- sb . AppendLine ( $ " writer.Write({ val } );") ;
446+ sb . AppendLine ( $ "{ indent } writer.Write({ val } );") ;
385447 }
386448
387- sb . AppendLine ( " #else") ;
388- sb . AppendLine ( $ " writer.Write(NinoTuple.Create({ string . Join ( ", " , valNames ) } ));") ;
389- sb . AppendLine ( " #endif") ;
449+ sb . AppendLine ( $ " { indent } #else") ;
450+ sb . AppendLine ( $ "{ indent } writer.Write(NinoTuple.Create({ string . Join ( ", " , valNames ) } ));") ;
451+ sb . AppendLine ( $ " { indent } #endif") ;
390452 }
391453 }
392454 }
393- }
455+ }
0 commit comments