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