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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use crate::Id;
use serde::Serialize;
use serde_with::serde_as;
use std::{sync::Arc, time::SystemTime};

/// The list of commits already recorded
pub type CommitList<CustomData> = Vec<Arc<Commit<CustomData>>>;

/// A representation of a generation within the tree
pub type CommitId = Id;

/// Identifies a cryptographically secured set of transactions on the tree.
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct Commit<CustomData>
where
    CustomData: Serialize,
{
    /// Cryptographic hash of the commit contents
    pub id: CommitId,

    /// Metadata associated with the commit
    pub metadata: CommitMetadata<CustomData>,
}

/// Hashed metadata of a [`Commit`] that are included in its
/// [`id`][Commit::id]
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct CommitMetadata<CustomData>
where
    CustomData: Serialize,
{
    /// Previous commit in the chain
    pub previous: Option<CommitId>,

    /// Any additional stringy message, just like in Git
    pub message: Option<String>,

    /// Time the commit was made
    #[serde_as(as = "serde_with::TimestampSecondsWithFrac<f64>")]
    pub time: SystemTime,

    /// Any machine-readable data you may need to store
    pub custom_data: CustomData,
}

impl<CustomData: Serialize + Default> Default for CommitMetadata<CustomData> {
    fn default() -> Self {
        Self {
            time: SystemTime::now(),
            previous: None,
            message: None,
            custom_data: CustomData::default(),
        }
    }
}

/// Enum to navigate the versions that are available in an Infinitree
pub enum CommitFilter {
    /// On querying, all versions will be crawled. This is the
    /// default.
    All,

    /// Only a single generation will be looked at during querying.
    Single(CommitId),

    /// All generations up to and including the given one will be queried.
    UpTo(CommitId),

    /// Only use generations between the two given versions.
    /// The first parameter **must** be earlier generation than the
    /// second.
    Range(CommitId, CommitId),
}

impl Default for CommitFilter {
    fn default() -> Self {
        Self::All
    }
}

/// A commit message. Mostly equivalent to Option<String>.
///
/// The main reason for a separate wrapper type is being able to use
/// versatile `From<T>` implementations that in return make the
/// `Infinitree` API nicer to use.
pub enum Message {
    /// No commit message.
    Empty,
    /// Use the `String` parameter as commit message
    Some(String),
}

impl From<&str> for Message {
    fn from(from: &str) -> Self {
        Self::Some(from.to_string())
    }
}

impl From<Option<String>> for Message {
    fn from(from: Option<String>) -> Self {
        match from {
            Some(s) => Self::Some(s),
            None => Self::Empty,
        }
    }
}

impl From<String> for Message {
    fn from(from: String) -> Self {
        Self::Some(from)
    }
}

impl From<Message> for Option<String> {
    fn from(from: Message) -> Option<String> {
        match from {
            Message::Empty => None,
            Message::Some(s) => Some(s),
        }
    }
}