1use crate::dif::DIFConvertible;
2use crate::dif::representation::DIFValueRepresentation;
3use crate::dif::r#type::DIFTypeDefinition;
4use crate::libs::core::CoreLibPointerId;
5use crate::runtime::memory::Memory;
6use crate::stdlib::string::ToString;
7use crate::types::definition::TypeDefinition;
8use crate::values::core_value::CoreValue;
9use crate::values::core_values::decimal::typed_decimal::{
10 DecimalTypeVariant, TypedDecimal,
11};
12use crate::values::core_values::integer::typed_integer::TypedInteger;
13use crate::values::core_values::map::{BorrowedMapKey, Map};
14use crate::values::pointer::PointerAddress;
15use crate::values::value::Value;
16use crate::values::value_container::ValueContainer;
17use core::cell::RefCell;
18use core::prelude::rust_2024::*;
19use core::result::Result;
20use serde::{Deserialize, Serialize};
21
22#[derive(Debug)]
23pub struct DIFReferenceNotFoundError;
24
25#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
27pub struct DIFValue {
28 pub value: DIFValueRepresentation,
29 #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
30 pub ty: Option<DIFTypeDefinition>,
31}
32impl DIFConvertible for DIFValue {}
33
34impl DIFValue {
35 pub fn to_value(
38 &self,
39 memory: &RefCell<Memory>,
40 ) -> Result<Value, DIFReferenceNotFoundError> {
41 Ok(if let Some(ty) = &self.ty {
42 self.value.to_value_with_type(ty, memory)?
43 } else {
44 self.value.to_default_value(memory)?
45 })
46 }
47}
48
49impl DIFValue {
50 pub fn new(
51 value: DIFValueRepresentation,
52 ty: Option<impl Into<DIFTypeDefinition>>,
53 ) -> Self {
54 DIFValue {
55 value,
56 ty: ty.map(Into::into),
57 }
58 }
59 pub fn as_container(&self) -> DIFValueContainer {
60 DIFValueContainer::from(self.clone())
61 }
62}
63
64impl From<DIFValueRepresentation> for DIFValue {
65 fn from(value: DIFValueRepresentation) -> Self {
66 DIFValue { value, ty: None }
67 }
68}
69
70#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
72#[serde(untagged)]
73pub enum DIFValueContainer {
74 Value(DIFValue),
75 Reference(PointerAddress),
76}
77impl DIFConvertible for DIFValueContainer {}
78
79impl DIFValueContainer {
80 pub fn to_value_container(
83 &self,
84 memory: &RefCell<Memory>,
85 ) -> Result<ValueContainer, DIFReferenceNotFoundError> {
86 Ok(match self {
87 DIFValueContainer::Reference(address) => ValueContainer::Reference(
88 memory
89 .borrow()
90 .get_reference(address)
91 .ok_or(DIFReferenceNotFoundError)?
92 .clone(),
93 ),
94 DIFValueContainer::Value(v) => {
95 ValueContainer::Value(v.to_value(memory)?)
96 }
97 })
98 }
99}
100
101impl From<DIFValue> for DIFValueContainer {
102 fn from(value: DIFValue) -> Self {
103 DIFValueContainer::Value(value)
104 }
105}
106impl From<&DIFValue> for DIFValueContainer {
107 fn from(value: &DIFValue) -> Self {
108 DIFValueContainer::Value(value.clone())
109 }
110}
111impl From<PointerAddress> for DIFValueContainer {
112 fn from(ptr: PointerAddress) -> Self {
113 DIFValueContainer::Reference(ptr)
114 }
115}
116
117impl DIFValueContainer {
118 pub fn from_value_container(
119 value_container: &ValueContainer,
120 memory: &RefCell<Memory>,
121 ) -> Self {
122 match value_container {
123 ValueContainer::Reference(reference) => {
124 let address = reference.ensure_pointer_address(memory);
126 DIFValueContainer::Reference(address)
127 }
128 ValueContainer::Value(value) => {
129 DIFValueContainer::Value(DIFValue::from_value(value, memory))
130 }
131 }
132 }
133}
134
135impl DIFValue {
136 fn from_value(value: &Value, memory: &RefCell<Memory>) -> Self {
137 let core_value = &value.inner;
138
139 let mut is_empty_map = false;
140
141 let dif_core_value = match core_value {
142 CoreValue::Type(ty) => {
143 core::todo!("#382 Type value not supported in DIF")
144 }
145 CoreValue::Callable(callable) => {
146 core::todo!("#616 Callable value not yet supported in DIF")
147 }
148 CoreValue::Null => DIFValueRepresentation::Null,
149 CoreValue::Boolean(bool) => DIFValueRepresentation::Boolean(bool.0),
150 CoreValue::Integer(integer) => {
151 DIFValueRepresentation::String(integer.to_string())
153 }
154 CoreValue::TypedInteger(integer) => {
155 match integer {
156 TypedInteger::I8(i) => {
157 DIFValueRepresentation::Number(*i as f64)
158 }
159 TypedInteger::U8(u) => {
160 DIFValueRepresentation::Number(*u as f64)
161 }
162 TypedInteger::I16(i) => {
163 DIFValueRepresentation::Number(*i as f64)
164 }
165 TypedInteger::U16(u) => {
166 DIFValueRepresentation::Number(*u as f64)
167 }
168 TypedInteger::I32(i) => {
169 DIFValueRepresentation::Number(*i as f64)
170 }
171 TypedInteger::U32(u) => {
172 DIFValueRepresentation::Number(*u as f64)
173 }
174 TypedInteger::I64(i) => {
176 DIFValueRepresentation::String(i.to_string())
177 }
178 TypedInteger::U64(u) => {
179 DIFValueRepresentation::String(u.to_string())
180 }
181 TypedInteger::I128(i) => {
182 DIFValueRepresentation::String(i.to_string())
183 }
184 TypedInteger::U128(u) => {
185 DIFValueRepresentation::String(u.to_string())
186 }
187 TypedInteger::IBig(i) => {
188 DIFValueRepresentation::String(i.to_string())
189 }
190 }
191 }
192 CoreValue::Decimal(decimal) => {
193 DIFValueRepresentation::String(decimal.to_string())
195 }
196 CoreValue::TypedDecimal(decimal) => match decimal {
197 TypedDecimal::F32(f) => {
198 DIFValueRepresentation::Number(f.0 as f64)
199 }
200 TypedDecimal::F64(f) => DIFValueRepresentation::Number(f.0),
201 TypedDecimal::Decimal(bd) => {
202 DIFValueRepresentation::String(bd.to_string())
203 }
204 },
205 CoreValue::Text(text) => {
206 DIFValueRepresentation::String(text.0.clone())
207 }
208 CoreValue::Endpoint(endpoint) => {
209 DIFValueRepresentation::String(endpoint.to_string())
210 }
211 CoreValue::List(list) => DIFValueRepresentation::Array(
212 list.iter()
213 .map(|v| DIFValueContainer::from_value_container(v, memory))
214 .collect(),
215 ),
216 CoreValue::Map(map) => match map {
217 Map::Structural(entries) => DIFValueRepresentation::Object(
218 entries
219 .iter()
220 .map(|(k, v)| {
221 (
222 k.clone(),
223 DIFValueContainer::from_value_container(
224 v, memory,
225 ),
226 )
227 })
228 .collect(),
229 ),
230 _ => {
231 if map.is_empty() {
232 is_empty_map = true;
233 };
234
235 DIFValueRepresentation::Map(
236 map.into_iter()
237 .map(|(k, v)| {
238 (
239 match k {
240 BorrowedMapKey::Text(text_key) => {
241 DIFValueContainer::Value(
242 DIFValueRepresentation::String(
243 text_key.to_string(),
244 )
245 .into(),
246 )
247 }
248 _ => {
249 DIFValueContainer::from_value_container(
250 &ValueContainer::from(k),
251 memory,
252 )
253 }
254 },
255 DIFValueContainer::from_value_container(
256 v, memory,
257 ),
258 )
259 })
260 .collect(),
261 )
262 }
263 },
264 };
265
266 DIFValue {
267 value: dif_core_value,
268 ty: get_type_if_non_default(
269 &value.actual_type,
270 memory,
271 is_empty_map,
272 ),
273 }
274 }
275}
276
277fn get_type_if_non_default(
286 type_definition: &TypeDefinition,
287 memory: &RefCell<Memory>,
288 is_empty_map: bool,
289) -> Option<DIFTypeDefinition> {
290 match type_definition {
291 TypeDefinition::Reference(inner) => {
292 if let Some(Ok(address)) = inner
293 .borrow()
294 .pointer_address
295 .as_ref()
296 .map(CoreLibPointerId::try_from)
297 && (core::matches!(
298 address,
299 CoreLibPointerId::Decimal(Some(DecimalTypeVariant::F64))
300 | CoreLibPointerId::Boolean
301 | CoreLibPointerId::Text
302 | CoreLibPointerId::List
303 | CoreLibPointerId::Null
304 ) ||
305 (core::matches!(address, CoreLibPointerId::Map) && !is_empty_map))
307 {
308 None
309 } else {
310 Some(DIFTypeDefinition::from_type_definition(
311 type_definition,
312 memory,
313 ))
314 }
315 }
316 _ => Some(DIFTypeDefinition::from_type_definition(
317 type_definition,
318 memory,
319 )),
320 }
321}
322
323#[cfg(test)]
324mod tests {
325 use crate::dif::DIFConvertible;
326 use crate::dif::r#type::DIFTypeDefinition;
327 use crate::runtime::memory::Memory;
328 use crate::values::core_values::endpoint::Endpoint;
329 use crate::values::core_values::map::Map;
330 use crate::values::value_container::ValueContainer;
331 use crate::{
332 dif::value::DIFValue, libs::core::CoreLibPointerId,
333 values::core_values::integer::typed_integer::IntegerTypeVariant,
334 };
335 use core::cell::RefCell;
336 use datex_core::values::value::Value;
337
338 fn get_mock_memory() -> RefCell<Memory> {
339 RefCell::new(Memory::new(Endpoint::default()))
340 }
341
342 #[test]
343 fn default_type() {
344 let memory = get_mock_memory();
345 let dif = DIFValue::from_value(&Value::from(true), &memory);
346 assert!(dif.ty.is_none());
347
348 let dif = DIFValue::from_value(&Value::from("hello"), &memory);
349 assert!(dif.ty.is_none());
350
351 let dif = DIFValue::from_value(&Value::null(), &memory);
352 assert!(dif.ty.is_none());
353
354 let dif = DIFValue::from_value(&Value::from(3.5f64), &memory);
355 assert!(dif.ty.is_none());
356
357 let dif = DIFValue::from_value(
358 &Value::from(vec![Value::from(1), Value::from(2), Value::from(3)]),
359 &memory,
360 );
361 assert!(dif.ty.is_none());
362
363 let dif = DIFValue::from_value(
364 &Value::from(Map::from(vec![
365 ("a".to_string(), ValueContainer::from(1)),
366 ("b".to_string(), ValueContainer::from(2)),
367 ])),
368 &memory,
369 );
370 assert!(dif.ty.is_none());
371 }
372
373 #[test]
374 fn non_default_type() {
375 let memory = get_mock_memory();
376 let dif = DIFValue::from_value(&Value::from(123u16), &memory);
377 assert!(dif.ty.is_some());
378 if let DIFTypeDefinition::Reference(reference) = dif.ty.unwrap() {
379 assert_eq!(
380 reference,
381 CoreLibPointerId::Integer(Some(IntegerTypeVariant::U16)).into()
382 );
383 } else {
384 core::panic!("Expected reference type");
385 }
386
387 let dif = DIFValue::from_value(&Value::from(123i64), &memory);
388 assert!(dif.ty.is_some());
389 if let DIFTypeDefinition::Reference(reference) = dif.ty.unwrap() {
390 assert_eq!(
391 reference,
392 CoreLibPointerId::Integer(Some(IntegerTypeVariant::I64)).into()
393 );
394 } else {
395 core::panic!("Expected reference type");
396 }
397 }
398
399 #[test]
400 fn serde_dif_value() {
401 let memory = get_mock_memory();
402 let dif = DIFValue::from_value(&Value::from("Hello, world!"), &memory);
403 let serialized = dif.as_json();
404 let deserialized = DIFValue::from_json(&serialized);
405 assert_eq!(dif, deserialized);
406 }
407}