Skip to main content

datex_core/core_compiler/
value_compiler.rs

1use crate::{
2    core_compiler::type_compiler::{
3        append_type, append_type_definition, append_type_metadata,
4        append_type_space_instruction_code,
5    },
6    global::{
7        instruction_codes::InstructionCode,
8        protocol_structures::instructions::TypeMetadataBin,
9        type_instruction_codes::TypeInstructionCode,
10    },
11    libs::core::{CoreLibPointerId, get_core_lib_type_definition},
12    shared_values::shared_container::SharedContainerMutability,
13    types::definition::TypeDefinition,
14    utils::buffers::{
15        append_f32, append_f64, append_i8, append_i16, append_i32, append_i64,
16        append_i128, append_u8, append_u16, append_u32, append_u64,
17        append_u128,
18    },
19    values::{
20        core_value::CoreValue,
21        core_values::{
22            decimal::{Decimal, typed_decimal::TypedDecimal},
23            endpoint::Endpoint,
24            integer::{Integer, typed_integer::TypedInteger},
25        },
26        value::Value,
27        value_container::ValueContainer,
28    },
29};
30use binrw::{BinWrite, io::Cursor};
31
32use crate::{
33    prelude::*,
34    shared_values::{
35        pointer::PointerReferenceMutability,
36        pointer_address::{PointerAddress, ReferencedPointerAddress},
37    },
38    values::core_values::r#type::TypeMetadata,
39};
40
41/// Compiles a given value container to a DXB body
42pub fn compile_value_container(value_container: &ValueContainer) -> Vec<u8> {
43    let mut buffer = Vec::with_capacity(256);
44    append_value_container(&mut buffer, value_container);
45
46    buffer
47}
48
49pub fn append_value_container(
50    buffer: &mut Vec<u8>,
51    value_container: &ValueContainer,
52) {
53    match value_container {
54        ValueContainer::Local(value) => append_value(buffer, value),
55        ValueContainer::Shared(reference) => {
56            // TODO #160: in this case, the ref might also be inserted by pointer id, depending on the compiler settings
57            // add CREATE_SHARED/CREATE_SHARED_MUT instruction
58            if reference.mutability() == SharedContainerMutability::Mutable {
59                append_instruction_code(
60                    buffer,
61                    InstructionCode::CREATE_SHARED_MUT,
62                );
63            } else {
64                append_instruction_code(buffer, InstructionCode::CREATE_SHARED);
65            }
66            // insert pointer id + value or only id
67            // add pointer to memory if not there yet
68            append_value(buffer, &reference.collapse_to_value().borrow())
69        }
70    }
71}
72
73pub fn append_value(buffer: &mut Vec<u8>, value: &Value) {
74    // append non-default type information
75    if !value.has_default_type() {
76        append_type_cast(buffer, &value.actual_type);
77    }
78    match &value.inner {
79        CoreValue::Type(_ty) => {
80            core::todo!("#439 Type value not supported in CompilationContext");
81        }
82        CoreValue::Callable(_callable) => {
83            core::todo!(
84                "#632 Callable value not supported in CompilationContext"
85            );
86        }
87        CoreValue::Integer(integer) => {
88            // NOTE: we might optimize this later, but using INT with big integer encoding
89            // for all integers for now
90            // let integer = integer.to_smallest_fitting();
91            // append_encoded_integer(buffer, &integer);
92            append_integer(buffer, integer);
93        }
94        CoreValue::TypedInteger(integer) => {
95            append_encoded_integer(buffer, integer);
96        }
97
98        CoreValue::Endpoint(endpoint) => append_endpoint(buffer, endpoint),
99        CoreValue::Decimal(decimal) => append_decimal(buffer, decimal),
100        CoreValue::TypedDecimal(val) => append_encoded_decimal(buffer, val),
101        CoreValue::Boolean(val) => append_boolean(buffer, val.0),
102        CoreValue::Null => {
103            append_instruction_code(buffer, InstructionCode::NULL)
104        }
105        CoreValue::Text(val) => {
106            append_text(buffer, &val.0);
107        }
108        CoreValue::List(val) => {
109            // if list size < 256, use SHORT_LIST
110            match val.len() {
111                0..=255 => {
112                    append_instruction_code(
113                        buffer,
114                        InstructionCode::SHORT_LIST,
115                    );
116                    append_u8(buffer, val.len() as u8);
117                }
118                _ => {
119                    append_instruction_code(buffer, InstructionCode::LIST);
120                    append_u32(buffer, val.len());
121                }
122            }
123
124            for item in val {
125                append_value_container(buffer, item);
126            }
127        }
128        CoreValue::Map(val) => {
129            // if map size < 256, use SHORT_MAP
130            match val.size() {
131                0..=255 => {
132                    append_instruction_code(buffer, InstructionCode::SHORT_MAP);
133                    append_u8(buffer, val.size() as u8);
134                }
135                _ => {
136                    append_instruction_code(buffer, InstructionCode::MAP);
137                    append_u32(buffer, val.size() as u32); // FIXME #633: casting from usize to u32 here
138                }
139            }
140            for (key, value) in val.iter() {
141                append_key_value_pair(
142                    buffer,
143                    &ValueContainer::from(key),
144                    value,
145                );
146            }
147        }
148        CoreValue::Range(range) => {
149            append_instruction_code(buffer, InstructionCode::RANGE);
150            append_value_container(buffer, &range.start);
151            append_value_container(buffer, &range.end);
152        }
153    }
154}
155
156pub fn append_type_cast(buffer: &mut Vec<u8>, ty: &TypeDefinition) {
157    append_instruction_code(buffer, InstructionCode::TYPED_VALUE);
158    // append instruction code
159    let instruction_code = TypeInstructionCode::from(ty);
160    append_type_space_instruction_code(buffer, instruction_code);
161
162    // append type information for non-core types
163    let metadata = TypeMetadataBin::from(&TypeMetadata::default());
164    append_type_metadata(buffer, metadata);
165
166    // append type definition
167    append_type_definition(buffer, ty);
168}
169
170pub fn append_text(buffer: &mut Vec<u8>, string: &str) {
171    let bytes = string.as_bytes();
172    let len = bytes.len();
173
174    if len < 256 {
175        append_instruction_code(buffer, InstructionCode::SHORT_TEXT);
176        append_u8(buffer, len as u8);
177    } else {
178        append_instruction_code(buffer, InstructionCode::TEXT);
179        append_u32(buffer, len as u32);
180    }
181
182    buffer.extend_from_slice(bytes);
183}
184
185pub fn append_boolean(buffer: &mut Vec<u8>, boolean: bool) {
186    if boolean {
187        append_instruction_code(buffer, InstructionCode::TRUE);
188    } else {
189        append_instruction_code(buffer, InstructionCode::FALSE);
190    }
191}
192
193pub fn append_decimal(buffer: &mut Vec<u8>, decimal: &Decimal) {
194    append_instruction_code(buffer, InstructionCode::DECIMAL);
195    append_big_decimal(buffer, decimal);
196}
197
198pub fn append_big_decimal(buffer: &mut Vec<u8>, decimal: &Decimal) {
199    // big_decimal binrw write into buffer
200    let original_length = buffer.len();
201    let mut buffer_writer = Cursor::new(&mut *buffer);
202    // set writer position to end
203    buffer_writer.set_position(original_length as u64);
204    decimal
205        .write_le(&mut buffer_writer)
206        .expect("Failed to write big decimal");
207}
208
209pub fn append_endpoint(buffer: &mut Vec<u8>, endpoint: &Endpoint) {
210    append_instruction_code(buffer, InstructionCode::ENDPOINT);
211    buffer.extend_from_slice(&endpoint.to_slice());
212}
213
214/// Appends a typed integer with explicit type casts
215pub fn append_typed_integer(buffer: &mut Vec<u8>, integer: &TypedInteger) {
216    append_type_cast(
217        buffer,
218        &get_core_lib_type_definition(CoreLibPointerId::from(integer)),
219    );
220    append_encoded_integer(buffer, integer);
221}
222
223/// Appends a default, unsized integer
224pub fn append_integer(buffer: &mut Vec<u8>, integer: &Integer) {
225    append_instruction_code(buffer, InstructionCode::INT);
226    append_big_integer(buffer, integer);
227}
228
229/// Appends an encoded integer without explicit type casts
230pub fn append_encoded_integer(buffer: &mut Vec<u8>, integer: &TypedInteger) {
231    match integer {
232        TypedInteger::I8(val) => {
233            append_instruction_code(buffer, InstructionCode::INT_8);
234            append_i8(buffer, *val);
235        }
236        TypedInteger::I16(val) => {
237            append_instruction_code(buffer, InstructionCode::INT_16);
238            append_i16(buffer, *val);
239        }
240        TypedInteger::I32(val) => {
241            append_instruction_code(buffer, InstructionCode::INT_32);
242            append_i32(buffer, *val);
243        }
244        TypedInteger::I64(val) => {
245            append_instruction_code(buffer, InstructionCode::INT_64);
246            append_i64(buffer, *val);
247        }
248        TypedInteger::I128(val) => {
249            append_instruction_code(buffer, InstructionCode::INT_128);
250            append_i128(buffer, *val);
251        }
252        TypedInteger::U8(val) => {
253            append_instruction_code(buffer, InstructionCode::UINT_8);
254            append_u8(buffer, *val);
255        }
256        TypedInteger::U16(val) => {
257            append_instruction_code(buffer, InstructionCode::UINT_16);
258            append_u16(buffer, *val);
259        }
260        TypedInteger::U32(val) => {
261            append_instruction_code(buffer, InstructionCode::UINT_32);
262            append_u32(buffer, *val);
263        }
264        TypedInteger::U64(val) => {
265            append_instruction_code(buffer, InstructionCode::UINT_64);
266            append_u64(buffer, *val);
267        }
268        TypedInteger::U128(val) => {
269            append_instruction_code(buffer, InstructionCode::UINT_128);
270            append_u128(buffer, *val);
271        }
272        TypedInteger::IBig(val) => {
273            append_instruction_code(buffer, InstructionCode::INT_BIG);
274            append_big_integer(buffer, val);
275        }
276    }
277}
278
279pub fn append_encoded_decimal(buffer: &mut Vec<u8>, decimal: &TypedDecimal) {
280    fn append_f32_or_f64(buffer: &mut Vec<u8>, decimal: &TypedDecimal) {
281        match decimal {
282            TypedDecimal::F32(val) => {
283                append_float32(buffer, val.into_inner());
284            }
285            TypedDecimal::F64(val) => {
286                append_float64(buffer, val.into_inner());
287            }
288            TypedDecimal::Decimal(val) => {
289                append_instruction_code(buffer, InstructionCode::DECIMAL_BIG);
290                append_big_decimal(buffer, val);
291            }
292        }
293    }
294
295    append_f32_or_f64(buffer, decimal);
296
297    // TODO #635: maybe use this in the future, but type casts are necessary to decide which actual type is represented
298    // match decimal.as_integer() {
299    //     Some(int) => {
300    //         let smallest = smallest_fitting_signed(int as i128);
301    //         match smallest {
302    //             TypedInteger::I8(val) => {
303    //                 append_float_as_i16(buffer, val as i16);
304    //             }
305    //             TypedInteger::I16(val) => {
306    //                 append_float_as_i16(buffer, val);
307    //             }
308    //             TypedInteger::I32(val) => {
309    //                 append_float_as_i32(buffer, val);
310    //             }
311    //             _ => append_f32_or_f64(buffer, decimal),
312    //         }
313    //     }
314    //     None => append_f32_or_f64(buffer, decimal),
315    // }
316}
317
318pub fn append_float32(buffer: &mut Vec<u8>, float32: f32) {
319    append_instruction_code(buffer, InstructionCode::DECIMAL_F32);
320    append_f32(buffer, float32);
321}
322pub fn append_float64(buffer: &mut Vec<u8>, float64: f64) {
323    append_instruction_code(buffer, InstructionCode::DECIMAL_F64);
324    append_f64(buffer, float64);
325}
326
327pub fn append_big_integer(buffer: &mut Vec<u8>, integer: &Integer) {
328    // use BinWrite to write the integer to the buffer
329    // big_integer binrw write into buffer
330    let original_length = buffer.len();
331    let mut buffer_writer = Cursor::new(&mut *buffer);
332    // set writer position to end
333    buffer_writer.set_position(original_length as u64);
334    integer
335        .write_le(&mut buffer_writer)
336        .expect("Failed to write big integer");
337}
338
339pub fn append_typed_decimal(buffer: &mut Vec<u8>, decimal: &TypedDecimal) {
340    append_type_cast(
341        buffer,
342        &get_core_lib_type_definition(CoreLibPointerId::from(decimal)),
343    );
344    append_encoded_decimal(buffer, decimal);
345}
346
347pub fn append_float_as_i16(buffer: &mut Vec<u8>, int: i16) {
348    append_instruction_code(buffer, InstructionCode::DECIMAL_AS_INT_16);
349    append_i16(buffer, int);
350}
351pub fn append_float_as_i32(buffer: &mut Vec<u8>, int: i32) {
352    append_instruction_code(buffer, InstructionCode::DECIMAL_AS_INT_32);
353    append_i32(buffer, int);
354}
355
356pub fn append_get_ref(
357    buffer: &mut Vec<u8>,
358    address: &PointerAddress,
359    mutability: &PointerReferenceMutability,
360) {
361    match address {
362        PointerAddress::Referenced(ReferencedPointerAddress::Internal(id)) => {
363            append_get_internal_ref(buffer, id);
364        }
365        PointerAddress::Owned(local_address) => {
366            append_instruction_code(
367                buffer,
368                InstructionCode::GET_LOCAL_SHARED_REF,
369            );
370            buffer.extend_from_slice(&local_address.address);
371        }
372        PointerAddress::Referenced(ReferencedPointerAddress::Remote(id)) => {
373            append_instruction_code(
374                buffer,
375                match mutability {
376                    PointerReferenceMutability::Immutable => {
377                        InstructionCode::GET_REMOTE_SHARED_REF
378                    }
379                    PointerReferenceMutability::Mutable => {
380                        InstructionCode::GET_REMOTE_SHARED_REF_MUT
381                    }
382                },
383            );
384            buffer.extend_from_slice(id);
385        }
386    }
387}
388
389pub fn append_get_internal_ref(buffer: &mut Vec<u8>, id: &[u8; 3]) {
390    append_instruction_code(buffer, InstructionCode::GET_INTERNAL_SHARED_REF);
391    buffer.extend_from_slice(id);
392}
393
394pub fn append_key_value_pair(
395    buffer: &mut Vec<u8>,
396    key: &ValueContainer,
397    value: &ValueContainer,
398) {
399    // insert key
400    match key {
401        // if text, append_key_string, else dynamic
402        ValueContainer::Local(Value {
403            inner: CoreValue::Text(text),
404            ..
405        }) => {
406            append_key_string(buffer, &text.0);
407        }
408        _ => {
409            append_instruction_code(buffer, InstructionCode::KEY_VALUE_DYNAMIC);
410            append_value_container(buffer, key);
411        }
412    }
413    // insert value
414    append_value_container(buffer, value);
415}
416
417pub fn append_key_string(buffer: &mut Vec<u8>, key_string: &str) {
418    let bytes = key_string.as_bytes();
419    let len = bytes.len();
420
421    if len < 256 {
422        append_instruction_code(buffer, InstructionCode::KEY_VALUE_SHORT_TEXT);
423        append_u8(buffer, len as u8);
424        buffer.extend_from_slice(bytes);
425    } else {
426        append_instruction_code(buffer, InstructionCode::KEY_VALUE_DYNAMIC);
427        append_text(buffer, key_string);
428    }
429}
430
431pub fn append_instruction_code(buffer: &mut Vec<u8>, code: InstructionCode) {
432    append_u8(buffer, code as u8);
433}