Skip to main content

sva_engine/render/
session.rs

1// Concern: what a session's renders last typed, retyping only what changed since and its readers | Non-concern: lowering a node (typing/), memory (cache/) | IO: (Instances, Order) -> Typing
2
3use std::collections::{BTreeMap, BTreeSet};
4
5use crate::error::EngineError;
6use crate::instantiate::{Instances, Resolution};
7use crate::schedule::Order;
8use crate::typing::Typing;
9
10/// Renders made in turn: each types only what changed since the last, and what reads it.
11#[derive(Default)]
12pub struct Session {
13    pub(super) own: Typed,
14    /// The composition with every volatile parameter at its stand-in.
15    pub(super) stand_in: Typed,
16}
17
18#[derive(Default)]
19pub(crate) struct Typed {
20    held: Option<Held>,
21}
22
23struct Held {
24    rate: u32,
25    typed: BTreeMap<String, Resolution>,
26    typing: Typing,
27}
28
29impl Typed {
30    /// On a refusal it holds what it held.
31    pub(crate) fn typed(
32        &mut self,
33        instances: &Instances,
34        order: &Order,
35    ) -> Result<&Typing, EngineError> {
36        let rate = instances.rate();
37        let held = match self.held.take() {
38            Some(held) if held.rate == rate => held,
39            _ => Held {
40                rate,
41                typed: BTreeMap::new(),
42                typing: Typing::default(),
43            },
44        };
45        let held = self.held.insert(held);
46        let now: BTreeMap<String, Resolution> = instances
47            .paths()
48            .filter_map(|path| Some((path.to_string(), instances.resolution(path)?)))
49            .collect();
50        let changed = now
51            .iter()
52            .filter(|(path, now)| held.typed.get(*path) != Some(now))
53            .map(|(path, _)| path.clone());
54        let region = upward(instances, changed.collect());
55        let groups: Vec<Vec<String>> = order
56            .groups
57            .iter()
58            .filter(|group| group.iter().any(|path| region.contains(path)))
59            .cloned()
60            .collect();
61        if let Err(refused) = held.typing.lower(instances, &groups) {
62            held.typing.abort();
63            return Err(refused);
64        }
65        let gone = held.typed.keys().filter(|path| !now.contains_key(*path));
66        held.typing.hide(gone.cloned().collect::<Vec<_>>());
67        held.typing.commit(instances);
68        held.typed = now;
69        Ok(&held.typing)
70    }
71}
72
73fn upward(instances: &Instances, changed: BTreeSet<String>) -> BTreeSet<String> {
74    let mut region = changed;
75    let mut open: Vec<String> = region.iter().cloned().collect();
76    while let Some(at) = open.pop() {
77        for reader in instances.readers(&at) {
78            if region.insert(reader.to_string()) {
79                open.push(reader.to_string());
80            }
81        }
82    }
83    region
84}