1use crate::SyncError;
4use coven_crypto::{ObjectDigest, ObjectHasher};
5use coven_merge::Slot;
6use coven_storage::{ObjectPath, Storage, StorageFailure};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
10pub enum DeviceIdEvidence {
11 UnattemptedSlot {
13 #[serde(with = "coven_database::slot_json")]
15 slot: Slot,
16 },
17 Replaced,
19}
20
21pub(crate) fn digest(bytes: &[u8]) -> (u64, ObjectDigest) {
23 let mut hasher = ObjectHasher::new();
24 hasher.update(bytes);
25 (bytes.len() as u64, hasher.finish())
26}
27
28pub(crate) async fn stored_digest(
31 storage: &dyn Storage,
32 path: &ObjectPath,
33) -> Result<(u64, ObjectDigest), SyncError> {
34 let mut stream = storage.stream_object(path, None).await?;
35 if &stream.metadata().path != path {
36 return Err(StorageFailure::Protocol
37 .with_source("occupant response names another path")
38 .into());
39 }
40 let mut hasher = ObjectHasher::new();
41 let mut length = 0u64;
42 let mut buffer = vec![0; 64 * 1024];
43 loop {
44 let read = stream.read(&mut buffer).await?;
45 if read == 0 {
46 break;
47 }
48 hasher.update(&buffer[..read]);
49 length += read as u64;
50 }
51 Ok((length, hasher.finish()))
52}
53
54pub(crate) async fn settle_occupied(
57 storage: &dyn Storage,
58 path: &ObjectPath,
59 expected: (u64, ObjectDigest),
60) -> Result<(), SyncError> {
61 if stored_digest(storage, path).await? == expected {
62 return Ok(());
63 }
64 Err(crate::write_object::wrong_identity(path))
65}
66
67#[cfg(test)]
68#[path = "identity_tests.rs"]
69mod tests;