mlua_swarm/blueprint/store/
inmemory.rs1use super::types::*;
9use super::{blueprint_version, canonical_yaml, BlueprintStore};
10use crate::blueprint::Blueprint;
11use async_trait::async_trait;
12use std::collections::{BTreeMap, HashMap};
13use std::sync::Mutex;
14
15#[derive(Default)]
17pub struct InMemoryBlueprintStore {
18 inner: Mutex<InMemoryInner>,
19}
20
21#[derive(Default)]
22struct InMemoryInner {
23 objects: BTreeMap<(BlueprintId, BlueprintVersion), StoredObject>,
25 heads: HashMap<BlueprintId, BlueprintVersion>,
27 history: HashMap<BlueprintId, Vec<BlueprintVersion>>,
29}
30
31struct StoredObject {
32 blueprint: Blueprint,
33 trace: Trace,
34 rationale: String,
35}
36
37impl InMemoryBlueprintStore {
38 pub fn new() -> Self {
40 Self::default()
41 }
42}
43
44#[async_trait]
45impl BlueprintStore for InMemoryBlueprintStore {
46 fn name(&self) -> &str {
47 "in-memory"
48 }
49
50 async fn read_head(&self, id: &BlueprintId) -> Result<Traced<Blueprint>, BlueprintStoreError> {
51 let inner = self.inner.lock().unwrap();
52 let head = inner
53 .heads
54 .get(id)
55 .ok_or_else(|| BlueprintStoreError::HeadEmpty(id.clone()))?;
56 let obj = inner
57 .objects
58 .get(&(id.clone(), *head))
59 .ok_or(BlueprintStoreError::NotFound {
60 id: id.clone(),
61 version: *head,
62 })?;
63 Ok(Traced::new(obj.blueprint.clone(), obj.trace.clone()))
64 }
65
66 async fn write_new(
67 &self,
68 id: &BlueprintId,
69 new_bp: &Blueprint,
70 parents: &[BlueprintVersion],
71 metadata: CommitMetadata,
72 ) -> Result<BlueprintVersion, BlueprintStoreError> {
73 let _yaml = canonical_yaml(new_bp)?;
75 let version = blueprint_version(new_bp)?;
76
77 let parents_refs: Vec<TraceRef> = parents
78 .iter()
79 .map(|p| TraceRef {
80 origin: TraceOrigin::Inline,
81 hash: p.0,
82 })
83 .collect();
84
85 let trace = Trace::new(
86 TraceOrigin::Inline,
87 version,
88 metadata.epoch_id.started_at_ms,
89 )
90 .with_parents(parents_refs);
91
92 let mut inner = self.inner.lock().unwrap();
93 inner.objects.insert(
94 (id.clone(), version),
95 StoredObject {
96 blueprint: new_bp.clone(),
97 trace,
98 rationale: metadata.rationale.clone(),
99 },
100 );
101 inner.heads.insert(id.clone(), version);
102 inner
103 .history
104 .entry(id.clone())
105 .or_default()
106 .insert(0, version);
107 let _ = metadata;
108 Ok(version)
109 }
110
111 async fn read_commit_rationale(
112 &self,
113 id: &BlueprintId,
114 version: BlueprintVersion,
115 ) -> Result<Option<String>, BlueprintStoreError> {
116 let inner = self.inner.lock().unwrap();
117 Ok(inner
118 .objects
119 .get(&(id.clone(), version))
120 .map(|o| o.rationale.clone()))
121 }
122
123 async fn read_version(
124 &self,
125 id: &BlueprintId,
126 version: BlueprintVersion,
127 ) -> Result<Traced<Blueprint>, BlueprintStoreError> {
128 let inner = self.inner.lock().unwrap();
129 let obj =
130 inner
131 .objects
132 .get(&(id.clone(), version))
133 .ok_or(BlueprintStoreError::NotFound {
134 id: id.clone(),
135 version,
136 })?;
137 Ok(Traced::new(obj.blueprint.clone(), obj.trace.clone()))
138 }
139
140 async fn history(
141 &self,
142 id: &BlueprintId,
143 limit: usize,
144 ) -> Result<Vec<BlueprintVersion>, BlueprintStoreError> {
145 let inner = self.inner.lock().unwrap();
146 let hist = inner.history.get(id).cloned().unwrap_or_default();
147 Ok(hist.into_iter().take(limit).collect())
148 }
149
150 async fn list_ids(&self) -> Result<Vec<BlueprintId>, BlueprintStoreError> {
151 let inner = self.inner.lock().unwrap();
152 Ok(inner.heads.keys().cloned().collect())
153 }
154}