1use serde::{Deserialize, Serialize};
2
3use crate::dif::{DIFConvertible, value::DIFValueContainer};
4use crate::references::observers::TransceiverId;
5
6#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
8#[serde(tag = "kind", rename_all = "lowercase", content = "value")]
9pub enum DIFProperty {
10 Text(String),
12 Index(i64),
15 Value(DIFValueContainer),
17}
18
19impl From<String> for DIFProperty {
20 fn from(s: String) -> Self {
21 DIFProperty::Text(s)
22 }
23}
24impl From<&str> for DIFProperty {
25 fn from(s: &str) -> Self {
26 DIFProperty::Text(s.to_string())
27 }
28}
29impl From<i64> for DIFProperty {
30 fn from(i: i64) -> Self {
31 DIFProperty::Index(i)
32 }
33}
34impl From<DIFValueContainer> for DIFProperty {
35 fn from(v: DIFValueContainer) -> Self {
36 DIFProperty::Value(v)
37 }
38}
39
40#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
41pub struct DIFUpdate {
42 pub source_id: TransceiverId,
43 pub data: DIFUpdateData,
44}
45
46impl DIFUpdate {
47 pub fn new(source_id: TransceiverId, data: DIFUpdateData) -> Self {
49 DIFUpdate { source_id, data }
50 }
51}
52
53#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
58#[serde(tag = "kind", rename_all = "lowercase")]
59pub enum DIFUpdateData {
60 Replace { value: DIFValueContainer },
62
63 Set {
66 key: DIFProperty,
67 value: DIFValueContainer,
68 },
69
70 Remove { key: DIFProperty },
72
73 Clear,
75
76 Push { value: DIFValueContainer },
78}
79
80impl DIFConvertible for DIFUpdateData {}
81
82impl DIFUpdateData {
83 pub fn replace(value: impl Into<DIFValueContainer>) -> Self {
85 DIFUpdateData::Replace {
86 value: value.into(),
87 }
88 }
89
90 pub fn set(
92 key: impl Into<DIFProperty>,
93 value: impl Into<DIFValueContainer>,
94 ) -> Self {
95 DIFUpdateData::Set {
96 key: key.into(),
97 value: value.into(),
98 }
99 }
100
101 pub fn remove(key: impl Into<DIFProperty>) -> Self {
103 DIFUpdateData::Remove { key: key.into() }
104 }
105
106 pub fn clear() -> Self {
108 DIFUpdateData::Clear
109 }
110
111 pub fn push(value: impl Into<DIFValueContainer>) -> Self {
113 DIFUpdateData::Push {
114 value: value.into(),
115 }
116 }
117
118 pub fn with_source(self, source_id: TransceiverId) -> DIFUpdate {
119 DIFUpdate {
120 source_id,
121 data: self,
122 }
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use crate::dif::representation::DIFValueRepresentation;
130 use crate::dif::value::DIFValue;
131
132 #[test]
133 fn serialize_replace() {
134 let dif_update =
135 DIFUpdateData::replace(DIFValueContainer::Value(DIFValue {
136 value: DIFValueRepresentation::String("Hello".to_string()),
137 r#type: None,
138 }));
139 let serialized = dif_update.as_json();
140 assert_eq!(
141 serialized,
142 r#"{"kind":"replace","value":{"value":"Hello"}}"#
143 );
144 let deserialized = DIFUpdateData::from_json(&serialized);
145 assert_eq!(dif_update, deserialized);
146 }
147
148 #[test]
149 fn serialize_set() {
150 let dif_update = DIFUpdateData::set(
151 "name",
152 DIFValueContainer::Value(DIFValue {
153 value: DIFValueRepresentation::Number(42.0),
154 r#type: None,
155 }),
156 );
157 let serialized = dif_update.as_json();
158 assert_eq!(
159 serialized,
160 r#"{"kind":"set","key":{"kind":"text","value":"name"},"value":{"value":42.0}}"#
161 );
162 let deserialized = DIFUpdateData::from_json(&serialized);
163 assert_eq!(dif_update, deserialized);
164 }
165
166 #[test]
167 fn serialize_remove() {
168 let dif_update = DIFUpdateData::remove("age");
169 let serialized = dif_update.as_json();
170 assert_eq!(
171 serialized,
172 r#"{"kind":"remove","key":{"kind":"text","value":"age"}}"#
173 );
174 let deserialized = DIFUpdateData::from_json(&serialized);
175 assert_eq!(dif_update, deserialized);
176 }
177
178 #[test]
179 fn serialize_clear() {
180 let dif_update = DIFUpdateData::clear();
181 let serialized = dif_update.as_json();
182 assert_eq!(serialized, r#"{"kind":"clear"}"#);
183 let deserialized = DIFUpdateData::from_json(&serialized);
184 assert_eq!(dif_update, deserialized);
185 }
186
187 #[test]
188 fn serialize_push() {
189 let dif_update =
190 DIFUpdateData::push(DIFValueContainer::Value(DIFValue {
191 value: DIFValueRepresentation::Boolean(true),
192 r#type: None,
193 }));
194 let serialized = dif_update.as_json();
195 assert_eq!(serialized, r#"{"kind":"push","value":{"value":true}}"#);
196 let deserialized = DIFUpdateData::from_json(&serialized);
197 assert_eq!(dif_update, deserialized);
198 }
199}