Skip to main content

mos_cache/
lib.rs

1//! Incremental build cache (manifest §7, §32).
2//!
3//! Today this crate holds the typed dependency-identity vocabulary
4//! ([`DependencyId`] / [`DependencyKind`] / [`ProjectPath`], plus the
5//! [`BibliographyDependency`] content boundary) and a tiny in-memory byte
6//! [`Cache`]. The `DepNode` graph and the persistent content-addressed
7//! `.mos-cache/` are MVP 5 work, still design-side in
8//! `docs/incremental-dependencies.md` (§9).
9
10#![doc(
11    html_logo_url = "https://mosaic.kjanat.dev/assets/A4.svg",
12    html_favicon_url = "https://mosaic.kjanat.dev/assets/A4.svg"
13)]
14
15use std::collections::HashMap;
16
17use mos_core::ContentHash;
18
19mod dependency;
20
21pub use dependency::{
22    BibliographyDependency, DependencyId, DependencyKind, ProjectPath, ProjectPathError,
23};
24
25/// A cache entry's address. Real keys include node, style, and width
26/// hashes (manifest §32). For now the type is opaque.
27///
28/// # Examples
29///
30/// ```
31/// use mos_cache::CacheKey;
32/// use mos_core::ContentHash;
33///
34/// let key = CacheKey(ContentHash(42));
35///
36/// assert_eq!(key.0, ContentHash(42));
37/// ```
38#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
39pub struct CacheKey(pub ContentHash);
40
41/// Cache trait. Implementations: in-memory (default), on-disk (MVP 5).
42///
43/// # Examples
44///
45/// ```
46/// use mos_cache::{Cache, CacheKey, InMemoryCache};
47/// use mos_core::ContentHash;
48///
49/// let mut cache = InMemoryCache::default();
50/// let key = CacheKey(ContentHash(7));
51/// cache.put(key, vec![1, 2, 3]);
52///
53/// assert_eq!(cache.get(&key), Some(vec![1, 2, 3]));
54/// ```
55pub trait Cache {
56    /// Return a cached payload for `key`, if present.
57    ///
58    /// # Examples
59    ///
60    /// ```
61    /// use mos_cache::{Cache, CacheKey, InMemoryCache};
62    /// use mos_core::ContentHash;
63    ///
64    /// let cache = InMemoryCache::default();
65    ///
66    /// assert_eq!(cache.get(&CacheKey(ContentHash(1))), None);
67    /// ```
68    fn get(&self, key: &CacheKey) -> Option<Vec<u8>>;
69
70    /// Store `value` under `key`, replacing any previous value.
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use mos_cache::{Cache, CacheKey, InMemoryCache};
76    /// use mos_core::ContentHash;
77    ///
78    /// let mut cache = InMemoryCache::default();
79    /// let key = CacheKey(ContentHash(1));
80    /// cache.put(key, vec![9]);
81    ///
82    /// assert_eq!(cache.get(&key), Some(vec![9]));
83    /// ```
84    fn put(&mut self, key: CacheKey, value: Vec<u8>);
85}
86
87/// Hash-map backed cache used by tests and the current MVP pipeline.
88///
89/// # Examples
90///
91/// ```
92/// use mos_cache::{Cache, CacheKey, InMemoryCache};
93/// use mos_core::ContentHash;
94///
95/// let mut cache = InMemoryCache::default();
96/// let key = CacheKey(ContentHash(5));
97/// cache.put(key, b"pdf".to_vec());
98///
99/// assert_eq!(cache.get(&key), Some(b"pdf".to_vec()));
100/// ```
101#[derive(Default, Debug)]
102pub struct InMemoryCache {
103    entries: HashMap<CacheKey, Vec<u8>>,
104}
105
106impl Cache for InMemoryCache {
107    fn get(&self, key: &CacheKey) -> Option<Vec<u8>> {
108        self.entries.get(key).cloned()
109    }
110
111    fn put(&mut self, key: CacheKey, value: Vec<u8>) {
112        self.entries.insert(key, value);
113    }
114}