/// <summary> /// Reads a <see cref="IBufferReader{T}"/> to completion, writing to a <see cref="IBufferWriterAsync{T}"/> /// </summary> /// <typeparam name="T">The type of element</typeparam> /// <param name="reader">The reader to read from</param> /// <param name="writer">The writer to write to</param> /// <param name="token">A cancellation token to abort the operation</param> /// <returns>A task representing the progress fo the write operation</returns> public static async ValueTask CopyToAsync <T>(this IBufferReader <T> reader, IBufferWriterAsync <T> writer, CancellationToken token = default) { while (reader.CanRead) { var InBuffer = reader.GetMemory(0); if (InBuffer.IsEmpty) { break; } InBuffer.Span.CopyTo(writer.GetSpan(InBuffer.Length)); await writer.AdvanceAsync(InBuffer.Length, token); reader.Advance(InBuffer.Length); } }
public static void CopyTo(this IBufferReader <byte> source, Stream target) => source.CopyTo(target, 81920); // Same buffer size as Stream.CopyTo /// <summary> /// Synchronously reads the bytes from the current <see cref="IBufferReader{Byte}"/> and writes them to a Stream /// </summary> /// <param name="source">The current buffer reader to read from</param> /// <param name="target">The stream to write to</param> /// <param name="blockSize">The size of the blocks to read and write</param> public static void CopyTo(this IBufferReader <byte> source, Stream target, int blockSize) { if (blockSize < 0) { throw new ArgumentOutOfRangeException(nameof(blockSize)); } #if NETSTANDARD2_0 byte[]? InBuffer = null; try { for (; ;) { var Buffer = source.GetMemory(blockSize); if (Buffer.IsEmpty) { break; } if (MemoryMarshal.TryGetArray(Buffer, out var Segment)) { // Have the stream write directly from the source buffer target.Write(Segment.Array, Segment.Offset, Segment.Count); source.Advance(Segment.Count); } else { // Not a buffer we can pass to Stream.Write, so we have to copy if (InBuffer == null) { InBuffer = ArrayPool <byte> .Shared.Rent(Buffer.Length); } var Length = Math.Min(Buffer.Length, InBuffer.Length); Buffer.Slice(0, Length).CopyTo(InBuffer); target.Write(InBuffer, 0, Length); source.Advance(Length); } } } finally { if (InBuffer != null) { ArrayPool <byte> .Shared.Return(InBuffer); } } #else for (; ;) { var Buffer = source.GetSpan(blockSize); if (Buffer.IsEmpty) { break; } target.Write(Buffer); source.Advance(Buffer.Length); } #endif }