Skip to content

Commit 77adbf2

Browse files
authored
[dotnet] [bidi] Avoid intermediate JsonDocument allocation to determine unordered discriminator (#15555)
1 parent 1a470d1 commit 77adbf2

File tree

6 files changed

+106
-58
lines changed

6 files changed

+106
-58
lines changed

dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/EvaluateResultConverter.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using OpenQA.Selenium.BiDi.Communication.Json.Internal;
2021
using OpenQA.Selenium.BiDi.Modules.Script;
2122
using System;
2223
using System.Text.Json;
@@ -29,12 +30,10 @@ internal class EvaluateResultConverter : JsonConverter<EvaluateResult>
2930
{
3031
public override EvaluateResult? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
3132
{
32-
var jsonDocument = JsonDocument.ParseValue(ref reader);
33-
34-
return jsonDocument.RootElement.GetProperty("type").ToString() switch
33+
return reader.GetDiscriminator("type") switch
3534
{
36-
"success" => jsonDocument.Deserialize<EvaluateResultSuccess>(options),
37-
"exception" => jsonDocument.Deserialize<EvaluateResultException>(options),
35+
"success" => JsonSerializer.Deserialize<EvaluateResultSuccess>(ref reader, options),
36+
"exception" => JsonSerializer.Deserialize<EvaluateResultException>(ref reader, options),
3837
_ => null,
3938
};
4039
}

dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/LogEntryConverter.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using OpenQA.Selenium.BiDi.Communication.Json.Internal;
2021
using OpenQA.Selenium.BiDi.Modules.Log;
2122
using System;
2223
using System.Text.Json;
@@ -29,12 +30,10 @@ internal class LogEntryConverter : JsonConverter<Modules.Log.LogEntry>
2930
{
3031
public override Modules.Log.LogEntry? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
3132
{
32-
var jsonDocument = JsonDocument.ParseValue(ref reader);
33-
34-
return jsonDocument.RootElement.GetProperty("type").ToString() switch
33+
return reader.GetDiscriminator("type") switch
3534
{
36-
"console" => jsonDocument.Deserialize<ConsoleLogEntry>(options),
37-
"javascript" => jsonDocument.Deserialize<JavascriptLogEntry>(options),
35+
"console" => JsonSerializer.Deserialize<ConsoleLogEntry>(ref reader, options),
36+
"javascript" => JsonSerializer.Deserialize<JavascriptLogEntry>(ref reader, options),
3837
_ => null,
3938
};
4039
}

dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/MessageConverter.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using OpenQA.Selenium.BiDi.Communication.Json.Internal;
2021
using System;
2122
using System.Text.Json;
2223
using System.Text.Json.Serialization;
@@ -28,13 +29,11 @@ internal class MessageConverter : JsonConverter<Message>
2829
{
2930
public override Message? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
3031
{
31-
var jsonDocument = JsonDocument.ParseValue(ref reader);
32-
33-
return jsonDocument.RootElement.GetProperty("type").ToString() switch
32+
return reader.GetDiscriminator("type") switch
3433
{
35-
"success" => jsonDocument.Deserialize<MessageSuccess>(options),
36-
"error" => jsonDocument.Deserialize<MessageError>(options),
37-
"event" => jsonDocument.Deserialize<MessageEvent>(options),
34+
"success" => JsonSerializer.Deserialize<MessageSuccess>(ref reader, options),
35+
"error" => JsonSerializer.Deserialize<MessageError>(ref reader, options),
36+
"event" => JsonSerializer.Deserialize<MessageEvent>(ref reader, options),
3837
_ => null,
3938
};
4039
}

dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RealmInfoConverter.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using OpenQA.Selenium.BiDi.Communication.Json.Internal;
2021
using OpenQA.Selenium.BiDi.Modules.Script;
2122
using System;
2223
using System.Text.Json;
@@ -29,18 +30,16 @@ internal class RealmInfoConverter : JsonConverter<RealmInfo>
2930
{
3031
public override RealmInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
3132
{
32-
var jsonDocument = JsonDocument.ParseValue(ref reader);
33-
34-
return jsonDocument.RootElement.GetProperty("type").ToString() switch
33+
return reader.GetDiscriminator("type") switch
3534
{
36-
"window" => jsonDocument.Deserialize<WindowRealmInfo>(options),
37-
"dedicated-worker" => jsonDocument.Deserialize<DedicatedWorkerRealmInfo>(options),
38-
"shared-worker" => jsonDocument.Deserialize<SharedWorkerRealmInfo>(options),
39-
"service-worker" => jsonDocument.Deserialize<ServiceWorkerRealmInfo>(options),
40-
"worker" => jsonDocument.Deserialize<WorkerRealmInfo>(options),
41-
"paint-worklet" => jsonDocument.Deserialize<PaintWorkletRealmInfo>(options),
42-
"audio-worklet" => jsonDocument.Deserialize<AudioWorkletRealmInfo>(options),
43-
"worklet" => jsonDocument.Deserialize<WorkletRealmInfo>(options),
35+
"window" => JsonSerializer.Deserialize<WindowRealmInfo>(ref reader, options),
36+
"dedicated-worker" => JsonSerializer.Deserialize<DedicatedWorkerRealmInfo>(ref reader, options),
37+
"shared-worker" => JsonSerializer.Deserialize<SharedWorkerRealmInfo>(ref reader, options),
38+
"service-worker" => JsonSerializer.Deserialize<ServiceWorkerRealmInfo>(ref reader, options),
39+
"worker" => JsonSerializer.Deserialize<WorkerRealmInfo>(ref reader, options),
40+
"paint-worklet" => JsonSerializer.Deserialize<PaintWorkletRealmInfo>(ref reader, options),
41+
"audio-worklet" => JsonSerializer.Deserialize<AudioWorkletRealmInfo>(ref reader, options),
42+
"worklet" => JsonSerializer.Deserialize<WorkletRealmInfo>(ref reader, options),
4443
_ => null,
4544
};
4645
}

dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RemoteValueConverter.cs

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using OpenQA.Selenium.BiDi.Communication.Json.Internal;
2021
using OpenQA.Selenium.BiDi.Modules.Script;
2122
using System;
2223
using System.Text.Json;
@@ -29,41 +30,39 @@ internal class RemoteValueConverter : JsonConverter<RemoteValue>
2930
{
3031
public override RemoteValue? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
3132
{
32-
var jsonDocument = JsonDocument.ParseValue(ref reader);
33-
34-
if (jsonDocument.RootElement.ValueKind == JsonValueKind.String)
33+
if (reader.TokenType == JsonTokenType.String)
3534
{
36-
return new StringRemoteValue(jsonDocument.RootElement.GetString()!);
35+
return new StringRemoteValue(reader.GetString()!);
3736
}
3837

39-
return jsonDocument.RootElement.GetProperty("type").ToString() switch
38+
return reader.GetDiscriminator("type") switch
4039
{
41-
"number" => jsonDocument.Deserialize<NumberRemoteValue>(options),
42-
"boolean" => jsonDocument.Deserialize<BooleanRemoteValue>(options),
43-
"bigint" => jsonDocument.Deserialize<BigIntRemoteValue>(options),
44-
"string" => jsonDocument.Deserialize<StringRemoteValue>(options),
45-
"null" => jsonDocument.Deserialize<NullRemoteValue>(options),
46-
"undefined" => jsonDocument.Deserialize<UndefinedRemoteValue>(options),
47-
"symbol" => jsonDocument.Deserialize<SymbolRemoteValue>(options),
48-
"array" => jsonDocument.Deserialize<ArrayRemoteValue>(options),
49-
"object" => jsonDocument.Deserialize<ObjectRemoteValue>(options),
50-
"function" => jsonDocument.Deserialize<FunctionRemoteValue>(options),
51-
"regexp" => jsonDocument.Deserialize<RegExpRemoteValue>(options),
52-
"date" => jsonDocument.Deserialize<DateRemoteValue>(options),
53-
"map" => jsonDocument.Deserialize<MapRemoteValue>(options),
54-
"set" => jsonDocument.Deserialize<SetRemoteValue>(options),
55-
"weakmap" => jsonDocument.Deserialize<WeakMapRemoteValue>(options),
56-
"weakset" => jsonDocument.Deserialize<WeakSetRemoteValue>(options),
57-
"generator" => jsonDocument.Deserialize<GeneratorRemoteValue>(options),
58-
"error" => jsonDocument.Deserialize<ErrorRemoteValue>(options),
59-
"proxy" => jsonDocument.Deserialize<ProxyRemoteValue>(options),
60-
"promise" => jsonDocument.Deserialize<PromiseRemoteValue>(options),
61-
"typedarray" => jsonDocument.Deserialize<TypedArrayRemoteValue>(options),
62-
"arraybuffer" => jsonDocument.Deserialize<ArrayBufferRemoteValue>(options),
63-
"nodelist" => jsonDocument.Deserialize<NodeListRemoteValue>(options),
64-
"htmlcollection" => jsonDocument.Deserialize<HtmlCollectionRemoteValue>(options),
65-
"node" => jsonDocument.Deserialize<NodeRemoteValue>(options),
66-
"window" => jsonDocument.Deserialize<WindowProxyRemoteValue>(options),
40+
"number" => JsonSerializer.Deserialize<NumberRemoteValue>(ref reader, options),
41+
"boolean" => JsonSerializer.Deserialize<BooleanRemoteValue>(ref reader, options),
42+
"bigint" => JsonSerializer.Deserialize<BigIntRemoteValue>(ref reader, options),
43+
"string" => JsonSerializer.Deserialize<StringRemoteValue>(ref reader, options),
44+
"null" => JsonSerializer.Deserialize<NullRemoteValue>(ref reader, options),
45+
"undefined" => JsonSerializer.Deserialize<UndefinedRemoteValue>(ref reader, options),
46+
"symbol" => JsonSerializer.Deserialize<SymbolRemoteValue>(ref reader, options),
47+
"array" => JsonSerializer.Deserialize<ArrayRemoteValue>(ref reader, options),
48+
"object" => JsonSerializer.Deserialize<ObjectRemoteValue>(ref reader, options),
49+
"function" => JsonSerializer.Deserialize<FunctionRemoteValue>(ref reader, options),
50+
"regexp" => JsonSerializer.Deserialize<RegExpRemoteValue>(ref reader, options),
51+
"date" => JsonSerializer.Deserialize<DateRemoteValue>(ref reader, options),
52+
"map" => JsonSerializer.Deserialize<MapRemoteValue>(ref reader, options),
53+
"set" => JsonSerializer.Deserialize<SetRemoteValue>(ref reader, options),
54+
"weakmap" => JsonSerializer.Deserialize<WeakMapRemoteValue>(ref reader, options),
55+
"weakset" => JsonSerializer.Deserialize<WeakSetRemoteValue>(ref reader, options),
56+
"generator" => JsonSerializer.Deserialize<GeneratorRemoteValue>(ref reader, options),
57+
"error" => JsonSerializer.Deserialize<ErrorRemoteValue>(ref reader, options),
58+
"proxy" => JsonSerializer.Deserialize<ProxyRemoteValue>(ref reader, options),
59+
"promise" => JsonSerializer.Deserialize<PromiseRemoteValue>(ref reader, options),
60+
"typedarray" => JsonSerializer.Deserialize<TypedArrayRemoteValue>(ref reader, options),
61+
"arraybuffer" => JsonSerializer.Deserialize<ArrayBufferRemoteValue>(ref reader, options),
62+
"nodelist" => JsonSerializer.Deserialize<NodeListRemoteValue>(ref reader, options),
63+
"htmlcollection" => JsonSerializer.Deserialize<HtmlCollectionRemoteValue>(ref reader, options),
64+
"node" => JsonSerializer.Deserialize<NodeRemoteValue>(ref reader, options),
65+
"window" => JsonSerializer.Deserialize<WindowProxyRemoteValue>(ref reader, options),
6766
_ => null,
6867
};
6968
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// <copyright file="JsonExtensions.cs" company="Selenium Committers">
2+
// Licensed to the Software Freedom Conservancy (SFC) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The SFC licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
// </copyright>
19+
20+
using System.Text.Json;
21+
22+
namespace OpenQA.Selenium.BiDi.Communication.Json.Internal;
23+
24+
internal static class JsonExtensions
25+
{
26+
public static string GetDiscriminator(this ref Utf8JsonReader reader, string name)
27+
{
28+
Utf8JsonReader readerClone = reader;
29+
30+
if (readerClone.TokenType != JsonTokenType.StartObject)
31+
throw new JsonException($"Cannot determine the discriminator of {readerClone.TokenType} token type while supported is {JsonTokenType.StartObject} only.");
32+
33+
string? discriminator = null;
34+
35+
readerClone.Read();
36+
while (readerClone.TokenType == JsonTokenType.PropertyName)
37+
{
38+
string? propertyName = readerClone.GetString();
39+
readerClone.Read();
40+
41+
if (propertyName == name)
42+
{
43+
discriminator = readerClone.GetString();
44+
break;
45+
}
46+
47+
readerClone.Skip();
48+
readerClone.Read();
49+
}
50+
51+
return discriminator ?? throw new JsonException($"Couldn't determine '{name}' descriminator.");
52+
}
53+
}

0 commit comments

Comments
 (0)