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