/// <summary>
 /// Helper method to try to read next character from <typeparamref name="TSource"/>, or throw if no more characters can be read.
 /// </summary>
 /// <typeparam name="TValue">The type of values that this reader produces.</typeparam>
 /// <typeparam name="TSource">The type of the source of this <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/>.</typeparam>
 /// <param name="reader">This <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/>.</param>
 /// <param name="source">The <typeparamref name="TSource"/> to read from.</param>
 /// <returns>A task which will return character read.</returns>
 /// <exception cref="NullReferenceException">If this <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/> is <c>null</c>.</exception>
 /// <exception cref="EndOfStreamException">If no more characters could be read from the source.</exception>
 public static async ValueTask <TValue> ReadNextAsync <TValue, TSource>(
     this PotentiallyAsyncReaderLogic <TValue?, TSource> reader,
     TSource source
     )
     where TValue : struct
 {
     return(await ArgumentValidator.ValidateNotNullReference(reader).TryReadNextAsync(source) ?? throw new EndOfStreamException());
 }
 /// <summary>
 /// Creates a new instance of <see cref="BoundPeekablePotentiallyAsyncReader{TValue, TSource}"/> with given reader and source.
 /// </summary>
 /// <param name="reader">The <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/>.</param>
 /// <param name="source">The source for <paramref name="reader"/>.</param>
 /// <exception cref="ArgumentNullException">If <paramref name="reader"/> is <c>null</c>.</exception>
 internal BoundPeekablePotentiallyAsyncReader(
     PotentiallyAsyncReaderLogic <TValue, TSource> reader,
     TSource source
     )
 {
     this.Reader = ArgumentValidator.ValidateNotNull(nameof(reader), reader);
     this.Source = source;
 }
 /// <summary>
 /// Helper method to try to read next value from <typeparamref name="TSource"/>, or throw if no more values can be read.
 /// </summary>
 /// <typeparam name="TValue">The type of values that this reader produces.</typeparam>
 /// <typeparam name="TSource">The type of the source of this <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/>.</typeparam>
 /// <param name="reader">This <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/>.</param>
 /// <param name="source">The <typeparamref name="TSource"/> to read from.</param>
 /// <param name="checker">Optional callback to check value. If it is supplied, this method will keep reading values until this callback returns <c>true</c>.</param>
 /// <returns>A task which will return last value read.</returns>
 /// <exception cref="NullReferenceException">If this <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/> is <c>null</c>.</exception>
 /// <exception cref="EndOfStreamException">If no more values could be read from the source.</exception>
 public static async ValueTask <TValue> ReadUntilAsync <TValue, TSource>(
     this PotentiallyAsyncReaderLogic <TValue?, TSource> reader,
     TSource source,
     Func <TValue, Boolean> checker
     )
     where TValue : struct
 {
     return(await reader.TryReadUntilAsync(source, checker) ?? throw new EndOfStreamException());
 }
 /// <summary>
 /// Creates new <see cref="BoundPeekablePotentiallyAsyncReader{TValue, TSource}"/> which reads nullable struct values.
 /// </summary>
 /// <param name="reader">The underlying <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/>.</param>
 /// <param name="source">The source to use with <paramref name="reader"/>.</param>
 /// <typeparam name="TValue">The struct type to read.</typeparam>
 /// <typeparam name="TSource">The source from which to read.</typeparam>
 /// <returns>A new <see cref="BoundPeekablePotentiallyAsyncReader{TValue, TSource}"/> which reads nullable struct values.</returns>
 /// <exception cref="ArgumentNullException">If <paramref name="reader"/> is <c>null</c>.</exception>
 public static BoundPeekablePotentiallyAsyncReader <TValue?, TSource> NewNullablePeekableValueReader <TValue, TSource>(
     PotentiallyAsyncReaderLogic <TValue?, TSource> reader,
     TSource source
     )
     where TValue : struct
 {
     return(new BoundPeekablePotentiallyAsyncReader <TValue?, TSource>(
                reader,
                source
                ));
 }
 internal BoundMemorizingPotentiallyAsyncReader(
     PotentiallyAsyncReaderLogic <TValue, TSource> reader,
     TSource source,
     ResizableArray <TBufferItem> buffer,
     Func <TValue, TBufferItem> transform,
     Func <TBufferItem, TValue> transformBack
     )
 {
     this.Reader         = ArgumentValidator.ValidateNotNull(nameof(reader), reader);
     this.Source         = source;
     this._buffer        = buffer ?? new ResizableArray <TBufferItem>();
     this._transform     = ArgumentValidator.ValidateNotNull(nameof(transform), transform);
     this._transformBack = ArgumentValidator.ValidateNotNull(nameof(transformBack), transformBack);
 }
 /// <summary>
 /// Creates new <see cref="BoundMemorizingPotentiallyAsyncReader{TValue, TBufferItem, TSource}"/> which reads nullable struct values.
 /// </summary>
 /// <param name="reader">The underlying <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/>.</param>
 /// <param name="source">The source to use with <paramref name="reader"/>.</param>
 /// <param name="buffer">The optional existing buffer to use.</param>
 /// <typeparam name="TValue">The struct type to read.</typeparam>
 /// <typeparam name="TSource">The source from which to read.</typeparam>
 /// <returns>A new <see cref="BoundMemorizingPotentiallyAsyncReader{TValue, TBuffer, TSource}"/> which reads nullable struct values.</returns>
 /// <exception cref="ArgumentNullException">If <paramref name="reader"/> is <c>null</c>.</exception>
 public static BoundMemorizingPotentiallyAsyncReader <TValue?, TValue, TSource> NewNullableMemorizingValueReader <TValue, TSource>(
     PotentiallyAsyncReaderLogic <TValue?, TSource> reader,
     TSource source,
     ResizableArray <TValue> buffer = null
     )
     where TValue : struct
 {
     return(new BoundMemorizingPotentiallyAsyncReader <TValue?, TValue, TSource>(
                reader,
                source,
                buffer,
                nullable => nullable.Value,
                existing => existing
                ));
 }
    /// <summary>
    /// Helper method to try to read next value from <typeparamref name="TSource"/> until suitable value has been read, or values will end.
    /// </summary>
    /// <typeparam name="TValue">The type of values that this reader produces.</typeparam>
    /// <typeparam name="TSource">The type of the source of this <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/>.</typeparam>
    /// <param name="reader">This <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/>.</param>
    /// <param name="source">The <typeparamref name="TSource"/> to read from.</param>
    /// <param name="checker">Optional callback to check value. If it is supplied, this method will keep reading values until this callback returns <c>true</c>.</param>
    /// <returns>A task which will return last value read.</returns>
    /// <exception cref="NullReferenceException">If this <see cref="PotentiallyAsyncReaderLogic{TValue, TSource}"/> is <c>null</c>.</exception>
    public static async ValueTask <TValue?> TryReadUntilAsync <TValue, TSource>(
        this PotentiallyAsyncReaderLogic <TValue?, TSource> reader,
        TSource source,
        Func <TValue, Boolean> checker
        )
        where TValue : struct
    {
        ArgumentValidator.ValidateNotNullReference(reader);
        TValue?charRead;

        do
        {
            charRead = await reader.TryReadNextAsync(source);
        } while (charRead.HasValue && !(checker?.Invoke(charRead.Value) ?? true));

        return(charRead);
    }