using System.Collections.Generic;
using System.IO.Pipelines;
using System.Threading.Tasks;
static readonly byte[] NewLineChars = {(byte)'\r', (byte)'\n'};
static readonly byte[] WhiteSpaceChars = {(byte)'\r', (byte)'\n', (byte)' ', (byte)'\t'};
private static async Task Main()
JsonSerializerOptions jsonOptions = new(JsonSerializerDefaults.Web);
var json = "{\"some\":\"thing1\"}\r\n{\"some\":\"thing2\"}\r\n{\"some\":\"thing3\"}";
var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(json));
var pipeReader = PipeReader.Create(contentStream);
await foreach (var foo in ReadItemsAsync<Foo>(pipeReader, jsonOptions))
Console.WriteLine($"foo: {foo.Some}");
static async IAsyncEnumerable<TValue> ReadItemsAsync<TValue>(PipeReader pipeReader, JsonSerializerOptions jsonOptions = null)
var result = await pipeReader.ReadAsync();
var buffer = result.Buffer;
bool isCompleted = result.IsCompleted;
SequencePosition bufferPosition = buffer.Start;
var(value, advanceSequence) = TryReadNextItem<TValue>(buffer, ref bufferPosition, isCompleted, jsonOptions);
pipeReader.AdvanceTo(bufferPosition, buffer.End);
static (TValue, bool) TryReadNextItem<TValue>(ReadOnlySequence<byte> sequence, ref SequencePosition sequencePosition, bool isCompleted, JsonSerializerOptions jsonOptions)
var reader = new SequenceReader<byte>(sequence.Slice(sequencePosition));
if (reader.TryReadToAny(out ReadOnlySpan<byte> itemBytes, NewLineChars, advancePastDelimiter: true))
sequencePosition = reader.Position;
if (itemBytes.TrimStart(WhiteSpaceChars).IsEmpty)
return (JsonSerializer.Deserialize<TValue>(itemBytes, jsonOptions), false);
var remainingReader = sequence.Slice(reader.Position);
using var memoryOwner = MemoryPool<byte>.Shared.Rent((int)remainingReader.Length);
remainingReader.CopyTo(memoryOwner.Memory.Span);
itemBytes = memoryOwner.Memory.Span.Slice(0, (int)remainingReader.Length);
reader.Advance(remainingReader.Length);
sequencePosition = reader.Position;
if (!itemBytes.TrimStart(WhiteSpaceChars).IsEmpty)
return (JsonSerializer.Deserialize<TValue>(itemBytes, jsonOptions), true);