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 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 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 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 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 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 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}