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 value::Value,
17 value_container::ValueContainer,
18 },
19};
20use core::{cell::RefCell, result::Result};
21use serde::{Deserialize, Serialize};
22
23use crate::{prelude::*, shared_values::pointer_address::PointerAddress};
24
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::Shared(
91 memory
92 .borrow()
93 .get_reference(address)
94 .ok_or(DIFReferenceNotFoundError)?
95 .clone(),
96 ),
97 DIFValueContainer::Value(v) => {
98 ValueContainer::Local(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(value_container: &ValueContainer) -> Self {
122 match value_container {
123 ValueContainer::Shared(reference) => {
124 DIFValueContainer::Reference(reference.pointer_address())
125 }
126 ValueContainer::Local(value) => {
127 DIFValueContainer::Value(DIFValue::from_value(value))
128 }
129 }
130 }
131}
132
133impl DIFValue {
134 fn from_value(value: &Value) -> Self {
135 let core_value = &value.inner;
136
137 let mut is_empty_map = false;
138
139 let dif_core_value = match core_value {
140 CoreValue::Type(_ty) => {
141 core::todo!("#382 Type value not supported in DIF")
142 }
143 CoreValue::Callable(_callable) => {
144 core::todo!("#616 Callable value not yet supported in DIF")
145 }
146 CoreValue::Null => DIFValueRepresentation::Null,
147 CoreValue::Boolean(bool) => DIFValueRepresentation::Boolean(bool.0),
148 CoreValue::Integer(integer) => {
149 DIFValueRepresentation::String(integer.to_string())
151 }
152 CoreValue::TypedInteger(integer) => {
153 match integer {
154 TypedInteger::I8(i) => {
155 DIFValueRepresentation::Number(*i as f64)
156 }
157 TypedInteger::U8(u) => {
158 DIFValueRepresentation::Number(*u as f64)
159 }
160 TypedInteger::I16(i) => {
161 DIFValueRepresentation::Number(*i as f64)
162 }
163 TypedInteger::U16(u) => {
164 DIFValueRepresentation::Number(*u as f64)
165 }
166 TypedInteger::I32(i) => {
167 DIFValueRepresentation::Number(*i as f64)
168 }
169 TypedInteger::U32(u) => {
170 DIFValueRepresentation::Number(*u as f64)
171 }
172 TypedInteger::I64(i) => {
174 DIFValueRepresentation::String(i.to_string())
175 }
176 TypedInteger::U64(u) => {
177 DIFValueRepresentation::String(u.to_string())
178 }
179 TypedInteger::I128(i) => {
180 DIFValueRepresentation::String(i.to_string())
181 }
182 TypedInteger::U128(u) => {
183 DIFValueRepresentation::String(u.to_string())
184 }
185 TypedInteger::IBig(i) => {
186 DIFValueRepresentation::String(i.to_string())
187 }
188 }
189 }
190 CoreValue::Range(_range) => {
191 core::todo!("#740 Range value not yet supported in DIF")
192 }
193 CoreValue::Decimal(decimal) => {
194 DIFValueRepresentation::String(decimal.to_string())
196 }
197 CoreValue::TypedDecimal(decimal) => match decimal {
198 TypedDecimal::F32(f) => {
199 DIFValueRepresentation::Number(f.0 as f64)
200 }
201 TypedDecimal::F64(f) => DIFValueRepresentation::Number(f.0),
202 TypedDecimal::Decimal(bd) => {
203 DIFValueRepresentation::String(bd.to_string())
204 }
205 },
206 CoreValue::Text(text) => {
207 DIFValueRepresentation::String(text.0.clone())
208 }
209 CoreValue::Endpoint(endpoint) => {
210 DIFValueRepresentation::String(endpoint.to_string())
211 }
212 CoreValue::List(list) => DIFValueRepresentation::Array(
213 list.iter()
214 .map(DIFValueContainer::from_value_container)
215 .collect(),
216 ),
217 CoreValue::Map(map) => match map {
218 Map::StructuralWithStringKeys(entries) => {
219 DIFValueRepresentation::Object(
220 entries
221 .iter()
222 .map(|(k, v)| {
223 (
224 k.clone(),
225 DIFValueContainer::from_value_container(v),
226 )
227 })
228 .collect(),
229 )
230 }
231 _ => {
232 if map.is_empty() {
233 is_empty_map = true;
234 };
235
236 DIFValueRepresentation::Map(
237 map.iter()
238 .map(|(k, v)| {
239 (
240 match k {
241 BorrowedMapKey::Text(text_key) => {
242 DIFValueContainer::Value(
243 DIFValueRepresentation::String(
244 text_key.to_string(),
245 )
246 .into(),
247 )
248 }
249 _ => {
250 DIFValueContainer::from_value_container(
251 &ValueContainer::from(k),
252 )
253 }
254 },
255 DIFValueContainer::from_value_container(
256 v
257 ),
258 )
259 })
260 .collect(),
261 )
262 }
263 },
264 };
265
266 DIFValue {
267 value: dif_core_value,
268 ty: get_type_if_non_default(&value.actual_type, is_empty_map),
269 }
270 }
271}
272
273fn get_type_if_non_default(
282 type_definition: &TypeDefinition,
283 is_empty_map: bool,
284) -> Option<DIFTypeDefinition> {
285 match type_definition {
286 TypeDefinition::SharedReference(inner) => {
287 if let Ok(address) =
288 CoreLibPointerId::try_from(&inner.borrow().pointer.address())
289 && (core::matches!(
290 address,
291 CoreLibPointerId::Decimal(Some(DecimalTypeVariant::F64))
292 | CoreLibPointerId::Boolean
293 | CoreLibPointerId::Text
294 | CoreLibPointerId::List
295 | CoreLibPointerId::Null
296 ) ||
297 (core::matches!(address, CoreLibPointerId::Map) && !is_empty_map))
299 {
300 None
301 } else {
302 Some(DIFTypeDefinition::from_type_definition(type_definition))
303 }
304 }
305 _ => Some(DIFTypeDefinition::from_type_definition(type_definition)),
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use crate::{
312 dif::{DIFConvertible, r#type::DIFTypeDefinition, value::DIFValue},
313 libs::core::CoreLibPointerId,
314 runtime::memory::Memory,
315 values::{
316 core_values::{
317 endpoint::Endpoint, integer::typed_integer::IntegerTypeVariant,
318 map::Map,
319 },
320 value_container::ValueContainer,
321 },
322 };
323
324 use crate::{prelude::*, values::value::Value};
325 use core::cell::RefCell;
326
327 fn get_mock_memory() -> RefCell<Memory> {
328 RefCell::new(Memory::new(Endpoint::default()))
329 }
330
331 #[test]
332 fn default_type() {
333 let dif = DIFValue::from_value(&Value::from(true));
334 assert!(dif.ty.is_none());
335
336 let dif = DIFValue::from_value(&Value::from("hello"));
337 assert!(dif.ty.is_none());
338
339 let dif = DIFValue::from_value(&Value::null());
340 assert!(dif.ty.is_none());
341
342 let dif = DIFValue::from_value(&Value::from(3.5f64));
343 assert!(dif.ty.is_none());
344
345 let dif = DIFValue::from_value(&Value::from(vec![
346 Value::from(1),
347 Value::from(2),
348 Value::from(3),
349 ]));
350 assert!(dif.ty.is_none());
351
352 let dif = DIFValue::from_value(&Value::from(Map::from(vec![
353 ("a".to_string(), ValueContainer::from(1)),
354 ("b".to_string(), ValueContainer::from(2)),
355 ])));
356 assert!(dif.ty.is_none());
357 }
358
359 #[test]
360 fn non_default_type() {
361 let dif = DIFValue::from_value(&Value::from(123u16));
362 assert!(dif.ty.is_some());
363 if let DIFTypeDefinition::Reference(reference) = dif.ty.unwrap() {
364 assert_eq!(
365 reference,
366 CoreLibPointerId::Integer(Some(IntegerTypeVariant::U16)).into()
367 );
368 } else {
369 core::panic!("Expected reference type");
370 }
371
372 let dif = DIFValue::from_value(&Value::from(123i64));
373 assert!(dif.ty.is_some());
374 if let DIFTypeDefinition::Reference(reference) = dif.ty.unwrap() {
375 assert_eq!(
376 reference,
377 CoreLibPointerId::Integer(Some(IntegerTypeVariant::I64)).into()
378 );
379 } else {
380 core::panic!("Expected reference type");
381 }
382 }
383
384 #[test]
385 fn serde_dif_value() {
386 let dif = DIFValue::from_value(&Value::from("Hello, world!"));
387 let serialized = dif.as_json();
388 let deserialized = DIFValue::from_json(&serialized);
389 assert_eq!(dif, deserialized);
390 }
391}