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}