Skip to content

Commit

Permalink
Add ReadOnlySpan<byte> and ReadOnlySpan<char> overloads to `Trans…
Browse files Browse the repository at this point in the history
…portSerializerExtensions`
  • Loading branch information
flobernd committed Oct 11, 2024
1 parent a3f1378 commit aaea31a
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/Elastic.Transport/Components/Serialization/Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public abstract class Serializer
/// <inheritdoc cref="Deserialize"/>
public abstract ValueTask<T> DeserializeAsync<T>(Stream stream, CancellationToken cancellationToken = default);

// TODO: Overloads for (object?, Type) inputs

/// <summary>
/// Serialize an instance of <typeparamref name="T"/> to <paramref name="stream"/> using <paramref name="formatting"/>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,10 @@ protected virtual void Initialized()
/// </summary>
/// <param name="formatting">The serialization formatting.</param>
/// <returns>The requested <see cref="JsonSerializerOptions"/> or <c>null</c>, if the serializer is not initialized yet.</returns>
protected internal JsonSerializerOptions? GetJsonSerializerOptions(SerializationFormatting formatting) => (formatting is SerializationFormatting.None)
? _options
: _indentedOptions;
protected internal JsonSerializerOptions? GetJsonSerializerOptions(SerializationFormatting formatting = SerializationFormatting.None) =>
(formatting is SerializationFormatting.None)
? _options
: _indentedOptions;

/// <summary>
/// Initializes a serializer instance such that its <see cref="JsonSerializerOptions"/> are populated.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.IO;
using System.Text.Json;
using System;
using System.Text;
using System.Text.Json.Nodes;

namespace Elastic.Transport.Extensions;
Expand Down Expand Up @@ -80,6 +81,124 @@ public static string SerializeToString<T>(

#region STJ Extensions

/// <summary>
/// Extension method that deserializes from a UTF8 <see cref="ReadOnlySpan{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the data to be deserialized.</typeparam>
/// <param name="serializer"><inheritdoc cref="Serializer" path="/summary"/></param>
/// <param name="span">The source <see cref="ReadOnlySpan{T}"/> that contains the UTF8 encoded JSON string.</param>
/// <param name="memoryStreamFactory">
/// A factory yielding <see cref="MemoryStream"/> instances, defaults to <see cref="RecyclableMemoryStreamFactory"/>
/// that yields memory streams backed by pooled byte arrays.
/// </param>
/// <returns>The deserialized data.</returns>
public static T? Deserialize<T>(
this Serializer serializer,
ReadOnlySpan<byte> span,
MemoryStreamFactory? memoryStreamFactory = null)
{
if (serializer is SystemTextJsonSerializer stjSerializer)
{
// When the serializer derives from `SystemTextJsonSerializer` we can avoid unnecessary allocations and
// deserialize straight from the span.
return JsonSerializer.Deserialize<T>(span, stjSerializer.GetJsonSerializerOptions());
}

memoryStreamFactory ??= TransportConfiguration.DefaultMemoryStreamFactory;
using var ms = memoryStreamFactory.Create(span.ToArray());

return serializer.Deserialize<T>(ms);
}

/// <summary>
/// Extension method that deserializes from a UTF8 <see cref="ReadOnlySpan{T}"/>.
/// </summary>
/// <param name="serializer"><inheritdoc cref="Serializer" path="/summary"/></param>
/// <param name="span">The source <see cref="ReadOnlySpan{T}"/> that contains the UTF8 encoded JSON.</param>
/// <param name="type">The type of the data to be deserialized.</param>
/// <param name="memoryStreamFactory">
/// A factory yielding <see cref="MemoryStream"/> instances, defaults to <see cref="RecyclableMemoryStreamFactory"/>
/// that yields memory streams backed by pooled byte arrays.
/// </param>
/// <returns>The deserialized data.</returns>
public static object? Deserialize(
this Serializer serializer,
ReadOnlySpan<byte> span,
Type type,
MemoryStreamFactory? memoryStreamFactory = null)
{
if (serializer is SystemTextJsonSerializer stjSerializer)
{
// When the serializer derives from `SystemTextJsonSerializer` we can avoid unnecessary allocations and
// deserialize straight from the span.
return JsonSerializer.Deserialize(span, type, stjSerializer.GetJsonSerializerOptions());
}

memoryStreamFactory ??= TransportConfiguration.DefaultMemoryStreamFactory;
using var ms = memoryStreamFactory.Create(span.ToArray());

return serializer.Deserialize(type, ms);
}

/// <summary>
/// Extension method that deserializes from a UTF8 <see cref="ReadOnlySpan{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the data to be deserialized.</typeparam>
/// <param name="serializer"><inheritdoc cref="Serializer" path="/summary"/></param>
/// <param name="span">The source <see cref="ReadOnlySpan{T}"/> that contains the UTF8 encoded JSON string.</param>
/// <param name="memoryStreamFactory">
/// A factory yielding <see cref="MemoryStream"/> instances, defaults to <see cref="RecyclableMemoryStreamFactory"/>
/// that yields memory streams backed by pooled byte arrays.
/// </param>
/// <returns>The deserialized data.</returns>
public static T? Deserialize<T>(
this Serializer serializer,
ReadOnlySpan<char> span,
MemoryStreamFactory? memoryStreamFactory = null)
{
if (serializer is SystemTextJsonSerializer stjSerializer)
{
// When the serializer derives from `SystemTextJsonSerializer` we can avoid unnecessary allocations and
// deserialize straight from the span.
return JsonSerializer.Deserialize<T>(span, stjSerializer.GetJsonSerializerOptions());
}

memoryStreamFactory ??= TransportConfiguration.DefaultMemoryStreamFactory;
using var ms = memoryStreamFactory.Create(Encoding.UTF8.GetBytes(span.ToArray()));

return serializer.Deserialize<T>(ms);
}

/// <summary>
/// Extension method that deserializes from a UTF8 <see cref="ReadOnlySpan{T}"/>.
/// </summary>
/// <param name="serializer"><inheritdoc cref="Serializer" path="/summary"/></param>
/// <param name="span">The source <see cref="ReadOnlySpan{T}"/> that contains the UTF8 encoded JSON.</param>
/// <param name="type">The type of the data to be deserialized.</param>
/// <param name="memoryStreamFactory">
/// A factory yielding <see cref="MemoryStream"/> instances, defaults to <see cref="RecyclableMemoryStreamFactory"/>
/// that yields memory streams backed by pooled byte arrays.
/// </param>
/// <returns>The deserialized data.</returns>
public static object? Deserialize(
this Serializer serializer,
ReadOnlySpan<char> span,
Type type,
MemoryStreamFactory? memoryStreamFactory = null)
{
if (serializer is SystemTextJsonSerializer stjSerializer)
{
// When the serializer derives from `SystemTextJsonSerializer` we can avoid unnecessary allocations and
// deserialize straight from the span.
return JsonSerializer.Deserialize(span, type, stjSerializer.GetJsonSerializerOptions());
}

memoryStreamFactory ??= TransportConfiguration.DefaultMemoryStreamFactory;
using var ms = memoryStreamFactory.Create(Encoding.UTF8.GetBytes(span.ToArray()));

return serializer.Deserialize(type, ms);
}

/// <summary>
/// Extension method that writes the serialized representation of an instance of <typeparamref name="T"/> to a
/// <see cref="Utf8JsonWriter"/>.
Expand Down Expand Up @@ -185,7 +304,7 @@ public static void Serialize(
{
// When the serializer derives from `SystemTextJsonSerializer` we can avoid unnecessary allocations and
// deserialize straight from the reader.
return JsonSerializer.Deserialize<T>(ref reader, stjSerializer.GetJsonSerializerOptions(SerializationFormatting.None));
return JsonSerializer.Deserialize<T>(ref reader, stjSerializer.GetJsonSerializerOptions());
}

using var jsonDoc = JsonSerializer.Deserialize<JsonDocument>(ref reader);
Expand Down Expand Up @@ -222,7 +341,7 @@ public static void Serialize(
{
// When the serializer derives from `SystemTextJsonSerializer` we can avoid unnecessary allocations and
// deserialize straight from the reader.
return JsonSerializer.Deserialize(ref reader, type, stjSerializer.GetJsonSerializerOptions(SerializationFormatting.None));
return JsonSerializer.Deserialize(ref reader, type, stjSerializer.GetJsonSerializerOptions());
}

using var jsonDoc = JsonSerializer.Deserialize<JsonDocument>(ref reader);
Expand Down Expand Up @@ -258,7 +377,7 @@ public static void Serialize(
{
// When the serializer derives from `SystemTextJsonSerializer` we can avoid unnecessary allocations and
// deserialize straight from the node.
return node.Deserialize<T>(stjSerializer.GetJsonSerializerOptions(SerializationFormatting.None));
return node.Deserialize<T>(stjSerializer.GetJsonSerializerOptions());
}

memoryStreamFactory ??= TransportConfiguration.DefaultMemoryStreamFactory;
Expand Down Expand Up @@ -293,7 +412,7 @@ public static void Serialize(
{
// When the serializer derives from `SystemTextJsonSerializer` we can avoid unnecessary allocations and
// deserialize straight from the node.
return node.Deserialize(type, stjSerializer.GetJsonSerializerOptions(SerializationFormatting.None));
return node.Deserialize(type, stjSerializer.GetJsonSerializerOptions());
}

memoryStreamFactory ??= TransportConfiguration.DefaultMemoryStreamFactory;
Expand Down Expand Up @@ -327,7 +446,7 @@ public static void Serialize(
{
// When the serializer derives from `SystemTextJsonSerializer` we can avoid unnecessary allocations and
// deserialize straight from the node.
return node.Deserialize<T>(stjSerializer.GetJsonSerializerOptions(SerializationFormatting.None));
return node.Deserialize<T>(stjSerializer.GetJsonSerializerOptions());
}

memoryStreamFactory ??= TransportConfiguration.DefaultMemoryStreamFactory;
Expand Down Expand Up @@ -362,7 +481,7 @@ public static void Serialize(
{
// When the serializer derives from `SystemTextJsonSerializer` we can avoid unnecessary allocations and
// deserialize straight from the node.
return node.Deserialize(type, stjSerializer.GetJsonSerializerOptions(SerializationFormatting.None));
return node.Deserialize(type, stjSerializer.GetJsonSerializerOptions());
}

memoryStreamFactory ??= TransportConfiguration.DefaultMemoryStreamFactory;
Expand Down

0 comments on commit aaea31a

Please sign in to comment.