warg_protocol/
lib.rs

1use indexmap::IndexSet;
2use serde::{de::DeserializeOwned, Serialize};
3use warg_crypto::{hash::AnyHash, Decode};
4
5pub mod operator;
6pub mod package;
7mod proto_envelope;
8pub mod registry;
9mod serde_envelope;
10
11pub use proto_envelope::{
12    ProtoEnvelope, ProtoEnvelopeBody, PublishedProtoEnvelope, PublishedProtoEnvelopeBody,
13};
14pub use semver::{Version, VersionReq};
15pub use serde_envelope::SerdeEnvelope;
16
17/// Trait implemented by the record types.
18pub trait Record: Clone + Decode + Send + Sync {
19    /// Gets the set of content hashes associated with the record.
20    ///
21    /// An empty set indicates that the record has no associated content.
22    fn contents(&self) -> IndexSet<&AnyHash>;
23}
24
25/// Trait implemented by the log state types.
26pub trait Validator:
27    std::fmt::Debug + Serialize + DeserializeOwned + Default + Send + Sync
28{
29    /// The type of record being validated.
30    type Record: Record;
31
32    /// The type of error returned when validation fails.
33    type Error: Send;
34
35    /// Validates the given record.
36    fn validate(self, record: &ProtoEnvelope<Self::Record>) -> Result<Self, Self::Error>;
37}
38
39/// Helpers for converting to and from protobuf
40
41fn prost_to_pbjson_timestamp(timestamp: prost_types::Timestamp) -> pbjson_types::Timestamp {
42    pbjson_types::Timestamp {
43        seconds: timestamp.seconds,
44        nanos: timestamp.nanos,
45    }
46}
47
48fn pbjson_to_prost_timestamp(timestamp: pbjson_types::Timestamp) -> prost_types::Timestamp {
49    prost_types::Timestamp {
50        seconds: timestamp.seconds,
51        nanos: timestamp.nanos,
52    }
53}
54
55/// Helper module for serializing and deserializing timestamps.
56///
57/// This is used over serde's built-in implementation to produce cleaner timestamps
58/// in serialized output.
59mod timestamp {
60    use serde::Deserializer;
61    use serde::{Deserialize, Serializer};
62    use std::time::{Duration, SystemTime, UNIX_EPOCH};
63
64    pub fn serialize<S>(timestamp: &SystemTime, serializer: S) -> Result<S::Ok, S::Error>
65    where
66        S: Serializer,
67    {
68        use serde::ser::Error;
69
70        let duration_since_epoch = match timestamp.duration_since(UNIX_EPOCH) {
71            Ok(duration_since_epoch) => duration_since_epoch,
72            Err(_) => return Err(S::Error::custom("timestamp must be later than UNIX_EPOCH")),
73        };
74
75        serializer.serialize_str(&format!(
76            "{secs}.{nsecs}",
77            secs = duration_since_epoch.as_secs(),
78            nsecs = duration_since_epoch.subsec_nanos()
79        ))
80    }
81
82    pub fn deserialize<'de, D>(deserializer: D) -> Result<SystemTime, D::Error>
83    where
84        D: Deserializer<'de>,
85    {
86        use serde::de::Error;
87
88        let s = String::deserialize(deserializer)?;
89        let (secs, nsecs) = s
90            .split_once('.')
91            .ok_or_else(|| D::Error::custom("timestamp must be in the format <secs>.<nsecs>"))?;
92
93        Ok(SystemTime::UNIX_EPOCH
94            + Duration::new(
95                secs.parse::<u64>().map_err(D::Error::custom)?,
96                nsecs.parse::<u32>().map_err(D::Error::custom)?,
97            ))
98    }
99}