public TimeSliceAsyncEnumerator(TimeSliceAsyncEnumerable <TValue, TAggr> source)
 {
     _source     = source;
     _enumerator = _source._series.GetEnumerator();
     _current    = default(KeyValuePair <DateTime, TAggr>);
     _position   = TimeSlicePosition.NotStarted;
 }
            public async Task <bool> MoveNext(CancellationToken cancellationToken)
            {
                var e = _enumerator as IAsyncEnumerator <KeyValuePair <DateTime, TValue> >;

                if (e == null)
                {
                    return(false);
                }
                switch (_position)
                {
                case TimeSlicePosition.NotStarted:
                    if (await e.MoveNext(cancellationToken))
                    {
                        var slice = StartOfSlice(_enumerator.Current.Key);
                        _current  = new KeyValuePair <DateTime, TAggr>(slice, _source._initState(_enumerator.Current.Value));
                        _position = TimeSlicePosition.Aggregating;
                        goto case TimeSlicePosition.Aggregating;
                    }
                    return(false);

                case TimeSlicePosition.FinishedSync:
                case TimeSlicePosition.Aggregating:
                    var prev = _current;
                    while (await e.MoveNext(cancellationToken))
                    {
                        var slice = StartOfSlice(_enumerator.Current.Key);
                        if (slice == prev.Key)
                        {
                            _current = new KeyValuePair <DateTime, TAggr>(slice, _source._aggregator(prev.Value, _enumerator.Current.Value));
                            prev     = _current;
                        }
                        else
                        {
                            _position = TimeSlicePosition.PassedToNext;
                            return(true);
                        }
                    }
                    _position = TimeSlicePosition.FinishedAsync;
                    return(true);

                case TimeSlicePosition.PassedToNext:
                    // here we have one unused value at the current position
                {
                    var slice = StartOfSlice(_enumerator.Current.Key);
                    _current  = new KeyValuePair <DateTime, TAggr>(slice, _source._initState(_enumerator.Current.Value));
                    _position = TimeSlicePosition.Aggregating;
                    goto case TimeSlicePosition.Aggregating;
                }

                case TimeSlicePosition.FinishedAsync:
                    return(false);

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            public bool MoveNext()
            {
                switch (_position)
                {
                case TimeSlicePosition.NotStarted:
                    if (_enumerator.MoveNext())
                    {
                        var slice = StartOfSlice(_enumerator.Current.Key);
                        _current  = new KeyValuePair <DateTime, TAggr>(slice, _source._initState(_enumerator.Current.Value));
                        _position = TimeSlicePosition.Aggregating;
                        goto case TimeSlicePosition.Aggregating;
                    }
                    _position = TimeSlicePosition.FinishedSync;
                    return(false);

                case TimeSlicePosition.Aggregating:
                    var prev = _current;
                    while (_enumerator.MoveNext())
                    {
                        var slice = StartOfSlice(_enumerator.Current.Key);
                        if (slice == prev.Key)
                        {
                            _current = new KeyValuePair <DateTime, TAggr>(slice, _source._aggregator(prev.Value, _enumerator.Current.Value));
                            prev     = _current;
                        }
                        else
                        {
                            _position = TimeSlicePosition.PassedToNext;
                            return(true);
                        }
                    }
                    _position = TimeSlicePosition.FinishedSync;
                    // at least one move was OK, need to return true
                    return(true);

                case TimeSlicePosition.PassedToNext:
                    // here we have one unused value at the current position
                {
                    var slice = StartOfSlice(_enumerator.Current.Key);
                    _current  = new KeyValuePair <DateTime, TAggr>(slice, _source._initState(_enumerator.Current.Value));
                    _position = TimeSlicePosition.Aggregating;
                    goto case TimeSlicePosition.Aggregating;
                }

                case TimeSlicePosition.FinishedSync:
                    return(false);

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }