@@ -210,6 +210,41 @@ type JsonUnionConverter<'T>
210
210
else
211
211
ValueNone
212
212
213
+ let casesByJsonType =
214
+ if fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.Untagged && fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.UnwrapSingleFieldCases then
215
+ let dict = Dictionary< JsonTokenType, Case>()
216
+ for c in cases do
217
+ let clrType = c.Fields[ 0 ]. Type
218
+ let typeCode = Type.GetTypeCode( c.Fields[ 0 ]. Type)
219
+ match typeCode with
220
+ | TypeCode.Byte
221
+ | TypeCode.SByte
222
+ | TypeCode.UInt16
223
+ | TypeCode.UInt32
224
+ | TypeCode.UInt64
225
+ | TypeCode.Int16
226
+ | TypeCode.Int32
227
+ | TypeCode.Int64
228
+ | TypeCode.Decimal
229
+ | TypeCode.Double
230
+ | TypeCode.Single ->
231
+ dict[ JsonTokenType.Number] <- c
232
+ | TypeCode.Boolean ->
233
+ dict[ JsonTokenType.True] <- c
234
+ dict[ JsonTokenType.False] <- c
235
+ | TypeCode.DateTime
236
+ | TypeCode.String ->
237
+ dict[ JsonTokenType.String] <- c
238
+ | TypeCode.Object when typeof< System.Collections.IEnumerable>. IsAssignableFrom( clrType) ->
239
+ dict[ JsonTokenType.StartArray] <- c
240
+ | TypeCode.Object ->
241
+ dict[ JsonTokenType.StartObject] <- c
242
+ | _ ->
243
+ ()
244
+ ValueSome dict
245
+ else
246
+ ValueNone
247
+
213
248
let getJsonName ( reader : byref < Utf8JsonReader >) =
214
249
match reader.TokenType with
215
250
| JsonTokenType.True -> JsonName.Bool true
@@ -533,6 +568,24 @@ type JsonUnionConverter<'T>
533
568
| ValueNone -> failExpecting " case field" & reader ty
534
569
| _ -> failExpecting " case field" & reader ty
535
570
571
+ let getCaseByElementType ( reader : byref < Utf8JsonReader >) =
572
+ let found =
573
+ match casesByJsonType with
574
+ | ValueNone ->
575
+ ValueNone
576
+ | ValueSome d ->
577
+ match d.TryGetValue( reader.TokenType) with
578
+ | true , p -> ValueSome p
579
+ | false , _ -> ValueNone
580
+ match found with
581
+ | ValueNone -> failf " Unknown case for union type %s due to unmatched field type: %s " ty.FullName ( reader.GetString())
582
+ | ValueSome case -> case
583
+
584
+ let readUnwrapedUntagged ( reader : byref < Utf8JsonReader >) =
585
+ let case = getCaseByElementType & reader
586
+ let field = JsonSerializer.Deserialize(& reader, case.Fields[ 0 ]. Type, options)
587
+ case.Ctor [| field |] :?> 'T
588
+
536
589
let writeFieldsAsRestOfArray ( writer : Utf8JsonWriter ) ( case : Case ) ( value : obj ) ( options : JsonSerializerOptions ) =
537
590
let fields = case.Fields
538
591
let values = case.Dector value
@@ -614,7 +667,10 @@ type JsonUnionConverter<'T>
614
667
writeFieldsAsRestOfArray writer case value options
615
668
616
669
let writeUntagged ( writer : Utf8JsonWriter ) ( case : Case ) ( value : obj ) ( options : JsonSerializerOptions ) =
617
- writeFieldsAsObject writer case value options
670
+ if case.UnwrappedSingleField then
671
+ JsonSerializer.Serialize( writer, ( case.Dector value)[ 0 ], case.Fields[ 0 ]. Type, options)
672
+ else
673
+ writeFieldsAsObject writer case value options
618
674
619
675
override _.Read ( reader , _typeToConvert , options ) =
620
676
match reader.TokenType with
@@ -633,11 +689,14 @@ type JsonUnionConverter<'T>
633
689
| JsonUnionEncoding.ExternalTag -> readExternalTag & reader options
634
690
| JsonUnionEncoding.InternalTag -> readInternalTag & reader options
635
691
| UntaggedBit ->
636
- if not hasDistinctFieldNames then
692
+ if fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.UnwrapSingleFieldCases then
693
+ readUnwrapedUntagged & reader
694
+ elif not hasDistinctFieldNames then
637
695
failf
638
696
" Union %s can't be deserialized as Untagged because it has duplicate field names across unions"
639
697
ty.FullName
640
- readUntagged & reader options
698
+ else
699
+ readUntagged & reader options
641
700
| _ -> failf " Invalid union encoding: %A " fsOptions.UnionEncoding
642
701
643
702
override _.Write ( writer , value , options ) =
0 commit comments