Example #1
0
        async Task <BucketBytes> DoRead(int requested)
        {
            if (_unread.Length > 0)
            {
                var bb = _unread.Slice(0, Math.Min(requested, _unread.Length));
                _unread = _unread.Slice(bb.Length);
                return(bb);
            }
            else if (_readEof)
            {
                return(BucketBytes.Eof);
            }

            int len = await Socket.ReceiveAsync(new ArraySegment <byte>(_inputBuffer), SocketFlags.None).ConfigureAwait(false);

            if (len > 0)
            {
                _bytesRead += len;
                if (len > requested)
                {
                    _unread = new BucketBytes(_inputBuffer, requested, len - requested);
                    return(new BucketBytes(_inputBuffer, 0, requested));
                }
                else
                {
                    return(new BucketBytes(_inputBuffer, 0, len));
                }
            }
            else
            {
                _readEof = true;
                return(BucketBytes.Eof);
            }
        }
Example #2
0
        public async ValueTask <BucketBytes> ReadAsync(int readBytes)
        {
            try
            {
                if (AlreadyRead == 0)
                {
                    return(await Bucket.ReadAsync(readBytes).ConfigureAwait(false));
                }
                else if (readBytes <= AlreadyRead)
                {
                    if (readBytes < AlreadyRead)
                    {
                        throw new InvalidOperationException();
                    }

                    AlreadyRead = 0;
                    var r = Data.Slice(0, readBytes);
                    Data = Data.Slice(readBytes);
                    return(r);
                }
                else if (readBytes > Data.Length)
                {
                    byte[] returnData;

                    if (readBytes < Data.Length)
                    {
                        returnData = Data.Slice(0, readBytes).ToArray();
                    }
                    else
                    {
                        returnData = Data.ToArray();
                    }

                    int consume = readBytes - AlreadyRead;
                    int copy    = AlreadyRead;
                    AlreadyRead = 0; // No errors in Dispose please

                    var bb = await Bucket.ReadAsync(consume).ConfigureAwait(false);

                    if (bb.IsEof)
                    {
                        return(new BucketBytes(returnData, 0, copy));
                    }

                    if (copy + bb.Length <= returnData.Length)
                    {
                        return(new BucketBytes(returnData, 0, copy + bb.Length)); // Data already available from peek buffer
                    }
                    // We got new and old data, but how can we return that?
                    var(arr, offset) = bb;

                    // Unlikely, but cheap: The return buffer is what we need
                    if (arr is not null &&
                        offset >= copy &&
                        new ReadOnlySpan <byte>(arr, offset - copy, copy).SequenceEqual(returnData))
                    {
                        return(new BucketBytes(arr, offset - copy, bb.Length + copy));
                    }

                    byte[] ret = new byte[bb.Length + copy];

                    Array.Copy(returnData, ret, copy);
                    bb.Span.CopyTo(new Span <byte>(ret, copy, bb.Length));

                    return(ret);
                }
                else
                {
                    int consume = readBytes - AlreadyRead;

                    BucketBytes slicedDataCopy = Data.Slice(0, Math.Min(readBytes, Data.Length)).ToArray();

                    var bb = await Bucket.ReadAsync(consume).ConfigureAwait(false);

                    AlreadyRead = Math.Max(0, AlreadyRead - bb.Length);

                    if (bb.Length == consume)
                    {
                        return(slicedDataCopy);
                    }
                    else if (bb.Length < consume)
                    {
                        return(slicedDataCopy.Slice(0, slicedDataCopy.Length - (consume - bb.Length)));
                    }
                    else
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
            finally
            {
                Data = BucketBytes.Empty;
            }
        }