1use std::collections::BTreeMap;
4use std::pin::Pin;
5use std::sync::Arc;
6
7use sva_ast::Graph;
8use sva_formula::NodeId;
9
10use super::value_graph;
11use super::world::{Reach, Reached, Walking, World};
12use super::{Render, RenderConfig, closed, driving, dropped, drove, ended, planned_over};
13use crate::cache::{Backend, Recording, Stored, Tier};
14use crate::error::EngineError;
15use crate::schedule;
16
17pub trait Abandon {
19 fn abandoned(&self) -> Pin<Box<dyn Future<Output = bool> + '_>>;
20}
21
22pub struct Never;
23
24#[derive(Default)]
26pub struct Session {
27 own: Option<World>,
28 pub(super) stand_in: Option<World>,
30}
31
32impl Abandon for Never {
33 fn abandoned(&self) -> Pin<Box<dyn Future<Output = bool> + '_>> {
34 Box::pin(std::future::ready(false))
35 }
36}
37
38pub async fn render_over<B: Backend>(
40 graph: &Graph,
41 target: &str,
42 config: RenderConfig,
43 tier: &Tier<B>,
44) -> Result<Render, EngineError> {
45 render_in(&mut Session::default(), graph, target, config, tier, &Never).await
46}
47
48pub async fn render_in<B: Backend>(
52 session: &mut Session,
53 graph: &Graph,
54 target: &str,
55 config: RenderConfig,
56 tier: &Tier<B>,
57 abandon: &dyn Abandon,
58) -> Result<Render, EngineError> {
59 let memory = tier.memory();
60 let mut recording = Recording::over(memory);
61 let Session { own, stand_in } = session;
62 let (world, root) = World::rendered(own, graph, target, config.rate)?;
63 let (instances, typed) = (&world.instances, &world.typing);
64 let id = typed
65 .id(&root)
66 .ok_or_else(|| EngineError::UnknownNode(root.clone()))?;
67 let (config, decided) = ended(typed, id, config);
68 let lowered = typed.lowered().to_vec();
69 let round = tier.begin();
70 let found = walked(world, (&root, &config), (tier, round, &mut recording)).await;
71 let tys = typed.clone();
72 if dropped(&config) && found.held.contains_key(&root) {
73 let schedule = schedule::plan(&tys, id, &config.asks);
74 let mut held = Render::shell((tys, id), (config, schedule), memory.clone());
75 let mut stats = recording.stats(memory);
76 stats.typed = lowered;
77 held.cache_stats = Some(stats);
78 return Ok(held);
79 }
80 let hits: BTreeMap<NodeId, Arc<Stored>> = found
81 .held
82 .iter()
83 .filter_map(|(path, stored)| Some((tys.id(path)?, Arc::clone(stored))))
84 .collect();
85 let mut held = planned_over(
86 (graph, target, instances),
87 (tys, id),
88 (config, &mut *stand_in, memory.clone()),
89 (decided, &hits),
90 )?;
91 let mut retyped = lowered;
92 retyped.append(&mut held.stand_in_typed);
93 if let (Some(value_graph), Some(range)) = (&mut held.value_graph, held.range) {
94 loop {
95 let mut needs = value_graph.needs(range);
96 while !needs.is_empty() {
97 let fetched = tier.fetch(&needs).await;
98 for (key, parts) in fetched.handed {
99 value_graph.took(key, &parts);
100 }
101 needs = fetched.left;
102 }
103 let short = value_graph.short((value_graph.root, range, value_graph::Past::Held));
104 if short.is_empty() {
105 break;
106 }
107 for at in short {
108 value_graph.read_on(&held.tys, at)?;
109 }
110 value_graph.settled(value_graph.root, &[], (range.start, false));
111 value_graph.refuse_endless(range)?;
112 }
113 value_graph.offers(&held.tys, range);
114 }
115 let walked = recording.stats(memory);
116 match driving(&mut held, (memory, recording))? {
117 Some(mut driver) => {
118 loop {
119 if abandon.abandoned().await {
120 return Err(EngineError::Abandoned);
121 }
122 if !driver.pull()? {
123 break;
124 }
125 let needs = driver.value_graph.needs(driver.next());
126 for (key, parts) in tier.fetch(&needs).await.handed {
127 driver.value_graph.took(key, &parts);
128 }
129 }
130 drove(&mut held, driver);
131 }
132 None => held.cache_stats = Some(walked),
133 }
134 let computed = held.value_graph.as_ref().map_or(Vec::new(), |value_graph| {
135 let computed = value_graph.values.iter();
136 let computed =
137 computed.filter(|(_, v)| !matches!(v.kind, value_graph::Kind::Resident { .. }));
138 computed.map(|(_, v)| v.name.clone()).collect()
139 });
140 if let Some(stats) = &mut held.cache_stats {
141 stats.typed = retyped;
142 stats.planned = computed;
143 stats.unslotted = held.unslotted.clone();
144 }
145 closed(&mut held)?;
146 Ok(held)
147}
148
149async fn walked<B: Backend>(
151 world: &World,
152 (root, config): (&str, &RenderConfig),
153 (tier, round, seen): (&Tier<B>, u64, &mut Recording),
154) -> Reached {
155 let walking = Walking {
156 root,
157 config,
158 whole: true,
159 };
160 loop {
161 let memory = tier.memory();
162 match world.walk(&walking, &mut |node, key| {
163 memory.answered((key, round), (node, seen))
164 }) {
165 Reach::Reached(reached) => return reached,
166 Reach::Asks(keys) => {
167 for key in keys {
168 tier.lookup(key, round).await;
169 }
170 }
171 }
172 }
173}