@@ -210,6 +210,38 @@ type JsonUnionConverter<'T>
210210 else
211211 ValueNone
212212
213+ let casesByJsonType =
214+ if fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.Untagged
215+ && fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.UnwrapSingleFieldCases then
216+ let dict = Dictionary< JsonTokenType, Case>()
217+ for c in cases do
218+ let clrType = c.Fields[ 0 ]. Type
219+ let typeCode = Type.GetTypeCode( c.Fields[ 0 ]. Type)
220+ match typeCode with
221+ | TypeCode.Byte
222+ | TypeCode.SByte
223+ | TypeCode.UInt16
224+ | TypeCode.UInt32
225+ | TypeCode.UInt64
226+ | TypeCode.Int16
227+ | TypeCode.Int32
228+ | TypeCode.Int64
229+ | TypeCode.Decimal
230+ | TypeCode.Double
231+ | TypeCode.Single -> dict[ JsonTokenType.Number] <- c
232+ | TypeCode.Boolean ->
233+ dict[ JsonTokenType.True] <- c
234+ dict[ JsonTokenType.False] <- c
235+ | TypeCode.DateTime
236+ | TypeCode.String -> dict[ JsonTokenType.String] <- c
237+ | TypeCode.Object when typeof< System.Collections.IEnumerable>. IsAssignableFrom ( clrType) ->
238+ dict[ JsonTokenType.StartArray] <- c
239+ | TypeCode.Object -> dict[ JsonTokenType.StartObject] <- c
240+ | _ -> ()
241+ ValueSome dict
242+ else
243+ ValueNone
244+
213245 let getJsonName ( reader : byref < Utf8JsonReader >) =
214246 match reader.TokenType with
215247 | JsonTokenType.True -> JsonName.Bool true
@@ -533,6 +565,24 @@ type JsonUnionConverter<'T>
533565 | ValueNone -> failExpecting " case field" & reader ty
534566 | _ -> failExpecting " case field" & reader ty
535567
568+ let getCaseByElementType ( reader : byref < Utf8JsonReader >) =
569+ let found =
570+ match casesByJsonType with
571+ | ValueNone -> ValueNone
572+ | ValueSome d ->
573+ match d.TryGetValue( reader.TokenType) with
574+ | true , p -> ValueSome p
575+ | false , _ -> ValueNone
576+ match found with
577+ | ValueNone ->
578+ failf " Unknown case for union type %s due to unmatched field type: %s " ty.FullName ( reader.GetString())
579+ | ValueSome case -> case
580+
581+ let readUnwrapedUntagged ( reader : byref < Utf8JsonReader >) =
582+ let case = getCaseByElementType & reader
583+ let field = JsonSerializer.Deserialize(& reader, case.Fields[ 0 ]. Type, options)
584+ case.Ctor [| field |] :?> 'T
585+
536586 let writeFieldsAsRestOfArray ( writer : Utf8JsonWriter ) ( case : Case ) ( value : obj ) ( options : JsonSerializerOptions ) =
537587 let fields = case.Fields
538588 let values = case.Dector value
@@ -614,7 +664,10 @@ type JsonUnionConverter<'T>
614664 writeFieldsAsRestOfArray writer case value options
615665
616666 let writeUntagged ( writer : Utf8JsonWriter ) ( case : Case ) ( value : obj ) ( options : JsonSerializerOptions ) =
617- writeFieldsAsObject writer case value options
667+ if case.UnwrappedSingleField then
668+ JsonSerializer.Serialize( writer, ( case.Dector value)[ 0 ], case.Fields[ 0 ]. Type, options)
669+ else
670+ writeFieldsAsObject writer case value options
618671
619672 override _.Read ( reader , _typeToConvert , options ) =
620673 match reader.TokenType with
@@ -633,11 +686,14 @@ type JsonUnionConverter<'T>
633686 | JsonUnionEncoding.ExternalTag -> readExternalTag & reader options
634687 | JsonUnionEncoding.InternalTag -> readInternalTag & reader options
635688 | UntaggedBit ->
636- if not hasDistinctFieldNames then
689+ if fsOptions.UnionEncoding.HasFlag JsonUnionEncoding.UnwrapSingleFieldCases then
690+ readUnwrapedUntagged & reader
691+ elif not hasDistinctFieldNames then
637692 failf
638693 " Union %s can't be deserialized as Untagged because it has duplicate field names across unions"
639694 ty.FullName
640- readUntagged & reader options
695+ else
696+ readUntagged & reader options
641697 | _ -> failf " Invalid union encoding: %A " fsOptions.UnionEncoding
642698
643699 override _.Write ( writer , value , options ) =
0 commit comments