Skip to content

Commit 75d3049

Browse files
committed
Added Stream overrides that take Span<byte> or Memory<byte>
1 parent b2f7c38 commit 75d3049

File tree

4 files changed

+718
-0
lines changed

4 files changed

+718
-0
lines changed

MimeKit/IO/BoundStream.cs

+201
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,60 @@ public override int Read (byte[] buffer, int offset, int count)
356356
return nread;
357357
}
358358

359+
#if NET6_0_OR_GREATER
360+
/// <summary>
361+
/// Read a sequence of bytes from the stream and advances the position
362+
/// within the stream by the number of bytes read.
363+
/// </summary>
364+
/// <remarks>
365+
/// Reads data from the <see cref="BaseStream"/>, not allowing it to
366+
/// read beyond the <see cref="EndBoundary"/>.
367+
/// </remarks>
368+
/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if
369+
/// that many bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
370+
/// <param name="buffer">The buffer to read data into.</param>
371+
/// <exception cref="System.ArgumentNullException">
372+
/// <paramref name="buffer"/> is <see langword="null"/>.
373+
/// </exception>
374+
/// <exception cref="System.ObjectDisposedException">
375+
/// The stream has been disposed.
376+
/// </exception>
377+
/// <exception cref="System.NotSupportedException">
378+
/// The stream does not support reading.
379+
/// </exception>
380+
/// <exception cref="System.IO.IOException">
381+
/// An I/O error occurred.
382+
/// </exception>
383+
public override int Read (Span<byte> buffer)
384+
{
385+
CheckDisposed ();
386+
CheckCanRead ();
387+
388+
if (buffer == null)
389+
throw new ArgumentNullException (nameof (buffer));
390+
391+
// if we are at the end of the stream, we cannot read anymore data
392+
if (EndBoundary != -1 && StartBoundary + position >= EndBoundary) {
393+
eos = true;
394+
return 0;
395+
}
396+
397+
// make sure that the source stream is in the expected position
398+
if (BaseStream.CanSeek && BaseStream.Position != StartBoundary + position)
399+
BaseStream.Seek (StartBoundary + position, SeekOrigin.Begin);
400+
401+
int n = EndBoundary != -1 ? (int) Math.Min (EndBoundary - (StartBoundary + position), buffer.Length) : buffer.Length;
402+
int nread = BaseStream.Read (buffer.Slice (0, n));
403+
404+
if (nread > 0)
405+
position += nread;
406+
else if (nread == 0)
407+
eos = true;
408+
409+
return nread;
410+
}
411+
#endif
412+
359413
/// <summary>
360414
/// Asynchronously read a sequence of bytes from the stream and advances the position
361415
/// within the stream by the number of bytes read.
@@ -419,6 +473,58 @@ public override async Task<int> ReadAsync (byte[] buffer, int offset, int count,
419473
return nread;
420474
}
421475

476+
#if NET6_0_OR_GREATER
477+
/// <summary>
478+
/// Asynchronously read a sequence of bytes from the stream and advances the position
479+
/// within the stream by the number of bytes read.
480+
/// </summary>
481+
/// <remarks>
482+
/// Reads data from the <see cref="BaseStream"/>, not allowing it to
483+
/// read beyond the <see cref="EndBoundary"/>.
484+
/// </remarks>
485+
/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if
486+
/// that many bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
487+
/// <param name="buffer">The buffer to read data into.</param>
488+
/// <param name="cancellationToken">The cancellation token.</param>
489+
/// <exception cref="System.ObjectDisposedException">
490+
/// The stream has been disposed.
491+
/// </exception>
492+
/// <exception cref="System.NotSupportedException">
493+
/// The stream does not support reading.
494+
/// </exception>
495+
/// <exception cref="System.OperationCanceledException">
496+
/// The operation was canceled via the cancellation token.
497+
/// </exception>
498+
/// <exception cref="System.IO.IOException">
499+
/// An I/O error occurred.
500+
/// </exception>
501+
public override async ValueTask<int> ReadAsync (Memory<byte> buffer, CancellationToken cancellationToken)
502+
{
503+
CheckDisposed ();
504+
CheckCanRead ();
505+
506+
// if we are at the end of the stream, we cannot read anymore data
507+
if (EndBoundary != -1 && StartBoundary + position >= EndBoundary) {
508+
eos = true;
509+
return 0;
510+
}
511+
512+
// make sure that the source stream is in the expected position
513+
if (BaseStream.CanSeek && BaseStream.Position != StartBoundary + position)
514+
BaseStream.Seek (StartBoundary + position, SeekOrigin.Begin);
515+
516+
int n = EndBoundary != -1 ? (int) Math.Min (EndBoundary - (StartBoundary + position), buffer.Length) : buffer.Length;
517+
int nread = await BaseStream.ReadAsync (buffer.Slice (0, n), cancellationToken).ConfigureAwait (false);
518+
519+
if (nread > 0)
520+
position += nread;
521+
else if (nread == 0)
522+
eos = true;
523+
524+
return nread;
525+
}
526+
#endif
527+
422528
/// <summary>
423529
/// Write a sequence of bytes to the stream and advances the current
424530
/// position within this stream by the number of bytes written.
@@ -472,6 +578,54 @@ public override void Write (byte[] buffer, int offset, int count)
472578
eos = true;
473579
}
474580

581+
#if NET6_0_OR_GREATER
582+
/// <summary>
583+
/// Write a sequence of bytes to the stream and advances the current
584+
/// position within this stream by the number of bytes written.
585+
/// </summary>
586+
/// <remarks>
587+
/// Writes data to the <see cref="BaseStream"/>, not allowing it to
588+
/// write beyond the <see cref="EndBoundary"/>.
589+
/// </remarks>
590+
/// <param name="buffer">The buffer to write.</param>
591+
/// <exception cref="System.ArgumentNullException">
592+
/// <paramref name="buffer"/> is <see langword="null"/>.
593+
/// </exception>
594+
/// <exception cref="System.ObjectDisposedException">
595+
/// The stream has been disposed.
596+
/// </exception>
597+
/// <exception cref="System.NotSupportedException">
598+
/// The stream does not support writing.
599+
/// </exception>
600+
/// <exception cref="System.IO.IOException">
601+
/// An I/O error occurred.
602+
/// </exception>
603+
public override void Write (ReadOnlySpan<byte> buffer)
604+
{
605+
CheckDisposed ();
606+
CheckCanWrite ();
607+
608+
if (buffer == null)
609+
throw new ArgumentNullException (nameof (buffer));
610+
611+
// if we are at the end of the stream, we cannot write anymore data
612+
if (EndBoundary != -1 && StartBoundary + position + buffer.Length > EndBoundary) {
613+
eos = StartBoundary + position >= EndBoundary;
614+
throw new IOException ();
615+
}
616+
617+
// make sure that the source stream is in the expected position
618+
if (BaseStream.CanSeek && BaseStream.Position != StartBoundary + position)
619+
BaseStream.Seek (StartBoundary + position, SeekOrigin.Begin);
620+
621+
BaseStream.Write (buffer);
622+
position += buffer.Length;
623+
624+
if (EndBoundary != -1 && StartBoundary + position >= EndBoundary)
625+
eos = true;
626+
}
627+
#endif
628+
475629
/// <summary>
476630
/// Asynchronously write a sequence of bytes to the stream and advances the current
477631
/// position within this stream by the number of bytes written.
@@ -530,6 +684,53 @@ public override async Task WriteAsync (byte[] buffer, int offset, int count, Can
530684
eos = true;
531685
}
532686

687+
#if NET6_0_OR_GREATER
688+
/// <summary>
689+
/// Asynchronously write a sequence of bytes to the stream and advances the current
690+
/// position within this stream by the number of bytes written.
691+
/// </summary>
692+
/// <remarks>
693+
/// Writes data to the <see cref="BaseStream"/>, not allowing it to
694+
/// write beyond the <see cref="EndBoundary"/>.
695+
/// </remarks>
696+
/// <returns>A task that represents the asynchronous write operation.</returns>
697+
/// <param name="buffer">The buffer to write.</param>
698+
/// <param name="cancellationToken">The cancellation token.</param>
699+
/// <exception cref="System.ObjectDisposedException">
700+
/// The stream has been disposed.
701+
/// </exception>
702+
/// <exception cref="System.NotSupportedException">
703+
/// The stream does not support writing.
704+
/// </exception>
705+
/// <exception cref="System.OperationCanceledException">
706+
/// The operation was canceled via the cancellation token.
707+
/// </exception>
708+
/// <exception cref="System.IO.IOException">
709+
/// An I/O error occurred.
710+
/// </exception>
711+
public override async ValueTask WriteAsync (ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
712+
{
713+
CheckDisposed ();
714+
CheckCanWrite ();
715+
716+
// if we are at the end of the stream, we cannot write anymore data
717+
if (EndBoundary != -1 && StartBoundary + position + buffer.Length > EndBoundary) {
718+
eos = StartBoundary + position >= EndBoundary;
719+
throw new IOException ();
720+
}
721+
722+
// make sure that the source stream is in the expected position
723+
if (BaseStream.CanSeek && BaseStream.Position != StartBoundary + position)
724+
BaseStream.Seek (StartBoundary + position, SeekOrigin.Begin);
725+
726+
await BaseStream.WriteAsync (buffer, cancellationToken).ConfigureAwait (false);
727+
position += buffer.Length;
728+
729+
if (EndBoundary != -1 && StartBoundary + position >= EndBoundary)
730+
eos = true;
731+
}
732+
#endif
733+
533734
/// <summary>
534735
/// Set the position within the current stream.
535736
/// </summary>

0 commit comments

Comments
 (0)