Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions Vostok.Commons.Binary.Tests/BinaryReadersWriters_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,18 @@ public void Should_correctly_write_and_read_byte_array_values(params byte[] valu
Test(value, (item, writer) => writer.WriteWithoutLength(item), reader => reader.ReadByteArray(value.Length));
}


#if NET6_0_OR_GREATER
[TestCase((byte)0xFF)]
[TestCase((byte)0xFF, (byte)0xAB)]
[TestCase((byte)0xC0, (byte)0xFF, (byte)0xEE, (byte)0xBA, (byte)0xBE)]
public void Should_correctly_write_and_read_bytes_span_values(params byte[] value)
{
Test(value.AsSpan(), (item, writer) => writer.WriteWithLength(item), reader => reader.ReadBytesSpan());
Test(value.AsSpan(), (item, writer) => writer.WriteWithoutLength(item), reader => reader.ReadBytesSpan(value.Length));
}
#endif

[Test]
public void Should_correctly_write_and_read_timespan_values()
{
Expand Down Expand Up @@ -312,7 +324,7 @@ public void Should_correctly_write_and_read_nullable_classes()
reader => reader.ReadNullable(r => r.ReadString()));
}

#region Helpers
#region Helpers

private static void Test<T>(T item, Action<T, IBinaryWriter> write, Func<IBinaryReader, T> read)
{
Expand Down Expand Up @@ -524,6 +536,6 @@ public override void Flush()
=> throw new NotSupportedException();
}

#endregion
#endregion
}
}
28 changes: 28 additions & 0 deletions Vostok.Commons.Binary/BinaryBufferReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -306,5 +306,33 @@ private void EnsureSufficientSizeRemaining(int size)
if (size > BytesRemaining)
throw new IndexOutOfRangeException($"Requested to read {size} bytes from buffer, but it only has {BytesRemaining} bytes remaining.");
}

#if NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<byte> ReadBytesSpan()
{
var size = ReadInt32();

EnsureSufficientSizeRemaining(size);

var result = new ReadOnlySpan<byte>(Buffer, (int)Position, size);

Position += size;

return result;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<byte> ReadBytesSpan(int size)
{
EnsureSufficientSizeRemaining(size);

var result = new ReadOnlySpan<byte>(Buffer, (int)Position, size);

Position += size;

return result;
}
#endif
}
}
30 changes: 30 additions & 0 deletions Vostok.Commons.Binary/BinaryBufferWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,36 @@ public void WriteWithoutLength(byte[] value, int offset, int length)
IncreaseLengthIfNeeded();
}

#if NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteWithLength(ReadOnlySpan<byte> value)
{
var length = value.Length;
EnsureCapacity(length + sizeof(int));

Write(length);

value.CopyTo(new Span<byte>(Buffer, position, length));

position += length;

IncreaseLengthIfNeeded();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteWithoutLength(ReadOnlySpan<byte> value)
{
var length = value.Length;
EnsureCapacity(length);

value.CopyTo(new Span<byte>(Buffer, position, length));

position += length;

IncreaseLengthIfNeeded();
}
#endif

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset(int neededCapacity = 0)
{
Expand Down
12 changes: 12 additions & 0 deletions Vostok.Commons.Binary/BinaryStreamReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@ public byte[] ReadByteArray(int size)
return result;
}

#if NET6_0_OR_GREATER
public ReadOnlySpan<byte> ReadBytesSpan()
{
return ReadByteArray().AsSpan();
}

public ReadOnlySpan<byte> ReadBytesSpan(int size)
{
return ReadByteArray(size).AsSpan();
}
#endif

private void LoadIntoBufferExactly(int size)
{
ReadFromStreamExactly(buffer.Buffer, 0, size);
Expand Down
13 changes: 13 additions & 0 deletions Vostok.Commons.Binary/BinaryStreamWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,19 @@ public void WriteWithoutLength(byte[] value, int offset, int length)
stream.Write(value, offset, length);
}

#if NET6_0_OR_GREATER
public void WriteWithLength(ReadOnlySpan<byte> value)
{
Write(value.Length);
WriteWithoutLength(value);
}

public void WriteWithoutLength(ReadOnlySpan<byte> value)
{
stream.Write(value);
}
#endif

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Flush()
{
Expand Down
15 changes: 15 additions & 0 deletions Vostok.Commons.Binary/IBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,20 @@ internal interface IBinaryReader
/// </summary>
[NotNull]
byte[] ReadByteArray(int size);

#if NET6_0_OR_GREATER
/// <summary>
/// <para>Reads a span of bytes.</para>
/// <para>Assumes that the value itself is prepended by its Int32 length.</para>
/// <para>The resulting ReadOnlySpan may hold a reference to the source buffer if it exists. Be careful not to use this span after buffer and this reader released. Underlying buffer may be returned to pool and used under another reader. Or you can keep a huge buffer while this span is alive too.</para>
/// </summary>
ReadOnlySpan<byte> ReadBytesSpan();

/// <summary>
/// <para>Reads a span of bytes of given <paramref name="size"/>.</para>
/// <para>The resulting ReadOnlySpan may hold a reference to the source buffer if it exists. Be careful not to hold this span forever to avoid holding the source buffer.</para>
/// </summary>
ReadOnlySpan<byte> ReadBytesSpan(int size);
#endif
}
}
14 changes: 14 additions & 0 deletions Vostok.Commons.Binary/IBinaryWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,19 @@ internal interface IBinaryWriter
/// <para>The value itself is not automatically prepended with length (readers of binary result must know the length from external sources).</para>
/// </summary>
void WriteWithoutLength([NotNull] byte[] value, int offset, int length);

#if NET6_0_OR_GREATER
/// <summary>
/// <para>Writes given span of bytes as bytes array in its entirety.</para>
/// <para>The value itself is automatically prepended with Int32 length (see <see cref="Write(int)"/>).</para>
/// </summary>
void WriteWithLength(ReadOnlySpan<byte> value);

/// <summary>
/// <para>Writes given span of bytes as bytes array in its entirety.</para>
/// <para>The value itself is not automatically prepended with length (readers of binary result must know the length from external sources).</para>
/// </summary>
void WriteWithoutLength(ReadOnlySpan<byte> value);
#endif
}
}