Skip to main content

xmtp_archive/
archive_options.rs

1use xmtp_proto::xmtp::device_sync::{
2    ArchiveOptions as ArchiveOptionsProto, BackupElementSelection as BackupElementSelectionProto,
3};
4
5/// Native representation of backup element selection with strongly-typed variants.
6///
7/// This wraps the proto `BackupElementSelection` to avoid working with raw `i32` values
8/// and protobuf-specific conventions like `Unspecified`.
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
10pub enum BackupElementSelection {
11    #[default]
12    Unspecified,
13    Messages,
14    Consent,
15    Event,
16}
17
18impl From<BackupElementSelectionProto> for BackupElementSelection {
19    #[allow(deprecated)]
20    fn from(proto: BackupElementSelectionProto) -> Self {
21        match proto {
22            BackupElementSelectionProto::Unspecified => Self::Unspecified,
23            BackupElementSelectionProto::Messages => Self::Messages,
24            BackupElementSelectionProto::Consent => Self::Consent,
25            BackupElementSelectionProto::Event => Self::Event,
26        }
27    }
28}
29
30impl From<BackupElementSelection> for BackupElementSelectionProto {
31    #[allow(deprecated)]
32    fn from(selection: BackupElementSelection) -> Self {
33        match selection {
34            BackupElementSelection::Unspecified => Self::Unspecified,
35            BackupElementSelection::Messages => Self::Messages,
36            BackupElementSelection::Consent => Self::Consent,
37            BackupElementSelection::Event => Self::Event,
38        }
39    }
40}
41
42/// Native representation of backup options with strongly-typed element selections.
43///
44/// This wraps the proto `ArchiveOptions` to provide a more ergonomic API,
45/// using `BackupElementSelection` enum values directly instead of raw `i32`.
46#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
47pub struct ArchiveOptions {
48    pub elements: Vec<BackupElementSelection>,
49    pub start_ns: Option<i64>,
50    pub end_ns: Option<i64>,
51    pub exclude_disappearing_messages: bool,
52}
53
54impl ArchiveOptions {
55    #[cfg(any(test, feature = "test-utils"))]
56    pub fn msgs_and_consent() -> Self {
57        Self {
58            elements: vec![
59                BackupElementSelection::Messages,
60                BackupElementSelection::Consent,
61            ],
62            start_ns: None,
63            end_ns: None,
64            exclude_disappearing_messages: false,
65        }
66    }
67}
68
69impl From<ArchiveOptionsProto> for ArchiveOptions {
70    fn from(proto: ArchiveOptionsProto) -> Self {
71        Self {
72            elements: proto.elements().map(BackupElementSelection::from).collect(),
73            start_ns: proto.start_ns,
74            end_ns: proto.end_ns,
75            exclude_disappearing_messages: proto.exclude_disappearing_messages,
76        }
77    }
78}
79
80impl From<ArchiveOptions> for ArchiveOptionsProto {
81    fn from(opts: ArchiveOptions) -> Self {
82        Self {
83            elements: opts
84                .elements
85                .into_iter()
86                .map(|e| BackupElementSelectionProto::from(e) as i32)
87                .collect(),
88            start_ns: opts.start_ns,
89            end_ns: opts.end_ns,
90            exclude_disappearing_messages: opts.exclude_disappearing_messages,
91        }
92    }
93}
94
95impl From<&ArchiveOptions> for ArchiveOptionsProto {
96    fn from(opts: &ArchiveOptions) -> Self {
97        Self {
98            elements: opts
99                .elements
100                .iter()
101                .map(|e| BackupElementSelectionProto::from(*e) as i32)
102                .collect(),
103            start_ns: opts.start_ns,
104            end_ns: opts.end_ns,
105            exclude_disappearing_messages: opts.exclude_disappearing_messages,
106        }
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_element_selection_round_trip() {
116        let variants = [
117            BackupElementSelection::Unspecified,
118            BackupElementSelection::Messages,
119            BackupElementSelection::Consent,
120            BackupElementSelection::Event,
121        ];
122
123        for variant in variants {
124            let proto: BackupElementSelectionProto = variant.into();
125            let round_tripped: BackupElementSelection = proto.into();
126            assert_eq!(variant, round_tripped);
127        }
128    }
129
130    #[test]
131    fn test_options_round_trip() {
132        let opts = ArchiveOptions {
133            elements: vec![
134                BackupElementSelection::Messages,
135                BackupElementSelection::Consent,
136            ],
137            start_ns: Some(1000),
138            end_ns: Some(2000),
139            exclude_disappearing_messages: true,
140        };
141
142        let proto: ArchiveOptionsProto = opts.clone().into();
143        let round_tripped: ArchiveOptions = proto.into();
144
145        assert_eq!(opts, round_tripped);
146    }
147
148    #[test]
149    fn test_default() {
150        let selection = BackupElementSelection::default();
151        assert_eq!(selection, BackupElementSelection::Unspecified);
152
153        let opts = ArchiveOptions::default();
154        assert!(opts.elements.is_empty());
155        assert_eq!(opts.start_ns, None);
156        assert_eq!(opts.end_ns, None);
157        assert!(!opts.exclude_disappearing_messages);
158    }
159
160    #[test]
161    fn test_from_ref() {
162        let opts = ArchiveOptions {
163            elements: vec![BackupElementSelection::Consent],
164            start_ns: Some(500),
165            end_ns: None,
166            exclude_disappearing_messages: false,
167        };
168
169        let proto: ArchiveOptionsProto = (&opts).into();
170        assert_eq!(
171            proto.elements,
172            vec![BackupElementSelectionProto::Consent as i32]
173        );
174        assert_eq!(proto.start_ns, Some(500));
175        assert_eq!(proto.end_ns, None);
176        assert!(!proto.exclude_disappearing_messages);
177    }
178}