mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-23 07:25:11 +00:00
change the rented versions to structs
This commit is contained in:
@@ -180,16 +180,23 @@ public partial class GZipArchive
|
||||
return true;
|
||||
}
|
||||
|
||||
private readonly struct GZipSignatureTryProcessor : Utility.ITryBufferProcessor<(bool, bool)>
|
||||
{
|
||||
public (bool, bool) OnSuccess(ReadOnlySpan<byte> buffer) => (true, buffer[0] == 0x1F && buffer[1] == 0x8B && buffer[2] == 8);
|
||||
public (bool, bool) OnFailure() => (false, false);
|
||||
}
|
||||
|
||||
public static async ValueTask<bool> IsGZipFileAsync(
|
||||
Stream stream,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var result = await stream.TryWithRentedBufferReadFullyAsync(
|
||||
var processor = new GZipSignatureTryProcessor();
|
||||
var result = await stream.TryReadFullyRentedAsync<GZipSignatureTryProcessor, (bool success, bool match)>(
|
||||
10,
|
||||
header => header[0] == 0x1F && header[1] == 0x8B && header[2] == 8,
|
||||
processor,
|
||||
cancellationToken
|
||||
);
|
||||
return result.success && result.result;
|
||||
return result.success && result.match;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,22 +173,37 @@ public partial class SevenZipArchive
|
||||
|
||||
private static ReadOnlySpan<byte> Signature => [(byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C];
|
||||
|
||||
private static bool SignatureMatch(Stream stream) =>
|
||||
stream.WithRentedBufferReadExact(
|
||||
private readonly struct SevenZipSignatureProcessor : Utility.IBufferProcessor<bool>
|
||||
{
|
||||
public bool Process(ReadOnlySpan<byte> buffer) => buffer.Slice(0, 6).SequenceEqual(Signature);
|
||||
}
|
||||
|
||||
private readonly struct SevenZipSignatureTryProcessor : Utility.ITryBufferProcessor<(bool, bool)>
|
||||
{
|
||||
public (bool, bool) OnSuccess(ReadOnlySpan<byte> buffer) => (true, buffer.Slice(0, 6).SequenceEqual(Signature));
|
||||
public (bool, bool) OnFailure() => (false, false);
|
||||
}
|
||||
|
||||
private static bool SignatureMatch(Stream stream)
|
||||
{
|
||||
var processor = new SevenZipSignatureProcessor();
|
||||
return stream.ReadExactRented<SevenZipSignatureProcessor, bool>(
|
||||
6,
|
||||
buffer => buffer.AsSpan().Slice(0, 6).SequenceEqual(Signature)
|
||||
ref processor
|
||||
);
|
||||
}
|
||||
|
||||
private static async ValueTask<bool> SignatureMatchAsync(
|
||||
Stream stream,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var result = await stream.TryWithRentedBufferReadFullyAsync(
|
||||
var processor = new SevenZipSignatureTryProcessor();
|
||||
var result = await stream.TryReadFullyRentedAsync<SevenZipSignatureTryProcessor, (bool success, bool match)>(
|
||||
6,
|
||||
buffer => buffer.AsSpan().Slice(0, 6).SequenceEqual(Signature),
|
||||
processor,
|
||||
cancellationToken
|
||||
);
|
||||
return result.success && result.result;
|
||||
return result.success && result.match;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@ namespace SharpCompress.Common.Zip;
|
||||
|
||||
internal partial class WinzipAesCryptoStream
|
||||
{
|
||||
private readonly struct DiscardProcessor : Utility.IBufferProcessor<int>
|
||||
{
|
||||
public int Process(ReadOnlySpan<byte> buffer) => 0; // Just consume the bytes, don't need the result
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
@@ -19,10 +24,11 @@ internal partial class WinzipAesCryptoStream
|
||||
try
|
||||
{
|
||||
// Read out last 10 auth bytes asynchronously
|
||||
var processor = new DiscardProcessor();
|
||||
await _stream
|
||||
.WithRentedBufferReadFullyAsync(
|
||||
.ReadFullyRentedAsync<DiscardProcessor, int>(
|
||||
10,
|
||||
_ => 0, // Just consume the bytes, don't need the result
|
||||
processor,
|
||||
CancellationToken.None
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -72,10 +72,11 @@ internal partial class WinzipAesCryptoStream : Stream
|
||||
// Read out last 10 auth bytes - catch exceptions for async-only streams
|
||||
if (Utility.UseSyncOverAsyncDispose())
|
||||
{
|
||||
var processor = new DiscardProcessor();
|
||||
_stream
|
||||
.WithRentedBufferReadFullyAsync(
|
||||
.ReadFullyRentedAsync<DiscardProcessor, int>(
|
||||
10,
|
||||
_ => 0, // Just consume the bytes, don't need the result
|
||||
processor,
|
||||
CancellationToken.None
|
||||
)
|
||||
.GetAwaiter()
|
||||
|
||||
@@ -25,6 +25,18 @@ public class ArcFactory : Factory, IReaderFactory
|
||||
yield return "arc";
|
||||
}
|
||||
|
||||
private readonly struct ArcSignatureProcessor : Utility.IBufferProcessor<bool>
|
||||
{
|
||||
public bool Process(ReadOnlySpan<byte> buffer) =>
|
||||
buffer[0] == 0x1A && buffer[1] < 10;
|
||||
}
|
||||
|
||||
private readonly struct ArcSignatureTryProcessor : Utility.ITryBufferProcessor<(bool, bool)>
|
||||
{
|
||||
public (bool, bool) OnSuccess(ReadOnlySpan<byte> buffer) => (true, buffer[0] == 0x1A && buffer[1] < 10);
|
||||
public (bool, bool) OnFailure() => (false, false);
|
||||
}
|
||||
|
||||
public override bool IsArchive(Stream stream, string? password = null)
|
||||
{
|
||||
//You may have to use some(paranoid) checks to ensure that you actually are
|
||||
@@ -33,11 +45,12 @@ public class ArcFactory : Factory, IReaderFactory
|
||||
//Hyper - archive, check the next two bytes for "HP" or "ST"(or look below for
|
||||
//"HYP").Also the ZOO archiver also does put a 01Ah at the start of the file,
|
||||
//see the ZOO entry below.
|
||||
return stream.TryWithRentedBufferReadFully(
|
||||
2,
|
||||
buffer => buffer[0] == 0x1A && buffer[1] < 10, //rather thin, but this is all we have
|
||||
out var result
|
||||
) && result;
|
||||
var processor = new ArcSignatureTryProcessor();
|
||||
var result = stream.TryReadFullyRented<ArcSignatureTryProcessor, (bool success, bool match)>(
|
||||
2,
|
||||
ref processor
|
||||
);
|
||||
return result.success && result.match;
|
||||
}
|
||||
|
||||
public IReader OpenReader(Stream stream, ReaderOptions? options) =>
|
||||
@@ -65,9 +78,10 @@ public class ArcFactory : Factory, IReaderFactory
|
||||
//Hyper - archive, check the next two bytes for "HP" or "ST"(or look below for
|
||||
//"HYP").Also the ZOO archiver also does put a 01Ah at the start of the file,
|
||||
//see the ZOO entry below.
|
||||
return await stream.WithRentedBufferReadExactAsync(
|
||||
var processor = new ArcSignatureProcessor();
|
||||
return await stream.ReadExactRentedAsync<ArcSignatureProcessor, bool>(
|
||||
2,
|
||||
buffer => buffer[0] == 0x1A && buffer[1] < 10, //rather thin, but this is all we have
|
||||
processor,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,21 +10,23 @@ namespace SharpCompress;
|
||||
internal static partial class Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// Rents a buffer from the shared ArrayPool, reads data into it asynchronously, and executes a callback with the buffer.
|
||||
/// Rents a buffer from the shared ArrayPool, reads data into it asynchronously, and executes a processor with the buffer.
|
||||
/// The buffer is automatically returned to the pool after use.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The return type of the callback</typeparam>
|
||||
/// <typeparam name="TProcessor">The processor type (struct)</typeparam>
|
||||
/// <typeparam name="TResult">The return type</typeparam>
|
||||
/// <param name="stream">The stream to read from</param>
|
||||
/// <param name="size">The size of the buffer to rent and read</param>
|
||||
/// <param name="callback">The callback to execute with the rented buffer</param>
|
||||
/// <param name="processor">The processor to execute with the rented buffer</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>The result of the callback</returns>
|
||||
public static async ValueTask<T> WithRentedBufferReadFullyAsync<T>(
|
||||
/// <returns>The result of the processor</returns>
|
||||
public static async ValueTask<TResult> ReadFullyRentedAsync<TProcessor, TResult>(
|
||||
this Stream stream,
|
||||
int size,
|
||||
Func<byte[], T> callback,
|
||||
TProcessor processor,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
where TProcessor : struct, IBufferProcessor<TResult>
|
||||
{
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(size);
|
||||
try
|
||||
@@ -37,7 +39,7 @@ internal static partial class Utility
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
return callback(buffer);
|
||||
return processor.Process(buffer.AsSpan(0, size));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -46,21 +48,23 @@ internal static partial class Utility
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents a buffer from the shared ArrayPool, reads data into it asynchronously, and executes a callback with the buffer.
|
||||
/// The buffer is automatically returned to the pool after use. Returns false if end of stream is reached.
|
||||
/// Rents a buffer from the shared ArrayPool, reads data into it asynchronously, and executes a processor with the buffer.
|
||||
/// The buffer is automatically returned to the pool after use. Returns failure result if end of stream is reached.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The return type of the callback</typeparam>
|
||||
/// <typeparam name="TProcessor">The processor type (struct)</typeparam>
|
||||
/// <typeparam name="TResult">The return type</typeparam>
|
||||
/// <param name="stream">The stream to read from</param>
|
||||
/// <param name="size">The size of the buffer to rent and read</param>
|
||||
/// <param name="callback">The callback to execute with the rented buffer</param>
|
||||
/// <param name="processor">The processor to execute with the rented buffer</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>A tuple containing success status and the result</returns>
|
||||
public static async ValueTask<(bool success, T result)> TryWithRentedBufferReadFullyAsync<T>(
|
||||
/// <returns>The result of the processor (success or failure)</returns>
|
||||
public static async ValueTask<TResult> TryReadFullyRentedAsync<TProcessor, TResult>(
|
||||
this Stream stream,
|
||||
int size,
|
||||
Func<byte[], T> callback,
|
||||
TProcessor processor,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
where TProcessor : struct, ITryBufferProcessor<TResult>
|
||||
{
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(size);
|
||||
try
|
||||
@@ -71,9 +75,9 @@ internal static partial class Utility
|
||||
.ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return (false, default!);
|
||||
return processor.OnFailure();
|
||||
}
|
||||
return (true, callback(buffer));
|
||||
return processor.OnSuccess(buffer.AsSpan(0, size));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -82,27 +86,29 @@ internal static partial class Utility
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents a buffer from the shared ArrayPool, reads exactly the specified amount of data asynchronously, and executes a callback with the buffer.
|
||||
/// Rents a buffer from the shared ArrayPool, reads exactly the specified amount of data asynchronously, and executes a processor with the buffer.
|
||||
/// The buffer is automatically returned to the pool after use. Throws EndOfStreamException if not enough data is available.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The return type of the callback</typeparam>
|
||||
/// <typeparam name="TProcessor">The processor type (struct)</typeparam>
|
||||
/// <typeparam name="TResult">The return type</typeparam>
|
||||
/// <param name="stream">The stream to read from</param>
|
||||
/// <param name="size">The size of the buffer to rent and read</param>
|
||||
/// <param name="callback">The callback to execute with the rented buffer</param>
|
||||
/// <param name="processor">The processor to execute with the rented buffer</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>The result of the callback</returns>
|
||||
public static async ValueTask<T> WithRentedBufferReadExactAsync<T>(
|
||||
/// <returns>The result of the processor</returns>
|
||||
public static async ValueTask<TResult> ReadExactRentedAsync<TProcessor, TResult>(
|
||||
this Stream stream,
|
||||
int size,
|
||||
Func<byte[], T> callback,
|
||||
TProcessor processor,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
where TProcessor : struct, IBufferProcessor<TResult>
|
||||
{
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(size);
|
||||
try
|
||||
{
|
||||
await stream.ReadExactAsync(buffer, 0, size, cancellationToken).ConfigureAwait(false);
|
||||
return callback(buffer);
|
||||
return processor.Process(buffer.AsSpan(0, size));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -139,19 +139,40 @@ internal static partial class Utility
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents a buffer from the shared ArrayPool, reads data into it, and executes a callback with the buffer.
|
||||
/// Interface for struct-based buffer processors.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The return type of the processor</typeparam>
|
||||
internal interface IBufferProcessor<TResult>
|
||||
{
|
||||
TResult Process(ReadOnlySpan<byte> buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for struct-based try buffer processors.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The return type of the processor</typeparam>
|
||||
internal interface ITryBufferProcessor<TResult>
|
||||
{
|
||||
TResult OnSuccess(ReadOnlySpan<byte> buffer);
|
||||
TResult OnFailure();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents a buffer from the shared ArrayPool, reads data into it, and executes a processor with the buffer.
|
||||
/// The buffer is automatically returned to the pool after use.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The return type of the callback</typeparam>
|
||||
/// <typeparam name="TProcessor">The processor type (struct)</typeparam>
|
||||
/// <typeparam name="TResult">The return type</typeparam>
|
||||
/// <param name="stream">The stream to read from</param>
|
||||
/// <param name="size">The size of the buffer to rent and read</param>
|
||||
/// <param name="callback">The callback to execute with the rented buffer</param>
|
||||
/// <returns>The result of the callback</returns>
|
||||
public static T WithRentedBufferReadFully<T>(
|
||||
/// <param name="processor">The processor to execute with the rented buffer</param>
|
||||
/// <returns>The result of the processor</returns>
|
||||
public static TResult ReadFullyRented<TProcessor, TResult>(
|
||||
this Stream stream,
|
||||
int size,
|
||||
Func<byte[], T> callback
|
||||
ref TProcessor processor
|
||||
)
|
||||
where TProcessor : struct, IBufferProcessor<TResult>
|
||||
{
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(size);
|
||||
try
|
||||
@@ -160,7 +181,7 @@ internal static partial class Utility
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
return callback(buffer);
|
||||
return processor.Process(buffer.AsSpan(0, size));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -169,32 +190,30 @@ internal static partial class Utility
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents a buffer from the shared ArrayPool, reads data into it, and executes a callback with the buffer.
|
||||
/// The buffer is automatically returned to the pool after use. Returns false if end of stream is reached.
|
||||
/// Rents a buffer from the shared ArrayPool, reads data into it, and executes a processor with the buffer.
|
||||
/// The buffer is automatically returned to the pool after use. Returns failure result if end of stream is reached.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The return type of the callback</typeparam>
|
||||
/// <typeparam name="TProcessor">The processor type (struct)</typeparam>
|
||||
/// <typeparam name="TResult">The return type</typeparam>
|
||||
/// <param name="stream">The stream to read from</param>
|
||||
/// <param name="size">The size of the buffer to rent and read</param>
|
||||
/// <param name="callback">The callback to execute with the rented buffer</param>
|
||||
/// <param name="result">The result of the callback, or default if read failed</param>
|
||||
/// <returns>True if the read was successful, false if end of stream was reached</returns>
|
||||
public static bool TryWithRentedBufferReadFully<T>(
|
||||
/// <param name="processor">The processor to execute with the rented buffer</param>
|
||||
/// <returns>The result of the processor (success or failure)</returns>
|
||||
public static TResult TryReadFullyRented<TProcessor, TResult>(
|
||||
this Stream stream,
|
||||
int size,
|
||||
Func<byte[], T> callback,
|
||||
out T result
|
||||
ref TProcessor processor
|
||||
)
|
||||
where TProcessor : struct, ITryBufferProcessor<TResult>
|
||||
{
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(size);
|
||||
try
|
||||
{
|
||||
if (!stream.ReadFully(buffer.AsSpan(0, size)))
|
||||
{
|
||||
result = default!;
|
||||
return false;
|
||||
return processor.OnFailure();
|
||||
}
|
||||
result = callback(buffer);
|
||||
return true;
|
||||
return processor.OnSuccess(buffer.AsSpan(0, size));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -203,25 +222,27 @@ internal static partial class Utility
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents a buffer from the shared ArrayPool, reads exactly the specified amount of data, and executes a callback with the buffer.
|
||||
/// Rents a buffer from the shared ArrayPool, reads exactly the specified amount of data, and executes a processor with the buffer.
|
||||
/// The buffer is automatically returned to the pool after use. Throws EndOfStreamException if not enough data is available.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The return type of the callback</typeparam>
|
||||
/// <typeparam name="TProcessor">The processor type (struct)</typeparam>
|
||||
/// <typeparam name="TResult">The return type</typeparam>
|
||||
/// <param name="stream">The stream to read from</param>
|
||||
/// <param name="size">The size of the buffer to rent and read</param>
|
||||
/// <param name="callback">The callback to execute with the rented buffer</param>
|
||||
/// <returns>The result of the callback</returns>
|
||||
public static T WithRentedBufferReadExact<T>(
|
||||
/// <param name="processor">The processor to execute with the rented buffer</param>
|
||||
/// <returns>The result of the processor</returns>
|
||||
public static TResult ReadExactRented<TProcessor, TResult>(
|
||||
this Stream stream,
|
||||
int size,
|
||||
Func<byte[], T> callback
|
||||
ref TProcessor processor
|
||||
)
|
||||
where TProcessor : struct, IBufferProcessor<TResult>
|
||||
{
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(size);
|
||||
try
|
||||
{
|
||||
stream.ReadExact(buffer, 0, size);
|
||||
return callback(buffer);
|
||||
return processor.Process(buffer.AsSpan(0, size));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
@@ -798,164 +799,214 @@ public class UtilityTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region WithRentedBufferReadFully Tests
|
||||
#region Rented Buffer Tests
|
||||
|
||||
private readonly struct SumProcessor : Utility.IBufferProcessor<int>
|
||||
{
|
||||
public int Process(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
sum += buffer[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly struct IdentityProcessor : Utility.IBufferProcessor<bool>
|
||||
{
|
||||
public bool Process(ReadOnlySpan<byte> buffer) => buffer.Length > 0 && buffer[0] != 0;
|
||||
}
|
||||
|
||||
private readonly struct ArcLikeTryProcessor : Utility.ITryBufferProcessor<(bool, bool)>
|
||||
{
|
||||
public (bool, bool) OnSuccess(ReadOnlySpan<byte> buffer) =>
|
||||
(true, buffer[0] == 0x1A && buffer[1] < 10);
|
||||
|
||||
public (bool, bool) OnFailure() => (false, false);
|
||||
}
|
||||
|
||||
private readonly struct AlwaysTrueTryProcessor : Utility.ITryBufferProcessor<(bool, bool)>
|
||||
{
|
||||
public (bool, bool) OnSuccess(ReadOnlySpan<byte> buffer) => (true, true);
|
||||
|
||||
public (bool, bool) OnFailure() => (false, false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithRentedBufferReadFully_ReadsAndProcessesData()
|
||||
public void ReadFullyRented_ReadsAndProcessesData()
|
||||
{
|
||||
var data = new byte[] { 1, 2, 3, 4, 5 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var sum = stream.WithRentedBufferReadFully(
|
||||
5,
|
||||
buffer => buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]
|
||||
);
|
||||
var processor = new SumProcessor();
|
||||
var sum = stream.ReadFullyRented<SumProcessor, int>(5, ref processor);
|
||||
|
||||
Assert.Equal(15, sum);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithRentedBufferReadFully_NotEnoughData_ThrowsEndOfStreamException()
|
||||
public void ReadFullyRented_NotEnoughData_ThrowsEndOfStreamException()
|
||||
{
|
||||
var data = new byte[] { 1, 2, 3 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var processor = new IdentityProcessor();
|
||||
Assert.Throws<EndOfStreamException>(() =>
|
||||
stream.WithRentedBufferReadFully(5, buffer => buffer[0])
|
||||
stream.ReadFullyRented<IdentityProcessor, bool>(5, ref processor)
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryWithRentedBufferReadFully_SuccessfulRead_ReturnsTrue()
|
||||
public void TryReadFullyRented_SuccessfulRead_ReturnsTrue()
|
||||
{
|
||||
var data = new byte[] { 0x1A, 0x05 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var success = stream.TryWithRentedBufferReadFully(
|
||||
var processor = new ArcLikeTryProcessor();
|
||||
var result = stream.TryReadFullyRented<ArcLikeTryProcessor, (bool success, bool match)>(
|
||||
2,
|
||||
buffer => buffer[0] == 0x1A && buffer[1] < 10,
|
||||
out var result
|
||||
ref processor
|
||||
);
|
||||
|
||||
Assert.True(success);
|
||||
Assert.True(result);
|
||||
Assert.True(result.success);
|
||||
Assert.True(result.match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryWithRentedBufferReadFully_NotEnoughData_ReturnsFalse()
|
||||
public void TryReadFullyRented_NotEnoughData_ReturnsFalse()
|
||||
{
|
||||
var data = new byte[] { 1, 2, 3 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var success = stream.TryWithRentedBufferReadFully(5, buffer => true, out var result);
|
||||
var processor = new AlwaysTrueTryProcessor();
|
||||
var result = stream.TryReadFullyRented<AlwaysTrueTryProcessor, (bool success, bool match)>(
|
||||
5,
|
||||
ref processor
|
||||
);
|
||||
|
||||
Assert.False(success);
|
||||
Assert.False(result);
|
||||
Assert.False(result.success);
|
||||
Assert.False(result.match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithRentedBufferReadExact_ReadsAndProcessesData()
|
||||
public void ReadExactRented_ReadsAndProcessesData()
|
||||
{
|
||||
var data = new byte[] { 1, 2, 3, 4, 5 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var sum = stream.WithRentedBufferReadExact(
|
||||
5,
|
||||
buffer => buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]
|
||||
);
|
||||
var processor = new SumProcessor();
|
||||
var sum = stream.ReadExactRented<SumProcessor, int>(5, ref processor);
|
||||
|
||||
Assert.Equal(15, sum);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithRentedBufferReadExact_NotEnoughData_ThrowsEndOfStreamException()
|
||||
public void ReadExactRented_NotEnoughData_ThrowsEndOfStreamException()
|
||||
{
|
||||
var data = new byte[] { 1, 2, 3 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var processor = new IdentityProcessor();
|
||||
Assert.Throws<EndOfStreamException>(() =>
|
||||
stream.WithRentedBufferReadExact(5, buffer => buffer[0])
|
||||
stream.ReadExactRented<IdentityProcessor, bool>(5, ref processor)
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region WithRentedBufferReadFullyAsync Tests
|
||||
|
||||
[Fact]
|
||||
public async ValueTask WithRentedBufferReadFullyAsync_ReadsAndProcessesData()
|
||||
public async ValueTask ReadFullyRentedAsync_ReadsAndProcessesData()
|
||||
{
|
||||
var data = new byte[] { 1, 2, 3, 4, 5 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var sum = await stream.WithRentedBufferReadFullyAsync(
|
||||
var processor = new SumProcessor();
|
||||
var sum = await stream.ReadFullyRentedAsync<SumProcessor, int>(
|
||||
5,
|
||||
buffer => buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]
|
||||
processor,
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
Assert.Equal(15, sum);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask WithRentedBufferReadFullyAsync_NotEnoughData_ThrowsEndOfStreamException()
|
||||
public async ValueTask ReadFullyRentedAsync_NotEnoughData_ThrowsEndOfStreamException()
|
||||
{
|
||||
var data = new byte[] { 1, 2, 3 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var processor = new IdentityProcessor();
|
||||
await Assert.ThrowsAsync<EndOfStreamException>(async () =>
|
||||
await stream.WithRentedBufferReadFullyAsync(5, buffer => buffer[0])
|
||||
await stream.ReadFullyRentedAsync<IdentityProcessor, bool>(
|
||||
5,
|
||||
processor,
|
||||
CancellationToken.None
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask TryWithRentedBufferReadFullyAsync_SuccessfulRead_ReturnsTrue()
|
||||
public async ValueTask TryReadFullyRentedAsync_SuccessfulRead_ReturnsTrue()
|
||||
{
|
||||
var data = new byte[] { 0x1A, 0x05 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var (success, result) = await stream.TryWithRentedBufferReadFullyAsync(
|
||||
2,
|
||||
buffer => buffer[0] == 0x1A && buffer[1] < 10
|
||||
);
|
||||
var processor = new ArcLikeTryProcessor();
|
||||
var result = await stream.TryReadFullyRentedAsync<
|
||||
ArcLikeTryProcessor,
|
||||
(bool success, bool match)
|
||||
>(2, processor, CancellationToken.None);
|
||||
|
||||
Assert.True(success);
|
||||
Assert.True(result);
|
||||
Assert.True(result.success);
|
||||
Assert.True(result.match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask TryWithRentedBufferReadFullyAsync_NotEnoughData_ReturnsFalse()
|
||||
public async ValueTask TryReadFullyRentedAsync_NotEnoughData_ReturnsFalse()
|
||||
{
|
||||
var data = new byte[] { 1, 2, 3 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var (success, result) = await stream.TryWithRentedBufferReadFullyAsync(5, buffer => true);
|
||||
var processor = new AlwaysTrueTryProcessor();
|
||||
var result = await stream.TryReadFullyRentedAsync<
|
||||
AlwaysTrueTryProcessor,
|
||||
(bool success, bool match)
|
||||
>(5, processor, CancellationToken.None);
|
||||
|
||||
Assert.False(success);
|
||||
Assert.False(result);
|
||||
Assert.False(result.success);
|
||||
Assert.False(result.match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask WithRentedBufferReadExactAsync_ReadsAndProcessesData()
|
||||
public async ValueTask ReadExactRentedAsync_ReadsAndProcessesData()
|
||||
{
|
||||
var data = new byte[] { 1, 2, 3, 4, 5 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var sum = await stream.WithRentedBufferReadExactAsync(
|
||||
var processor = new SumProcessor();
|
||||
var sum = await stream.ReadExactRentedAsync<SumProcessor, int>(
|
||||
5,
|
||||
buffer => buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]
|
||||
processor,
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
Assert.Equal(15, sum);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask WithRentedBufferReadExactAsync_NotEnoughData_ThrowsEndOfStreamException()
|
||||
public async ValueTask ReadExactRentedAsync_NotEnoughData_ThrowsEndOfStreamException()
|
||||
{
|
||||
var data = new byte[] { 1, 2, 3 };
|
||||
using var stream = new MemoryStream(data);
|
||||
|
||||
var processor = new IdentityProcessor();
|
||||
await Assert.ThrowsAsync<EndOfStreamException>(async () =>
|
||||
await stream.WithRentedBufferReadExactAsync(5, buffer => buffer[0])
|
||||
await stream.ReadExactRentedAsync<IdentityProcessor, bool>(
|
||||
5,
|
||||
processor,
|
||||
CancellationToken.None
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user