vortex_edition/
session.rs1use std::any::Any;
7use std::collections::BTreeMap;
8use std::sync::Arc;
9
10use parking_lot::RwLock;
11use vortex_session::ArcSwapMap;
12use vortex_session::SessionExt;
13use vortex_session::SessionGuard;
14use vortex_session::SessionVar;
15use vortex_session::registry::Id;
16
17use crate::ComponentKind;
18use crate::Edition;
19use crate::EditionDeclaration;
20use crate::EditionError;
21use crate::EditionId;
22use crate::EditionInclusion;
23use crate::parse_release;
24
25#[derive(Clone, Debug, Default)]
33pub struct EditionSession {
34 inner: Arc<RwLock<Inner>>,
35}
36
37#[derive(Debug, Default)]
38struct Inner {
39 editions: BTreeMap<String, Edition>,
41 inclusions: BTreeMap<ComponentKind, BTreeMap<Id, EditionInclusion>>,
45}
46
47type EditionsByFamily = ArcSwapMap<Id, EditionId>;
49
50#[derive(Clone, Debug, Default)]
60pub struct EnabledEditions {
61 inner: EditionsByFamily,
62}
63
64impl EnabledEditions {
65 pub fn editions(&self) -> Vec<EditionId> {
67 self.inner.read(|map| map.values().copied().collect())
68 }
69
70 fn enable(&self, edition: EditionId) {
71 self.inner.insert(Id::from(edition.family), edition);
74 }
75}
76
77impl EditionSession {
78 pub fn empty() -> Self {
80 Self {
81 inner: Arc::new(RwLock::new(Inner::default())),
82 }
83 }
84
85 pub fn declare(&self, declaration: &EditionDeclaration) -> Result<(), EditionError> {
89 self.declare_edition(declaration.edition)?;
90 for member in declaration.added {
91 self.declare_inclusion(EditionInclusion::new(
92 member.kind,
93 member.component,
94 declaration.edition.id,
95 ))?;
96 }
97 Ok(())
98 }
99
100 pub fn declare_edition(&self, edition: Edition) -> Result<(), EditionError> {
102 let mut inner = self.inner.write();
103 let key = edition.id.to_string();
104 if inner.editions.contains_key(&key) {
105 return Err(EditionError::new(format!("duplicate edition {key}")));
106 }
107 inner.editions.insert(key, edition);
108 Ok(())
109 }
110
111 pub fn declare_inclusion(&self, inclusion: EditionInclusion) -> Result<(), EditionError> {
115 let mut inner = self.inner.write();
116 let by_id = inner.inclusions.entry(inclusion.kind).or_default();
117 if by_id.contains_key(&inclusion.component_id) {
118 return Err(EditionError::new(format!(
119 "duplicate edition inclusion for {} {}",
120 inclusion.kind, inclusion.component_id
121 )));
122 }
123 by_id.insert(inclusion.component_id, inclusion);
124 Ok(())
125 }
126
127 pub fn editions(&self) -> Vec<Edition> {
131 let mut editions: Vec<Edition> = self.inner.read().editions.values().copied().collect();
132 editions.sort_by_key(|e| (e.id.family, e.id.year, e.id.month, e.id.version));
133 editions
134 }
135
136 pub fn find(&self, id: &EditionId) -> Option<Edition> {
138 self.inner.read().editions.get(&id.to_string()).copied()
139 }
140
141 pub fn current(&self, family: &str) -> Option<Edition> {
143 self.editions()
144 .into_iter()
145 .rfind(|e| e.id.family == family && !e.is_draft())
146 }
147
148 pub fn components_in(&self, edition: &EditionId, kind: ComponentKind) -> Vec<EditionInclusion> {
152 let inner = self.inner.read();
153 let Some(by_id) = inner.inclusions.get(&kind) else {
154 return vec![];
155 };
156 by_id
157 .values()
158 .filter(|inclusion| inclusion.since.is_at_or_before(edition))
159 .copied()
160 .collect()
161 }
162
163 pub fn validate(&self) -> Result<(), EditionError> {
168 let editions = self.editions();
169
170 for edition in &editions {
171 edition.id.validate()?;
172 if let Some(version) = edition.min_vortex_version
173 && parse_release(version).is_none()
174 {
175 return Err(EditionError::new(format!(
176 "edition {} declares malformed min_vortex_version {version:?}",
177 edition.id
178 )));
179 }
180 }
181
182 for pair in editions.windows(2) {
185 let (prev, next) = (&pair[0], &pair[1]);
186 if prev.id.family == next.id.family && prev.is_draft() && !next.is_draft() {
187 return Err(EditionError::new(format!(
188 "frozen edition {} follows draft {}; drafts must be newest in a family",
189 next.id, prev.id,
190 )));
191 }
192 }
193
194 let inner = self.inner.read();
195 for inclusion in inner.inclusions.values().flat_map(|by_id| by_id.values()) {
196 inclusion.validate()?;
197
198 let Some(edition) = inner.editions.get(&inclusion.since.to_string()) else {
199 return Err(EditionError::new(format!(
200 "{} {} is included in undeclared edition {}",
201 inclusion.kind, inclusion.component_id, inclusion.since
202 )));
203 };
204
205 if let Some(required) = inclusion.required_vortex_release.and_then(parse_release)
206 && let Some(declared) = edition.min_vortex_version.and_then(parse_release)
207 && required > declared
208 {
209 return Err(EditionError::new(format!(
210 "{} {} requires release {}, newer than edition {}'s declared \
211 min_vortex_version",
212 inclusion.kind,
213 inclusion.component_id,
214 inclusion.required_vortex_release.unwrap_or_default(),
215 edition.id,
216 )));
217 }
218 }
219
220 Ok(())
221 }
222}
223
224impl SessionVar for EditionSession {
225 fn as_any(&self) -> &dyn Any {
226 self
227 }
228
229 fn as_any_mut(&mut self) -> &mut dyn Any {
230 self
231 }
232}
233
234impl SessionVar for EnabledEditions {
235 fn as_any(&self) -> &dyn Any {
236 self
237 }
238
239 fn as_any_mut(&mut self) -> &mut dyn Any {
240 self
241 }
242}
243
244pub trait EditionSessionExt: SessionExt {
246 fn editions(&self) -> SessionGuard<'_, EditionSession> {
248 self.get::<EditionSession>()
249 }
250
251 fn enabled_editions(&self) -> SessionGuard<'_, EnabledEditions> {
256 self.get::<EnabledEditions>()
257 }
258
259 fn register_edition(&self, declaration: &EditionDeclaration) -> Result<(), EditionError> {
261 self.editions().declare(declaration)
262 }
263
264 fn enable_edition(&self, edition: EditionId) -> Result<(), EditionError> {
270 if self.editions().find(&edition).is_none() {
271 return Err(EditionError::new(format!(
272 "cannot enable unregistered edition {edition}"
273 )));
274 }
275 self.enabled_editions().enable(edition);
276 Ok(())
277 }
278
279 fn enabled_component_ids(&self, kind: ComponentKind) -> Vec<Id> {
285 let Some(enabled) = self.get_opt::<EnabledEditions>() else {
286 return vec![];
287 };
288 let editions = self.editions();
289 let mut ids: Vec<Id> = enabled
290 .editions()
291 .iter()
292 .flat_map(|edition| editions.components_in(edition, kind))
293 .map(|inclusion| inclusion.component_id)
294 .collect();
295 ids.sort_unstable();
296 ids.dedup();
297 ids
298 }
299}
300
301impl<S: SessionExt> EditionSessionExt for S {}