intuicio_frontend_simpleton/library/
reflect.rs

1use crate::{Array, Boolean, Function, Integer, Map, Real, Reference, Text, Type};
2use intuicio_core::{context::Context, define_native_struct, object::Object, registry::Registry};
3use intuicio_derive::intuicio_function;
4use std::collections::HashSet;
5
6#[intuicio_function(module_name = "reflect", use_registry)]
7pub fn find_type_by_name(
8    registry: &Registry,
9    name: Reference,
10    module_name: Reference,
11) -> Reference {
12    Reference::new_type(
13        Type::by_name(
14            name.read::<Text>().unwrap().as_str(),
15            module_name.read::<Text>().unwrap().as_str(),
16            registry,
17        )
18        .unwrap(),
19        registry,
20    )
21}
22
23#[intuicio_function(module_name = "reflect", use_registry)]
24pub fn type_of(registry: &Registry, value: Reference) -> Reference {
25    Reference::new_type(value.type_of().unwrap(), registry)
26}
27
28#[intuicio_function(module_name = "reflect", use_registry)]
29pub fn type_name(registry: &Registry, ty: Reference) -> Reference {
30    Reference::new_text(
31        ty.read::<Type>()
32            .unwrap()
33            .handle()
34            .unwrap()
35            .name()
36            .to_owned(),
37        registry,
38    )
39}
40
41#[intuicio_function(module_name = "reflect", use_registry)]
42pub fn type_fields(registry: &Registry, ty: Reference) -> Reference {
43    Reference::new_array(
44        ty.read::<Type>()
45            .unwrap()
46            .handle()
47            .unwrap()
48            .struct_fields()
49            .unwrap()
50            .iter()
51            .map(|field| Reference::new_text(field.name.to_owned(), registry))
52            .collect::<Array>(),
53        registry,
54    )
55}
56
57#[intuicio_function(module_name = "reflect", use_registry)]
58pub fn type_byte_size(registry: &Registry, ty: Reference) -> Reference {
59    Reference::new_integer(
60        ty.read::<Type>().unwrap().handle().unwrap().layout().size() as Integer,
61        registry,
62    )
63}
64
65#[intuicio_function(module_name = "reflect")]
66pub fn get_field(object: Reference, name: Reference) -> Reference {
67    object
68        .read_object()
69        .unwrap()
70        .read_field::<Reference>(name.read::<Text>().unwrap().as_str())
71        .unwrap()
72        .clone()
73}
74
75#[intuicio_function(module_name = "reflect")]
76pub fn set_field(mut object: Reference, name: Reference, value: Reference) -> Reference {
77    *object
78        .write_object()
79        .unwrap()
80        .write_field::<Reference>(name.read::<Text>().unwrap().as_str())
81        .unwrap() = value;
82    Reference::null()
83}
84
85#[intuicio_function(module_name = "reflect")]
86pub fn new(ty: Reference, properties: Reference) -> Reference {
87    let type_ = ty.read::<Type>().unwrap().handle().unwrap().clone();
88    let mut result = Object::new(type_);
89    for (key, value) in properties.read::<Map>().unwrap().iter() {
90        *result.write_field::<Reference>(key).unwrap() = value.clone();
91    }
92    Reference::new_raw(result)
93}
94
95#[intuicio_function(module_name = "reflect")]
96pub fn pack(mut object: Reference, properties: Reference) -> Reference {
97    let mut object = object.write_object().unwrap();
98    for (key, value) in properties.read::<Map>().unwrap().iter() {
99        *object.write_field::<Reference>(key).unwrap() = value.clone();
100    }
101    Reference::null()
102}
103
104#[intuicio_function(module_name = "reflect", use_registry)]
105pub fn unpack(registry: &Registry, object: Reference) -> Reference {
106    let object = object.read_object().unwrap();
107    let result = object
108        .type_handle()
109        .struct_fields()
110        .unwrap()
111        .iter()
112        .map(|field| {
113            (
114                field.name.to_owned(),
115                object.read_field::<Reference>(&field.name).unwrap().clone(),
116            )
117        })
118        .collect();
119    Reference::new_map(result, registry)
120}
121
122#[intuicio_function(module_name = "reflect", use_registry)]
123pub fn find_function_by_name(
124    registry: &Registry,
125    name: Reference,
126    module_name: Reference,
127) -> Reference {
128    Reference::new_function(
129        Function::by_name(
130            name.read::<Text>().unwrap().as_str(),
131            module_name.read::<Text>().unwrap().as_str(),
132            registry,
133        )
134        .unwrap(),
135        registry,
136    )
137}
138
139#[intuicio_function(module_name = "reflect", use_context, use_registry)]
140pub fn call(
141    context: &mut Context,
142    registry: &Registry,
143    function: Reference,
144    arguments: Reference,
145) -> Reference {
146    for argument in arguments.read::<Array>().unwrap().iter().rev() {
147        context.stack().push(argument.clone());
148    }
149    function
150        .read::<Function>()
151        .unwrap()
152        .handle()
153        .unwrap()
154        .invoke(context, registry);
155    context.stack().pop::<Reference>().unwrap_or_default()
156}
157
158#[intuicio_function(module_name = "reflect", use_registry)]
159pub fn function_name(registry: &Registry, value: Reference) -> Reference {
160    Reference::new_text(
161        value
162            .read::<Function>()
163            .unwrap()
164            .handle()
165            .unwrap()
166            .signature()
167            .name
168            .to_owned(),
169        registry,
170    )
171}
172
173#[intuicio_function(module_name = "reflect", use_registry)]
174pub fn function_arguments(registry: &Registry, value: Reference) -> Reference {
175    Reference::new_array(
176        value
177            .read::<Function>()
178            .unwrap()
179            .handle()
180            .unwrap()
181            .signature()
182            .inputs
183            .iter()
184            .map(|argument| Reference::new_text(argument.name.to_owned(), registry))
185            .collect::<Array>(),
186        registry,
187    )
188}
189
190#[intuicio_function(module_name = "reflect")]
191pub fn select(mut value: Reference, path: Reference) -> Reference {
192    let path = path.read::<Text>().unwrap();
193    if path.is_empty() {
194        return value;
195    }
196    for part in path.split('/') {
197        if value.is_null() {
198            return value;
199        }
200        let found = if let Some(array) = value.read::<Array>() {
201            if let Ok(index) = part.parse::<usize>() {
202                array[index].clone()
203            } else {
204                return Reference::null();
205            }
206        } else if let Some(map) = value.read::<Map>() {
207            if let Some(item) = map.get(part) {
208                item.clone()
209            } else {
210                return Reference::null();
211            }
212        } else if let Some(item) = value.read_object().unwrap().read_field::<Reference>(part) {
213            item.clone()
214        } else {
215            return Reference::null();
216        };
217        value = found;
218    }
219    value
220}
221
222#[intuicio_function(module_name = "reflect")]
223pub fn pass_or(value: Reference, default: Reference) -> Reference {
224    if value.is_null() {
225        default
226    } else {
227        value
228    }
229}
230
231#[intuicio_function(module_name = "reflect", use_registry)]
232pub fn is_null(registry: &Registry, value: Reference) -> Reference {
233    Reference::new_boolean(value.is_null(), registry)
234}
235
236#[intuicio_function(module_name = "reflect", use_registry)]
237pub fn is_valid(registry: &Registry, value: Reference) -> Reference {
238    Reference::new_boolean(!value.is_null(), registry)
239}
240
241#[intuicio_function(module_name = "reflect", use_registry)]
242pub fn is_being_written(registry: &Registry, mut value: Reference) -> Reference {
243    Reference::new_boolean(value.is_being_written(), registry)
244}
245
246#[intuicio_function(module_name = "reflect", use_registry)]
247pub fn references_count(registry: &Registry, value: Reference) -> Reference {
248    Reference::new_integer(value.references_count() as Integer - 1, registry)
249}
250
251#[intuicio_function(module_name = "reflect", use_registry)]
252pub fn does_share_reference(registry: &Registry, a: Reference, b: Reference) -> Reference {
253    Reference::new_boolean(a.does_share_reference(&b, false), registry)
254}
255
256#[intuicio_function(module_name = "reflect", use_registry)]
257pub fn does_share_type(registry: &Registry, a: Reference, b: Reference) -> Reference {
258    let a = if let Some(type_) = a.read::<Type>() {
259        type_.clone()
260    } else if let Some(type_) = a.type_of() {
261        type_.clone()
262    } else {
263        return Reference::new_boolean(false, registry);
264    };
265    let b = if let Some(type_) = b.read::<Type>() {
266        type_.clone()
267    } else if let Some(type_) = b.type_of() {
268        type_.clone()
269    } else {
270        return Reference::new_boolean(false, registry);
271    };
272    Reference::new_boolean(a.is_same_as(&b), registry)
273}
274
275pub fn are_same_impl(a: &Reference, b: &Reference) -> bool {
276    if a.is_null() && b.is_null() {
277        true
278    } else if let (Some(a), Some(b)) = (a.read::<Boolean>(), b.read::<Boolean>()) {
279        *a == *b
280    } else if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
281        *a == *b
282    } else if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
283        *a == *b
284    } else if let (Some(a), Some(b)) = (a.read::<Text>(), b.read::<Text>()) {
285        *a == *b
286    } else if let (Some(a), Some(b)) = (a.read::<Array>(), b.read::<Array>()) {
287        a.len() == b.len() && a.iter().zip(b.iter()).all(|(a, b)| are_same_impl(a, b))
288    } else if let (Some(a), Some(b)) = (a.read::<Map>(), b.read::<Map>()) {
289        a.len() == b.len()
290            && a.keys().collect::<HashSet<_>>() == b.keys().collect::<HashSet<_>>()
291            && a.iter().all(|(k, v)| are_same_impl(v, b.get(k).unwrap()))
292    } else if let (Some(a), Some(b)) = (a.read::<Type>(), b.read::<Type>()) {
293        a.is_same_as(&b)
294    } else if let (Some(a), Some(b)) = (a.read::<Function>(), b.read::<Function>()) {
295        a.is_same_as(&b)
296    } else {
297        let a = a.read_object().unwrap();
298        let b = b.read_object().unwrap();
299        let keys = a
300            .type_handle()
301            .struct_fields()
302            .unwrap()
303            .iter()
304            .map(|field| &field.name)
305            .chain(
306                b.type_handle()
307                    .struct_fields()
308                    .unwrap()
309                    .iter()
310                    .map(|field| &field.name),
311            )
312            .collect::<HashSet<_>>();
313        if keys.is_empty() {
314            false
315        } else {
316            keys.into_iter()
317                .map(|key| {
318                    (
319                        a.read_field::<Reference>(key),
320                        b.read_field::<Reference>(key),
321                    )
322                })
323                .all(|(a, b)| a.is_some() && b.is_some() && are_same_impl(a.unwrap(), b.unwrap()))
324        }
325    }
326}
327
328#[intuicio_function(module_name = "reflect", use_registry)]
329pub fn are_same(registry: &Registry, a: Reference, b: Reference) -> Reference {
330    Reference::new_boolean(are_same_impl(&a, &b), registry)
331}
332
333#[intuicio_function(module_name = "reflect", use_registry)]
334pub fn to_boolean(registry: &Registry, value: Reference) -> Reference {
335    if value.type_of().unwrap().is::<Boolean>() {
336        return value;
337    }
338    if let Some(value) = value.read::<Integer>() {
339        return Reference::new_boolean(*value != 0, registry);
340    }
341    if let Some(value) = value.read::<Real>() {
342        return Reference::new_boolean(*value != 0.0, registry);
343    }
344    if let Some(value) = value.read::<Text>() {
345        if let Ok(value) = value.parse::<Boolean>() {
346            return Reference::new_boolean(value, registry);
347        }
348    }
349    if let Some(value) = value.read::<Array>() {
350        return Reference::new_boolean(!value.is_empty(), registry);
351    }
352    if let Some(value) = value.read::<Map>() {
353        return Reference::new_boolean(!value.is_empty(), registry);
354    }
355    Reference::null()
356}
357
358#[intuicio_function(module_name = "reflect", use_registry)]
359pub fn to_integer(registry: &Registry, value: Reference) -> Reference {
360    if value.type_of().unwrap().is::<Integer>() {
361        return value;
362    }
363    if let Some(value) = value.read::<Boolean>() {
364        return Reference::new_integer(if *value { 1 } else { 0 }, registry);
365    }
366    if let Some(value) = value.read::<Real>() {
367        return Reference::new_integer(*value as Integer, registry);
368    }
369    if let Some(value) = value.read::<Text>() {
370        if let Ok(value) = value.parse::<Integer>() {
371            return Reference::new_integer(value, registry);
372        }
373    }
374    Reference::null()
375}
376
377#[intuicio_function(module_name = "reflect", use_registry)]
378pub fn to_real(registry: &Registry, value: Reference) -> Reference {
379    if value.type_of().unwrap().is::<Real>() {
380        return value;
381    }
382    if let Some(value) = value.read::<Boolean>() {
383        return Reference::new_real(if *value { 1.0 } else { 0.0 }, registry);
384    }
385    if let Some(value) = value.read::<Integer>() {
386        return Reference::new_real(*value as Real, registry);
387    }
388    if let Some(value) = value.read::<Text>() {
389        if let Ok(value) = value.parse::<Real>() {
390            return Reference::new_real(value, registry);
391        }
392    }
393    Reference::null()
394}
395
396#[intuicio_function(module_name = "reflect", use_registry)]
397pub fn to_text(registry: &Registry, value: Reference) -> Reference {
398    if value.type_of().unwrap().is::<Text>() {
399        return value;
400    }
401    if let Some(value) = value.read::<Boolean>() {
402        return Reference::new_text(value.to_string(), registry);
403    }
404    if let Some(value) = value.read::<Integer>() {
405        return Reference::new_text(value.to_string(), registry);
406    }
407    if let Some(value) = value.read::<Real>() {
408        return Reference::new_text(value.to_string(), registry);
409    }
410    if let Some(value) = value.read::<Array>() {
411        let mut result = "[".to_owned();
412        for (index, value) in value.iter().enumerate() {
413            if index > 0 {
414                result.push_str(", ");
415            }
416            result.push_str(value.read::<Text>().unwrap().as_str());
417        }
418        result.push(']');
419        return Reference::new_text(result, registry);
420    }
421    if let Some(value) = value.read::<Map>() {
422        let mut result = "{".to_owned();
423        for (index, (key, value)) in value.iter().enumerate() {
424            if index > 0 {
425                result.push_str(", ");
426            }
427            result.push_str(key.as_str());
428            result.push_str(": ");
429            result.push_str(value.read::<Text>().unwrap().as_str());
430        }
431        result.push('}');
432        return Reference::new_text(result, registry);
433    }
434    if let Some(value) = value.read::<Type>() {
435        let handle = value.handle().unwrap();
436        let mut result = "struct ".to_owned();
437        if let Some(name) = handle.module_name() {
438            result.push_str(name);
439            result.push_str("::");
440        }
441        result.push_str(handle.name());
442        result.push_str(" {");
443        for (index, field) in handle.struct_fields().unwrap().iter().enumerate() {
444            if index > 0 {
445                result.push_str(", ");
446            }
447            result.push_str(&field.name);
448        }
449        result.push('}');
450        return Reference::new_text(result, registry);
451    }
452    if let Some(value) = value.read::<Function>() {
453        let handle = value.handle().unwrap();
454        let mut result = "func ".to_owned();
455        if let Some(name) = handle.signature().module_name.as_ref() {
456            result.push_str(name.as_str());
457            result.push_str("::");
458        }
459        result.push_str(&handle.signature().name);
460        result.push_str(" {");
461        for (index, argument) in handle.signature().inputs.iter().enumerate() {
462            if index > 0 {
463                result.push_str(", ");
464            }
465            result.push_str(&argument.name);
466        }
467        result.push('}');
468        return Reference::new_text(result, registry);
469    }
470    Reference::null()
471}
472
473#[intuicio_function(module_name = "reflect", use_context, use_registry)]
474pub fn stack_size(context: &mut Context, registry: &Registry) -> Reference {
475    Reference::new_integer(context.stack().position() as Integer, registry)
476}
477
478#[intuicio_function(module_name = "reflect", use_context, use_registry)]
479pub fn registers_size(context: &mut Context, registry: &Registry) -> Reference {
480    Reference::new_integer(context.registers().position() as Integer, registry)
481}
482
483pub fn install(registry: &mut Registry) {
484    registry.add_type(define_native_struct! {
485        registry => mod reflect struct Reference (Reference) {}
486        [override_send = true]
487    });
488    registry.add_type(define_native_struct! {
489        registry => mod reflect struct Type (Type) {}
490    });
491    registry.add_type(define_native_struct! {
492        registry => mod reflect struct Function (Function) {}
493    });
494    registry.add_function(find_type_by_name::define_function(registry));
495    registry.add_function(type_of::define_function(registry));
496    registry.add_function(type_name::define_function(registry));
497    registry.add_function(type_fields::define_function(registry));
498    registry.add_function(type_byte_size::define_function(registry));
499    registry.add_function(get_field::define_function(registry));
500    registry.add_function(set_field::define_function(registry));
501    registry.add_function(new::define_function(registry));
502    registry.add_function(pack::define_function(registry));
503    registry.add_function(unpack::define_function(registry));
504    registry.add_function(find_function_by_name::define_function(registry));
505    registry.add_function(call::define_function(registry));
506    registry.add_function(function_name::define_function(registry));
507    registry.add_function(function_arguments::define_function(registry));
508    registry.add_function(select::define_function(registry));
509    registry.add_function(pass_or::define_function(registry));
510    registry.add_function(is_null::define_function(registry));
511    registry.add_function(is_valid::define_function(registry));
512    registry.add_function(is_being_written::define_function(registry));
513    registry.add_function(references_count::define_function(registry));
514    registry.add_function(does_share_reference::define_function(registry));
515    registry.add_function(does_share_type::define_function(registry));
516    registry.add_function(are_same::define_function(registry));
517    registry.add_function(to_boolean::define_function(registry));
518    registry.add_function(to_integer::define_function(registry));
519    registry.add_function(to_real::define_function(registry));
520    registry.add_function(to_text::define_function(registry));
521    registry.add_function(stack_size::define_function(registry));
522    registry.add_function(registers_size::define_function(registry));
523}