datex_core/runtime/
dif_interface.rs

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