private static ProjectData ForwardPass(this ProjectData project)
        {
            var computedTasks = new HashSet <TaskId>();
            var toBeScheduled = new Queue <TaskId>(project.Tasks);

            while (toBeScheduled.Count > 0)
            {
                var taskId                  = toBeScheduled.Dequeue();
                var predecessors            = project.Get(TaskFields.PredecessorLinks, taskId);
                var allPredecessorsComputed = predecessors.All(l => computedTasks.Contains(l.PredecessorId));
                if (!allPredecessorsComputed)
                {
                    toBeScheduled.Enqueue(taskId);
                }
                else
                {
                    ComputeEarlyStartAndFinish(project, taskId, predecessors, out var earlyStart, out var earlyFinish);

                    project = project.SetRaw(TaskFields.EarlyStart, taskId, earlyStart)
                              .SetRaw(TaskFields.EarlyFinish, taskId, earlyFinish);

                    computedTasks.Add(taskId);
                }
            }

            var projectFinish = ComputeProjectFinish(project);
            var information   = project.Information.WithFinish(projectFinish);

            return(project.WithInformation(information));
        }