xmtp_proto/types/
orphaned_envelope.rs

1use derive_builder::Builder;
2
3use crate::ConversionError;
4use crate::types::{Cursor, GlobalCursor, GroupId};
5use bytes::Bytes;
6use std::hash::Hash;
7
8/// An envelope whose parent dependencies have not yet been seen
9#[derive(Builder, Clone, Debug)]
10#[builder(setter(into), build_fn(error = "ConversionError"))]
11pub struct OrphanedEnvelope {
12    // the cursor of this envelope
13    pub cursor: Cursor,
14    /// the envelopes this orphan depends on
15    #[builder(setter(each(name = "depending_on")))]
16    pub depends_on: GlobalCursor,
17    /// the original payload
18    pub payload: Bytes,
19    /// the group this orphan belongs to
20    pub group_id: GroupId,
21}
22
23impl std::fmt::Display for OrphanedEnvelope {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        write!(
26            f,
27            "orphan {} depends on {} of group {}",
28            self.cursor, self.depends_on, self.group_id
29        )
30    }
31}
32
33// prost grpc encoding is _not_ deterministic.
34// https://github.com/tokio-rs/prost/issues/965
35// so we ned to write a custom Hash implementation to
36// ignore the payload field
37impl Hash for OrphanedEnvelope {
38    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
39        self.cursor.hash(state);
40        self.group_id.hash(state);
41        self.depends_on.hash(state);
42    }
43}
44
45// needed for parity with Hash impl
46impl PartialEq<OrphanedEnvelope> for OrphanedEnvelope {
47    fn eq(&self, other: &OrphanedEnvelope) -> bool {
48        self.cursor == other.cursor
49            && self.depends_on == other.depends_on
50            && self.group_id == other.group_id
51    }
52}
53
54impl Eq for OrphanedEnvelope {}
55
56impl OrphanedEnvelope {
57    pub fn builder() -> OrphanedEnvelopeBuilder {
58        OrphanedEnvelopeBuilder::default()
59    }
60
61    ///  turn this envelope back into its parts
62    pub fn into_payload(self) -> Bytes {
63        self.payload
64    }
65
66    /// check if we are dependant on [`Cursor`]
67    pub fn is_child_of(&self, cursor: &Cursor) -> bool {
68        self.depends_on.contains_key(&cursor.originator_id)
69            && self.depends_on.get(&cursor.originator_id) == cursor.sequence_id
70    }
71}