harmos_runtime/evidence/
draft.rs1use std::path::{Path, PathBuf};
18use std::sync::{Arc, Mutex};
19use tokio::sync::watch;
21use super::EvidenceError;
23use super::vault::Keeping;
24use crate::DefinitionId;
25
26#[derive(Clone)]
35pub struct Draft {
36 pub(crate) open: Arc<Open>,
37}
38
39pub(crate) struct Open {
40 pub(crate) kind: DefinitionId,
41 pub(crate) version: u32,
42 pub(crate) scope: String,
43 pub(crate) key: String,
44 pub(crate) name: String,
45 pub(crate) described: Vec<u8>,
46 pub(crate) external: Option<PathBuf>,
47 vault: Arc<dyn Keeping>,
48 writing: tokio::sync::Mutex<()>,
49 growth: Mutex<Growth>,
50}
51
52struct Growth {
53 length: u64,
54 watchers: Option<watch::Sender<u64>>,
55 finalizing: bool,
56 released: bool,
57}
58
59pub(crate) struct Staged {
60 pub(crate) kind: DefinitionId,
61 pub(crate) version: u32,
62 pub(crate) scope: String,
63 pub(crate) key: String,
64 pub(crate) name: String,
65 pub(crate) described: Vec<u8>,
66 pub(crate) external: Option<PathBuf>,
67 pub(crate) length: u64,
68}
69
70impl Draft {
77 pub fn kind(&self) -> &DefinitionId {
78 &self.open.kind
79 }
80
81 pub fn scope(&self) -> &str {
82 &self.open.scope
83 }
84
85 pub fn key(&self) -> &str {
86 &self.open.key
87 }
88
89 pub fn length(&self) -> u64 {
90 self.open.length()
91 }
92
93 pub fn path(&self) -> Option<&Path> {
94 self.open.external.as_deref()
95 }
96
97 pub async fn write(&self, bytes: &[u8]) -> Result<u64, EvidenceError> {
98 self.open.append(bytes).await
99 }
100}
101
102impl std::fmt::Debug for Draft {
103 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 formatter
105 .debug_struct("Draft")
106 .field("kind", &self.open.kind)
107 .field("scope", &self.open.scope)
108 .field("key", &self.open.key)
109 .field("length", &self.open.length())
110 .finish()
111 }
112}
113
114impl Open {
115 pub(crate) fn new(staged: Staged, vault: Arc<dyn Keeping>) -> Self {
116 let Staged { kind, version, scope, key, name, described, external, length } = staged;
117
118 Self {
119 kind,
120 version,
121 scope,
122 key,
123 name,
124 described,
125 external,
126 vault,
127 writing: tokio::sync::Mutex::new(()),
128 growth: Mutex::new(Growth { length, watchers: None, finalizing: false, released: false }),
129 }
130 }
131
132 pub(crate) fn length(&self) -> u64 {
133 self.held().length
134 }
135
136 pub(crate) fn released(&self) -> bool {
137 self.held().released
138 }
139
140 async fn append(&self, bytes: &[u8]) -> Result<u64, EvidenceError> {
141 if self.external.is_some() {
142 return Err(EvidenceError::Foreign);
143 }
144 let _writing = self.writing.lock().await;
145 if self.released() {
146 return Err(EvidenceError::Unknown);
147 }
148 let length = self.vault.append(&self.name, bytes).await?;
149 self.observed(length);
150
151 Ok(length)
152 }
153
154 pub(crate) fn observed(&self, length: u64) {
155 let mut held = self.held();
156 if held.length == length {
157 return;
158 }
159 held.length = length;
160 if let Some(watchers) = &held.watchers {
161 let _ = watchers.send(length);
162 }
163 }
164
165 pub(crate) fn watch(&self) -> (watch::Receiver<u64>, bool) {
166 let mut held = self.held();
167 match &held.watchers {
168 Some(watchers) => (watchers.subscribe(), false),
169 None => {
170 let (sender, receiver) = watch::channel(held.length);
171 held.watchers = Some(sender);
172
173 (receiver, true)
174 }
175 }
176 }
177
178 pub(crate) fn idle(&self) -> bool {
179 let mut held = self.held();
180 let gone = held.watchers.as_ref().is_some_and(|watchers| watchers.receiver_count() == 0);
181 if gone {
182 held.watchers = None;
183 }
184
185 gone
186 }
187
188 pub(crate) fn begin_finalize(&self) -> bool {
189 let mut held = self.held();
190 if held.finalizing || held.released {
191 return false;
192 }
193 held.finalizing = true;
194
195 true
196 }
197
198 pub(crate) fn end_finalize(&self) {
199 self.held().finalizing = false;
200 }
201
202 pub(crate) async fn observe(&self) -> Result<(), EvidenceError> {
203 let length = self.vault.length(&self.name).await?;
204 self.observed(length);
205
206 Ok(())
207 }
208
209 pub(crate) fn release(&self, length: u64) {
210 let mut held = self.held();
211 held.released = true;
212 held.length = length;
213 if let Some(watchers) = held.watchers.take() {
214 let _ = watchers.send(length);
215 }
216 }
217
218 fn held(&self) -> std::sync::MutexGuard<'_, Growth> {
219 self.growth.lock().expect("the draft lock is healthy")
220 }
221}
222
223