Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed issue #40 regarding partial streams #185

Merged
merged 4 commits into from
Oct 29, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
58 changes: 58 additions & 0 deletions src/Hyperion.Tests/PartialStreamTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.IO;

namespace Hyperion.Tests
{
public class PartialStreamTest : PrimitivesTest
{
public PartialStreamTest()
: base(x => new OneBytePerReadStream(x))
{
}

private class OneBytePerReadStream : Stream
{
private readonly Stream _baseStream;

public OneBytePerReadStream(Stream baseStream)
{
_baseStream = baseStream;
}

public override void Flush()
{
_baseStream.Flush();
}

public override long Seek(long offset, SeekOrigin origin)
{
return _baseStream.Seek(offset, origin);
}

public override void SetLength(long value)
{
_baseStream.SetLength(value);
}

public override int Read(byte[] buffer, int offset, int count)
{
return _baseStream.Read(buffer, offset, count > 0 ? 1 : 0);
}

public override void Write(byte[] buffer, int offset, int count)
{
_baseStream.Write(buffer, offset, count);
}

public override bool CanRead => _baseStream.CanRead;
public override bool CanSeek => _baseStream.CanSeek;
public override bool CanWrite => _baseStream.CanWrite;
public override long Length => _baseStream.Length;

public override long Position
{
get => _baseStream.Position;
set => _baseStream.Position = value;
}
}
}
}
10 changes: 10 additions & 0 deletions src/Hyperion.Tests/PrimitivesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,23 @@
#endregion

using System;
using System.IO;
using Xunit;

namespace Hyperion.Tests
{

public class PrimitivesTest : TestBase
{
public PrimitivesTest()
{
}

protected PrimitivesTest(Func<Stream, Stream> streamFacade)
: base(streamFacade)
{
}

[Fact]
public void CanSerializeTuple1()
{
Expand Down
10 changes: 8 additions & 2 deletions src/Hyperion.Tests/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// -----------------------------------------------------------------------
#endregion

using System;
using System.IO;
using Xunit;

Expand All @@ -15,12 +16,17 @@ namespace Hyperion.Tests
public abstract class TestBase
{
private Serializer _serializer;
private readonly MemoryStream _stream;
private readonly Stream _stream;

protected TestBase()
: this(x => x)
{
}

protected TestBase(Func<Stream, Stream> streamFacade)
{
_serializer = new Serializer();
_stream = new MemoryStream();
_stream = streamFacade(new MemoryStream());
}

protected void CustomInit(Serializer serializer)
Expand Down
37 changes: 32 additions & 5 deletions src/Hyperion/Extensions/StreamEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ namespace Hyperion.Extensions
{
internal static class StreamEx
{

public static uint ReadVarint32(this Stream stream)
{
int result = 0;
Expand Down Expand Up @@ -75,15 +74,15 @@ public static void WriteVarint64(this Stream stream, ulong value)
public static uint ReadUInt16(this Stream self, DeserializerSession session)
{
var buffer = session.GetBuffer(2);
self.Read(buffer, 0, 2);
self.ReadFull(buffer, 0, 2);
Arkatufus marked this conversation as resolved.
Show resolved Hide resolved
var res = BitConverter.ToUInt16(buffer, 0);
return res;
}

public static int ReadInt32(this Stream self, DeserializerSession session)
{
var buffer = session.GetBuffer(4);
self.Read(buffer, 0, 4);
self.ReadFull(buffer, 0, 4);
var res = BitConverter.ToInt32(buffer, 0);
return res;
}
Expand All @@ -92,7 +91,7 @@ public static byte[] ReadLengthEncodedByteArray(this Stream self, DeserializerSe
{
var length = self.ReadInt32(session);
var buffer = new byte[length];
self.Read(buffer, 0, length);
self.ReadFull(buffer, 0, length);
return buffer;
}

Expand Down Expand Up @@ -190,9 +189,37 @@ public static string ReadString(this Stream stream, DeserializerSession session)

var buffer = session.GetBuffer(length);

stream.Read(buffer, 0, length);
stream.ReadFull(buffer, 0, length);
var res = StringEx.FromUtf8Bytes(buffer, 0, length);
return res;
}

/// <summary>
/// Repeats reading from stream until requested bytes were read.
/// Returns with partial result if stream can't provide enough bytes
/// Fixes issue: https://github.com/akkadotnet/Hyperion/issues/40
/// Reference for allowed partial streams: https://docs.microsoft.com/en-us/dotnet/api/system.io.stream.read?redirectedfrom=MSDN&view=netcore-3.1#System_IO_Stream_Read_System_Byte___System_Int32_System_Int32_
/// -> "An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached."
/// </summary>
public static int ReadFull(this Stream stream, byte[] buffer, int offset, int count)
Arkatufus marked this conversation as resolved.
Show resolved Hide resolved
{
// fast path for streams which doesn't deliver partial results
var totalReadBytes = stream.Read(buffer, offset, count);
if (totalReadBytes == count)
return totalReadBytes;

// support streams with partial results
do
{
var readBytes = stream.Read(buffer, offset + totalReadBytes, count - totalReadBytes);
if (readBytes == 0)
break;
Arkatufus marked this conversation as resolved.
Show resolved Hide resolved

totalReadBytes += readBytes;
}
while (totalReadBytes < count);

return totalReadBytes;
}
}
}
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/CharSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand All @@ -24,7 +25,7 @@ public CharSerializer() : base(Manifest, () => WriteValueImpl, () => ReadValueIm

public static char ReadValueImpl(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
return BitConverter.ToChar(bytes, 0);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Hyperion/ValueSerializers/ConsistentArraySerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public override object ReadValue(Stream stream, DeserializerSession session)
var size = elementType.GetTypeSize();
var totalSize = size*length;
var buffer = session.GetBuffer(totalSize);
stream.Read(buffer, 0, totalSize);
stream.ReadFull(buffer, 0, totalSize);
Buffer.BlockCopy(buffer, 0, array, 0, totalSize);
}
else
Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/DateTimeOffsetSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand Down Expand Up @@ -36,7 +37,7 @@ public static DateTimeOffset ReadValueImpl(Stream stream, byte[] bytes)

private static DateTimeOffset ReadDateTimeOffset(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
var dateTimeTicks = BitConverter.ToInt64(bytes, 0);
var offsetTicks = BitConverter.ToInt64(bytes, sizeof(long));
var dateTimeOffset = new DateTimeOffset(dateTimeTicks, TimeSpan.FromTicks(offsetTicks));
Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/DateTimeSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand Down Expand Up @@ -36,7 +37,7 @@ public static DateTime ReadValueImpl(Stream stream, byte[] bytes)

private static DateTime ReadDateTime(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
var ticks = BitConverter.ToInt64(bytes, 0);
var kind = (DateTimeKind) bytes[Size - 1]; //avoid reading a single byte from the stream
var dateTime = new DateTime(ticks, kind);
Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/DoubleSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand All @@ -30,7 +31,7 @@ public static void WriteValueImpl(Stream stream, double d, byte[] bytes)

public static double ReadValueImpl(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
return BitConverter.ToDouble(bytes, 0);
}

Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/FloatSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand All @@ -30,7 +31,7 @@ public static void WriteValueImpl(Stream stream, float f, byte[] bytes)

public static float ReadValueImpl(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
return BitConverter.ToSingle(bytes, 0);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Hyperion/ValueSerializers/GuidSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static void WriteValueImpl(Stream stream, Guid g)
public static Guid ReadValueImpl(Stream stream)
{
var buffer = new byte[16];
stream.Read(buffer, 0, 16);
stream.ReadFull(buffer, 0, 16);
return new Guid(buffer);
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/Int16Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand All @@ -30,7 +31,7 @@ public static void WriteValueImpl(Stream stream, short sh, byte[] bytes)

public static short ReadValueImpl(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
return BitConverter.ToInt16(bytes, 0);
}

Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/Int32Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand Down Expand Up @@ -37,7 +38,7 @@ public static void WriteValueImpl(Stream stream, int i, SerializerSession sessio

public static int ReadValueImpl(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
return BitConverter.ToInt32(bytes, 0);
}

Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/Int64Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand All @@ -30,7 +31,7 @@ public static void WriteValueImpl(Stream stream, long l, byte[] bytes)

public static long ReadValueImpl(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
return BitConverter.ToInt64(bytes, 0);
}

Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/UInt16Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand All @@ -35,7 +36,7 @@ public static void WriteValueImpl(Stream stream, ushort u, SerializerSession ses

public static ushort ReadValueImpl(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
return BitConverter.ToUInt16(bytes, 0);
}

Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/UInt32Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand All @@ -30,7 +31,7 @@ public static void WriteValueImpl(Stream stream, uint u, byte[] bytes)

public static uint ReadValueImpl(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
return BitConverter.ToUInt32(bytes, 0);
}

Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion/ValueSerializers/UInt64Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using System;
using System.IO;
using Hyperion.Extensions;

namespace Hyperion.ValueSerializers
{
Expand All @@ -30,7 +31,7 @@ public static void WriteValueImpl(Stream stream, ulong ul, byte[] bytes)

public static ulong ReadValueImpl(Stream stream, byte[] bytes)
{
stream.Read(bytes, 0, Size);
stream.ReadFull(bytes, 0, Size);
return BitConverter.ToUInt64(bytes, 0);
}

Expand Down