1use std::{
7 cell::RefCell,
8 collections::{BTreeMap, BTreeSet, HashMap, HashSet},
9};
10
11use super::Saved;
12use crate::{
13 graph::EvalStatus,
14 store::RequestView,
15 types::{ArtifactName, EvalId, RequestStatus},
16};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum Source {
21 Executed,
22 Provisional,
23 Reused,
24 Saved,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30pub enum Queue {
31 Ready,
33 Jobs,
35 Slot(crate::config::Backend),
37 Joined,
39}
40
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub enum Activity {
43 Running,
44 Human(Option<crate::types::ReviewerId>),
46 Queued(Queue),
47}
48
49#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct Waits {
53 pub artifacts: Vec<crate::types::ArtifactName>,
54 pub root: Option<(crate::types::ArtifactName, crate::types::ArtifactName)>,
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
58pub enum NotRun {
59 Dependency(Waits),
61 Budget,
62 Stale,
63 Unreviewed,
64 Absent,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub enum EvalView {
70 Done(Source),
71 Failed {
73 verdict: bool,
74 },
75 InProgress(Activity),
76 WaitingOn(Waits),
78 BlockedBy(Vec<crate::types::ArtifactName>),
80 NotRun(NotRun),
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
85pub enum Rank {
86 Failed,
87 InProgress,
88 Blocked,
89 Waiting,
90 NotRun,
91 Done,
92}
93
94impl EvalView {
95 pub fn rank(&self) -> Rank {
96 match self {
97 Self::Failed { .. } => Rank::Failed,
98 Self::InProgress(_) => Rank::InProgress,
99 Self::BlockedBy(_) => Rank::Blocked,
100 Self::WaitingOn(_) => Rank::Waiting,
101 Self::NotRun(_) => Rank::NotRun,
102 Self::Done(_) => Rank::Done,
103 }
104 }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
109pub enum Busy {
110 Running,
111 Human,
112 Queued,
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum Completion {
118 Complete,
120 InProgress(Busy),
121 Waiting {
123 blocked: bool,
124 },
125 Failed {
127 verdict: bool,
128 },
129}
130
131impl Completion {
132 pub(super) fn rank(self) -> Rank {
134 match self {
135 Self::Failed { .. } => Rank::Failed,
136 Self::InProgress(_) => Rank::InProgress,
137 Self::Waiting { .. } => Rank::Waiting,
138 Self::Complete => Rank::Done,
139 }
140 }
141}
142
143#[derive(Debug, Clone, PartialEq, Eq)]
145pub struct Upstream {
146 pub artifact: crate::types::ArtifactName,
147 pub completion: Completion,
148}
149
150pub(super) struct Index<'a> {
153 pub order: Vec<&'a ArtifactName>,
154 position: HashMap<&'a ArtifactName, usize>,
155 requests: HashMap<&'a EvalId, &'a RequestView>,
156 pub evals: BTreeMap<&'a ArtifactName, Vec<&'a EvalId>>,
157 pub upstream: BTreeMap<&'a EvalId, Vec<&'a ArtifactName>>,
159 gates: BTreeMap<&'a EvalId, Vec<&'a EvalId>>,
160 execution_order: Vec<&'a EvalId>,
161 targets: BTreeMap<&'a EvalId, &'a ArtifactName>,
162 pub peers: BTreeMap<&'a ArtifactName, Vec<&'a ArtifactName>>,
164 pub parts: BTreeMap<&'a ArtifactName, Vec<&'a ArtifactName>>,
166 pub cyclic: BTreeSet<&'a ArtifactName>,
167}
168
169type Component = crate::store::definitions::Component;
170
171fn members(component: &Component) -> Vec<&ArtifactName> {
172 component.artifacts.value().into_iter().flatten().collect()
173}
174
175impl<'a> Index<'a> {
176 pub fn new(saved: &Saved<'a>) -> Self {
177 let order = saved.artifact_ids();
178 let position: HashMap<_, _> = order
179 .iter()
180 .enumerate()
181 .map(|(index, id)| (*id, index))
182 .collect();
183 let mut requests = HashMap::new();
184 for view in saved.requests {
185 requests.entry(&view.request.eval_id).or_insert(view);
186 }
187 let definitions: HashMap<_, _> = saved
188 .eval_definitions()
189 .iter()
190 .map(|eval| (&eval.id, eval))
191 .collect();
192 let mut targets: HashMap<&ArtifactName, Vec<&EvalId>> = HashMap::new();
194 for eval in saved.eval_definitions() {
195 targets.entry(&eval.target).or_default().push(&eval.id);
196 }
197 for view in saved.requests {
198 let request = &view.request;
199 if !definitions.contains_key(&request.eval_id) {
200 let evals = targets.entry(&request.target).or_default();
201 if !evals.contains(&&request.eval_id) {
202 evals.push(&request.eval_id);
203 }
204 }
205 }
206 let evals: BTreeMap<_, _> = order
207 .iter()
208 .map(|&artifact| {
209 let mut ids = targets.remove(artifact).unwrap_or_default();
210 ids.sort_unstable();
211 (artifact, ids)
212 })
213 .collect();
214 let components = saved.components();
215 let mut peers = BTreeMap::new();
216 let mut cyclic = BTreeSet::new();
217 for component in components {
218 let mut names = members(component);
219 names.sort_unstable();
220 for &artifact in &names {
221 peers.insert(
222 artifact,
223 names.iter().copied().filter(|id| *id != artifact).collect(),
224 );
225 if component.cyclic.value() == Some(&true) {
226 cyclic.insert(artifact);
227 }
228 }
229 }
230 let targets: BTreeMap<_, _> = evals
231 .iter()
232 .flat_map(|(&target, ids)| ids.iter().map(move |&id| (id, target)))
233 .collect();
234 let inputs: BTreeMap<_, Vec<_>> = targets
236 .iter()
237 .map(|(&eval, _)| {
238 let deps: Vec<_> = definitions
239 .get(eval)
240 .and_then(|definition| definition.deps.value())
241 .map(|deps| deps.iter().collect())
242 .unwrap_or_else(|| {
243 requests
244 .get(eval)
245 .map_or(Vec::new(), |view| view.request.deps.iter().collect())
246 });
247 (eval, deps)
248 })
249 .collect();
250 let human = |eval: &EvalId| match requests.get(eval) {
251 Some(view) => view.request.profile.kind() == crate::config::ProfileKind::Human,
252 None => definitions
253 .get(eval)
254 .and_then(|definition| definition.declaration.value())
255 .and_then(|declaration| declaration.profile.value())
256 .is_some_and(|profile| {
257 matches!(profile.known, crate::config::StoredProfile::Human { .. })
258 }),
259 };
260 let schedule =
261 crate::graph::schedule::Schedule::new(targets.iter().map(|(&eval, &target)| {
262 crate::graph::schedule::Input {
263 id: eval,
264 target,
265 deps: inputs[eval].clone(),
266 human: human(eval),
267 }
268 }));
269 let upstream = inputs
270 .into_iter()
271 .map(|(eval, mut deps)| {
272 deps.extend(schedule.gates[eval].iter().map(|gate| targets[gate]));
273 let mut deps: Vec<_> = deps
274 .into_iter()
275 .collect::<BTreeSet<_>>()
276 .into_iter()
277 .collect();
278 deps.sort_by_key(|id| position.get(id).copied().unwrap_or(usize::MAX));
279 (eval, deps)
280 })
281 .collect();
282 let execution_order = schedule.order;
283 Self {
284 order,
285 position,
286 requests,
287 evals,
288 upstream,
289 gates: schedule.gates,
290 execution_order,
291 targets,
292 peers,
293 parts: saved.parts(),
294 cyclic,
295 }
296 }
297}
298
299pub(super) struct States<'a> {
301 run: &'a crate::store::Run,
302 #[cfg(any(test, feature = "test-support"))]
303 pub derivations: std::cell::Cell<usize>,
304 pub index: Index<'a>,
305 pub running: bool,
306 views: RefCell<HashMap<&'a EvalId, Option<EvalView>>>,
307 effective: RefCell<HashMap<&'a EvalId, Option<EvalStatus>>>,
308 completions: RefCell<HashMap<&'a ArtifactName, Completion>>,
309 waits: RefCell<HashMap<&'a ArtifactName, Vec<ArtifactName>>>,
310 held: HashMap<&'a EvalId, bool>,
311}
312
313impl<'a> States<'a> {
314 pub fn new(saved: &Saved<'a>) -> Self {
317 let run = &saved.run.run;
318 let mut states = Self {
319 run,
320 #[cfg(any(test, feature = "test-support"))]
321 derivations: std::cell::Cell::new(0),
322 index: Index::new(saved),
323 running: run.status().is_open(),
324 views: RefCell::new(HashMap::new()),
325 effective: RefCell::new(HashMap::new()),
326 completions: RefCell::new(HashMap::new()),
327 waits: RefCell::new(HashMap::new()),
328 held: HashMap::new(),
329 };
330 for &eval in &states.index.execution_order {
331 states.effective(eval);
332 let held = states.index.gates[eval].iter().any(|&gate| {
333 matches!(
334 states.effective(gate),
335 EvalStatus::Red | EvalStatus::Blocked | EvalStatus::Error
336 ) || states.held[gate]
337 });
338 states.held.insert(eval, held);
339 }
340 for artifact in states.upstream_first() {
341 states.completion(artifact);
342 states.waits_of(artifact);
343 }
344 states
345 }
346
347 fn upstream_first(&self) -> Vec<&'a ArtifactName> {
350 let mut done = HashSet::new();
351 let mut seen = HashSet::new();
352 let mut ordered = Vec::with_capacity(self.index.order.len());
353 for &start in &self.index.order {
354 if !seen.insert(start) {
355 continue;
356 }
357 let mut stack = vec![(start, self.dependencies(start), 0)];
358 while let Some((artifact, dependencies, next)) = stack.last_mut() {
359 if let Some(&dependency) = dependencies.get(*next) {
360 *next += 1;
361 if seen.insert(dependency) {
362 let dependencies = self.dependencies(dependency);
363 stack.push((dependency, dependencies, 0));
364 }
365 } else {
366 if done.insert(*artifact) {
367 ordered.push(*artifact);
368 }
369 stack.pop();
370 }
371 }
372 }
373 ordered
374 }
375
376 fn dependencies(&self, artifact: &ArtifactName) -> Vec<&'a ArtifactName> {
377 let mut dependencies: Vec<&'a ArtifactName> = Vec::new();
378 for eval in self.evals(artifact) {
379 for &upstream in self.upstream(eval) {
380 if !dependencies.contains(&upstream) {
381 dependencies.push(upstream);
382 }
383 }
384 }
385 dependencies
386 }
387
388 fn key(&self, artifact: &ArtifactName) -> Option<&'a ArtifactName> {
390 self.index
391 .position
392 .get_key_value(artifact)
393 .map(|(&id, _)| id)
394 }
395
396 pub fn request(&self, eval: &EvalId) -> Option<&'a RequestView> {
397 self.index.requests.get(eval).copied()
398 }
399
400 fn outside(&self, eval: &EvalId) -> Option<RequestStatus> {
403 if let Some(status) = self.run.evidence.get(eval) {
404 return Some(*status);
405 }
406 let saved = self.run.validation.snapshot()?.evals.value()?;
407 let status = *saved
408 .iter()
409 .find(|saved| &saved.id == eval)?
410 .status
411 .value()?;
412 matches!(
413 status,
414 RequestStatus::Green | RequestStatus::Red | RequestStatus::Error | RequestStatus::Stale
415 )
416 .then_some(status)
417 }
418
419 pub fn evals(&self, artifact: &ArtifactName) -> &[&'a EvalId] {
420 self.index.evals.get(artifact).map_or(&[], Vec::as_slice)
421 }
422
423 pub fn upstream(&self, eval: &EvalId) -> &[&'a ArtifactName] {
424 self.index.upstream.get(eval).map_or(&[], Vec::as_slice)
425 }
426
427 fn position(&self, artifact: &ArtifactName) -> usize {
428 self.index
429 .position
430 .get(artifact)
431 .copied()
432 .unwrap_or(usize::MAX)
433 }
434
435 pub fn view(&self, eval: &'a EvalId) -> EvalView {
436 if let Some(view) = self.views.borrow().get(eval) {
437 return view.clone().unwrap_or(EvalView::NotRun(NotRun::Unreviewed));
439 }
440 self.views.borrow_mut().insert(eval, None);
441 #[cfg(any(test, feature = "test-support"))]
442 self.derivations.set(self.derivations.get() + 1);
443 let view = self.derive(eval);
444 self.views.borrow_mut().insert(eval, Some(view.clone()));
445 view
446 }
447
448 pub fn effective(&self, eval: &'a EvalId) -> EvalStatus {
451 if let Some(status) = self.effective.borrow().get(eval) {
452 return status.unwrap_or(EvalStatus::Wait);
454 }
455 self.effective.borrow_mut().insert(eval, None);
456 #[cfg(any(test, feature = "test-support"))]
457 self.derivations.set(self.derivations.get() + 1);
458 let status = self.evaluate(eval);
459 self.effective.borrow_mut().insert(eval, Some(status));
460 status
461 }
462
463 fn evaluate(&self, eval: &'a EvalId) -> EvalStatus {
466 let request = self.request(eval).map(|view| &view.request);
467 let status = request
468 .map(|request| request.status())
469 .or_else(|| self.outside(eval));
470 let unmet: Vec<_> = self
471 .index
472 .gates
473 .get(eval)
474 .into_iter()
475 .flatten()
476 .map(|&gate| (gate, self.effective(gate)))
477 .filter(|(_, status)| !status.passes_gate())
478 .collect();
479 if unmet
480 .iter()
481 .any(|&(gate, status)| self.status_blocks(eval, gate, status))
482 {
483 return EvalStatus::Blocked;
484 }
485 if !unmet.is_empty() {
486 return EvalStatus::Wait;
487 }
488 match status {
489 Some(RequestStatus::Deferred) => EvalStatus::Deferred,
490 Some(RequestStatus::Provisional) if self.pending(eval).is_empty() => EvalStatus::Green,
492 Some(RequestStatus::Provisional) => EvalStatus::Provisional,
493 Some(RequestStatus::Green) => EvalStatus::Green,
494 Some(RequestStatus::Red) => EvalStatus::Red,
495 Some(RequestStatus::Error) => EvalStatus::Error,
496 Some(RequestStatus::Stale) => EvalStatus::Stale,
497 _ => EvalStatus::Unreviewed,
498 }
499 }
500
501 fn met(&self, artifact: &ArtifactName) -> bool {
502 self.evals(artifact)
503 .iter()
504 .all(|eval| self.effective(eval) == EvalStatus::Green)
505 }
506
507 fn derive(&self, eval: &'a EvalId) -> EvalView {
508 let Some(view) = self.request(eval) else {
509 return match self.outside(eval) {
511 Some(RequestStatus::Green) => EvalView::Done(Source::Saved),
512 Some(RequestStatus::Red) => EvalView::Failed { verdict: true },
513 Some(RequestStatus::Error) => EvalView::Failed { verdict: false },
514 Some(RequestStatus::Stale) => EvalView::NotRun(NotRun::Stale),
515 _ => EvalView::NotRun(NotRun::Absent),
516 };
517 };
518 let request = &view.request;
519 match request.status() {
520 RequestStatus::Provisional if self.effective(eval) == EvalStatus::Provisional => {
521 EvalView::Done(Source::Provisional)
522 }
523 RequestStatus::Provisional | RequestStatus::Green => {
524 EvalView::Done(if crate::query::reused(request) {
525 Source::Reused
526 } else {
527 Source::Executed
528 })
529 }
530 RequestStatus::Red => EvalView::Failed { verdict: true },
531 RequestStatus::Error => EvalView::Failed { verdict: false },
532 RequestStatus::Running => EvalView::InProgress(Activity::Running),
533 RequestStatus::WaitingHuman | RequestStatus::Deferred => EvalView::InProgress(
534 Activity::Human(view.claim.as_ref().map(|claim| claim.reviewer.clone())),
535 ),
536 RequestStatus::BudgetExhausted => EvalView::NotRun(NotRun::Budget),
537 RequestStatus::Stale => EvalView::NotRun(NotRun::Stale),
538 RequestStatus::Queued
539 | RequestStatus::WaitDependency
540 | RequestStatus::Unreviewed
541 | RequestStatus::Blocked => {
542 let unmet = self.unmet(eval);
543 let blocking: Vec<_> = unmet
544 .iter()
545 .filter(|artifact| self.gate_blocks(eval, artifact))
546 .cloned()
547 .collect();
548 if !blocking.is_empty() {
549 return EvalView::BlockedBy(blocking);
550 }
551 if self.run.modes.speculate {
552 return self.ready(view);
553 }
554 if !unmet.is_empty() {
555 let waits = Waits {
556 root: self.root(&unmet),
557 artifacts: unmet,
558 };
559 return if self.running {
560 EvalView::WaitingOn(waits)
561 } else {
562 EvalView::NotRun(NotRun::Dependency(waits))
563 };
564 }
565 self.ready(view)
566 }
567 }
568 }
569
570 fn ready(&self, view: &RequestView) -> EvalView {
572 let request = &view.request;
573 if !self.running || request.status() != RequestStatus::Queued {
574 return EvalView::NotRun(NotRun::Unreviewed);
575 }
576 EvalView::InProgress(Activity::Queued(
577 if let Some(crate::store::QueueReason::Slot { backend }) = request.queue.clone() {
578 Queue::Slot(backend)
579 } else if request.execution_id.is_some() {
580 Queue::Joined
581 } else if self.run.jobs.is_some() {
582 Queue::Jobs
583 } else {
584 Queue::Ready
585 },
586 ))
587 }
588
589 fn pending(&self, eval: &EvalId) -> Vec<ArtifactName> {
592 let mut artifacts: Vec<_> = self
593 .index
594 .gates
595 .get(eval)
596 .into_iter()
597 .flatten()
598 .filter(|&&gate| {
599 matches!(
600 self.effective(gate),
601 EvalStatus::Deferred | EvalStatus::Provisional
602 )
603 })
604 .map(|gate| self.index.targets[gate])
605 .collect::<BTreeSet<_>>()
606 .into_iter()
607 .collect();
608 artifacts
609 .sort_by_key(|artifact| (self.completion(artifact).rank(), self.position(artifact)));
610 artifacts.into_iter().cloned().collect()
611 }
612
613 fn unmet(&self, eval: &EvalId) -> Vec<ArtifactName> {
615 let mut artifacts: Vec<_> = self
616 .index
617 .gates
618 .get(eval)
619 .into_iter()
620 .flatten()
621 .filter(|&&gate| !self.effective(gate).passes_gate())
622 .map(|gate| self.index.targets[gate])
623 .collect::<BTreeSet<_>>()
624 .into_iter()
625 .collect();
626 artifacts
627 .sort_by_key(|artifact| (self.completion(artifact).rank(), self.position(artifact)));
628 artifacts.into_iter().cloned().collect()
629 }
630
631 fn views_of(&self, artifact: &ArtifactName) -> Vec<EvalView> {
632 self.evals(artifact)
633 .iter()
634 .map(|eval| self.view(eval))
635 .collect()
636 }
637
638 pub fn completion(&self, artifact: &ArtifactName) -> Completion {
641 if let Some(completion) = self.completions.borrow().get(artifact) {
642 return *completion;
643 }
644 let own = self.own_completion(artifact);
645 let completion = self
646 .index
647 .parts
648 .get(artifact)
649 .into_iter()
650 .flatten()
651 .map(|part| self.completion(part))
652 .chain([own])
653 .min_by_key(|completion| match completion {
654 Completion::Failed { verdict } => (completion.rank(), *verdict),
655 _ => (completion.rank(), true),
656 })
657 .expect("its own completion");
658 if let Some(id) = self.key(artifact) {
659 self.completions.borrow_mut().insert(id, completion);
660 }
661 completion
662 }
663
664 fn own_completion(&self, artifact: &ArtifactName) -> Completion {
665 let views = self.views_of(artifact);
666 let busy = views
667 .iter()
668 .filter_map(|view| match view {
669 EvalView::InProgress(Activity::Running) => Some(Busy::Running),
670 EvalView::InProgress(Activity::Human(_)) => Some(Busy::Human),
671 EvalView::InProgress(Activity::Queued(_)) => Some(Busy::Queued),
672 _ => None,
673 })
674 .min();
675 if views
676 .iter()
677 .any(|view| matches!(view, EvalView::Failed { .. }))
678 {
679 Completion::Failed {
681 verdict: !views.contains(&EvalView::Failed { verdict: false }),
682 }
683 } else if let Some(busy) = busy {
684 Completion::InProgress(busy)
685 } else if views.iter().any(|view| !matches!(view, EvalView::Done(_))) || !self.met(artifact)
686 {
687 Completion::Waiting {
688 blocked: self.blocks(artifact)
689 || views
690 .iter()
691 .any(|view| matches!(view, EvalView::BlockedBy(_))),
692 }
693 } else {
694 Completion::Complete
695 }
696 }
697
698 fn gate_blocks(&self, eval: &EvalId, artifact: &ArtifactName) -> bool {
700 self.index
701 .gates
702 .get(eval)
703 .into_iter()
704 .flatten()
705 .filter(|gate| self.index.targets[*gate] == artifact)
706 .any(|&gate| self.status_blocks(eval, gate, self.effective(gate)))
707 }
708
709 fn status_blocks(&self, eval: &EvalId, gate: &EvalId, status: EvalStatus) -> bool {
712 match status {
713 EvalStatus::Red | EvalStatus::Blocked => true,
714 EvalStatus::Error => {
715 self.run.modes.speculate
716 || self.index.targets.get(gate) == self.index.targets.get(eval)
717 }
718 _ => false,
719 }
720 }
721
722 pub fn held_for_run(&self, eval: &EvalId) -> bool {
725 self.held.get(eval).copied().unwrap_or(false)
726 }
727
728 fn blocks(&self, artifact: &ArtifactName) -> bool {
730 self.evals(artifact).iter().any(|eval| {
731 matches!(self.effective(eval), EvalStatus::Red | EvalStatus::Blocked)
732 || (self.run.modes.speculate && self.effective(eval) == EvalStatus::Error)
733 })
734 }
735
736 fn held(&self, artifact: &ArtifactName, blocked: bool) -> Vec<crate::types::ArtifactName> {
738 let mut x: Vec<crate::types::ArtifactName> = Vec::new();
739 for &eval in self.evals(artifact) {
740 let wanted = if blocked {
741 EvalStatus::Blocked
742 } else {
743 EvalStatus::Wait
744 };
745 if matches!(self.view(eval), EvalView::Done(_)) && self.effective(eval) == wanted {
746 for id in self.unmet(eval) {
747 if (!blocked || self.gate_blocks(eval, &id)) && !x.contains(&id) {
748 x.push(id);
749 }
750 }
751 }
752 if !blocked && self.effective(eval) == EvalStatus::Provisional {
754 for id in self.pending(eval) {
755 if !x.contains(&id) {
756 x.push(id);
757 }
758 }
759 }
760 }
761 x
762 }
763
764 pub fn waits_of(&self, artifact: &ArtifactName) -> Vec<crate::types::ArtifactName> {
766 if let Some(x) = self.waits.borrow().get(artifact) {
767 return x.clone();
768 }
769 let mut x = self.held(artifact, false);
770 for view in self.views_of(artifact) {
771 if let EvalView::WaitingOn(waits) | EvalView::NotRun(NotRun::Dependency(waits)) = view {
772 for id in waits.artifacts {
773 if !x.contains(&id) {
774 x.push(id);
775 }
776 }
777 }
778 }
779 x.sort_by_key(|id| (self.completion(id).rank(), self.position(id)));
780 if let Some(id) = self.key(artifact) {
781 self.waits.borrow_mut().insert(id, x.clone());
782 }
783 x
784 }
785
786 pub fn blockers_of(&self, artifact: &ArtifactName) -> Vec<crate::types::ArtifactName> {
788 let mut x = self.held(artifact, true);
789 for view in self.views_of(artifact) {
790 if let EvalView::BlockedBy(blockers) = view {
791 for id in blockers {
792 if !x.contains(&id) {
793 x.push(id);
794 }
795 }
796 }
797 }
798 x
799 }
800
801 fn root(
803 &self,
804 x: &[crate::types::ArtifactName],
805 ) -> Option<(crate::types::ArtifactName, crate::types::ArtifactName)> {
806 if x.iter()
807 .any(|id| !matches!(self.completion(id), Completion::Waiting { blocked: false }))
808 {
809 return None;
810 }
811 let via = x.first()?.clone();
812 let cause = self.waits_of(&via).into_iter().next()?;
813 Some((via, cause))
814 }
815
816 pub fn upstream_states(&self, eval: &EvalId) -> Vec<Upstream> {
818 let mut upstream: Vec<_> = self
819 .upstream(eval)
820 .iter()
821 .map(|artifact| Upstream {
822 artifact: (*artifact).clone(),
823 completion: self.completion(artifact),
824 })
825 .collect();
826 upstream.sort_by_key(|upstream| {
827 (
828 upstream.completion.rank(),
829 self.position(&upstream.artifact),
830 )
831 });
832 upstream
833 }
834}