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    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    // FIXME #398 implement async resolution
31    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                // Observe the pointer
294                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                                // unobserve after first update
303                                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                // Update the pointer value
315                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                // Check if the observed value matches the update
328                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                // try unobserve again, should fail
339                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}