Skip to main content

datex_core/runtime/
dif_interface.rs

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