use std::num::NonZeroU64;
use serde::{Deserialize, Serialize};
use crate::FORMAT;
use crate::canonical::Digest;
use crate::document::DerivedFrom;
use crate::identity::Key;
use crate::ids::{AuthoredStateId, DocumentId};
use crate::manifest::{ALGORITHM, ManifestError, check_identifiers};
use crate::publish::time::{PublishedAt, TimeError};
pub const LOCK: &str = "loft.lock.json";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Lock {
pub document_key: DocumentId,
pub state_root: Digest,
pub content_root: Digest,
pub binding_root: Digest,
pub publish_sequence: NonZeroU64,
pub published_at: PublishedAt,
pub derived_from: Option<DerivedFrom>,
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum LockError {
#[error("{0}")]
Shape(String),
#[error(transparent)]
Identifier(#[from] ManifestError),
#[error(transparent)]
Time(#[from] TimeError),
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
struct Wire {
format: String,
algorithm: String,
document_key: Key,
state_root: Digest,
content_root: Digest,
binding_root: Digest,
publish_sequence: NonZeroU64,
published_at: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
derived_from: Option<WireDerivedFrom>,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
struct WireDerivedFrom {
authored_state_id: Key,
content_address: Digest,
publish_sequence: u64,
}
impl Lock {
pub fn read(bytes: &[u8]) -> Result<Self, LockError> {
let wire: Wire =
serde_json::from_slice(bytes).map_err(|error| LockError::Shape(error.to_string()))?;
check_identifiers(&wire.format, &wire.algorithm)?;
Ok(Self {
document_key: DocumentId::new(wire.document_key),
state_root: wire.state_root,
content_root: wire.content_root,
binding_root: wire.binding_root,
publish_sequence: wire.publish_sequence,
published_at: wire.published_at.parse()?,
derived_from: wire.derived_from.map(|derived| DerivedFrom {
authored_state_id: AuthoredStateId::new(derived.authored_state_id),
content_address: derived.content_address,
publish_sequence: derived.publish_sequence,
}),
})
}
#[must_use]
pub fn to_bytes(&self) -> Vec<u8> {
let wire = Wire {
format: FORMAT.to_owned(),
algorithm: ALGORITHM.to_owned(),
document_key: self.document_key.key(),
state_root: self.state_root,
content_root: self.content_root,
binding_root: self.binding_root,
publish_sequence: self.publish_sequence,
published_at: self.published_at.to_string(),
derived_from: self.derived_from.as_ref().map(|derived| WireDerivedFrom {
authored_state_id: derived.authored_state_id.key(),
content_address: derived.content_address,
publish_sequence: derived.publish_sequence,
}),
};
let mut bytes = serde_json::to_vec_pretty(&wire).expect("a lock serialises");
bytes.push(b'\n');
bytes
}
}