datex_core/libs/
core.rs

1use crate::references::reference::Reference;
2use crate::references::type_reference::{
3    NominalTypeDeclaration, TypeReference,
4};
5use crate::runtime::memory::Memory;
6use crate::types::definition::TypeDefinition;
7use crate::types::type_container::TypeContainer;
8use crate::values::core_values::decimal::typed_decimal::DecimalTypeVariant;
9use crate::values::core_values::integer::typed_integer::IntegerTypeVariant;
10use crate::values::core_values::r#type::Type;
11use datex_core::values::core_values::map::Map;
12use datex_core::values::pointer::PointerAddress;
13use datex_core::values::value_container::ValueContainer;
14use datex_macros::LibTypeString;
15use std::cell::RefCell;
16use std::collections::HashMap;
17use std::iter::once;
18use std::rc::Rc;
19use strum::IntoEnumIterator;
20
21thread_local! {
22    pub static CORE_LIB_TYPES: HashMap<CoreLibPointerId, TypeContainer> = create_core_lib();
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Hash, LibTypeString)]
26pub enum CoreLibPointerId {
27    Core,                                // #core
28    Type,                                // #core.type
29    Null,                                // #core.null
30    Boolean,                             // #core.boolean
31    Integer(Option<IntegerTypeVariant>), // #core.integer
32    Decimal(Option<DecimalTypeVariant>), // #core.decimal
33    Text,                                // #core.text
34    Endpoint,                            // #core.endpoint
35    List,                                // #core.List
36    Map,                                 // #core.Map
37    Function,                            // #core.Function
38    Unit,                                // #core.Unit
39}
40
41impl CoreLibPointerId {
42    const INTEGER_BASE: u16 = 100;
43    const DECIMAL_BASE: u16 = 300;
44
45    pub fn to_u16(&self) -> u16 {
46        match self {
47            CoreLibPointerId::Core => 0,
48            CoreLibPointerId::Null => 1,
49            CoreLibPointerId::Type => 2,
50            CoreLibPointerId::Boolean => 3,
51            CoreLibPointerId::Function => 5,
52            CoreLibPointerId::Endpoint => 7,
53            CoreLibPointerId::Text => 8,
54            CoreLibPointerId::List => 9,
55            CoreLibPointerId::Unit => 11,
56            CoreLibPointerId::Map => 12,
57            CoreLibPointerId::Integer(None) => Self::INTEGER_BASE,
58            CoreLibPointerId::Integer(Some(v)) => {
59                let v: u8 = (*v).into();
60                CoreLibPointerId::Integer(None).to_u16() + v as u16
61            }
62            CoreLibPointerId::Decimal(None) => Self::DECIMAL_BASE,
63            CoreLibPointerId::Decimal(Some(v)) => {
64                let v: u8 = (*v).into();
65                CoreLibPointerId::Decimal(None).to_u16() + v as u16
66            }
67        }
68    }
69
70    pub fn from_u16(id: u16) -> Option<Self> {
71        match id {
72            0 => Some(CoreLibPointerId::Core),
73            1 => Some(CoreLibPointerId::Null),
74            2 => Some(CoreLibPointerId::Type),
75            3 => Some(CoreLibPointerId::Boolean),
76            5 => Some(CoreLibPointerId::Function),
77            7 => Some(CoreLibPointerId::Endpoint),
78            8 => Some(CoreLibPointerId::Text),
79            9 => Some(CoreLibPointerId::List),
80            11 => Some(CoreLibPointerId::Unit),
81            12 => Some(CoreLibPointerId::Map),
82
83            Self::INTEGER_BASE => Some(CoreLibPointerId::Integer(None)),
84            n if (Self::INTEGER_BASE + 1..Self::DECIMAL_BASE).contains(&n) => {
85                IntegerTypeVariant::try_from((n - Self::INTEGER_BASE) as u8)
86                    .ok()
87                    .map(|v| CoreLibPointerId::Integer(Some(v)))
88            }
89
90            Self::DECIMAL_BASE => Some(CoreLibPointerId::Decimal(None)),
91            n if n > Self::DECIMAL_BASE => {
92                DecimalTypeVariant::try_from((n - Self::DECIMAL_BASE) as u8)
93                    .ok()
94                    .map(|v| CoreLibPointerId::Decimal(Some(v)))
95            }
96
97            _ => None,
98        }
99    }
100}
101
102impl From<CoreLibPointerId> for PointerAddress {
103    fn from(id: CoreLibPointerId) -> Self {
104        let id_bytes: [u8; 3] =
105            (id.to_u16() as u32).to_le_bytes()[0..3].try_into().unwrap();
106        PointerAddress::Internal(id_bytes)
107    }
108}
109
110impl TryFrom<&PointerAddress> for CoreLibPointerId {
111    type Error = String;
112    fn try_from(address: &PointerAddress) -> Result<Self, Self::Error> {
113        match address {
114            PointerAddress::Internal(id_bytes) => {
115                let mut id_array = [0u8; 4];
116                id_array[0..3].copy_from_slice(id_bytes);
117                let id = u32::from_le_bytes(id_array);
118                match CoreLibPointerId::from_u16(id as u16) {
119                    Some(core_id) => Ok(core_id),
120                    None => Err("Invalid CoreLibPointerId".to_string()),
121                }
122            }
123            e => Err(format!(
124                "CoreLibPointerId can only be created from Internal PointerAddress, got: {:?}",
125                e
126            )),
127        }
128    }
129}
130
131pub fn get_core_lib_type(id: impl Into<CoreLibPointerId>) -> TypeContainer {
132    let id = id.into();
133    if !has_core_lib_type(id.clone()) {
134        panic!("Core lib type not found: {:?}", id);
135    }
136    CORE_LIB_TYPES.with(|core| core.get(&id).unwrap().clone())
137}
138
139pub fn get_core_lib_type_reference(
140    id: impl Into<CoreLibPointerId>,
141) -> Rc<RefCell<TypeReference>> {
142    let type_container = get_core_lib_type(id);
143    match type_container {
144        TypeContainer::TypeReference(tr) => tr,
145        _ => panic!("Core lib type is not a TypeReference"),
146    }
147}
148
149fn has_core_lib_type<T>(id: T) -> bool
150where
151    T: Into<CoreLibPointerId>,
152{
153    CORE_LIB_TYPES.with(|core| core.contains_key(&id.into()))
154}
155
156/// Loads the core library into the provided memory instance.
157pub fn load_core_lib(memory: &mut Memory) {
158    CORE_LIB_TYPES.with(|core| {
159        let structure = core
160            .values()
161            .map(|def| match def {
162                TypeContainer::TypeReference(def) => {
163                    let name = def
164                        .borrow()
165                        .nominal_type_declaration
166                        .as_ref()
167                        .unwrap()
168                        .to_string();
169                    let reference = Reference::TypeReference(def.clone());
170                    memory.register_reference(&reference);
171                    (name, ValueContainer::Reference(reference))
172                }
173                _ => panic!("Core lib type is not a TypeReference"),
174            })
175            .collect::<Vec<(String, ValueContainer)>>();
176
177        // TODO #455: dont store variants as separate entries in core_struct (e.g., integer/u8, integer/i32, only keep integer)
178        // Import variants directly by variant access operator from base type (e.g., integer -> integer/u8)
179        let core_struct =
180            Reference::from(ValueContainer::from(Map::from_iter(structure)));
181        core_struct.set_pointer_address(CoreLibPointerId::Core.into());
182        memory.register_reference(&core_struct);
183    });
184}
185
186/// Creates a new instance of the core library as a ValueContainer
187/// including all core types as properties.
188pub fn create_core_lib() -> HashMap<CoreLibPointerId, TypeContainer> {
189    let integer = integer();
190    let decimal = decimal();
191    vec![
192        r#type(),
193        text(),
194        list(),
195        boolean(),
196        endpoint(),
197        unit(),
198        map(),
199        null(),
200    ]
201    .into_iter()
202    .chain(once(integer.clone()))
203    .chain(
204        IntegerTypeVariant::iter()
205            .map(|variant| integer_variant(integer.1.clone(), variant)),
206    )
207    .chain(once(decimal.clone()))
208    .chain(
209        DecimalTypeVariant::iter()
210            .map(|variant| decimal_variant(decimal.1.clone(), variant)),
211    )
212    .collect::<HashMap<CoreLibPointerId, TypeContainer>>()
213}
214
215type CoreLibTypeDefinition = (CoreLibPointerId, TypeContainer);
216pub fn r#type() -> CoreLibTypeDefinition {
217    create_core_type("type", None, None, CoreLibPointerId::Type)
218}
219pub fn null() -> CoreLibTypeDefinition {
220    create_core_type("null", None, None, CoreLibPointerId::Null)
221}
222pub fn list() -> CoreLibTypeDefinition {
223    create_core_type("List", None, None, CoreLibPointerId::List)
224}
225pub fn map() -> CoreLibTypeDefinition {
226    create_core_type("Map", None, None, CoreLibPointerId::Map)
227}
228
229pub fn unit() -> CoreLibTypeDefinition {
230    create_core_type("Unit", None, None, CoreLibPointerId::Unit)
231}
232
233pub fn boolean() -> CoreLibTypeDefinition {
234    create_core_type("boolean", None, None, CoreLibPointerId::Boolean)
235}
236
237pub fn decimal() -> CoreLibTypeDefinition {
238    create_core_type("decimal", None, None, CoreLibPointerId::Decimal(None))
239}
240
241pub fn decimal_variant(
242    base_type: TypeContainer,
243    variant: DecimalTypeVariant,
244) -> CoreLibTypeDefinition {
245    let variant_name = variant.as_ref().to_string();
246    create_core_type(
247        "decimal",
248        Some(variant_name),
249        Some(base_type),
250        CoreLibPointerId::Decimal(Some(variant)),
251    )
252}
253pub fn endpoint() -> CoreLibTypeDefinition {
254    create_core_type("endpoint", None, None, CoreLibPointerId::Endpoint)
255}
256
257pub fn text() -> CoreLibTypeDefinition {
258    create_core_type("text", None, None, CoreLibPointerId::Text)
259}
260
261pub fn integer() -> CoreLibTypeDefinition {
262    create_core_type("integer", None, None, CoreLibPointerId::Integer(None))
263}
264
265pub fn integer_variant(
266    base_type: TypeContainer,
267    variant: IntegerTypeVariant,
268) -> CoreLibTypeDefinition {
269    let variant_name = variant.as_ref().to_string();
270    create_core_type(
271        "integer",
272        Some(variant_name),
273        Some(base_type),
274        CoreLibPointerId::Integer(Some(variant)),
275    )
276}
277
278/// Creates a core type with the given parameters.
279fn create_core_type(
280    name: &str,
281    variant: Option<String>,
282    base_type: Option<TypeContainer>,
283    pointer_id: CoreLibPointerId,
284) -> CoreLibTypeDefinition {
285    let base_type_ref = match base_type {
286        Some(TypeContainer::TypeReference(reference)) => Some(reference),
287        Some(TypeContainer::Type(_)) => {
288            panic!("Base type must be a TypeReference")
289        }
290        None => None,
291    };
292    (
293        pointer_id.clone(),
294        TypeContainer::TypeReference(Rc::new(RefCell::new(TypeReference {
295            nominal_type_declaration: Some(NominalTypeDeclaration {
296                name: name.to_string(),
297                variant,
298            }),
299            type_value: Type {
300                base_type: base_type_ref,
301                reference_mutability: None,
302                type_definition: TypeDefinition::Unit,
303            },
304            pointer_address: Some(PointerAddress::from(pointer_id)),
305        }))),
306    )
307}
308
309#[cfg(test)]
310mod tests {
311    use crate::values::core_values::endpoint::Endpoint;
312
313    use super::*;
314    use itertools::Itertools;
315    use std::{assert_matches::assert_matches, str::FromStr};
316
317    #[test]
318    fn core_lib() {
319        assert!(has_core_lib_type(CoreLibPointerId::Endpoint));
320        assert!(has_core_lib_type(CoreLibPointerId::Null));
321        assert!(has_core_lib_type(CoreLibPointerId::Boolean));
322        assert!(has_core_lib_type(CoreLibPointerId::Integer(None)));
323        assert!(has_core_lib_type(CoreLibPointerId::Decimal(None)));
324        for variant in IntegerTypeVariant::iter() {
325            assert!(has_core_lib_type(CoreLibPointerId::Integer(Some(
326                variant
327            ))));
328        }
329        for variant in DecimalTypeVariant::iter() {
330            assert!(has_core_lib_type(CoreLibPointerId::Decimal(Some(
331                variant
332            ))));
333        }
334    }
335
336    #[test]
337    fn debug() {
338        let mut memory = Memory::new(Endpoint::LOCAL);
339        load_core_lib(&mut memory);
340        println!(
341            "{}",
342            memory
343                .get_value_reference(&CoreLibPointerId::Core.into())
344                .unwrap()
345                .borrow()
346                .value_container
347        );
348    }
349
350    #[test]
351    fn core_lib_type_addresses() {
352        let integer_base = "integer";
353        let integer_u8 = "integer/u8";
354        let integer_i32 = "integer/i32";
355        let decimal_base = "decimal";
356        let decimal_f64 = "decimal/f64";
357
358        assert_eq!(
359            CoreLibPointerId::from_str(integer_base),
360            Ok(CoreLibPointerId::Integer(None))
361        );
362        assert_eq!(
363            CoreLibPointerId::from_str(integer_u8),
364            Ok(CoreLibPointerId::Integer(Some(IntegerTypeVariant::U8)))
365        );
366        assert_eq!(
367            CoreLibPointerId::from_str(integer_i32),
368            Ok(CoreLibPointerId::Integer(Some(IntegerTypeVariant::I32)))
369        );
370        assert_eq!(
371            CoreLibPointerId::from_str(decimal_base),
372            Ok(CoreLibPointerId::Decimal(None))
373        );
374        assert_eq!(
375            CoreLibPointerId::from_str(decimal_f64),
376            Ok(CoreLibPointerId::Decimal(Some(DecimalTypeVariant::F64)))
377        );
378
379        assert_eq!(CoreLibPointerId::Integer(None).to_string(), integer_base);
380        assert_eq!(
381            CoreLibPointerId::Integer(Some(IntegerTypeVariant::U8)).to_string(),
382            integer_u8
383        );
384        assert_eq!(
385            CoreLibPointerId::Integer(Some(IntegerTypeVariant::I32))
386                .to_string(),
387            integer_i32
388        );
389        assert_eq!(CoreLibPointerId::Decimal(None).to_string(), decimal_base);
390        assert_eq!(
391            CoreLibPointerId::Decimal(Some(DecimalTypeVariant::F64))
392                .to_string(),
393            decimal_f64
394        );
395    }
396
397    #[test]
398    fn core_lib_pointer_id_conversion() {
399        let core_id = CoreLibPointerId::Core;
400        let pointer_address: PointerAddress = core_id.clone().into();
401        let converted_id: CoreLibPointerId =
402            (&pointer_address).try_into().unwrap();
403        assert_eq!(core_id, converted_id);
404
405        let boolean_id = CoreLibPointerId::Boolean;
406        let pointer_address: PointerAddress = boolean_id.clone().into();
407        let converted_id: CoreLibPointerId =
408            (&pointer_address).try_into().unwrap();
409        assert_eq!(boolean_id, converted_id);
410
411        let integer_id =
412            CoreLibPointerId::Integer(Some(IntegerTypeVariant::I32));
413        let pointer_address: PointerAddress = integer_id.clone().into();
414        let converted_id: CoreLibPointerId =
415            (&pointer_address).try_into().unwrap();
416        assert_eq!(integer_id, converted_id);
417
418        let decimal_id =
419            CoreLibPointerId::Decimal(Some(DecimalTypeVariant::F64));
420        let pointer_address: PointerAddress = decimal_id.clone().into();
421        let converted_id: CoreLibPointerId =
422            (&pointer_address).try_into().unwrap();
423        assert_eq!(decimal_id, converted_id);
424
425        let type_id = CoreLibPointerId::Type;
426        let pointer_address: PointerAddress = type_id.clone().into();
427        let converted_id: CoreLibPointerId =
428            (&pointer_address).try_into().unwrap();
429        assert_eq!(type_id, converted_id);
430    }
431
432    #[test]
433    fn base_type_simple() {
434        // integer -> integer -> integer ...
435        let integer_type = get_core_lib_type(CoreLibPointerId::Integer(None));
436        let integer_base = integer_type.base_type();
437        assert_matches!(integer_base, TypeContainer::TypeReference(_));
438        assert_eq!(integer_base.to_string(), "integer");
439
440        let base = integer_base.base_type();
441        assert_matches!(base, TypeContainer::TypeReference(_));
442        assert_eq!(base.to_string(), "integer");
443
444        assert_eq!(integer_base, base);
445    }
446
447    #[test]
448    fn base_type_complex() {
449        // integer/u8 -> integer -> integer -> integer ...
450        let integer_u8_type = get_core_lib_type(CoreLibPointerId::Integer(
451            Some(IntegerTypeVariant::U8),
452        ));
453        assert_matches!(integer_u8_type, TypeContainer::TypeReference(_));
454        assert_eq!(integer_u8_type.to_string(), "integer/u8");
455
456        let integer = integer_u8_type.base_type();
457        assert_matches!(integer, TypeContainer::TypeReference(_));
458        assert_eq!(integer.to_string(), "integer");
459        assert_ne!(integer, integer_u8_type);
460
461        let integer_again = integer.base_type();
462        assert_matches!(integer_again, TypeContainer::TypeReference(_));
463        assert_eq!(integer_again.to_string(), "integer");
464        assert_eq!(integer_again, integer);
465    }
466
467    #[ignore]
468    #[test]
469    fn print_core_lib_addresses_as_hex() {
470        let sorted_entries = CORE_LIB_TYPES.with(|core| {
471            core.keys()
472                .map(|k| (k.clone(), PointerAddress::from(k.clone())))
473                .sorted_by_key(|(_, address)| address.bytes().to_vec())
474                .collect::<Vec<_>>()
475        });
476        for (core_lib_id, address) in sorted_entries {
477            println!("{:?}: {}", core_lib_id, address);
478        }
479    }
480}