1use std::collections::BTreeMap;
11use std::time::SystemTime;
12
13use serde::{Deserialize, Serialize};
14
15#[derive(Debug)]
23pub struct Event<'a> {
24 pub name: &'static str,
27 pub category: EventCategory,
28 pub timestamp: SystemTime,
29 pub install_id: Option<&'a str>,
31 pub session_id: &'a str,
33 pub schema_version: u32,
36 pub props: &'a [Prop<'a>],
37}
38
39impl<'a> Event<'a> {
40 pub fn to_owned(&self) -> OwnedEvent {
41 OwnedEvent {
42 name: self.name.to_owned(),
43 category: self.category,
44 timestamp: self.timestamp,
45 install_id: self.install_id.map(str::to_owned),
46 session_id: self.session_id.to_owned(),
47 schema_version: self.schema_version,
48 props: self.props.iter().map(Prop::to_owned).collect(),
49 }
50 }
51}
52
53#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
54pub enum EventCategory {
55 Intent,
56 Lifecycle,
57 Navigation,
58 Census,
59 Custom,
60}
61
62impl EventCategory {
63 pub fn as_str(self) -> &'static str {
64 match self {
65 Self::Intent => "intent",
66 Self::Lifecycle => "lifecycle",
67 Self::Navigation => "navigation",
68 Self::Census => "census",
69 Self::Custom => "custom",
70 }
71 }
72}
73
74#[derive(Debug, Clone)]
76pub struct Prop<'a> {
77 pub key: &'static str,
78 pub value: PropValue<'a>,
79}
80
81impl<'a> Prop<'a> {
82 pub fn to_owned(&self) -> OwnedProp {
83 OwnedProp {
84 key: self.key.to_owned(),
85 value: self.value.to_owned(),
86 }
87 }
88}
89
90#[derive(Debug, Clone)]
97pub enum PropValue<'a> {
98 StaticStr(&'static str),
101 BoundedStr(&'a str),
105 U32(u32),
106 I64(i64),
107 F64Bucket(F64Bucket),
111 Bool(bool),
112 Enum {
114 variant: &'static str,
115 },
116 HistogramStrU32(&'a [(&'static str, u32)]),
118}
119
120impl<'a> PropValue<'a> {
121 pub fn to_owned(&self) -> OwnedPropValue {
122 match self {
123 Self::StaticStr(s) => OwnedPropValue::Str((*s).to_owned()),
124 Self::BoundedStr(s) => OwnedPropValue::Str((*s).to_owned()),
125 Self::U32(v) => OwnedPropValue::U32(*v),
126 Self::I64(v) => OwnedPropValue::I64(*v),
127 Self::F64Bucket(b) => OwnedPropValue::F64Bucket(*b),
128 Self::Bool(v) => OwnedPropValue::Bool(*v),
129 Self::Enum { variant } => OwnedPropValue::Str((*variant).to_owned()),
130 Self::HistogramStrU32(entries) => OwnedPropValue::HistogramStrU32(
131 entries.iter().map(|(k, v)| ((*k).to_owned(), *v)).collect(),
132 ),
133 }
134 }
135}
136
137#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
138pub struct F64Bucket {
139 pub min_x100: i64,
143 pub max_x100: i64,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct OwnedEvent {
156 pub name: String,
157 pub category: EventCategory,
158 pub timestamp: SystemTime,
159 pub install_id: Option<String>,
160 pub session_id: String,
161 pub schema_version: u32,
162 pub props: Vec<OwnedProp>,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct OwnedProp {
167 pub key: String,
168 pub value: OwnedPropValue,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub enum OwnedPropValue {
173 Str(String),
174 U32(u32),
175 I64(i64),
176 F64Bucket(F64Bucket),
177 Bool(bool),
178 HistogramStrU32(Vec<(String, u32)>),
179}
180
181#[derive(Copy, Clone, Debug, PartialEq, Eq)]
188pub enum IntentSource {
189 Shortcut,
190 Menu,
191 Handler,
192 Programmatic,
193 Accessibility,
194 Unknown,
195}
196
197impl IntentSource {
198 pub fn as_str(self) -> &'static str {
199 match self {
200 Self::Shortcut => "shortcut",
201 Self::Menu => "menu",
202 Self::Handler => "handler",
203 Self::Programmatic => "programmatic",
204 Self::Accessibility => "accessibility",
205 Self::Unknown => "unknown",
206 }
207 }
208}
209
210#[derive(Debug, Clone, Serialize)]
222pub struct RemoteDataExport {
223 pub install_id: String,
224 pub fetched_at: SystemTime,
225 pub adapter: &'static str,
226 pub endpoint: String,
227 pub schema_version: u32,
228 pub events: Vec<RemoteEvent>,
229 pub server_metadata: BTreeMap<String, RemoteValue>,
230}
231
232#[derive(Debug, Clone, Serialize)]
233pub struct RemoteEvent {
234 pub name: String,
235 pub timestamp: SystemTime,
236 pub properties: BTreeMap<String, RemoteValue>,
237}
238
239#[derive(Debug, Clone, PartialEq, Serialize)]
243pub enum RemoteValue {
244 String(String),
245 Int(i64),
246 Float(f64),
247 Bool(bool),
248 Null,
249}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254
255 #[test]
256 fn event_to_owned_round_trip() {
257 let props = [
258 Prop {
259 key: "name",
260 value: PropValue::StaticStr("app.save"),
261 },
262 Prop {
263 key: "count",
264 value: PropValue::U32(3),
265 },
266 ];
267 let event = Event {
268 name: "intent.dispatched",
269 category: EventCategory::Intent,
270 timestamp: SystemTime::UNIX_EPOCH,
271 install_id: None,
272 session_id: "abc",
273 schema_version: 1,
274 props: &props,
275 };
276 let owned = event.to_owned();
277 assert_eq!(owned.name, "intent.dispatched");
278 assert_eq!(owned.props.len(), 2);
279 assert!(matches!(owned.props[0].value, OwnedPropValue::Str(ref s) if s == "app.save"));
280 assert!(matches!(owned.props[1].value, OwnedPropValue::U32(3)));
281 }
282
283 #[test]
284 fn intent_source_str() {
285 assert_eq!(IntentSource::Shortcut.as_str(), "shortcut");
286 assert_eq!(IntentSource::Unknown.as_str(), "unknown");
287 }
288}