1use std::collections::{BTreeSet, HashMap, VecDeque};
2
3use std::sync::Arc;
4
5use crate::card::SavedCard;
6use crate::common::{get_last_modified, system_time_as_unix_time};
7use crate::Id;
8
9#[derive(Debug, Default)]
10pub struct CardCache(HashMap<Id, Arc<SavedCard>>);
11
12impl CardCache {
13 fn maybe_update(&mut self, id: Id) {
19 let card_needs_update = match self.0.get(&id) {
20 Some(cached_card) => {
21 let path = cached_card.as_path();
22 if path.exists() {
23 let metadata = std::fs::metadata(path.as_path()).unwrap();
25 let last_modified_time = system_time_as_unix_time(metadata.modified().unwrap());
26
27 Some(last_modified_time > cached_card.last_modified())
29 } else {
30 None
31 }
32 }
33 None => None, };
35
36 match card_needs_update {
37 Some(true) => {
38 let path = self.0.get(&id).unwrap().as_path();
39 let updated_card = SavedCard::from_path(path.as_path());
40 self.0.insert(id, updated_card.into());
41 }
42 Some(false) => {}
44 None => {
45 if let Some(card) = SavedCard::from_id(&id) {
48 self.0.insert(id, card.into());
49 };
50 }
51 };
52 }
53
54 pub fn ids_as_vec(&self) -> Vec<Id> {
55 self.0.keys().copied().collect()
56 }
57
58 pub fn all_ids(&self) -> Vec<Id> {
60 let mut pairs: Vec<_> = self.0.iter().collect();
61 pairs.sort_by_key(|&(_, v)| {
62 if v.is_outdated() {
63 get_last_modified(v.as_path())
64 } else {
65 v.last_modified().to_owned()
66 }
67 });
68 pairs.reverse();
69 pairs.into_iter().map(|(k, _)| k.to_owned()).collect()
70 }
71
72 pub fn exists(&self, id: &Id) -> bool {
73 self.0.get(id).is_some()
74 }
75
76 pub fn insert(&mut self, card: SavedCard) {
77 let id = card.id();
78 self.0.insert(id, card.into());
79 }
80
81 pub fn remove(&mut self, id: Id) {
82 self.0.remove(&id);
83 }
84
85 pub fn dependencies(&mut self, id: Id) -> BTreeSet<Id> {
86 let Some(card) = self.try_get_ref(id) else {
87 return Default::default();
88 };
89
90 card.dependency_ids()
91 .iter()
92 .map(ToOwned::to_owned)
93 .collect()
94 }
95
96 pub fn dependents(&mut self, id: Id) -> BTreeSet<Id> {
97 let Some(card) = self.try_get_ref(id) else {
98 return Default::default();
99 };
100
101 card.dependent_ids().iter().map(ToOwned::to_owned).collect()
102 }
103
104 pub fn recursive_dependencies(&mut self, id: Id) -> BTreeSet<Id> {
105 let mut dependencies = BTreeSet::new();
106 let mut stack = VecDeque::new();
107 stack.push_back(id);
108
109 while let Some(card) = stack.pop_back() {
110 if !dependencies.contains(&card) {
111 dependencies.insert(card);
112
113 let card_dependencies = self.dependencies(card);
114
115 for dependency in card_dependencies {
116 stack.push_back(dependency);
117 }
118 }
119 }
120
121 dependencies.remove(&id);
122 dependencies
123 }
124
125 pub fn recursive_dependents(&mut self, id: Id) -> BTreeSet<Id> {
126 let mut dependencies = BTreeSet::new();
127 let mut stack = VecDeque::new();
128 stack.push_back(id);
129
130 while let Some(card) = stack.pop_back() {
131 if !dependencies.contains(&card) {
132 dependencies.insert(card);
133
134 let card_dependencies = self.dependents(card);
135
136 for dependency in card_dependencies {
137 stack.push_back(dependency);
138 }
139 }
140 }
141
142 dependencies.remove(&id);
143 dependencies
144 }
145
146 pub fn try_get_ref(&mut self, id: Id) -> Option<Arc<SavedCard>> {
147 self.maybe_update(id);
148 self.0.get(&id).cloned()
149 }
150
151 pub fn get_owned(&mut self, id: Id) -> SavedCard {
152 (*self.get_ref(id)).clone()
153 }
154
155 pub fn get_ref(&mut self, id: Id) -> Arc<SavedCard> {
156 self.try_get_ref(id).unwrap()
157 }
158
159 pub fn new() -> Self {
160 let mut cache = Self::default();
161 cache.cache_all();
162 cache
163 }
164
165 pub fn refresh(&mut self) {
166 *self = Self::new();
167 }
168
169 fn cache_all(&mut self) {
170 let all_cards = SavedCard::load_all_cards();
171 for card in all_cards {
172 self.cache_one(card);
173 }
174 }
175
176 pub fn cache_one(&mut self, card: SavedCard) {
177 self.0.insert(card.id(), card.into());
178 }
179
180 pub fn new_empty() -> Self {
181 CardCache(HashMap::new())
182 }
183}