ReadOnlySequence<char> conversion from ReadOnlySequence<byte>?

1.2k Views Asked by At

I'm trying to use System.IO.Pipelines to parse large text files.

But I can't find no conversion function from ReadOnlySequence to ReadOnlySequence. For example like MemoryMarshal.Cast<byte,char>.

IMHO it is pretty useless having a generic ReadOnlySequence<T> if there is only one particular type (byte) applicable.

    static async Task ReadPipeAsync(PipeReader reader, IStringValueFactory factory)
    {
      while (true)
      {
        ReadResult result = await reader.ReadAsync();

        ReadOnlySequence<byte> buffer = result.Buffer;

        //ReadOnlySequence<char> chars = buffer.CastTo<char>(); ???
       }
     }
1

There are 1 best solutions below

0
On

You would have to write a conversion operator to achieve this cast. You cannot cast it explicitly. Be aware that a char[] is two bytes, so you need to choose your encoding algorithm.

IMHO it is pretty useless having a generic ReadOnlySequence<T> if there is only one particular type (byte) applicable.

While it's true that System.IO.Pipelines will only give you a ReadOnlySequence<byte> because of the fact that a PipeReader is attached to a Stream which is just a stream of bytes, there are other use cases for a ReadOnlySequence<T> eg,

ReadOnlySequence<char> roChars = new ReadOnlySequence<char>("some chars".ToCharArray());
ReadOnlySequence<string> roStrings = new ReadOnlySequence<string>(new string[] { "string1", "string2", "Another String" });

Your conversion operator would have similar logic to the below, but you would set your encoding appropriately.

    static void Main(string[] args)
    {
        // create a 64k Readonly sequence of random bytes
        var ros = new ReadOnlySequence<byte>(GenerateRandomBytes(64000));

        //Optionally extract the section of the ReadOnlySequence we are interested in
        var mySlice = ros.Slice(22222, 55555);

        char[] charArray;

        // Check if the slice is a single segment - not really necessary
        // included for explanation only
        if(mySlice.IsSingleSegment)
        {
            charArray = Encoding.ASCII.GetString(mySlice.FirstSpan).ToCharArray();
        }
        else
        // Could only do this and always assume multiple spans
        // which is highly likley for a PipeReader stream
        {
            Span<byte> theSpan = new byte[ros.Length];
            mySlice.CopyTo(theSpan);
            // ASCII Encoding - one byte of span = 2 bytes of char
            charArray = Encoding.ASCII.GetString(theSpan).ToCharArray();
        }

        // Convert the char array back to a ReadOnlySegment<char>
        var rosChar = new ReadOnlySequence<char>(charArray);

    }

    public static byte[] GenerateRandomBytes(int length)
    {
        // Create a buffer
        byte[] randBytes;

        if (length >= 1)
            randBytes = new byte[length];
        else
            randBytes = new byte[1];

        // Create a new RNGCryptoServiceProvider.
        System.Security.Cryptography.RNGCryptoServiceProvider rand =
             new System.Security.Cryptography.RNGCryptoServiceProvider();

        // Fill the buffer with random bytes.
        rand.GetBytes(randBytes);

        // return the bytes.
        return randBytes;
    }