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