1use crate::{
2 dif::{
3 interface::{
4 DIFApplyError, DIFCreatePointerError, DIFInterface,
5 DIFObserveError, DIFResolveReferenceError, DIFUpdateError,
6 },
7 reference::DIFReference,
8 r#type::DIFTypeDefinition,
9 update::{DIFKey, DIFUpdateData},
10 value::{DIFReferenceNotFoundError, DIFValueContainer},
11 },
12 prelude::*,
13 runtime::RuntimeInternal,
14 shared_values::{
15 observers::{ObserveOptions, Observer, TransceiverId},
16 pointer_address::PointerAddress,
17 shared_container::{SharedContainer, SharedContainerMutability},
18 },
19 values::value_container::ValueContainer,
20};
21use core::result::Result;
22
23impl RuntimeInternal {
24 fn resolve_in_memory_reference(
25 &self,
26 address: &PointerAddress,
27 ) -> Option<SharedContainer> {
28 self.memory.borrow().get_reference(address).cloned()
29 }
30 async fn resolve_reference(
32 &self,
33 address: &PointerAddress,
34 ) -> Option<SharedContainer> {
35 self.memory.borrow().get_reference(address).cloned()
36 }
37}
38
39impl DIFInterface for RuntimeInternal {
40 fn update(
41 &self,
42 source_id: TransceiverId,
43 address: PointerAddress,
44 update: &DIFUpdateData,
45 ) -> Result<(), DIFUpdateError> {
46 let reference = self
47 .resolve_in_memory_reference(&address)
48 .ok_or(DIFUpdateError::ReferenceNotFound)?;
49 match update {
50 DIFUpdateData::Set { key, value } => {
51 let value_container = value.to_value_container(&self.memory)?;
52 match key {
53 DIFKey::Text(key) => reference.try_set_property(
54 source_id,
55 Some(update),
56 key,
57 value_container,
58 )?,
59 DIFKey::Index(key) => reference.try_set_property(
60 source_id,
61 Some(update),
62 *key,
63 value_container,
64 )?,
65 DIFKey::Value(key) => {
66 let key = key.to_value_container(&self.memory)?;
67 reference.try_set_property(
68 source_id,
69 Some(update),
70 &key,
71 value_container,
72 )?
73 }
74 }
75 }
76 DIFUpdateData::Replace { value } => reference.try_replace(
77 source_id,
78 Some(update),
79 value.to_value_container(&self.memory)?,
80 )?,
81 DIFUpdateData::Append { value } => reference.try_append_value(
82 source_id,
83 Some(update),
84 value.to_value_container(&self.memory)?,
85 )?,
86 DIFUpdateData::Clear => reference.try_clear(source_id)?,
87 DIFUpdateData::Delete { key } => match key {
88 DIFKey::Text(key) => reference.try_delete_property(
89 source_id,
90 Some(update),
91 key,
92 )?,
93 DIFKey::Index(key) => reference.try_delete_property(
94 source_id,
95 Some(update),
96 *key,
97 )?,
98 DIFKey::Value(key) => {
99 let key = key.to_value_container(&self.memory)?;
100 reference.try_delete_property(
101 source_id,
102 Some(update),
103 &key,
104 )?
105 }
106 },
107 DIFUpdateData::ListSplice {
108 start,
109 delete_count,
110 items,
111 } => {
112 reference.try_list_splice(
113 source_id,
114 Some(update),
115 *start..(start + delete_count),
116 items
117 .iter()
118 .map(|item| item.to_value_container(&self.memory))
119 .collect::<Result<
120 Vec<ValueContainer>,
121 DIFReferenceNotFoundError,
122 >>()?,
123 )?
124 }
125 };
126
127 Ok(())
128 }
129
130 fn apply(
131 &self,
132 _callee: DIFValueContainer,
133 _value: DIFValueContainer,
134 ) -> Result<DIFValueContainer, DIFApplyError> {
135 core::todo!("#400 Undescribed by author.")
136 }
137
138 fn create_pointer(
139 &self,
140 value: DIFValueContainer,
141 allowed_type: Option<DIFTypeDefinition>,
142 mutability: SharedContainerMutability,
143 ) -> Result<PointerAddress, DIFCreatePointerError> {
144 let container = value.to_value_container(&self.memory)?;
145 let type_container = if let Some(_allowed_type) = &allowed_type {
146 core::todo!(
147 "FIXME: Implement type_container creation from DIFTypeDefinition"
148 )
149 } else {
150 None
151 };
152
153 let pointer = self.memory.borrow_mut().get_new_owned_local_pointer();
154 let address = pointer.address();
155
156 let reference = SharedContainer::try_boxed(
157 container,
158 type_container,
159 pointer,
160 mutability,
161 )?;
162 self.memory
163 .borrow_mut()
164 .register_shared_container(&reference);
165 Ok(address)
166 }
167
168 async fn resolve_pointer_address_external(
169 &self,
170 address: PointerAddress,
171 ) -> Result<DIFReference, DIFResolveReferenceError> {
172 let reference = self.resolve_in_memory_reference(&address);
173 match reference {
174 Some(ptr) => Ok(DIFReference::from_reference(&ptr)),
175 None => {
176 core::todo!("#399 Implement async resolution of references")
177 }
178 }
179 }
180
181 fn resolve_pointer_address_in_memory(
182 &self,
183 address: PointerAddress,
184 ) -> Result<DIFReference, DIFResolveReferenceError> {
185 let reference = self.resolve_in_memory_reference(&address);
186 match reference {
187 Some(ptr) => Ok(DIFReference::from_reference(&ptr)),
188 None => Err(DIFResolveReferenceError::ReferenceNotFound),
189 }
190 }
191
192 fn observe_pointer(
193 &self,
194 transceiver_id: TransceiverId,
195 address: PointerAddress,
196 options: ObserveOptions,
197 callback: impl Fn(&DIFUpdateData, TransceiverId) + 'static,
198 ) -> Result<u32, DIFObserveError> {
199 let reference = self
200 .resolve_in_memory_reference(&address)
201 .ok_or(DIFObserveError::ReferenceNotFound)?;
202 Ok(reference.observe(Observer {
203 transceiver_id,
204 options,
205 callback: Rc::new(callback),
206 })?)
207 }
208
209 fn update_observer_options(
210 &self,
211 address: PointerAddress,
212 observer_id: u32,
213 options: ObserveOptions,
214 ) -> Result<(), DIFObserveError> {
215 let reference = self
216 .resolve_in_memory_reference(&address)
217 .ok_or(DIFObserveError::ReferenceNotFound)?;
218 reference
219 .update_observer_options(observer_id, options)
220 .map_err(DIFObserveError::ObserveError)
221 }
222
223 fn unobserve_pointer(
224 &self,
225 address: PointerAddress,
226 observer_id: u32,
227 ) -> Result<(), DIFObserveError> {
228 let reference = self
229 .resolve_in_memory_reference(&address)
230 .ok_or(DIFObserveError::ReferenceNotFound)?;
231 reference
232 .unobserve(observer_id)
233 .map_err(DIFObserveError::ObserveError)
234 }
235}
236
237#[cfg(test)]
238mod tests {
239
240 use crate::{
241 dif::{
242 interface::DIFInterface,
243 representation::DIFValueRepresentation,
244 update::DIFUpdateData,
245 value::{DIFValue, DIFValueContainer},
246 },
247 prelude::*,
248 runtime::{RuntimeConfig, RuntimeRunner},
249 shared_values::{
250 observers::ObserveOptions,
251 shared_container::SharedContainerMutability,
252 },
253 values::{core_values::map::Map, value_container::ValueContainer},
254 };
255 use core::cell::RefCell;
256
257 #[test]
258 fn struct_serde() {
259 let map = ValueContainer::from(Map::from(vec![
260 ("a".to_string(), 1.into()),
261 ("b".to_string(), "text".into()),
262 ]));
263 let dif_value = DIFValueContainer::from_value_container(&map);
264 let _ = serde_json::to_string(&dif_value).unwrap();
265 }
266
267 #[tokio::test]
268 async fn test_create_and_observe_pointer() {
269 RuntimeRunner::new(RuntimeConfig::default())
270 .run(async |runtime| {
271 let runtime = runtime.internal;
272
273 let pointer_address = runtime
274 .create_pointer(
275 DIFValueContainer::Value(DIFValue::from(
276 DIFValueRepresentation::String(
277 "Hello, world!".to_string(),
278 ),
279 )),
280 None,
281 SharedContainerMutability::Mutable,
282 )
283 .expect("Failed to create pointer");
284
285 let observed = Rc::new(RefCell::new(None));
286 let observed_clone = observed.clone();
287
288 let observer_id = Rc::new(RefCell::new(None));
289 let observer_id_clone = observer_id.clone();
290 let runtime_clone = runtime.clone();
291 let pointer_address_clone = pointer_address.clone();
292
293 observer_id.replace(Some(
295 runtime
296 .observe_pointer(
297 0,
298 pointer_address_clone.clone(),
299 ObserveOptions::default(),
300 move |update, _| {
301 observed_clone.replace(Some(update.clone()));
302 runtime_clone
304 .unobserve_pointer(
305 pointer_address_clone.clone(),
306 observer_id_clone.borrow().unwrap(),
307 )
308 .unwrap();
309 },
310 )
311 .expect("Failed to observe pointer"),
312 ));
313
314 runtime
316 .update(
317 1,
318 pointer_address.clone(),
319 &DIFUpdateData::replace(DIFValue::from(
320 DIFValueRepresentation::String(
321 "Hello, Datex!".to_string(),
322 ),
323 )),
324 )
325 .expect("Failed to update pointer");
326
327 let observed_value = observed.borrow();
329 assert_eq!(
330 *observed_value,
331 Some(DIFUpdateData::replace(DIFValue::from(
332 DIFValueRepresentation::String(
333 "Hello, Datex!".to_string(),
334 )
335 )))
336 );
337
338 assert!(
340 runtime
341 .unobserve_pointer(
342 pointer_address.clone(),
343 observer_id.borrow().unwrap()
344 )
345 .is_err()
346 );
347 })
348 .await;
349 }
350}