Skip to content

Commit

Permalink
Deserialize empty payloads (#455)
Browse files Browse the repository at this point in the history
* Deserialize empty payloads option

* Revert "Deserialize empty payloads option"

This reverts commit f7863dd.

* INatsDeserializeWithEmpty marker interface

* docs

* docs

* don't check payload length

* test

* fix chain

* tests and format

* tests

* tests

[nats:update-docs]
  • Loading branch information
mtmk authored Apr 3, 2024
1 parent c886412 commit 4bda883
Show file tree
Hide file tree
Showing 5 changed files with 322 additions and 10 deletions.
62 changes: 62 additions & 0 deletions src/NATS.Client.Core/INatsSerialize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -370,13 +370,18 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)
{
if (typeof(T) == typeof(string))
{
if (buffer.Length == 0)
return default;
return (T)(object)Encoding.UTF8.GetString(buffer);
}

var span = buffer.IsSingleSegment ? buffer.FirstSpan : buffer.ToArray();

if (typeof(T) == typeof(DateTime) || typeof(T) == typeof(DateTime?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out DateTime value, out _))
{
return (T)(object)value;
Expand All @@ -387,6 +392,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(DateTimeOffset) || typeof(T) == typeof(DateTimeOffset?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out DateTimeOffset value, out _))
{
return (T)(object)value;
Expand All @@ -397,6 +405,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(Guid) || typeof(T) == typeof(Guid?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out Guid value, out _))
{
return (T)(object)value;
Expand All @@ -407,6 +418,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(TimeSpan) || typeof(T) == typeof(TimeSpan?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out TimeSpan value, out _))
{
return (T)(object)value;
Expand All @@ -417,6 +431,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(bool) || typeof(T) == typeof(bool?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out bool value, out _))
{
return (T)(object)value;
Expand All @@ -427,6 +444,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out byte value, out _))
{
return (T)(object)value;
Expand All @@ -437,6 +457,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out decimal value, out _))
{
return (T)(object)value;
Expand All @@ -447,6 +470,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(double) || typeof(T) == typeof(double?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out double value, out _))
{
return (T)(object)value;
Expand All @@ -457,6 +483,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out float value, out _))
{
return (T)(object)value;
Expand All @@ -467,6 +496,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out int value, out _))
{
return (T)(object)value;
Expand All @@ -477,6 +509,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out long value, out _))
{
return (T)(object)value;
Expand All @@ -487,6 +522,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out sbyte value, out _))
{
return (T)(object)value;
Expand All @@ -497,6 +535,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out short value, out _))
{
return (T)(object)value;
Expand All @@ -507,6 +548,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out uint value, out _))
{
return (T)(object)value;
Expand All @@ -517,6 +561,9 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)

if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
{
if (buffer.Length == 0)
return default;

if (Utf8Parser.TryParse(span, out ulong value, out _))
{
return (T)(object)value;
Expand Down Expand Up @@ -615,26 +662,36 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)
{
if (typeof(T) == typeof(byte[]))
{
if (buffer.Length == 0)
return default;
return (T)(object)buffer.ToArray();
}

if (typeof(T) == typeof(Memory<byte>))
{
if (buffer.Length == 0)
return default;
return (T)(object)new Memory<byte>(buffer.ToArray());
}

if (typeof(T) == typeof(ReadOnlyMemory<byte>))
{
if (buffer.Length == 0)
return default;
return (T)(object)new ReadOnlyMemory<byte>(buffer.ToArray());
}

if (typeof(T) == typeof(ReadOnlySequence<byte>))
{
if (buffer.Length == 0)
return default;
return (T)(object)new ReadOnlySequence<byte>(buffer.ToArray());
}

if (typeof(T) == typeof(IMemoryOwner<byte>) || typeof(T) == typeof(NatsMemoryOwner<byte>))
{
if (buffer.Length == 0)
return default;
var memoryOwner = NatsMemoryOwner<byte>.Allocate((int)buffer.Length);
buffer.CopyTo(memoryOwner.Memory.Span);
return (T)(object)memoryOwner;
Expand Down Expand Up @@ -725,6 +782,11 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T value)
/// <inheritdoc />
public T? Deserialize(in ReadOnlySequence<byte> buffer)
{
if (buffer.Length == 0)
{
return default;
}

foreach (var context in _contexts)
{
if (context.GetTypeInfo(typeof(T)) is JsonTypeInfo<T> jsonTypeInfo)
Expand Down
5 changes: 1 addition & 4 deletions src/NATS.Client.Core/NatsMsg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,8 @@ internal static NatsMsg<T> Build(

headers?.SetReadOnly();

// Consider an empty payload as null or default value for value types. This way we are able to
// receive sentinels as nulls or default values. This might cause an issue with where we are not
// able to differentiate between an empty sentinel and actual default value of a struct e.g. 0 (zero).
T? data;
if (headers?.Error == null && payloadBuffer.Length > 0)
if (headers?.Error == null)
{
try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ internal sealed class NatsJSErrorAwareJsonSerializer<T> : INatsDeserialize<T>

public T? Deserialize(in ReadOnlySequence<byte> buffer)
{
if (buffer.Length == 0)
{
return default;
}

// We need to determine what type we're deserializing into
// .NET 6 new APIs to the rescue: we can read the buffer once
// by deserializing into a document, inspect and using the new
Expand Down
5 changes: 5 additions & 0 deletions src/NATS.Client.Serializers.Json/NatsJsonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public void Serialize(IBufferWriter<byte> bufferWriter, T? value)
/// <inheritdoc />
public T? Deserialize(in ReadOnlySequence<byte> buffer)
{
if (buffer.Length == 0)
{
return default;
}

var reader = new Utf8JsonReader(buffer); // Utf8JsonReader is ref struct, no allocate.
return JsonSerializer.Deserialize<T>(ref reader, _opts);
}
Expand Down
Loading

0 comments on commit 4bda883

Please sign in to comment.