1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4use crate::ids::{ComponentName, EntityPath, Timeline};
5
6#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
7pub enum ComponentKind {
8 Transform3D,
9 Points3D,
10 Scalar,
11 ImageRef,
12 Annotation,
13}
14
15impl ComponentKind {
16 pub const ALL: [Self; 5] = [
17 Self::Transform3D,
18 Self::Points3D,
19 Self::Scalar,
20 Self::ImageRef,
21 Self::Annotation,
22 ];
23
24 pub fn as_str(&self) -> &'static str {
25 match self {
26 Self::Transform3D => "Transform3D",
27 Self::Points3D => "Points3D",
28 Self::Scalar => "Scalar",
29 Self::ImageRef => "ImageRef",
30 Self::Annotation => "Annotation",
31 }
32 }
33
34 pub fn parse(s: &str) -> Option<Self> {
35 match s {
36 "Transform3D" => Some(Self::Transform3D),
37 "Points3D" => Some(Self::Points3D),
38 "Scalar" => Some(Self::Scalar),
39 "ImageRef" => Some(Self::ImageRef),
40 "Annotation" => Some(Self::Annotation),
41 _ => None,
42 }
43 }
44}
45
46impl fmt::Display for ComponentKind {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 f.write_str(self.as_str())
49 }
50}
51
52#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
53#[serde(tag = "kind")]
54pub enum Payload {
55 Transform3D {
56 tx: f64,
57 ty: f64,
58 tz: f64,
59 qx: f64,
60 qy: f64,
61 qz: f64,
62 qw: f64,
63 },
64 Points3D {
65 points: Vec<[f64; 3]>,
66 },
67 Scalar {
68 value: f64,
69 #[serde(default, skip_serializing_if = "Option::is_none")]
70 unit: Option<String>,
71 },
72 ImageRef {
73 uri: String,
74 width: i32,
75 height: i32,
76 format: String,
77 },
78 Annotation {
79 label: String,
80 },
81}
82
83impl Payload {
84 pub fn kind(&self) -> ComponentKind {
85 match self {
86 Self::Transform3D { .. } => ComponentKind::Transform3D,
87 Self::Points3D { .. } => ComponentKind::Points3D,
88 Self::Scalar { .. } => ComponentKind::Scalar,
89 Self::ImageRef { .. } => ComponentKind::ImageRef,
90 Self::Annotation { .. } => ComponentKind::Annotation,
91 }
92 }
93}
94
95#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
96pub struct Event {
97 pub entity_path: EntityPath,
98 pub timeline: Timeline,
99 pub t_ns: i64,
100 pub component: ComponentName,
101 pub payload: Payload,
102}
103
104impl Event {
105 pub fn kind(&self) -> ComponentKind {
106 self.payload.kind()
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn component_kind_roundtrip() {
116 for kind in ComponentKind::ALL {
117 assert_eq!(ComponentKind::parse(kind.as_str()), Some(kind));
118 }
119 assert_eq!(ComponentKind::parse("Nope"), None);
120 }
121
122 #[test]
123 fn event_json_roundtrip() {
124 let event = Event {
125 entity_path: EntityPath::new("/robot/base").unwrap(),
126 timeline: Timeline::wall(),
127 t_ns: 1_000_000_000,
128 component: ComponentName::new("pose"),
129 payload: Payload::Transform3D {
130 tx: 1.0,
131 ty: 2.0,
132 tz: 3.0,
133 qx: 0.0,
134 qy: 0.0,
135 qz: 0.0,
136 qw: 1.0,
137 },
138 };
139 let json = serde_json::to_string(&event).unwrap();
140 let back: Event = serde_json::from_str(&json).unwrap();
141 assert_eq!(event, back);
142 }
143}