Skip to content

Commit bd9622e

Browse files
committed
fix: multiple performance fixes for type serialization
feat: adds to identifier mapping to non nullable enum Signed-off-by: Vincent Biret <[email protected]>
1 parent cb5bb27 commit bd9622e

File tree

3 files changed

+61
-56
lines changed

3 files changed

+61
-56
lines changed

src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,27 @@ namespace Microsoft.OpenApi.Extensions
1313
/// </summary>
1414
public static class OpenApiTypeMapper
1515
{
16+
#nullable enable
1617
/// <summary>
1718
/// Maps a JsonSchema data type to an identifier.
1819
/// </summary>
1920
/// <param name="schemaType"></param>
2021
/// <returns></returns>
21-
public static string ToIdentifier(this JsonSchemaType? schemaType)
22+
public static string? ToIdentifier(this JsonSchemaType? schemaType)
23+
{
24+
if (schemaType is null)
25+
{
26+
return null;
27+
}
28+
return schemaType.Value.ToIdentifier();
29+
}
30+
31+
/// <summary>
32+
/// Maps a JsonSchema data type to an identifier.
33+
/// </summary>
34+
/// <param name="schemaType"></param>
35+
/// <returns></returns>
36+
public static string? ToIdentifier(this JsonSchemaType schemaType)
2237
{
2338
return schemaType switch
2439
{
@@ -32,6 +47,7 @@ public static string ToIdentifier(this JsonSchemaType? schemaType)
3247
_ => null,
3348
};
3449
}
50+
#nullable restore
3551

3652
/// <summary>
3753
/// Converts a schema type's identifier into the enum equivalent

src/Microsoft.OpenApi/Models/OpenApiSchema.cs

Lines changed: 42 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -476,10 +476,7 @@ public void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
476476
writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (nodeWriter, s) => nodeWriter.WriteAny(s));
477477

478478
// type
479-
if (Type is not null)
480-
{
481-
SerializeTypeProperty(Type, writer, version);
482-
}
479+
SerializeTypeProperty(Type, writer, version);
483480

484481
// allOf
485482
writer.WriteOptionalCollection(OpenApiConstants.AllOf, AllOf, callback);
@@ -660,10 +657,7 @@ internal void SerializeAsV2(
660657
writer.WriteStartObject();
661658

662659
// type
663-
if (Type is not null)
664-
{
665-
SerializeTypeProperty(Type, writer, OpenApiSpecVersion.OpenApi2_0);
666-
}
660+
SerializeTypeProperty(Type, writer, OpenApiSpecVersion.OpenApi2_0);
667661

668662
// description
669663
writer.WriteProperty(OpenApiConstants.Description, Description);
@@ -794,8 +788,11 @@ internal void SerializeAsV2(
794788

795789
private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, OpenApiSpecVersion version)
796790
{
797-
var flagsCount = CountEnumSetFlags(type);
798-
if (flagsCount is 1)
791+
if (type is null)
792+
{
793+
return;
794+
}
795+
if (!HasMultipleTypes(type.Value))
799796
{
800797
// check whether nullable is true for upcasting purposes
801798
if (version is OpenApiSpecVersion.OpenApi3_1 && (Nullable || Extensions.ContainsKey(OpenApiConstants.NullableExtension)))
@@ -804,61 +801,50 @@ private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer,
804801
}
805802
else
806803
{
807-
writer.WriteProperty(OpenApiConstants.Type, type.ToIdentifier());
804+
writer.WriteProperty(OpenApiConstants.Type, type.Value.ToIdentifier());
808805
}
809806
}
810-
else if(flagsCount > 1)
807+
else
811808
{
812809
// type
813810
if (version is OpenApiSpecVersion.OpenApi2_0 || version is OpenApiSpecVersion.OpenApi3_0)
814811
{
815-
DowncastTypeArrayToV2OrV3(type, writer, version, flagsCount);
812+
DowncastTypeArrayToV2OrV3(type.Value, writer, version);
816813
}
817814
else
818815
{
819-
if (type is not null)
816+
var list = new List<JsonSchemaType>();
817+
foreach (JsonSchemaType flag in jsonSchemaTypeValues)
820818
{
821-
var list = new List<JsonSchemaType?>();
822-
foreach (JsonSchemaType flag in System.Enum.GetValues(typeof(JsonSchemaType)))
819+
if (type.Value.HasFlag(flag))
823820
{
824-
if (type.Value.HasFlag(flag))
825-
{
826-
list.Add(flag);
827-
}
821+
list.Add(flag);
828822
}
823+
}
829824

830-
writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s.ToIdentifier()));
831-
}
825+
writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s.ToIdentifier()));
832826
}
833827
}
834828
}
835829

836-
private static int CountEnumSetFlags(JsonSchemaType? schemaType)
830+
private static bool IsPowerOfTwo(int x)
837831
{
838-
int count = 0;
839-
840-
if (schemaType != null)
841-
{
842-
// Check each flag in the enum
843-
foreach (JsonSchemaType value in System.Enum.GetValues(typeof(JsonSchemaType)))
844-
{
845-
// Check if the flag is set
846-
if (schemaType.Value.HasFlag(value))
847-
{
848-
count++;
849-
}
850-
}
851-
}
832+
return x != 0 && (x & (x - 1)) == 0;
833+
}
852834

853-
return count;
835+
private static bool HasMultipleTypes(JsonSchemaType schemaType)
836+
{
837+
var schemaTypeNumeric = (int)schemaType;
838+
return !IsPowerOfTwo(schemaTypeNumeric) && // Boolean, Integer, Number, String, Array, Object
839+
schemaTypeNumeric != (int)JsonSchemaType.Null;
854840
}
855841

856842
private void UpCastSchemaTypeToV31(JsonSchemaType? type, IOpenApiWriter writer)
857843
{
858844
// create a new array and insert the type and "null" as values
859845
Type = type | JsonSchemaType.Null;
860846
var list = new List<string>();
861-
foreach (JsonSchemaType? flag in System.Enum.GetValues(typeof(JsonSchemaType)))
847+
foreach (JsonSchemaType? flag in jsonSchemaTypeValues)
862848
{
863849
// Check if the flag is set in 'type' using a bitwise AND operation
864850
if (Type.Value.HasFlag(flag))
@@ -870,7 +856,9 @@ private void UpCastSchemaTypeToV31(JsonSchemaType? type, IOpenApiWriter writer)
870856
writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s));
871857
}
872858

873-
private void DowncastTypeArrayToV2OrV3(JsonSchemaType? schemaType, IOpenApiWriter writer, OpenApiSpecVersion version, int flagsCount)
859+
private static readonly Array jsonSchemaTypeValues = System.Enum.GetValues(typeof(JsonSchemaType));
860+
861+
private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter writer, OpenApiSpecVersion version)
874862
{
875863
/* If the array has one non-null value, emit Type as string
876864
* If the array has one null value, emit x-nullable as true
@@ -882,23 +870,12 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType? schemaType, IOpenApiWrite
882870
? OpenApiConstants.NullableExtension
883871
: OpenApiConstants.Nullable;
884872

885-
if (flagsCount is 1)
873+
if (!HasMultipleTypes(schemaType ^ JsonSchemaType.Null) && (schemaType & JsonSchemaType.Null) == JsonSchemaType.Null) // checks for two values and one is null
886874
{
887-
if (schemaType is JsonSchemaType.Null)
888-
{
889-
writer.WriteProperty(nullableProp, true);
890-
}
891-
else
892-
{
893-
writer.WriteProperty(OpenApiConstants.Type, schemaType.ToIdentifier());
894-
}
895-
}
896-
else if (flagsCount is 2 && (schemaType & JsonSchemaType.Null) == JsonSchemaType.Null) // checks for two values and one is null
897-
{
898-
foreach (JsonSchemaType? flag in System.Enum.GetValues(typeof(JsonSchemaType)))
875+
foreach (JsonSchemaType? flag in jsonSchemaTypeValues)
899876
{
900877
// Skip if the flag is not set or if it's the Null flag
901-
if (schemaType.Value.HasFlag(flag) && flag != JsonSchemaType.Null)
878+
if (schemaType.HasFlag(flag) && flag != JsonSchemaType.Null)
902879
{
903880
// Write the non-null flag value to the writer
904881
writer.WriteProperty(OpenApiConstants.Type, flag.ToIdentifier());
@@ -909,6 +886,17 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType? schemaType, IOpenApiWrite
909886
writer.WriteProperty(nullableProp, true);
910887
}
911888
}
889+
else if (!HasMultipleTypes(schemaType))
890+
{
891+
if (schemaType is JsonSchemaType.Null)
892+
{
893+
writer.WriteProperty(nullableProp, true);
894+
}
895+
else
896+
{
897+
writer.WriteProperty(OpenApiConstants.Type, schemaType.ToIdentifier());
898+
}
899+
}
912900
}
913901
}
914902
}

test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ namespace Microsoft.OpenApi.Extensions
192192
{
193193
public static System.Type MapOpenApiPrimitiveTypeToSimpleType(this Microsoft.OpenApi.Models.OpenApiSchema schema) { }
194194
public static Microsoft.OpenApi.Models.OpenApiSchema MapTypeToOpenApiPrimitiveType(this System.Type type) { }
195-
public static string ToIdentifier(this Microsoft.OpenApi.Models.JsonSchemaType? schemaType) { }
195+
public static string? ToIdentifier(this Microsoft.OpenApi.Models.JsonSchemaType schemaType) { }
196+
public static string? ToIdentifier(this Microsoft.OpenApi.Models.JsonSchemaType? schemaType) { }
196197
public static Microsoft.OpenApi.Models.JsonSchemaType ToJsonSchemaType(this string identifier) { }
197198
}
198199
public static class StringExtensions

0 commit comments

Comments
 (0)