1use crate::{
2 dif::{DIFConvertible, value::DIFValueContainer},
3 references::observers::TransceiverId,
4 runtime::memory::Memory,
5 values::value_container::ValueKey,
6};
7use core::{cell::RefCell, prelude::rust_2024::*};
8use serde::{Deserialize, Serialize};
9
10use crate::prelude::*;
11#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
13#[serde(tag = "kind", rename_all = "lowercase", content = "value")]
14pub enum DIFKey {
15 Text(String),
17 Index(i64),
20 Value(DIFValueContainer),
22}
23
24impl DIFKey {
25 pub fn from_value_key(key: &ValueKey, memory: &RefCell<Memory>) -> Self {
26 match key {
27 ValueKey::Text(s) => DIFKey::Text(s.to_string()),
28 ValueKey::Index(i) => DIFKey::Index(*i),
29 ValueKey::Value(v) => DIFKey::Value(
30 DIFValueContainer::from_value_container(v, memory),
31 ),
32 }
33 }
34}
35
36impl From<String> for DIFKey {
37 fn from(s: String) -> Self {
38 DIFKey::Text(s)
39 }
40}
41impl From<&str> for DIFKey {
42 fn from(s: &str) -> Self {
43 DIFKey::Text(s.to_string())
44 }
45}
46impl From<i64> for DIFKey {
47 fn from(i: i64) -> Self {
48 DIFKey::Index(i)
49 }
50}
51impl From<DIFValueContainer> for DIFKey {
52 fn from(v: DIFValueContainer) -> Self {
53 DIFKey::Value(v)
54 }
55}
56
57#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
58pub struct DIFUpdate<'a> {
59 pub source_id: TransceiverId,
60 pub data: Cow<'a, DIFUpdateData>,
61}
62
63impl<'a> DIFUpdate<'a> {
64 pub fn new(source_id: TransceiverId, data: Cow<'a, DIFUpdateData>) -> Self {
66 DIFUpdate { source_id, data }
67 }
68}
69
70#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
75#[serde(tag = "kind", rename_all = "snake_case")]
76pub enum DIFUpdateData {
77 Replace { value: DIFValueContainer },
79
80 Set {
83 key: DIFKey,
84 value: DIFValueContainer,
85 },
86
87 Delete { key: DIFKey },
89
90 Clear,
92
93 Append { value: DIFValueContainer },
95
96 ListSplice {
98 start: u32,
99 delete_count: u32,
100 items: Vec<DIFValueContainer>,
101 },
102}
103
104impl DIFConvertible for DIFUpdateData {}
105
106impl DIFUpdateData {
107 pub fn replace(value: impl Into<DIFValueContainer>) -> Self {
109 DIFUpdateData::Replace {
110 value: value.into(),
111 }
112 }
113
114 pub fn set(
116 key: impl Into<DIFKey>,
117 value: impl Into<DIFValueContainer>,
118 ) -> Self {
119 DIFUpdateData::Set {
120 key: key.into(),
121 value: value.into(),
122 }
123 }
124
125 pub fn delete(key: impl Into<DIFKey>) -> Self {
127 DIFUpdateData::Delete { key: key.into() }
128 }
129
130 pub fn clear() -> Self {
132 DIFUpdateData::Clear
133 }
134
135 pub fn append(value: impl Into<DIFValueContainer>) -> Self {
137 DIFUpdateData::Append {
138 value: value.into(),
139 }
140 }
141
142 pub fn list_splice(
144 range: core::ops::Range<u32>,
145 items: Vec<DIFValueContainer>,
146 ) -> Self {
147 DIFUpdateData::ListSplice {
148 start: range.start,
149 delete_count: range.end - range.start,
150 items,
151 }
152 }
153
154 pub fn with_source(&self, source_id: TransceiverId) -> DIFUpdate<'_> {
155 DIFUpdate {
156 source_id,
157 data: Cow::Borrowed(self),
158 }
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 use crate::dif::{representation::DIFValueRepresentation, value::DIFValue};
166
167 #[test]
168 fn serialize_replace() {
169 let dif_update =
170 DIFUpdateData::replace(DIFValueContainer::Value(DIFValue {
171 value: DIFValueRepresentation::String("Hello".to_string()),
172 ty: None,
173 }));
174 let serialized = dif_update.as_json();
175 assert_eq!(
176 serialized,
177 r#"{"kind":"replace","value":{"value":"Hello"}}"#
178 );
179 let deserialized = DIFUpdateData::from_json(&serialized);
180 assert_eq!(dif_update, deserialized);
181 }
182
183 #[test]
184 fn serialize_set() {
185 let dif_update = DIFUpdateData::set(
186 "name",
187 DIFValueContainer::Value(DIFValue {
188 value: DIFValueRepresentation::Number(42.0),
189 ty: None,
190 }),
191 );
192 let serialized = dif_update.as_json();
193 assert_eq!(
194 serialized,
195 r#"{"kind":"set","key":{"kind":"text","value":"name"},"value":{"value":42.0}}"#
196 );
197 let deserialized = DIFUpdateData::from_json(&serialized);
198 assert_eq!(dif_update, deserialized);
199 }
200
201 #[test]
202 fn serialize_remove() {
203 let dif_update = DIFUpdateData::delete("age");
204 let serialized = dif_update.as_json();
205 assert_eq!(
206 serialized,
207 r#"{"kind":"delete","key":{"kind":"text","value":"age"}}"#
208 );
209 let deserialized = DIFUpdateData::from_json(&serialized);
210 assert_eq!(dif_update, deserialized);
211 }
212
213 #[test]
214 fn serialize_clear() {
215 let dif_update = DIFUpdateData::clear();
216 let serialized = dif_update.as_json();
217 assert_eq!(serialized, r#"{"kind":"clear"}"#);
218 let deserialized = DIFUpdateData::from_json(&serialized);
219 assert_eq!(dif_update, deserialized);
220 }
221
222 #[test]
223 fn serialize_push() {
224 let dif_update =
225 DIFUpdateData::append(DIFValueContainer::Value(DIFValue {
226 value: DIFValueRepresentation::Boolean(true),
227 ty: None,
228 }));
229 let serialized = dif_update.as_json();
230 assert_eq!(serialized, r#"{"kind":"append","value":{"value":true}}"#);
231 let deserialized = DIFUpdateData::from_json(&serialized);
232 assert_eq!(dif_update, deserialized);
233 }
234}