1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use indexmap::IndexSet;
use serde::{de::DeserializeOwned, Serialize};
use warg_crypto::{hash::AnyHash, Decode};

pub mod operator;
pub mod package;
mod proto_envelope;
pub mod registry;
mod serde_envelope;

pub use proto_envelope::{
    ProtoEnvelope, ProtoEnvelopeBody, PublishedProtoEnvelope, PublishedProtoEnvelopeBody,
};
pub use semver::{Version, VersionReq};
pub use serde_envelope::SerdeEnvelope;

/// Trait implemented by the record types.
pub trait Record: Clone + Decode + Send + Sync {
    /// Gets the set of content hashes associated with the record.
    ///
    /// An empty set indicates that the record has no associated content.
    fn contents(&self) -> IndexSet<&AnyHash>;
}

/// Trait implemented by the log state types.
pub trait Validator:
    std::fmt::Debug + Serialize + DeserializeOwned + Default + Send + Sync
{
    /// The type of record being validated.
    type Record: Record;

    /// The type of error returned when validation fails.
    type Error: Send;

    /// Validates the given record.
    fn validate(self, record: &ProtoEnvelope<Self::Record>) -> Result<Self, Self::Error>;
}

/// Helpers for converting to and from protobuf

fn prost_to_pbjson_timestamp(timestamp: prost_types::Timestamp) -> pbjson_types::Timestamp {
    pbjson_types::Timestamp {
        seconds: timestamp.seconds,
        nanos: timestamp.nanos,
    }
}

fn pbjson_to_prost_timestamp(timestamp: pbjson_types::Timestamp) -> prost_types::Timestamp {
    prost_types::Timestamp {
        seconds: timestamp.seconds,
        nanos: timestamp.nanos,
    }
}

/// Helper module for serializing and deserializing timestamps.
///
/// This is used over serde's built-in implementation to produce cleaner timestamps
/// in serialized output.
mod timestamp {
    use serde::Deserializer;
    use serde::{Deserialize, Serializer};
    use std::time::{Duration, SystemTime, UNIX_EPOCH};

    pub fn serialize<S>(timestamp: &SystemTime, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        use serde::ser::Error;

        let duration_since_epoch = match timestamp.duration_since(UNIX_EPOCH) {
            Ok(duration_since_epoch) => duration_since_epoch,
            Err(_) => return Err(S::Error::custom("timestamp must be later than UNIX_EPOCH")),
        };

        serializer.serialize_str(&format!(
            "{secs}.{nsecs}",
            secs = duration_since_epoch.as_secs(),
            nsecs = duration_since_epoch.subsec_nanos()
        ))
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<SystemTime, D::Error>
    where
        D: Deserializer<'de>,
    {
        use serde::de::Error;

        let s = String::deserialize(deserializer)?;
        let (secs, nsecs) = s
            .split_once('.')
            .ok_or_else(|| D::Error::custom("timestamp must be in the format <secs>.<nsecs>"))?;

        Ok(SystemTime::UNIX_EPOCH
            + Duration::new(
                secs.parse::<u64>().map_err(D::Error::custom)?,
                nsecs.parse::<u32>().map_err(D::Error::custom)?,
            ))
    }
}