xmtp_api_d14n/protocol/sort/
timestamp.rs1use crate::protocol::{Envelope, EnvelopeError, Sort};
2
3pub struct TimestampSort<'a, E> {
4 envelopes: &'a mut [E],
5}
6
7impl<'b, 'a: 'b, E> Sort<()> for TimestampSort<'b, E>
8where
9 E: Envelope<'a>,
10{
11 fn sort(mut self) -> Result<Option<()>, EnvelopeError> {
12 let envelopes = &mut self.envelopes;
13 envelopes.sort_unstable_by_key(|e| e.timestamp());
15 Ok(None)
17 }
18}
19
20pub fn timestamp<'b, 'a: 'b, E: Envelope<'a>>(envelopes: &'b mut [E]) -> impl Sort<()> {
31 TimestampSort { envelopes }
32}
33
34#[cfg(test)]
35mod tests {
36 use crate::protocol::sort;
37 use chrono::Utc;
38 use proptest::prelude::*;
39 use xmtp_common::Generate;
40 use xmtp_proto::xmtp::xmtpv4::envelopes::ClientEnvelope;
41 use xmtp_proto::xmtp::xmtpv4::envelopes::client_envelope::Payload;
42
43 use super::*;
44
45 #[derive(Debug)]
46 struct TestEnvelope {
47 time: Option<chrono::DateTime<Utc>>,
48 }
49
50 impl TestEnvelope {
51 fn new(time: i64) -> Self {
52 Self {
53 time: Some(chrono::DateTime::from_timestamp_nanos(time)),
54 }
55 }
56 }
57
58 impl Generate for TestEnvelope {
59 fn generate() -> Self {
60 TestEnvelope {
61 time: Some(chrono::DateTime::from_timestamp_nanos(
62 xmtp_common::rand_i64(),
63 )),
64 }
65 }
66 }
67
68 impl Envelope<'_> for TestEnvelope {
69 fn topic(&self) -> Result<xmtp_proto::types::Topic, crate::protocol::EnvelopeError> {
70 unreachable!()
71 }
72
73 fn payload(&self) -> Result<Payload, crate::protocol::EnvelopeError> {
74 unreachable!()
75 }
76
77 fn timestamp(&self) -> Option<chrono::DateTime<Utc>> {
78 self.time
79 }
80
81 fn client_envelope(&self) -> Result<ClientEnvelope, crate::protocol::EnvelopeError> {
82 unreachable!()
83 }
84
85 fn group_message(
86 &self,
87 ) -> Result<Option<xmtp_proto::types::GroupMessage>, crate::protocol::EnvelopeError>
88 {
89 unreachable!()
90 }
91
92 fn welcome_message(
93 &self,
94 ) -> Result<Option<xmtp_proto::types::WelcomeMessage>, crate::protocol::EnvelopeError>
95 {
96 unreachable!()
97 }
98
99 fn cursor(&self) -> Result<xmtp_proto::types::Cursor, EnvelopeError> {
100 unreachable!()
101 }
102
103 fn depends_on(&self) -> Result<Option<xmtp_proto::types::GlobalCursor>, EnvelopeError> {
104 unreachable!()
105 }
106
107 fn sha256_hash(&self) -> Result<Vec<u8>, EnvelopeError> {
108 unreachable!()
109 }
110
111 fn bytes(&self) -> Result<Vec<u8>, EnvelopeError> {
112 unreachable!()
113 }
114
115 fn orphan(&self) -> Result<xmtp_proto::types::OrphanedEnvelope, EnvelopeError> {
116 todo!()
117 }
118 }
119
120 prop_compose! {
121 fn envelope_all_some()(id in 1..u32::MAX) -> TestEnvelope {
122 TestEnvelope::new(id as i64)
123 }
124 }
125
126 fn is_sorted(sorted: &[TestEnvelope]) -> bool {
127 sorted.is_sorted_by_key(|e| e.time)
128 }
129
130 #[xmtp_common::test]
131 fn sorts_by_timestamp() {
132 proptest!(|(mut envelopes in prop::collection::vec(envelope_all_some(), 0 .. 100))| {
133 sort::timestamp(&mut envelopes).sort().unwrap();
134 assert!(is_sorted(&envelopes), "envelopes were not sorted")
135 });
136 }
137}