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}