public void UsePartitionGenerator(IPartitionGenerator partitioner)
        {
            VerifyDisposure();

            if (HasSource)
            {
                throw new Exceptions.SourceAlreadyConfiguredException();
            }

            lock (Partitions)
            {
                PartitionGenerator = partitioner;
            }
        }
        public async Task FromAsync(Stream source, bool disposeWhenDone = false, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                VerifyDisposure();

                IPartitionGenerator partitioner = null;

                lock (Partitions)
                {
                    if (source == null)
                    {
                        throw new ArgumentNullException(nameof(source));
                    }
                    if (HasSource)
                    {
                        throw new Exceptions.MultipleSourceException();
                    }
                    HasSource   = true;
                    partitioner = this.PartitionGenerator;
                }

                if (partitioner == null)
                {
                    partitioner = PartitionGeneratorFactory.Create();
                }

                var asyncGenerator = partitioner.GenerateAsync(source, cancellationToken);
                while (await asyncGenerator.MoveNext())
                {
                    var part = asyncGenerator.Current();
                    if (part != null)
                    {
                        try
                        {
                            PartitionEditorLock.EnterWriteLock();
                            this.TotalStreamLength += part.Size;
                            this.Partitions.AddLast(part);
                        }
                        finally
                        { PartitionEditorLock.ExitWriteLock(); }

                        lock (Partitions)
                        {
                            var x = TCS_ReceivedNextPartition;
                            TCS_ReceivedNextPartition = new TaskCompletionSource <long>();
                            x.SetResult(part.Size);
                        }
                    }
                }

                SourceRead = true;
            }
            catch (TaskCanceledException tce)
            {
                lock (Partitions)
                {
                    TCS_ReceivedNextPartition.TrySetCanceled(tce.CancellationToken);
                    TCS_ReceivedLastPartition.TrySetCanceled(tce.CancellationToken);
                }
                throw;
            }
            finally
            {
                if (disposeWhenDone)
                {
                    source.Dispose();
                }

                lock (Partitions)
                {
                    if (!TCS_ReceivedNextPartition.Task.IsCanceled)
                    {
                        TCS_ReceivedNextPartition.SetResult(StreamLength);
                    }
                    if (!TCS_ReceivedLastPartition.Task.IsCanceled)
                    {
                        TCS_ReceivedLastPartition.SetResult(StreamLength);
                    }
                }
            }
        }
        public void From(Stream source, bool disposeWhenDone = false)
        {
            try
            {
                VerifyDisposure();

                IPartitionGenerator partitioner = null;

                lock (Partitions)
                {
                    if (source == null)
                    {
                        throw new ArgumentNullException(nameof(source));
                    }
                    if (HasSource)
                    {
                        throw new Exceptions.MultipleSourceException();
                    }
                    HasSource   = true;
                    partitioner = this.PartitionGenerator;
                }

                if (partitioner == null)
                {
                    partitioner = PartitionGeneratorFactory.Create();
                }

                foreach (var part in partitioner.Generate(source))
                {
                    if (part == null)
                    {
                        continue;
                    }
                    try
                    {
                        PartitionEditorLock.EnterWriteLock();
                        this.TotalStreamLength += part.Size;
                        this.Partitions.AddLast(part);
                    }
                    finally
                    { PartitionEditorLock.ExitWriteLock(); }

                    lock (Partitions)
                    {
                        var x = TCS_ReceivedNextPartition;
                        TCS_ReceivedNextPartition = new TaskCompletionSource <long>();
                        x.SetResult(part.Size);
                    }
                }

                lock (Partitions)
                {
                    SourceRead = true;
                    TCS_ReceivedNextPartition.SetResult(StreamLength);
                    TCS_ReceivedLastPartition.SetResult(StreamLength);
                }
            }
            finally
            {
                if (disposeWhenDone)
                {
                    source.Dispose();
                }
            }
        }