1use std::collections::{BTreeMap, BTreeSet};
4
5use sva_ast::Graph;
6use sva_formula::{Hash, NodeId};
7
8use super::offer::{Offers, readable};
9use super::table::{self, Table};
10use super::{Render, RenderConfig, closed, driving, dropped, drove, frontier, planned_over};
11use crate::cache::{Backend, Recording, Tier};
12use crate::error::EngineError;
13use crate::instantiate;
14use crate::schedule;
15use crate::typing;
16
17pub async fn render_over<B: Backend>(
21 graph: &Graph,
22 target: &str,
23 config: RenderConfig,
24 tier: &Tier<B>,
25) -> Result<Render, EngineError> {
26 let round = tier.begin();
27 let mut recording = Recording::over(tier.memory());
28 let instances = instantiate::instantiate(graph, target, config.rate)?;
29 let root = instances.instance_of(target)?;
30 let order = schedule::schedule_from(&instances, std::slice::from_ref(&root))?;
31 let keys = keys(graph, &instances, &order, &config);
32 let mut found = frontier::Frontier::from((&instances, &order), &keys, &root, &config);
33 found.walked(tier, round).await;
34 if dropped(&config) && found.stored.contains_key(&root) {
35 recording.found(std::mem::take(&mut found.lookups));
36 let tys = typing::infer_over(&instances, &order.within(&found.visited), &found.stored)?;
37 let id = tys.id(&root).ok_or(EngineError::UnknownNode(root))?;
38 let schedule = schedule::plan(&tys, id, &config.asks);
39 let mut held = Render::shell(tys, id, config, schedule);
40 held.cache_stats = Some(recording.stats());
41 return Ok(held);
42 }
43 let (mut held, typed) = loop {
44 found.walked(tier, round).await;
45 let tys = typing::infer_over(&instances, &order.within(&found.visited), &found.stored)?;
46 let id = tys
47 .id(&root)
48 .ok_or_else(|| EngineError::UnknownNode(root.clone()))?;
49 let bounds: BTreeSet<NodeId> = keys
50 .keys()
51 .filter_map(|path| tys.id(path))
52 .filter(|id| readable(&tys, *id))
53 .collect();
54 let typed = tys.lowered().to_vec();
55 let mut held = planned_over(&instances, (tys, id), config.clone(), &bounds)?;
56 let short = match (&mut held.table, held.range) {
57 (Some(table), Some(range)) => {
58 let mut needs = table.needs(range);
59 while !needs.is_empty() {
60 let fetched = tier.fetch(&needs).await;
61 for (key, parts) in fetched.handed {
62 table.took(key, &parts);
63 }
64 needs = fetched.left;
65 }
66 short(table, range)
67 }
68 _ => Vec::new(),
69 };
70 if short.is_empty() {
71 break (held, typed);
72 }
73 for path in short {
74 found.reopen(&path);
75 }
76 };
77 let mut offers = Offers::of(&mut held, (&keys, &found), tier.memory());
78 recording.found(std::mem::take(&mut found.lookups));
79 let walked = recording.stats();
80 match driving(&mut held, recording)? {
81 Some(mut driver) => {
82 while driver.pull()? {
83 offers.whole(&driver.table, tier.memory());
84 let needs = driver.table.needs(driver.next());
85 for (key, parts) in tier.fetch(&needs).await.handed {
86 driver.table.took(key, &parts);
87 }
88 }
89 offers.rest(&driver.table, tier.memory());
90 drove(&mut held, driver);
91 }
92 None => held.cache_stats = Some(walked),
93 }
94 let computed = held.table.as_ref().map_or(Vec::new(), |table| {
95 let computed = table.values.iter();
96 let computed = computed.filter(|(_, v)| !matches!(v.kind, table::Kind::Resident { .. }));
97 computed.map(|(_, v)| v.name.clone()).collect()
98 });
99 if let Some(stats) = &mut held.cache_stats {
100 stats.typed = typed;
101 stats.planned = computed;
102 }
103 closed(&mut held)?;
104 Ok(held)
105}
106
107pub(crate) fn keys(
109 graph: &Graph,
110 instances: &instantiate::Instances,
111 order: &schedule::Order,
112 config: &RenderConfig,
113) -> BTreeMap<String, Hash> {
114 crate::source::identities(graph, instances, order)
115 .into_iter()
116 .map(|(path, identity)| {
117 let key = crate::cache::node_key(identity, config.rate, &config.profile);
118 (path, key)
119 })
120 .collect()
121}
122
123fn short(table: &Table, range: sva_samples::Extent) -> Vec<String> {
125 let needs = table.demand(range);
126 table
127 .values
128 .iter()
129 .filter(|(at, value)| {
130 matches!(value.kind, table::Kind::Resident { .. }) && !needs[*at].compute.is_empty()
131 })
132 .map(|(_, value)| value.name.clone())
133 .collect()
134}