.NET-Community-Toolkit/CommunityToolkit.HighPerfor.../Streams/MemoryStream.cs

92 lines
3.9 KiB
C#

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Buffers;
using System.IO;
using System.Runtime.InteropServices;
namespace CommunityToolkit.HighPerformance.Streams;
/// <summary>
/// A factory class to produce <see cref="MemoryStream{TSource}"/> instances.
/// </summary>
internal static partial class MemoryStream
{
/// <summary>
/// Creates a new <see cref="Stream"/> from the input <see cref="ReadOnlyMemory{T}"/> of <see cref="byte"/> instance.
/// </summary>
/// <param name="memory">The input <see cref="ReadOnlyMemory{T}"/> instance.</param>
/// <param name="isReadOnly">Indicates whether or not <paramref name="memory"/> can be written to.</param>
/// <returns>A <see cref="Stream"/> wrapping the underlying data for <paramref name="memory"/>.</returns>
/// <exception cref="ArgumentException">Thrown when <paramref name="memory"/> has an invalid data store.</exception>
public static Stream Create(ReadOnlyMemory<byte> memory, bool isReadOnly)
{
if (memory.IsEmpty)
{
// Return an empty stream if the memory was empty
return new MemoryStream<ArrayOwner>(ArrayOwner.Empty, isReadOnly);
}
if (MemoryMarshal.TryGetArray(memory, out ArraySegment<byte> segment))
{
ArrayOwner arraySpanSource = new(segment.Array!, segment.Offset, segment.Count);
return new MemoryStream<ArrayOwner>(arraySpanSource, isReadOnly);
}
if (MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<byte>? memoryManager, out int start, out int length))
{
MemoryManagerOwner memoryManagerSpanSource = new(memoryManager!, start, length);
return new MemoryStream<MemoryManagerOwner>(memoryManagerSpanSource, isReadOnly);
}
return ThrowNotSupportedExceptionForInvalidMemory();
}
/// <summary>
/// Creates a new <see cref="Stream"/> from the input <see cref="IMemoryOwner{T}"/> of <see cref="byte"/> instance.
/// </summary>
/// <param name="memoryOwner">The input <see cref="IMemoryOwner{T}"/> instance.</param>
/// <returns>A <see cref="Stream"/> wrapping the underlying data for <paramref name="memoryOwner"/>.</returns>
/// <exception cref="ArgumentException">Thrown when <paramref name="memoryOwner"/> has an invalid data store.</exception>
public static Stream Create(IMemoryOwner<byte> memoryOwner)
{
Memory<byte> memory = memoryOwner.Memory;
if (memory.IsEmpty)
{
// Return an empty stream if the memory was empty
return new IMemoryOwnerStream<ArrayOwner>(ArrayOwner.Empty, memoryOwner);
}
if (MemoryMarshal.TryGetArray(memory, out ArraySegment<byte> segment))
{
ArrayOwner arraySpanSource = new(segment.Array!, segment.Offset, segment.Count);
return new IMemoryOwnerStream<ArrayOwner>(arraySpanSource, memoryOwner);
}
if (MemoryMarshal.TryGetMemoryManager<byte, MemoryManager<byte>>(memory, out MemoryManager<byte>? memoryManager, out int start, out int length))
{
MemoryManagerOwner memoryManagerSpanSource = new(memoryManager, start, length);
return new IMemoryOwnerStream<MemoryManagerOwner>(memoryManagerSpanSource, memoryOwner);
}
return ThrowNotSupportedExceptionForInvalidMemory();
}
/// <summary>
/// Throws a <see cref="ArgumentException"/> when a given <see cref="Memory{T}"/>
/// or <see cref="IMemoryOwner{T}"/> instance has an unsupported backing store.
/// </summary>
/// <returns>Nothing, this method always throws.</returns>
private static Stream ThrowNotSupportedExceptionForInvalidMemory()
{
throw new ArgumentException("The input instance doesn't have a valid underlying data store.");
}
}