motion_content/vector/
deferred.rs1use super::{VectorTree, WriteOptions};
4use motion_core::sync::MutexExt;
5use motion_core::{Node, ValidationError};
6use std::{
7 collections::{BTreeMap, BTreeSet},
8 sync::{Arc, Mutex},
9};
10
11const MAX_SLOTS: usize = 8;
13
14pub struct CompileCache<K, V> {
21 key: Arc<K>,
22 slots: Arc<Mutex<BTreeMap<u64, V>>>,
23}
24
25impl<K, V> Clone for CompileCache<K, V> {
26 fn clone(&self) -> Self {
27 Self {
28 key: self.key.clone(),
29 slots: self.slots.clone(),
30 }
31 }
32}
33
34impl<K: std::fmt::Debug, V> std::fmt::Debug for CompileCache<K, V> {
35 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 formatter
37 .debug_struct("CompileCache")
38 .field("key", &self.key)
39 .finish_non_exhaustive()
40 }
41}
42
43impl<K, V: Clone> CompileCache<K, V> {
44 pub fn new(key: K) -> Self {
46 Self {
47 key: Arc::new(key),
48 slots: Arc::default(),
49 }
50 }
51
52 pub fn key(&self) -> &K {
54 &self.key
55 }
56
57 pub fn shares(&self, other: &Self) -> bool {
59 Arc::ptr_eq(&self.slots, &other.slots)
60 }
61
62 pub fn is_compiled(&self) -> bool {
64 !self.slots.lock_unpoisoned().is_empty()
65 }
66
67 pub fn get_or_compile(&self, variant: u64, compile: impl FnOnce(&K) -> V) -> V {
71 let mut slots = self.slots.lock_unpoisoned();
72 if let Some(result) = slots.get(&variant) {
73 return result.clone();
74 }
75 let result = compile(&self.key);
76 if slots.len() >= MAX_SLOTS {
77 slots.clear();
78 }
79 slots.insert(variant, result.clone());
80 result
81 }
82}
83
84impl<K: Clone + PartialEq, V: Clone> CompileCache<K, V> {
85 pub fn map_key(&self, change: impl FnOnce(&mut K)) -> Self {
88 let mut key = (*self.key).clone();
89 change(&mut key);
90 if key == *self.key {
91 self.clone()
92 } else {
93 Self::new(key)
94 }
95 }
96}
97
98type Modify = Arc<dyn Fn(Node) -> Node + Send + Sync>;
99
100#[derive(Clone)]
102pub struct VectorSelection {
103 addresses: Arc<BTreeSet<Vec<usize>>>,
104 modify: Modify,
105}
106
107impl VectorSelection {
108 pub fn new(
110 addresses: impl IntoIterator<Item = Vec<usize>>,
111 modify: impl Fn(Node) -> Node + Send + Sync + 'static,
112 ) -> Self {
113 Self {
114 addresses: Arc::new(addresses.into_iter().collect()),
115 modify: Arc::new(modify),
116 }
117 }
118
119 pub fn shared(addresses: impl IntoIterator<Item = Vec<usize>>, modify: &Modify) -> Self {
121 Self {
122 addresses: Arc::new(addresses.into_iter().collect()),
123 modify: modify.clone(),
124 }
125 }
126}
127
128impl VectorTree {
129 pub fn reveal(
132 &self,
133 selections: &[VectorSelection],
134 write: Option<f64>,
135 ) -> Result<Node, ValidationError> {
136 let map = |address: &[usize], mut node: Node| {
137 for selection in selections {
138 if selection.addresses.contains(address) {
139 node = (selection.modify)(node);
140 }
141 }
142 node
143 };
144 match write {
145 Some(progress) => self.write_mapped(progress, WriteOptions::default(), &map),
146 None => Ok(self.node_mapped(&map)),
147 }
148 }
149}