Skip to main content

kernel/artifacts/
gallery.rs

1//! Pure arrangement over a list of artifacts: the distinct model list and
2//! newest/oldest-first ordering. All comparisons use `(created_at, id)` so ties
3//! are total and stable.
4
5use super::artifact::Artifact;
6
7/// Newest-first or oldest-first ordering.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum GallerySort {
10    NewestFirst,
11    OldestFirst,
12}
13
14/// A model that owns at least one artifact.
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16pub struct GalleryModel {
17    pub id: String,
18    pub name: String,
19}
20
21/// Gallery arrangement helpers.
22pub struct Gallery;
23
24impl Gallery {
25    /// The distinct models across `artifacts`, ordered by each model's newest
26    /// artifact (dedup keyed on model id, first-seen after a newest-first sort).
27    pub fn models(artifacts: &[Artifact]) -> Vec<GalleryModel> {
28        let mut sorted: Vec<&Artifact> = artifacts.iter().collect();
29        sorted.sort_by(|a, b| newest(a, b));
30        let mut seen = std::collections::HashSet::new();
31        sorted
32            .into_iter()
33            .filter(|artifact| seen.insert(artifact.model_id.clone()))
34            .map(|artifact| GalleryModel {
35                id: artifact.model_id.clone(),
36                name: artifact.model.clone(),
37            })
38            .collect()
39    }
40
41    /// Filter `artifacts` to `model_id` (when given) and sort by `sort`.
42    pub fn arrange(
43        artifacts: &[Artifact],
44        model_id: Option<&str>,
45        sort: GallerySort,
46    ) -> Vec<Artifact> {
47        let mut filtered: Vec<Artifact> = artifacts
48            .iter()
49            .filter(|artifact| model_id.is_none_or(|id| artifact.model_id == id))
50            .cloned()
51            .collect();
52        match sort {
53            GallerySort::NewestFirst => filtered.sort_by(newest),
54            GallerySort::OldestFirst => filtered.sort_by(|a, b| newest(b, a)),
55        }
56        filtered
57    }
58}
59
60/// The newest-first total order (`(created_at, id)` descending) shared by the
61/// gallery and the store's listing.
62pub(crate) fn newest(a: &Artifact, b: &Artifact) -> std::cmp::Ordering {
63    (b.created_at, &b.id).cmp(&(a.created_at, &a.id))
64}