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); } }
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; } }