public async Task CanConsumeLessDataThanProduced()
        {
            var stream = new CallbackStream(async(s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello ");
                await sw.FlushAsync();
                await sw.WriteAsync("World");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();

            int index   = 0;
            var message = "Hello World";

            while (true)
            {
                var result = await reader.ReadAsync();

                var buffer = result.Buffer;

                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }

                var ch = (char)buffer.First.Span[0];
                Assert.Equal(message[index++], ch);
                reader.Advance(buffer.Start.Seek(1, buffer.End));
            }

            Assert.Equal(message.Length, index);
        }
        public async Task AccessingUnownedMemoryThrowsIfUsedAfterAdvance()
        {
            var stream = new CallbackStream(async(s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello ");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();

            var data = Memory <byte> .Empty;

            while (true)
            {
                var result = await reader.ReadAsync();

                var buffer = result.Buffer;

                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }
                data = buffer.First;
                reader.Advance(buffer.End);
            }

            Assert.Throws <ObjectDisposedException>(() => data.Span);
        }
        public async Task CancellingBeforeAdvance()
        {
            var stream = new CallbackStream(async(s, token) =>
            {
                var bytes = Encoding.ASCII.GetBytes("Hello World");
                await s.WriteAsync(bytes, 0, bytes.Length);
            });

            var reader = stream.AsPipelineReader();

            var result = await reader.ReadAsync();

            var buffer = result.Buffer;

            Assert.Equal(11, buffer.Length);
            Assert.False(result.IsCancelled);
            Assert.True(buffer.IsSingleSpan);
            var array = new byte[11];

            buffer.First.Span.CopyTo(array);
            Assert.Equal("Hello World", Encoding.ASCII.GetString(array));

            reader.CancelPendingRead();

            reader.Advance(buffer.End);

            var awaitable = reader.ReadAsync();

            Assert.True(awaitable.IsCompleted);

            result = await awaitable;

            Assert.True(result.IsCancelled);
        }
Beispiel #4
0
        public async Task PreservingUnownedBufferCopies()
        {
            var stream = new CallbackStream(async(s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello ");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();
            var result = await reader.ReadAsync();

            var buffer    = result.Buffer;
            var preserved = buffer.Preserve();

            // Make sure we can access the span
            EnsureSpanValid(buffer.First);
            Assert.True(buffer.First.Length > 0);
            buffer.First.Span[0] = (byte)'J';
            Assert.Equal("Jello ", Encoding.UTF8.GetString(buffer.ToArray()));

            reader.Advance(buffer.End);

            result = await reader.ReadAsync();

            Assert.True(result.IsCompleted);

            using (preserved)
            {
                // Preserved was copied, so it still contains "Hello " instead of "Jello ".
                Assert.Equal("Hello ", Encoding.UTF8.GetString(preserved.Buffer.ToArray()));
            }

            // There is currently no way to verify that OwnedArray<byte> is fully released.
        }
        public async Task NotCallingAdvanceWillCauseReadToThrow()
        {
            var stream = new CallbackStream(async(s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello");
                await sw.FlushAsync();
                await sw.WriteAsync("World");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();

            int calls = 0;

            InvalidOperationException thrown = null;

            while (true)
            {
                ReadResult     result;
                ReadableBuffer buffer;
                try
                {
                    result = await reader.ReadAsync();

                    buffer = result.Buffer;
                }
                catch (InvalidOperationException ex)
                {
                    thrown = ex;
                    break;
                }

                calls++;
                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }

                var segment = buffer.ToArray();

                var data = Encoding.UTF8.GetString(segment);
                if (calls == 1)
                {
                    Assert.Equal("Hello", data);
                }
                else
                {
                    Assert.Equal("World", data);
                }
            }
            Assert.Equal(1, calls);
            Assert.NotNull(thrown);
            Assert.Equal("Cannot Read until the previous read has been acknowledged by calling Advance", thrown.Message);
        }
        public async Task CanCancelConsumingData()
        {
            var cts    = new CancellationTokenSource();
            var stream = new CallbackStream(async(s, token) =>
            {
                var hello = Encoding.UTF8.GetBytes("Hello");
                var world = Encoding.UTF8.GetBytes("World");
                await s.WriteAsync(hello, 0, hello.Length, token);
                cts.Cancel();
                await s.WriteAsync(world, 0, world.Length, token);
            });

            var reader = stream.AsPipelineReader(cts.Token);

            int calls = 0;

            while (true)
            {
                ReadResult     result;
                ReadableBuffer buffer;
                try
                {
                    result = await reader.ReadAsync();

                    buffer = result.Buffer;
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                finally
                {
                    calls++;
                }
                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }

                var segment = buffer.ToArray();

                var data = Encoding.UTF8.GetString(segment);
                Assert.Equal("Hello", data);

                reader.Advance(buffer.End);
            }

            Assert.Equal(2, calls);
        }
        public async Task CanCancelConsumingData()
        {
            var cts = new CancellationTokenSource();
            var stream = new CallbackStream(async (s, token) =>
            {
                var hello = Encoding.UTF8.GetBytes("Hello");
                var world = Encoding.UTF8.GetBytes("World");
                await s.WriteAsync(hello, 0, hello.Length, token);
                cts.Cancel();
                await s.WriteAsync(world, 0, world.Length, token);
            });

            var reader = stream.AsPipelineReader(cts.Token);

            int calls = 0;

            while (true)
            {
                ReadResult result;
                ReadableBuffer buffer;
                try
                {
                    result = await reader.ReadAsync();
                    buffer = result.Buffer;
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                finally
                {
                    calls++;
                }
                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }

                var segment = buffer.ToArray();

                var data = Encoding.UTF8.GetString(segment);
                Assert.Equal("Hello", data);

                reader.Advance(buffer.End);
            }

            Assert.Equal(2, calls);
        }
        public async Task CanConsumeData()
        {
            var stream = new CallbackStream(async(s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello");
                await sw.FlushAsync();
                await sw.WriteAsync("World");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();

            int calls = 0;

            while (true)
            {
                var result = await reader.ReadAsync();

                var buffer = result.Buffer;
                calls++;
                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }

                var segment = buffer.ToArray();

                var data = Encoding.UTF8.GetString(segment);
                if (calls == 1)
                {
                    Assert.Equal("Hello", data);
                }
                else
                {
                    Assert.Equal("World", data);
                }

                reader.Advance(buffer.End);
            }
        }
        public async Task CanConsumeData()
        {
            var stream = new CallbackStream(async (s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello");
                await sw.FlushAsync();
                await sw.WriteAsync("World");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();

            int calls = 0;

            while (true)
            {
                var result = await reader.ReadAsync();
                var buffer = result.Buffer;
                calls++;
                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }

                var segment = buffer.ToArray();

                var data = Encoding.UTF8.GetString(segment);
                if (calls == 1)
                {
                    Assert.Equal("Hello", data);
                }
                else
                {
                    Assert.Equal("World", data);
                }

                reader.Advance(buffer.End);
            }
        }
        public async Task CancellingPendingAfterReadAsync()
        {
            var tcs    = new TaskCompletionSource <object>();
            var stream = new CallbackStream(async(s, token) =>
            {
                await tcs.Task;
                var bytes = Encoding.ASCII.GetBytes("Hello World");
                await s.WriteAsync(bytes, 0, bytes.Length);
            });

            var reader = stream.AsPipelineReader();

            var task = Task.Run(async() =>
            {
                var result = await reader.ReadAsync();
                var buffer = result.Buffer;
                reader.Advance(buffer.End);

                Assert.False(result.IsCompleted);
                Assert.True(result.IsCancelled);
                Assert.True(buffer.IsEmpty);

                tcs.TrySetResult(null);

                result = await reader.ReadAsync();
                buffer = result.Buffer;

                Assert.Equal(11, buffer.Length);
                Assert.False(result.IsCancelled);
                Assert.True(buffer.IsSingleSpan);
                var array = new byte[11];
                buffer.First.Span.CopyTo(array);
                Assert.Equal("Hello World", Encoding.ASCII.GetString(array));
            });

            await((UnownedBufferReader)reader).ReadingStarted;

            reader.CancelPendingRead();

            await task;
        }
        public async Task PreservingUnownedBufferCopies()
        {
            var stream = new CallbackStream(async(s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello ");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();

            var preserved = default(PreservedBuffer);

            while (true)
            {
                var result = await reader.ReadAsync();

                var buffer = result.Buffer;

                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }

                preserved = buffer.Preserve();

                // Make sure we can acccess the span
                var span = buffer.First.Span;

                reader.Advance(buffer.End);
            }

            using (preserved)
            {
                Assert.Equal("Hello ", Encoding.UTF8.GetString(preserved.Buffer.ToArray()));
            }

            Assert.Throws <ObjectDisposedException>(() => preserved.Buffer.First.Span);
        }
        public async Task CanConsumeLessDataThanProducedWithBufferReuse()
        {
            var stream = new CallbackStream(async(s, token) =>
            {
                var data = new byte[4096];
                Encoding.UTF8.GetBytes("Hello ", 0, 6, data, 0);
                await s.WriteAsync(data, 0, 6);
                Encoding.UTF8.GetBytes("World", 0, 5, data, 0);
                await s.WriteAsync(data, 0, 5);
            });

            var reader = stream.AsPipelineReader();

            int index   = 0;
            var message = "Hello World";

            while (index <= message.Length)
            {
                var result = await reader.ReadAsync();

                var buffer = result.Buffer;

                var ch = Encoding.UTF8.GetString(buffer.Slice(0, index).ToArray());
                Assert.Equal(message.Substring(0, index), ch);

                // Never consume, to force buffers to be copied
                reader.Advance(buffer.Start, buffer.Start.Seek(index, buffer.End));

                // Yield the task. This will ensure that we don't have any Tasks idling
                // around in UnownedBufferReader.OnCompleted
                await Task.Yield();

                index++;
            }

            Assert.Equal(message.Length + 1, index);
        }
        public async Task CancellingPendingAfterReadAsync()
        {
            var tcs = new TaskCompletionSource<object>();
            var stream = new CallbackStream(async (s, token) =>
            {
                await tcs.Task;
                var bytes = Encoding.ASCII.GetBytes("Hello World");
                await s.WriteAsync(bytes, 0, bytes.Length);
            });

            var reader = stream.AsPipelineReader();

            var task = Task.Run(async () =>
            {
                var result = await reader.ReadAsync();
                var buffer = result.Buffer;
                reader.Advance(buffer.End);

                Assert.False(result.IsCompleted);
                Assert.True(result.IsCancelled);
                Assert.True(buffer.IsEmpty);

                tcs.TrySetResult(null);

                result = await reader.ReadAsync();
                buffer = result.Buffer;

                Assert.Equal(11, buffer.Length);
                Assert.False(result.IsCancelled);
                Assert.True(buffer.IsSingleSpan);
                var array = new byte[11];
                buffer.First.Span.CopyTo(array);
                Assert.Equal("Hello World", Encoding.ASCII.GetString(array));
            });

            await ((UnownedBufferReader)reader).ReadingStarted;

            reader.CancelPendingRead();

            await task;
        }
        public async Task AccessingUnownedMemoryThrowsIfUsedAfterAdvance()
        {
            var stream = new CallbackStream(async (s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello ");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();

            var data = Memory<byte>.Empty;

            while (true)
            {
                var result = await reader.ReadAsync();
                var buffer = result.Buffer;

                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }
                data = buffer.First;
                reader.Advance(buffer.End);
            }

            Assert.Throws<ObjectDisposedException>(() => data.Span);
        }
        public async Task PreservingUnownedBufferCopies()
        {
            var stream = new CallbackStream(async (s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello ");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();

            var preserved = default(PreservedBuffer);

            while (true)
            {
                var result = await reader.ReadAsync();
                var buffer = result.Buffer;

                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }

                preserved = buffer.Preserve();

                // Make sure we can acccess the span
                var span = buffer.First.Span;

                reader.Advance(buffer.End);
            }

            using (preserved)
            {
                Assert.Equal("Hello ", Encoding.UTF8.GetString(preserved.Buffer.ToArray()));
            }

            Assert.Throws<ObjectDisposedException>(() => preserved.Buffer.First.Span);
        }
        public async Task CanConsumeLessDataThanProducedAndPreservingUnOwnedBuffers()
        {
            var stream = new CallbackStream(async (s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello ");
                await sw.FlushAsync();
                await sw.WriteAsync("World");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();

            int index = 0;
            var message = "Hello World";

            while (true)
            {
                var result = await reader.ReadAsync();
                var buffer = result.Buffer;

                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }

                using (buffer.Preserve())
                {
                    var ch = (char)buffer.First.Span[0];
                    Assert.Equal(message[index++], ch);
                    reader.Advance(buffer.Start.Seek(1));
                }
            }

            Assert.Equal(message.Length, index);
        }
        public async Task CancellingBeforeAdvance()
        {
            var stream = new CallbackStream(async (s, token) =>
            {
                var bytes = Encoding.ASCII.GetBytes("Hello World");
                await s.WriteAsync(bytes, 0, bytes.Length);
            });

            var reader = stream.AsPipelineReader();

            var result = await reader.ReadAsync();
            var buffer = result.Buffer;

            Assert.Equal(11, buffer.Length);
            Assert.False(result.IsCancelled);
            Assert.True(buffer.IsSingleSpan);
            var array = new byte[11];
            buffer.First.Span.CopyTo(array);
            Assert.Equal("Hello World", Encoding.ASCII.GetString(array));

            reader.CancelPendingRead();

            reader.Advance(buffer.End);

            var awaitable = reader.ReadAsync();

            Assert.True(awaitable.IsCompleted);

            result = await awaitable;

            Assert.True(result.IsCancelled);
        }
        public async Task NotCallingAdvanceWillCauseReadToThrow()
        {
            var stream = new CallbackStream(async (s, token) =>
            {
                var sw = new StreamWriter(s);
                await sw.WriteAsync("Hello");
                await sw.FlushAsync();
                await sw.WriteAsync("World");
                await sw.FlushAsync();
            });

            var reader = stream.AsPipelineReader();

            int calls = 0;

            InvalidOperationException thrown = null;
            while (true)
            {
                ReadResult result;
                ReadableBuffer buffer;
                try
                {
                    result = await reader.ReadAsync();
                    buffer = result.Buffer;
                }
                catch (InvalidOperationException ex)
                {
                    thrown = ex;
                    break;
                }

                calls++;
                if (buffer.IsEmpty && result.IsCompleted)
                {
                    // Done
                    break;
                }

                var segment = buffer.ToArray();

                var data = Encoding.UTF8.GetString(segment);
                if (calls == 1)
                {
                    Assert.Equal("Hello", data);
                }
                else
                {
                    Assert.Equal("World", data);
                }
            }
            Assert.Equal(1, calls);
            Assert.NotNull(thrown);
            Assert.Equal("Cannot Read until the previous read has been acknowledged by calling Advance", thrown.Message);
        }
        public async Task CanConsumeLessDataThanProducedWithBufferReuse()
        {
            var stream = new CallbackStream(async (s, token) =>
            {
                var data = new byte[4096];
                Encoding.UTF8.GetBytes("Hello ", 0, 6, data, 0);
                await s.WriteAsync(data, 0, 6);
                Encoding.UTF8.GetBytes("World", 0, 5, data, 0);
                await s.WriteAsync(data, 0, 5);
            });

            var reader = stream.AsPipelineReader();

            int index = 0;
            var message = "Hello World";

            while (index <= message.Length)
            {
                var result = await reader.ReadAsync();
                var buffer = result.Buffer;

                var ch = Encoding.UTF8.GetString(buffer.Slice(0, index).ToArray());
                Assert.Equal(message.Substring(0, index), ch);

                // Never consume, to force buffers to be copied
                reader.Advance(buffer.Start, buffer.Start.Seek(index));

                // Yield the task. This will ensure that we don't have any Tasks idling
                // around in UnownedBufferReader.OnCompleted
                await Task.Yield();

                index++;
            }

            Assert.Equal(message.Length + 1, index);
        }