ad_astra/runtime/
ops.rs

1////////////////////////////////////////////////////////////////////////////////
2// This file is part of "Ad Astra", an embeddable scripting programming       //
3// language platform.                                                         //
4//                                                                            //
5// This work is proprietary software with source-available code.              //
6//                                                                            //
7// To copy, use, distribute, or contribute to this work, you must agree to    //
8// the terms of the General License Agreement:                                //
9//                                                                            //
10// https://github.com/Eliah-Lakhin/ad-astra/blob/master/EULA.md               //
11//                                                                            //
12// The agreement grants a Basic Commercial License, allowing you to use       //
13// this work in non-commercial and limited commercial products with a total   //
14// gross revenue cap. To remove this commercial limit for one of your         //
15// products, you must acquire a Full Commercial License.                      //
16//                                                                            //
17// If you contribute to the source code, documentation, or related materials, //
18// you must grant me an exclusive license to these contributions.             //
19// Contributions are governed by the "Contributions" section of the General   //
20// License Agreement.                                                         //
21//                                                                            //
22// Copying the work in parts is strictly forbidden, except as permitted       //
23// under the General License Agreement.                                       //
24//                                                                            //
25// If you do not or cannot agree to the terms of this Agreement,              //
26// do not use this work.                                                      //
27//                                                                            //
28// This work is provided "as is", without any warranties, express or implied, //
29// except where such disclaimers are legally invalid.                         //
30//                                                                            //
31// Copyright (c) 2024 Ilya Lakhin (Илья Александрович Лахин).                 //
32// All rights reserved.                                                       //
33////////////////////////////////////////////////////////////////////////////////
34
35use std::{
36    cmp::Ordering,
37    fmt::{Debug, Display, Formatter},
38    hash::Hash,
39};
40
41pub(crate) use crate::runtime::ops::functions::{
42    Fn0Repr,
43    Fn1Repr,
44    Fn2Repr,
45    Fn3Repr,
46    Fn4Repr,
47    Fn5Repr,
48    Fn6Repr,
49    Fn7Repr,
50};
51pub use crate::runtime::ops::{
52    functions::{Fn0, Fn1, Fn2, Fn3, Fn4, Fn5, Fn6, Fn7},
53    types::{DynamicArgument, DynamicReturn, DynamicType},
54};
55use crate::runtime::{Arg, Cell, Ident, InvocationMeta, Origin, RuntimeResult};
56
57/// A script assignment operator: `lhs = rhs`.
58///
59/// Implementing this trait enables the
60/// [Object::assign](crate::runtime::Object::assign) operation.
61///
62/// The trait must be implemented for the
63/// [registered type](crate::runtime::ScriptType), and the implementation must
64/// be exported using the [export](crate::export) macro. For more details,
65/// see the [module documentation](crate::runtime::ops).
66pub trait ScriptAssign {
67    /// A rough estimation of the type of the right-hand side of the operation.
68    ///
69    /// This type must implement [ScriptType](crate::runtime::ScriptType).
70    type RHS: ?Sized;
71
72    /// Operation implementation.
73    ///
74    /// The parameters and return type of this function correspond to those of
75    /// the [Object::assign](crate::runtime::Object::assign) function.
76    fn script_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
77}
78
79/// A script concatenation operator: `[a, b, c]`.
80///
81/// Implementing this trait enables the
82/// [TypeMeta::concat](crate::runtime::TypeMeta::concat) operation.
83///
84/// The trait must be implemented for the
85/// [registered type](crate::runtime::ScriptType), and the implementation must
86/// be exported using the [export](crate::export) macro. For more details, see
87/// the [module documentation](crate::runtime::ops).
88pub trait ScriptConcat {
89    /// A rough estimation of the result type of this operation.
90    ///
91    /// This type must implement [ScriptType](crate::runtime::ScriptType).
92    type Result: ?Sized;
93
94    /// Operation implementation.
95    ///
96    /// The parameters and return type of this function correspond to those of
97    /// the [TypeMeta::concat](crate::runtime::TypeMeta::concat) function.
98    fn script_concat(origin: Origin, items: &mut [Arg]) -> RuntimeResult<Cell>;
99}
100
101/// A dynamic resolver of the object fields: `foo.bar`.
102///
103/// Implementing this trait enables the
104/// [Object::field](crate::runtime::Object::field) operation.
105///
106/// The trait must be implemented for the
107/// [registered type](crate::runtime::ScriptType), and the implementation must
108/// be exported using the [export](crate::export) macro. For more details, see
109/// the [module documentation](crate::runtime::ops).
110pub trait ScriptField {
111    /// A rough estimation of the result type of this operation.
112    ///
113    /// This type must implement [ScriptType](crate::runtime::ScriptType).
114    ///
115    /// If the type is fully dynamic, consider using the [DynamicType] type as
116    /// a `Result` specification.
117    type Result: ?Sized;
118
119    /// Operation implementation.
120    ///
121    /// The parameters and return type of this function correspond to those of
122    /// the [Object::field](crate::runtime::Object::field) function.
123    fn script_field(origin: Origin, lhs: Arg, rhs: Ident) -> RuntimeResult<Cell>;
124}
125
126/// A script [cloning](Clone) operator: `*foo`.
127///
128/// Implementing this trait enables the
129/// [Object::clone](crate::runtime::Object::clone) operation.
130///
131/// The underlying type on which this trait is implemented must also implement
132/// the [Clone] trait, which provides the actual implementation of the script
133/// cloning operation.
134///
135/// The trait must be implemented for the
136/// [registered type](crate::runtime::ScriptType), and the implementation must
137/// be exported using the [export](crate::export) macro. For more details, see
138/// the [module documentation](crate::runtime::ops).
139pub trait ScriptClone: Clone {}
140
141/// A script [debugging](Debug) formatting operator.
142///
143/// Implementing this trait enables the
144/// [Object::debug](crate::runtime::Object::debug) operation.
145///
146/// The underlying type on which this trait is implemented must also implement
147/// the [Debug] trait, which provides the actual implementation of the script
148/// debugging operation.
149///
150/// The trait must be implemented for the
151/// [registered type](crate::runtime::ScriptType), and the implementation must
152/// be exported using the [export](crate::export) macro. For more details, see
153/// the [module documentation](crate::runtime::ops).
154pub trait ScriptDebug: Debug {}
155
156/// A script [displaying](Display) formatting operator.
157///
158/// Implementing this trait enables the
159/// [Object::display](crate::runtime::Object::display) operation.
160///
161/// The underlying type on which this trait is implemented must also implement
162/// the [Display] trait, which provides the actual implementation of the script
163/// debugging operation.
164///
165/// The trait must be implemented for the
166/// [registered type](crate::runtime::ScriptType), and the implementation must
167/// be exported using the [export](crate::export) macro. For more details, see
168/// the [module documentation](crate::runtime::ops).
169pub trait ScriptDisplay: Display {}
170
171/// A script equality operator: `lhs == rhs`.
172///
173/// Implementing this trait enables the
174/// [Object::partial_eq](crate::runtime::Object::partial_eq) operation.
175///
176/// Note that the implementation of [ScriptPartialEq::script_eq] serves both
177/// partial and [full equality](Eq) purposes.
178///
179/// The trait must be implemented for the
180/// [registered type](crate::runtime::ScriptType), and the implementation must
181/// be exported using the [export](crate::export) macro. For more details, see
182/// the [module documentation](crate::runtime::ops).
183pub trait ScriptPartialEq {
184    /// A rough estimation of the type of the right-hand side of the operation.
185    ///
186    /// This type must implement [ScriptType](crate::runtime::ScriptType).
187    type RHS: ?Sized;
188
189    /// Operation implementation.
190    ///
191    /// The parameters and return type of this function correspond to those of
192    /// the [Object::partial_eq](crate::runtime::Object::partial_eq) function.
193    fn script_eq(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<bool>;
194}
195
196/// A default constructor for a script object.
197///
198/// Implementing this trait enables the
199/// [TypeMeta::instantiate](crate::runtime::TypeMeta::instantiate) operation.
200///
201/// The trait must be implemented for the
202/// [registered type](crate::runtime::ScriptType), and the implementation must
203/// be exported using the [export](crate::export) macro. For more details, see
204/// the [module documentation](crate::runtime::ops).
205pub trait ScriptDefault {
206    /// Operation implementation.
207    ///
208    /// The parameter and return type of this function correspond to those of
209    /// the [TypeMeta::instantiate](crate::runtime::TypeMeta::instantiate)
210    /// function.
211    fn script_default(origin: Origin) -> RuntimeResult<Cell>;
212}
213
214/// A script partial ordering operator: `lhs >= rhs`, `lhs < rhs`, etc.
215///
216/// Implementing this trait enables the
217/// [Object::partial_ord](crate::runtime::Object::partial_ord) operation.
218///
219/// The trait must be implemented for the
220/// [registered type](crate::runtime::ScriptType), and the implementation must
221/// be exported using the [export](crate::export) macro. For more details, see
222/// the [module documentation](crate::runtime::ops).
223pub trait ScriptPartialOrd {
224    /// A rough estimation of the type of the right-hand side of the operation.
225    ///
226    /// This type must implement [ScriptType](crate::runtime::ScriptType).
227    type RHS: ?Sized;
228
229    /// Operation implementation.
230    ///
231    /// The parameters and return type of this function correspond to those of
232    /// the [Object::partial_ord](crate::runtime::Object::partial_ord) function.
233    fn script_partial_cmp(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Option<Ordering>>;
234}
235
236/// A script full ordering operator: `lhs >= rhs`, `lhs < rhs`, etc.
237///
238/// Implementing this trait enables the
239/// [Object::ord](crate::runtime::Object::ord) operation.
240///
241/// The trait must be implemented for the
242/// [registered type](crate::runtime::ScriptType), and the implementation must
243/// be exported using the [export](crate::export) macro. For more details, see
244/// the [module documentation](crate::runtime::ops).
245pub trait ScriptOrd {
246    /// Operation implementation.
247    ///
248    /// The parameters and return type of this function correspond to those of
249    /// the [Object::ord](crate::runtime::Object::ord) function.
250    fn script_cmp(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Ordering>;
251}
252
253/// A script data [hashing](Hash) operator.
254///
255/// Implementing this trait enables the
256/// [Object::hash](crate::runtime::Object::hash) operation.
257///
258/// The underlying type on which this trait is implemented must also implement
259/// the [Hash] trait, which provides the actual implementation of the script
260/// data hashing operation.
261///
262/// The trait must be implemented for the
263/// [registered type](crate::runtime::ScriptType), and the implementation must
264/// be exported using the [export](crate::export) macro. For more details, see
265/// the [module documentation](crate::runtime::ops).
266pub trait ScriptHash: Hash {}
267
268/// A script invocation operator: `foo(arg1, arg2, arg3)`.
269///
270/// Implementing this trait enables the
271/// [Object::invoke](crate::runtime::Object::invoke) operation.
272///
273/// The trait must be implemented for the
274/// [registered type](crate::runtime::ScriptType), and the implementation must
275/// be exported using the [export](crate::export) macro. For more details, see
276/// the [module documentation](crate::runtime::ops).
277pub trait ScriptInvocation {
278    /// Operation implementation.
279    ///
280    /// The parameters and return type of this function correspond to those of
281    /// the [Object::invoke](crate::runtime::Object::invoke) function.
282    fn invoke(origin: Origin, lhs: Arg, arguments: &mut [Arg]) -> RuntimeResult<Cell>;
283
284    /// Returns the invocation signature description.
285    ///
286    /// The function returns None if the signature is fully dynamic.
287    fn hint() -> Option<&'static InvocationMeta>;
288}
289
290/// A script context binding operator.
291///
292/// Implementing this trait enables the
293/// [Object::bind](crate::runtime::Object::bind) operation.
294///
295/// The trait must be implemented for the
296/// [registered type](crate::runtime::ScriptType), and the implementation must
297/// be exported using the [export](crate::export) macro. For more details, see
298/// the [module documentation](crate::runtime::ops).
299pub trait ScriptBinding {
300    /// A rough estimation of the type of the right-hand side of the operation.
301    ///
302    /// This type must implement [ScriptType](crate::runtime::ScriptType).
303    type RHS: ?Sized;
304
305    /// Operation implementation.
306    ///
307    /// The parameters and return type of this function correspond to those of
308    /// the [Object::bind](crate::runtime::Object::bind) function.
309    fn script_binding(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
310}
311
312/// A script addition operator: `lhs + rhs`.
313///
314/// Implementing this trait enables the
315/// [Object::add](crate::runtime::Object::add) operation.
316///
317/// The trait must be implemented for the
318/// [registered type](crate::runtime::ScriptType), and the implementation must
319/// be exported using the [export](crate::export) macro. For more details, see
320/// the [module documentation](crate::runtime::ops).
321pub trait ScriptAdd {
322    /// A rough estimation of the type of the right-hand side of the operation.
323    ///
324    /// This type must implement [ScriptType](crate::runtime::ScriptType).
325    type RHS: ?Sized;
326
327    /// A rough estimation of the result type of this operation.
328    ///
329    /// This type must implement [ScriptType](crate::runtime::ScriptType).
330    type Result: ?Sized;
331
332    /// Operation implementation.
333    ///
334    /// The parameters and return type of this function correspond to those of
335    /// the [Object::add](crate::runtime::Object::add) function.
336    fn script_add(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
337}
338
339/// A script addition and assignment operator: `lhs += rhs`.
340///
341/// Implementing this trait enables the
342/// [Object::add_assign](crate::runtime::Object::add_assign) operation.
343///
344/// The trait must be implemented for the
345/// [registered type](crate::runtime::ScriptType), and the implementation must
346/// be exported using the [export](crate::export) macro. For more details, see
347/// the [module documentation](crate::runtime::ops).
348pub trait ScriptAddAssign {
349    /// A rough estimation of the type of the right-hand side of the operation.
350    ///
351    /// This type must implement [ScriptType](crate::runtime::ScriptType).
352    type RHS: ?Sized;
353
354    /// Operation implementation.
355    ///
356    /// The parameters and return type of this function correspond to those of
357    /// the [Object::add_assign](crate::runtime::Object::add_assign) function.
358    fn script_add_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
359}
360
361/// A script subtraction operator: `lhs - rhs`.
362///
363/// Implementing this trait enables the
364/// [Object::sub](crate::runtime::Object::sub) operation.
365///
366/// The trait must be implemented for the
367/// [registered type](crate::runtime::ScriptType), and the implementation must
368/// be exported using the [export](crate::export) macro. For more details, see
369/// the [module documentation](crate::runtime::ops).
370pub trait ScriptSub {
371    /// A rough estimation of the type of the right-hand side of the operation.
372    ///
373    /// This type must implement [ScriptType](crate::runtime::ScriptType).
374    type RHS: ?Sized;
375
376    /// A rough estimation of the result type of this operation.
377    ///
378    /// This type must implement [ScriptType](crate::runtime::ScriptType).
379    type Result: ?Sized;
380
381    /// Operation implementation.
382    ///
383    /// The parameters and return type of this function correspond to those of
384    /// the [Object::sub](crate::runtime::Object::sub) function.
385    fn script_sub(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
386}
387
388/// A script subtraction and assignment operator: `lhs -= rhs`.
389///
390/// Implementing this trait enables the
391/// [Object::sub_assign](crate::runtime::Object::sub_assign) operation.
392///
393/// The trait must be implemented for the
394/// [registered type](crate::runtime::ScriptType), and the implementation must
395/// be exported using the [export](crate::export) macro. For more details, see
396/// the [module documentation](crate::runtime::ops).
397pub trait ScriptSubAssign {
398    /// A rough estimation of the type of the right-hand side of the operation.
399    ///
400    /// This type must implement [ScriptType](crate::runtime::ScriptType).
401    type RHS: ?Sized;
402
403    /// Operation implementation.
404    ///
405    /// The parameters and return type of this function correspond to those of
406    /// the [Object::sub_assign](crate::runtime::Object::sub_assign) function.
407    fn script_sub_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
408}
409
410/// A script multiplication operator: `lhs * rhs`.
411///
412/// Implementing this trait enables the
413/// [Object::mul](crate::runtime::Object::mul) operation.
414///
415/// The trait must be implemented for the
416/// [registered type](crate::runtime::ScriptType), and the implementation must
417/// be exported using the [export](crate::export) macro. For more details, see
418/// the [module documentation](crate::runtime::ops).
419pub trait ScriptMul {
420    /// A rough estimation of the type of the right-hand side of the operation.
421    ///
422    /// This type must implement [ScriptType](crate::runtime::ScriptType).
423    type RHS: ?Sized;
424
425    /// A rough estimation of the result type of this operation.
426    ///
427    /// This type must implement [ScriptType](crate::runtime::ScriptType).
428    type Result: ?Sized;
429
430    /// Operation implementation.
431    ///
432    /// The parameters and return type of this function correspond to those of
433    /// the [Object::mul](crate::runtime::Object::mul) function.
434    fn script_mul(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
435}
436
437/// A script multiplication and assignment operator: `lhs *= rhs`.
438///
439/// Implementing this trait enables the
440/// [Object::mul_assign](crate::runtime::Object::mul_assign) operation.
441///
442/// The trait must be implemented for the
443/// [registered type](crate::runtime::ScriptType), and the implementation must
444/// be exported using the [export](crate::export) macro. For more details, see
445/// the [module documentation](crate::runtime::ops).
446pub trait ScriptMulAssign {
447    /// A rough estimation of the type of the right-hand side of the operation.
448    ///
449    /// This type must implement [ScriptType](crate::runtime::ScriptType).
450    type RHS: ?Sized;
451
452    /// Operation implementation.
453    ///
454    /// The parameters and return type of this function correspond to those of
455    /// the [Object::mul_assign](crate::runtime::Object::mul_assign) function.
456    fn script_mul_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
457}
458
459/// A script division operator: `lhs / rhs`.
460///
461/// Implementing this trait enables the
462/// [Object::div](crate::runtime::Object::div) operation.
463///
464/// The trait must be implemented for the
465/// [registered type](crate::runtime::ScriptType), and the implementation must
466/// be exported using the [export](crate::export) macro. For more details, see
467/// the [module documentation](crate::runtime::ops).
468pub trait ScriptDiv {
469    /// A rough estimation of the type of the right-hand side of the operation.
470    ///
471    /// This type must implement [ScriptType](crate::runtime::ScriptType).
472    type RHS: ?Sized;
473
474    /// A rough estimation of the result type of this operation.
475    ///
476    /// This type must implement [ScriptType](crate::runtime::ScriptType).
477    type Result: ?Sized;
478
479    /// Operation implementation.
480    ///
481    /// The parameters and return type of this function correspond to those of
482    /// the [Object::div](crate::runtime::Object::div) function.
483    fn script_div(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
484}
485
486/// A script division and assignment operator: `lhs /= rhs`.
487///
488/// Implementing this trait enables the
489/// [Object::div_assign](crate::runtime::Object::div_assign) operation.
490///
491/// The trait must be implemented for the
492/// [registered type](crate::runtime::ScriptType), and the implementation must
493/// be exported using the [export](crate::export) macro. For more details, see
494/// the [module documentation](crate::runtime::ops).
495pub trait ScriptDivAssign {
496    /// A rough estimation of the type of the right-hand side of the operation.
497    ///
498    /// This type must implement [ScriptType](crate::runtime::ScriptType).
499    type RHS: ?Sized;
500
501    /// Operation implementation.
502    ///
503    /// The parameters and return type of this function correspond to those of
504    /// the [Object::div_assign](crate::runtime::Object::div_assign) function.
505    fn script_div_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
506}
507
508/// A script logical conjunction operator: `lhs && rhs`.
509///
510/// Implementing this trait enables the
511/// [Object::and](crate::runtime::Object::and) operation.
512///
513/// The trait must be implemented for the
514/// [registered type](crate::runtime::ScriptType), and the implementation must
515/// be exported using the [export](crate::export) macro. For more details, see
516/// the [module documentation](crate::runtime::ops).
517pub trait ScriptAnd {
518    /// A rough estimation of the type of the right-hand side of the operation.
519    ///
520    /// This type must implement [ScriptType](crate::runtime::ScriptType).
521    type RHS: ?Sized;
522
523    /// A rough estimation of the result type of this operation.
524    ///
525    /// This type must implement [ScriptType](crate::runtime::ScriptType).
526    type Result: ?Sized;
527
528    /// Operation implementation.
529    ///
530    /// The parameters and return type of this function correspond to those of
531    /// the [Object::and](crate::runtime::Object::and) function.
532    fn script_and(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
533}
534
535/// A script logical disjunction operator: `lhs || rhs`.
536///
537/// Implementing this trait enables the
538/// [Object::or](crate::runtime::Object::or) operation.
539///
540/// The trait must be implemented for the
541/// [registered type](crate::runtime::ScriptType), and the implementation must
542/// be exported using the [export](crate::export) macro. For more details, see
543/// the [module documentation](crate::runtime::ops).
544pub trait ScriptOr {
545    /// A rough estimation of the type of the right-hand side of the operation.
546    ///
547    /// This type must implement [ScriptType](crate::runtime::ScriptType).
548    type RHS: ?Sized;
549
550    /// A rough estimation of the result type of this operation.
551    ///
552    /// This type must implement [ScriptType](crate::runtime::ScriptType).
553    type Result: ?Sized;
554
555    /// Operation implementation.
556    ///
557    /// The parameters and return type of this function correspond to those of
558    /// the [Object::or](crate::runtime::Object::or) function.
559    fn script_or(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
560}
561
562/// A script logical negation operator: `!foo`.
563///
564/// Implementing this trait enables the
565/// [Object::not](crate::runtime::Object::not) operation.
566///
567/// The trait must be implemented for the
568/// [registered type](crate::runtime::ScriptType), and the implementation must
569/// be exported using the [export](crate::export) macro. For more details, see
570/// the [module documentation](crate::runtime::ops).
571pub trait ScriptNot {
572    /// A rough estimation of the result type of this operation.
573    ///
574    /// This type must implement [ScriptType](crate::runtime::ScriptType).
575    type Result: ?Sized;
576
577    /// Operation implementation.
578    ///
579    /// The parameters and return type of this function correspond to those of
580    /// the [Object::not](crate::runtime::Object::not) function.
581    fn script_not(origin: Origin, lhs: Arg) -> RuntimeResult<Cell>;
582}
583
584/// A script numeric negation operator: `-foo`.
585///
586/// Implementing this trait enables the
587/// [Object::neg](crate::runtime::Object::neg) operation.
588///
589/// The trait must be implemented for the
590/// [registered type](crate::runtime::ScriptType), and the implementation must
591/// be exported using the [export](crate::export) macro. For more details, see
592/// the [module documentation](crate::runtime::ops).
593pub trait ScriptNeg {
594    /// A rough estimation of the result type of this operation.
595    ///
596    /// This type must implement [ScriptType](crate::runtime::ScriptType).
597    type Result: ?Sized;
598
599    /// Operation implementation.
600    ///
601    /// The parameters and return type of this function correspond to those of
602    /// the [Object::neg](crate::runtime::Object::neg) function.
603    fn script_neg(origin: Origin, lhs: Arg) -> RuntimeResult<Cell>;
604}
605
606/// A script bitwise conjunction operator: `lhs & rhs`.
607///
608/// Implementing this trait enables the
609/// [Object::bit_and](crate::runtime::Object::bit_and) operation.
610///
611/// The trait must be implemented for the
612/// [registered type](crate::runtime::ScriptType), and the implementation must
613/// be exported using the [export](crate::export) macro. For more details, see
614/// the [module documentation](crate::runtime::ops).
615pub trait ScriptBitAnd {
616    /// A rough estimation of the type of the right-hand side of the operation.
617    ///
618    /// This type must implement [ScriptType](crate::runtime::ScriptType).
619    type RHS: ?Sized;
620
621    /// A rough estimation of the result type of this operation.
622    ///
623    /// This type must implement [ScriptType](crate::runtime::ScriptType).
624    type Result: ?Sized;
625
626    /// Operation implementation.
627    ///
628    /// The parameters and return type of this function correspond to those of
629    /// the [Object::bit_and](crate::runtime::Object::bit_and) function.
630    fn script_bit_and(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
631}
632
633/// A script bitwise conjunction and assignment operator: `lhs &= rhs`.
634///
635/// Implementing this trait enables the
636/// [Object::bit_and_assign](crate::runtime::Object::bit_and_assign) operation.
637///
638/// The trait must be implemented for the
639/// [registered type](crate::runtime::ScriptType), and the implementation must
640/// be exported using the [export](crate::export) macro. For more details, see
641/// the [module documentation](crate::runtime::ops).
642pub trait ScriptBitAndAssign {
643    /// A rough estimation of the type of the right-hand side of the operation.
644    ///
645    /// This type must implement [ScriptType](crate::runtime::ScriptType).
646    type RHS: ?Sized;
647
648    /// Operation implementation.
649    ///
650    /// The parameters and return type of this function correspond to those of
651    /// the [Object::bit_and_assign](crate::runtime::Object::bit_and_assign)
652    /// function.
653    fn script_bit_and_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
654}
655
656/// A script bitwise disjunction operator: `lhs | rhs`.
657///
658/// Implementing this trait enables the
659/// [Object::bit_or](crate::runtime::Object::bit_or) operation.
660///
661/// The trait must be implemented for the
662/// [registered type](crate::runtime::ScriptType), and the implementation must
663/// be exported using the [export](crate::export) macro. For more details, see
664/// the [module documentation](crate::runtime::ops).
665pub trait ScriptBitOr {
666    /// A rough estimation of the type of the right-hand side of the operation.
667    ///
668    /// This type must implement [ScriptType](crate::runtime::ScriptType).
669    type RHS: ?Sized;
670
671    /// A rough estimation of the result type of this operation.
672    ///
673    /// This type must implement [ScriptType](crate::runtime::ScriptType).
674    type Result: ?Sized;
675
676    /// Operation implementation.
677    ///
678    /// The parameters and return type of this function correspond to those of
679    /// the [Object::bit_or](crate::runtime::Object::bit_or) function.
680    fn script_bit_or(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
681}
682
683/// A script bitwise disjunction and assignment operator: `lhs |= rhs`.
684///
685/// Implementing this trait enables the
686/// [Object::bit_or_assign](crate::runtime::Object::bit_or_assign) operation.
687///
688/// The trait must be implemented for the
689/// [registered type](crate::runtime::ScriptType), and the implementation must
690/// be exported using the [export](crate::export) macro. For more details, see
691/// the [module documentation](crate::runtime::ops).
692pub trait ScriptBitOrAssign {
693    /// A rough estimation of the type of the right-hand side of the operation.
694    ///
695    /// This type must implement [ScriptType](crate::runtime::ScriptType).
696    type RHS: ?Sized;
697
698    /// Operation implementation.
699    ///
700    /// The parameters and return type of this function correspond to those of
701    /// the [Object::bit_or_assign](crate::runtime::Object::bit_or_assign)
702    /// function.
703    fn script_bit_or_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
704}
705
706/// A script bitwise exclusive disjunction operator: `lhs ^ rhs`.
707///
708/// Implementing this trait enables the
709/// [Object::bit_xor](crate::runtime::Object::bit_xor) operation.
710///
711/// The trait must be implemented for the
712/// [registered type](crate::runtime::ScriptType), and the implementation must
713/// be exported using the [export](crate::export) macro. For more details, see
714/// the [module documentation](crate::runtime::ops).
715pub trait ScriptBitXor {
716    /// A rough estimation of the type of the right-hand side of the operation.
717    ///
718    /// This type must implement [ScriptType](crate::runtime::ScriptType).
719    type RHS: ?Sized;
720
721    /// A rough estimation of the result type of this operation.
722    ///
723    /// This type must implement [ScriptType](crate::runtime::ScriptType).
724    type Result: ?Sized;
725
726    /// Operation implementation.
727    ///
728    /// The parameters and return type of this function correspond to those of
729    /// the [Object::bit_xor](crate::runtime::Object::bit_xor) function.
730    fn script_bit_xor(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
731}
732
733/// A script bitwise exclusive disjunction and assignment operator:
734/// `lhs ^= rhs`.
735///
736/// Implementing this trait enables the
737/// [Object::bit_xor_assign](crate::runtime::Object::bit_xor_assign) operation.
738///
739/// The trait must be implemented for the
740/// [registered type](crate::runtime::ScriptType), and the implementation must
741/// be exported using the [export](crate::export) macro. For more details, see
742/// the [module documentation](crate::runtime::ops).
743pub trait ScriptBitXorAssign {
744    /// A rough estimation of the type of the right-hand side of the operation.
745    ///
746    /// This type must implement [ScriptType](crate::runtime::ScriptType).
747    type RHS: ?Sized;
748
749    /// Operation implementation.
750    ///
751    /// The parameters and return type of this function correspond to those of
752    /// the [Object::bit_xor_assign](crate::runtime::Object::bit_xor_assign)
753    /// function.
754    fn script_bit_xor_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
755}
756
757/// A script bitwise left shift operator: `lhs << rhs`.
758///
759/// Implementing this trait enables the
760/// [Object::shl](crate::runtime::Object::shl) operation.
761///
762/// The trait must be implemented for the
763/// [registered type](crate::runtime::ScriptType), and the implementation must
764/// be exported using the [export](crate::export) macro. For more details, see
765/// the [module documentation](crate::runtime::ops).
766pub trait ScriptShl {
767    /// A rough estimation of the type of the right-hand side of the operation.
768    ///
769    /// This type must implement [ScriptType](crate::runtime::ScriptType).
770    type RHS: ?Sized;
771
772    /// A rough estimation of the result type of this operation.
773    ///
774    /// This type must implement [ScriptType](crate::runtime::ScriptType).
775    type Result: ?Sized;
776
777    /// Operation implementation.
778    ///
779    /// The parameters and return type of this function correspond to those of
780    /// the [Object::shl](crate::runtime::Object::shl) function.
781    fn script_shl(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
782}
783
784/// A script bitwise left shift and assignment operator: `lhs <<= rhs`.
785///
786/// Implementing this trait enables the
787/// [Object::shl_assign](crate::runtime::Object::shl_assign) operation.
788///
789/// The trait must be implemented for the
790/// [registered type](crate::runtime::ScriptType), and the implementation must
791/// be exported using the [export](crate::export) macro. For more details, see
792/// the [module documentation](crate::runtime::ops).
793pub trait ScriptShlAssign {
794    /// A rough estimation of the type of the right-hand side of the operation.
795    ///
796    /// This type must implement [ScriptType](crate::runtime::ScriptType).
797    type RHS: ?Sized;
798
799    /// Operation implementation.
800    ///
801    /// The parameters and return type of this function correspond to those of
802    /// the [Object::shl_assign](crate::runtime::Object::shl_assign) function.
803    fn script_shl_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
804}
805
806/// A script bitwise right shift operator: `lhs >> rhs`.
807///
808/// Implementing this trait enables the
809/// [Object::shr](crate::runtime::Object::shr) operation.
810///
811/// The trait must be implemented for the
812/// [registered type](crate::runtime::ScriptType), and the implementation must
813/// be exported using the [export](crate::export) macro. For more details, see
814/// the [module documentation](crate::runtime::ops).
815pub trait ScriptShr {
816    /// A rough estimation of the type of the right-hand side of the operation.
817    ///
818    /// This type must implement [ScriptType](crate::runtime::ScriptType).
819    type RHS: ?Sized;
820
821    /// A rough estimation of the result type of this operation.
822    ///
823    /// This type must implement [ScriptType](crate::runtime::ScriptType).
824    type Result: ?Sized;
825
826    /// Operation implementation.
827    ///
828    /// The parameters and return type of this function correspond to those of
829    /// the [Object::shr](crate::runtime::Object::shr) function.
830    fn script_shr(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
831}
832
833/// A script bitwise right shift and assignment operator: `lhs >>= rhs`.
834///
835/// Implementing this trait enables the
836/// [Object::shr_assign](crate::runtime::Object::shr_assign) operation.
837///
838/// The trait must be implemented for the
839/// [registered type](crate::runtime::ScriptType), and the implementation must
840/// be exported using the [export](crate::export) macro. For more details, see
841/// the [module documentation](crate::runtime::ops).
842pub trait ScriptShrAssign {
843    /// A rough estimation of the type of the right-hand side of the operation.
844    ///
845    /// This type must implement [ScriptType](crate::runtime::ScriptType).
846    type RHS: ?Sized;
847
848    /// Operation implementation.
849    ///
850    /// The parameters and return type of this function correspond to those of
851    /// the [Object::shr_assign](crate::runtime::Object::shr_assign) function.
852    fn script_shr_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
853}
854
855/// A script reminder of division operator: `lhs % rhs`.
856///
857/// Implementing this trait enables the
858/// [Object::rem](crate::runtime::Object::rem) operation.
859///
860/// The trait must be implemented for the
861/// [registered type](crate::runtime::ScriptType), and the implementation must
862/// be exported using the [export](crate::export) macro. For more details, see
863/// the [module documentation](crate::runtime::ops).
864pub trait ScriptRem {
865    /// A rough estimation of the type of the right-hand side of the operation.
866    ///
867    /// This type must implement [ScriptType](crate::runtime::ScriptType).
868    type RHS: ?Sized;
869
870    /// A rough estimation of the result type of this operation.
871    ///
872    /// This type must implement [ScriptType](crate::runtime::ScriptType).
873    type Result: ?Sized;
874
875    /// Operation implementation.
876    ///
877    /// The parameters and return type of this function correspond to those of
878    /// the [Object::rem](crate::runtime::Object::rem) function.
879    fn script_rem(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<Cell>;
880}
881
882/// A script reminder of division and assignment operator: `lhs %= rhs`.
883///
884/// Implementing this trait enables the
885/// [Object::rem_assign](crate::runtime::Object::rem_assign) operation.
886///
887/// The trait must be implemented for the
888/// [registered type](crate::runtime::ScriptType), and the implementation must
889/// be exported using the [export](crate::export) macro. For more details, see
890/// the [module documentation](crate::runtime::ops).
891pub trait ScriptRemAssign {
892    /// A rough estimation of the type of the right-hand side of the operation.
893    ///
894    /// This type must implement [ScriptType](crate::runtime::ScriptType).
895    type RHS: ?Sized;
896
897    /// Operation implementation.
898    ///
899    /// The parameters and return type of this function correspond to those of
900    /// the [Object::rem_assign](crate::runtime::Object::rem_assign) function.
901    fn script_rem_assign(origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()>;
902}
903
904/// A marker trait indicating that the underlying type represents void data.
905///
906/// When this trait is implemented for a script type, the
907/// [Prototype::implements_none](crate::runtime::Prototype::implements_none)
908/// function will return `true`.
909///
910/// The trait must be implemented for the
911/// [registered type](crate::runtime::ScriptType), and the implementation must
912/// be exported using the [export](crate::export) macro. For more details, see
913/// the [module documentation](crate::runtime::ops).
914pub trait ScriptNone {}
915
916/// A type of the script operator.
917#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
918#[non_exhaustive]
919pub enum OperatorKind {
920    /// An assignment operator: `lhs = rhs`.
921    Assign,
922
923    /// An array constructor: `[a, b, c]`.
924    Concat,
925
926    /// A field access operator: `foo.bar`.
927    Field,
928
929    /// A cloning operator: `*foo`.
930    Clone,
931
932    /// A [Debug] formatting operator.
933    Debug,
934
935    /// A [Display] formatting operator.
936    Display,
937
938    /// An equality operator: `lhs == rhs`.
939    PartialEq,
940
941    /// An object's default constructor.
942    Default,
943
944    /// A partial ordering operator: `lhs >= rhs`, `lhs < rhs`, etc.
945    PartialOrd,
946
947    /// A full ordering operator: `lhs >= rhs`, `lhs < rhs`, etc.
948    Ord,
949
950    /// A data [Hash] operator.
951    Hash,
952
953    /// An invocation operator: `foo(arg1, arg2, arg3)`.
954    Invocation,
955
956    /// A context binding operator.
957    Binding,
958
959    /// An addition operator: `lhs + rhs`.
960    Add,
961
962    /// An addition and assignment operator: `lhs += rhs`.
963    AddAssign,
964
965    /// An subtraction operator: `lhs - rhs`.
966    Sub,
967
968    /// An subtraction and assignment operator: `lhs -= rhs`.
969    SubAssign,
970
971    /// A multiplication operator: `lhs * rhs`.
972    Mul,
973
974    /// A multiplication and assignment operator: `lhs *= rhs`.
975    MulAssign,
976
977    /// A division operator: `lhs / rhs`.
978    Div,
979
980    /// A division and assignment operator: `lhs /= rhs`.
981    DivAssign,
982
983    /// A logical conjunction operator: `lhs && rhs`.
984    And,
985
986    /// A logical disjunction operator: `lhs || rhs`.
987    Or,
988
989    /// A logical negation operator: `!foo`.
990    Not,
991
992    /// A numeric negation operator: `-foo`.
993    Neg,
994
995    /// A bitwise conjunction operator: `lhs & rhs`.
996    BitAnd,
997
998    /// A bitwise conjunction and assignment operator: `lhs &= rhs`.
999    BitAndAssign,
1000
1001    /// A bitwise disjunction operator: `lhs | rhs`.
1002    BitOr,
1003
1004    /// A bitwise disjunction and assignment operator: `lhs |= rhs`.
1005    BitOrAssign,
1006
1007    /// A bitwise exclusive disjunction operator: `lhs ^ rhs`.
1008    BitXor,
1009
1010    /// A bitwise exclusive disjunction and assignment operator: `lhs ^= rhs`.
1011    BitXorAssign,
1012
1013    /// A bitwise left shift operator: `lhs << rhs`.
1014    Shl,
1015
1016    /// A bitwise left shift and assignment operator: `lhs <<= rhs`.
1017    ShlAssign,
1018
1019    /// A bitwise right shift operator: `lhs >> rhs`.
1020    Shr,
1021
1022    /// A bitwise right shift and assignment operator: `lhs >>= rhs`.
1023    ShrAssign,
1024
1025    /// A reminder of division operator: `lhs % rhs`.
1026    Rem,
1027
1028    /// A reminder of division and assignment operator: `lhs %= rhs`.
1029    RemAssign,
1030}
1031
1032impl Display for OperatorKind {
1033    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
1034        match self {
1035            Self::Assign => formatter.write_str("= operator"),
1036            Self::Concat => formatter.write_str("[] operator"),
1037            Self::Field => formatter.write_str("field access operator"),
1038            Self::Clone => formatter.write_str("clone operator"),
1039            Self::Debug => formatter.write_str("debug operator"),
1040            Self::Display => formatter.write_str("display operator"),
1041            Self::PartialEq => formatter.write_str("== operator"),
1042            Self::Default => formatter.write_str("default constructor"),
1043            Self::PartialOrd => formatter.write_str("ordering"),
1044            Self::Ord => formatter.write_str("ordering"),
1045            Self::Hash => formatter.write_str("hash interface"),
1046            Self::Invocation => formatter.write_str("invocation"),
1047            Self::Binding => formatter.write_str("binding"),
1048            Self::Add => formatter.write_str("+ operator"),
1049            Self::AddAssign => formatter.write_str("+= operator"),
1050            Self::Sub => formatter.write_str("- operator"),
1051            Self::SubAssign => formatter.write_str("-= operator"),
1052            Self::Mul => formatter.write_str("* operator"),
1053            Self::MulAssign => formatter.write_str("*= operator"),
1054            Self::Div => formatter.write_str("/ operator"),
1055            Self::DivAssign => formatter.write_str("/= operator"),
1056            Self::And => formatter.write_str("&& operator"),
1057            Self::Or => formatter.write_str("|| operator"),
1058            Self::Not => formatter.write_str("! operator"),
1059            Self::Neg => formatter.write_str("negative - operator"),
1060            Self::BitAnd => formatter.write_str("& operator"),
1061            Self::BitAndAssign => formatter.write_str("&= operator"),
1062            Self::BitOr => formatter.write_str("| operator"),
1063            Self::BitOrAssign => formatter.write_str("|= operator"),
1064            Self::BitXor => formatter.write_str("^ operator"),
1065            Self::BitXorAssign => formatter.write_str("^= operator"),
1066            Self::Shl => formatter.write_str("<< operator"),
1067            Self::ShlAssign => formatter.write_str("<<= operator"),
1068            Self::Shr => formatter.write_str(">> operator"),
1069            Self::ShrAssign => formatter.write_str(">>= operator"),
1070            Self::Rem => formatter.write_str("% operator"),
1071            Self::RemAssign => formatter.write_str("%= operator"),
1072        }
1073    }
1074}
1075
1076mod types {
1077    use std::marker::PhantomData;
1078
1079    use crate::{
1080        export,
1081        runtime::{
1082            Arg,
1083            Cell,
1084            Downcast,
1085            Origin,
1086            Provider,
1087            RuntimeResult,
1088            ScriptType,
1089            TypeHint,
1090            Upcast,
1091        },
1092    };
1093
1094    /// A type that cannot be inferred during static semantic analysis.
1095    ///
1096    /// Normally, you should not instantiate or use this object in
1097    /// implementations, but you can use this type as a hint for the analyzer
1098    /// when the implementation nature is fully dynamic.
1099    ///
1100    /// ```
1101    /// # use ad_astra::{
1102    /// #     export,
1103    /// #     runtime::{
1104    /// #         ops::{DynamicType, ScriptAssign},
1105    /// #         Arg,
1106    /// #         Origin,
1107    /// #         RuntimeResult,
1108    /// #     },
1109    /// # };
1110    /// #
1111    /// struct Foo;
1112    ///
1113    /// #[export]
1114    /// type FooAlias = Foo;
1115    ///
1116    /// #[export]
1117    /// impl ScriptAssign for Foo {
1118    ///     // `type RHS = Foo;` would be more preferable in this case.
1119    ///     type RHS = DynamicType;
1120    ///
1121    ///     fn script_assign(_origin: Origin, lhs: Arg, rhs: Arg) -> RuntimeResult<()> {
1122    ///         let rhs = rhs.data.take::<Foo>(rhs.origin)?;
1123    ///
1124    ///         let (lhs_origin, mut lhs_cell) = lhs.split();
1125    ///
1126    ///         let lhs = lhs_cell.borrow_mut::<Foo>(lhs_origin)?;
1127    ///
1128    ///         *lhs = rhs;
1129    ///
1130    ///         Ok(())
1131    ///     }
1132    /// }
1133    /// ```
1134    ///
1135    /// Generally, it is recommended to use this type as sparingly as possible,
1136    /// preferring more specific types even if they provide an imprecise
1137    /// description.
1138    ///
1139    /// If you need more control over the exported function's arguments and
1140    /// result type casting, consider using [DynamicArgument] and
1141    /// [DynamicReturn] wrappers instead.
1142    pub struct DynamicType;
1143
1144    /// Unknown type.
1145    ///
1146    /// This type cannot be inferred statically.
1147    #[export(include)]
1148    #[export(name "?")]
1149    type DynamicTypeExport = DynamicType;
1150
1151    /// A type of a function's parameter that may have a more dynamic casting
1152    /// nature than usual.
1153    ///
1154    /// The analyzer will assume that the argument's type belongs to the
1155    /// [type family](crate::runtime::TypeFamily) of the `T` type, but the
1156    /// Script Engine will not automatically [downcast](Downcast) the script's
1157    /// argument, allowing the implementation to manually cast the argument's
1158    /// [Cell].
1159    ///
1160    /// ```
1161    /// # use ad_astra::{
1162    /// #     export,
1163    /// #     runtime::{ops::DynamicArgument, Downcast, Provider, RuntimeResult},
1164    /// # };
1165    /// #
1166    /// #[export]
1167    /// fn plus_10(mut arg: DynamicArgument<usize>) -> RuntimeResult<usize> {
1168    ///     let mut arg_ty = arg.data.type_match();
1169    ///
1170    ///     if arg_ty.belongs_to::<usize>() {
1171    ///         let arg = <usize>::downcast(arg.origin, Provider::Borrowed(&mut arg.data))?;
1172    ///
1173    ///         return Ok(arg + 10);
1174    ///     }
1175    ///
1176    ///     if arg_ty.is::<str>() {
1177    ///         let arg = arg.data.borrow_str(arg.origin)?;
1178    ///
1179    ///         return Ok(arg.len() + 10);
1180    ///     }
1181    ///
1182    ///     Err(arg_ty.mismatch(arg.origin))
1183    /// }
1184    /// ```
1185    pub struct DynamicArgument<T> {
1186        /// A Rust or Script source code range where the argument has been
1187        /// provided.
1188        pub origin: Origin,
1189
1190        /// The actual data of the argument.
1191        pub data: Cell,
1192
1193        phantom: PhantomData<T>,
1194    }
1195
1196    impl<T> DynamicArgument<T> {
1197        /// A helper function that converts this instance into an operator's
1198        /// [argument](Arg).
1199        #[inline(always)]
1200        pub fn into_argument(self) -> Arg {
1201            Arg {
1202                origin: self.origin,
1203                data: self.data,
1204            }
1205        }
1206    }
1207
1208    impl<'a, T: ScriptType> Downcast<'a> for DynamicArgument<T> {
1209        #[inline(always)]
1210        fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
1211            Ok(DynamicArgument {
1212                origin,
1213                data: provider.to_owned(),
1214                phantom: PhantomData,
1215            })
1216        }
1217
1218        #[inline(always)]
1219        fn hint() -> TypeHint {
1220            TypeHint::Type(T::type_meta())
1221        }
1222    }
1223
1224    /// A type for a function's return value that may have a more dynamic
1225    /// casting nature than usual.
1226    ///
1227    /// The analyzer will assume that the return type belongs to the
1228    /// [type family](crate::runtime::TypeFamily) of the `T` type, but the
1229    /// Script Engine will not automatically [upcast](Upcast) the Rust value,
1230    /// allowing the implementation to manually cast the result into a [Cell].
1231    ///
1232    /// ```
1233    /// # use ad_astra::{
1234    /// #     export,
1235    /// #     runtime::{ops::DynamicReturn, Cell, Origin, RuntimeResult},
1236    /// # };
1237    /// #
1238    /// #[export]
1239    /// fn string_or_number(is_string: bool) -> RuntimeResult<DynamicReturn<usize>> {
1240    ///     match is_string {
1241    ///         true => Ok(DynamicReturn::new(Cell::give(Origin::nil(), "string")?)),
1242    ///         false => Ok(DynamicReturn::new(Cell::give(Origin::nil(), 100usize)?)),
1243    ///     }
1244    /// }
1245    /// ```
1246    #[repr(transparent)]
1247    pub struct DynamicReturn<T> {
1248        /// The underlying return object.
1249        pub data: Cell,
1250        phantom: PhantomData<T>,
1251    }
1252
1253    impl<T> DynamicReturn<T> {
1254        /// A constructor that wraps the provided `data` [Cell] into a
1255        /// DynamicReturn.
1256        #[inline(always)]
1257        pub fn new(data: Cell) -> Self {
1258            DynamicReturn {
1259                data,
1260                phantom: PhantomData,
1261            }
1262        }
1263    }
1264
1265    impl<'a, T: ScriptType> Upcast<'a> for DynamicReturn<T> {
1266        type Output = Cell;
1267
1268        #[inline(always)]
1269        fn upcast(_origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
1270            Ok(this.data)
1271        }
1272
1273        #[inline(always)]
1274        fn hint() -> TypeHint {
1275            TypeHint::Type(T::type_meta())
1276        }
1277    }
1278}
1279
1280mod functions {
1281    use lady_deirdre::sync::Lazy;
1282
1283    use crate::{
1284        export,
1285        report::system_panic,
1286        runtime::{
1287            ops::{OperatorKind, ScriptConcat, ScriptInvocation},
1288            ty::ScriptType,
1289            Arg,
1290            Cell,
1291            Downcast,
1292            InvocationMeta,
1293            Origin,
1294            Param,
1295            Provider,
1296            RuntimeError,
1297            RuntimeResult,
1298            TypeHint,
1299            Upcast,
1300        },
1301    };
1302
1303    #[repr(transparent)]
1304    pub struct FnRepr<const ARGS: usize, F: ?Sized> {
1305        callable: Box<F>,
1306    }
1307
1308    macro_rules! impl_fn {
1309        (
1310            $(#[doc = $fn_doc:expr])*
1311            $fn_ty:ident;
1312            $fn_repr_ty:ident [$arity:expr] as $name:expr => $($arg:ident: $index:expr),*;
1313        ) => {
1314            $(#[doc = $fn_doc])*
1315            pub type $fn_ty<$($arg, )* R> = Box<dyn Fn($($arg),*) -> RuntimeResult<R> + Send + Sync + 'static>;
1316
1317            $(#[doc = $fn_doc])*
1318            #[export(include)]
1319            #[export(name $name)]
1320            #[export(family &crate::runtime::__intrinsics::FUNCTION_FAMILY)]
1321            pub(crate) type $fn_repr_ty = FnRepr<
1322                0,
1323                dyn Fn(Origin, &mut [Arg; $arity]) -> RuntimeResult<Cell> + Send + Sync + 'static,
1324            >;
1325
1326            impl<'a $(, $arg)*, R> Downcast<'a> for $fn_ty<$($arg, )* R>
1327            where
1328                $(
1329                $arg: Upcast<'static>,
1330                )*
1331                R: Downcast<'static>,
1332            {
1333                #[inline]
1334                fn downcast(downcast_origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
1335                    let cell = provider.to_owned();
1336                    let ty = cell.ty();
1337
1338                    if !ty.prototype().implements_invocation() {
1339                        return Err(RuntimeError::UndefinedOperator {
1340                            access_origin: downcast_origin,
1341                            receiver_origin: Some(cell.origin()),
1342                            receiver_type: ty,
1343                            operator: OperatorKind::Invocation,
1344                        });
1345                    }
1346
1347                    Ok(Box::new(move |$(#[allow(non_snake_case)] $arg: $arg),*| {
1348                        let object = cell.clone().into_object();
1349
1350                        let mut arguments: [Arg; $arity] = [
1351                            $(Arg {
1352                                origin: downcast_origin,
1353                                data: Cell::give(downcast_origin, $arg)?
1354                            }),*
1355                        ];
1356
1357                        let result = object.invoke(
1358                            downcast_origin,
1359                            downcast_origin,
1360                            &mut arguments,
1361                        )?;
1362
1363                        <R as Downcast<'static>>::downcast(
1364                            downcast_origin,
1365                            Provider::Owned(result),
1366                        )
1367                    }))
1368                }
1369
1370                #[inline(always)]
1371                fn hint() -> TypeHint {
1372                    TypeHint::Type(<$fn_repr_ty>::type_meta())
1373                }
1374            }
1375
1376            impl<'a $(, $arg)*, R> Upcast<'a> for $fn_ty<$($arg, )* R>
1377            where
1378                $($arg: Downcast<'static>,)*
1379                R: Upcast<'static>,
1380            {
1381                type Output = Box<$fn_repr_ty>;
1382
1383                #[inline]
1384                fn upcast(_origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
1385                    Ok(Box::new($fn_repr_ty {
1386                        callable: Box::new(
1387                            move |
1388                                origin: Origin,
1389                                #[allow(unused)] arguments: &mut [Arg; $arity],
1390                            | {
1391                                $(
1392                                // Safety: Index is lesser than array length.
1393                                #[allow(non_snake_case)]
1394                                let $arg = unsafe {
1395                                    Arg::take_unchecked(arguments, $index)
1396                                };
1397                                #[allow(non_snake_case)]
1398                                let $arg = <$arg as Downcast<'static>>::downcast(
1399                                    $arg.origin,
1400                                    $arg.into_provider(),
1401                                )?;
1402                                )*
1403
1404                                let result = this($($arg),*)?;
1405
1406                                Cell::give(origin, result)
1407                            },
1408                        ),
1409                    }))
1410                }
1411
1412                #[inline(always)]
1413                fn hint() -> TypeHint {
1414                    TypeHint::Type(<$fn_repr_ty>::type_meta())
1415                }
1416            }
1417
1418            #[export(include)]
1419            impl ScriptConcat for $fn_repr_ty {
1420                type Result = Self;
1421
1422                fn script_concat(origin: Origin, items: &mut [Arg]) -> RuntimeResult<Cell> {
1423                    $crate::runtime::__intrinsics::canonicals::script_concat::<Self>(origin, items)
1424                }
1425            }
1426
1427            #[export(include)]
1428            impl ScriptInvocation for $fn_repr_ty {
1429                fn invoke(origin: Origin, lhs: Arg, arguments: &mut [Arg]) -> RuntimeResult<Cell> {
1430                    let function = lhs.data.take::<Self>(origin)?;
1431
1432                    let arguments_count = arguments.len();
1433
1434                    if arguments_count != $arity {
1435                        return Err(RuntimeError::ArityMismatch {
1436                            invocation_origin: origin,
1437                            function_origin: Origin::default(),
1438                            parameters: $arity,
1439                            arguments: arguments_count,
1440                        });
1441                    }
1442
1443                    let arguments = match arguments.try_into() {
1444                        Ok(array) => array,
1445
1446                        Err(_) => {
1447                            system_panic!("Argument slice to array casting failure.")
1448                        }
1449                    };
1450
1451                    (function.callable)(origin, arguments)
1452                }
1453
1454                fn hint() -> Option<&'static InvocationMeta> {
1455                    static META: Lazy<InvocationMeta> = Lazy::new(|| {
1456                        InvocationMeta {
1457                            origin: Origin::default(),
1458                            name: None,
1459                            doc: Some(concat!($($fn_doc),*)),
1460                            receiver: None,
1461                            inputs: Some(vec![
1462                                $(
1463                                Param {
1464                                    name: {
1465                                        #[allow(unused)]
1466                                        #[allow(non_snake_case)]
1467                                        let $arg = ();
1468                                        None
1469                                    },
1470                                    hint: TypeHint::dynamic(),
1471                                },
1472                                )*
1473                            ]),
1474                            output: TypeHint::dynamic(),
1475                        }
1476                    });
1477
1478                    Some(&META)
1479                }
1480            }
1481        };
1482    }
1483
1484    impl_fn!(
1485        /// A function with 0 arguments.
1486        Fn0;
1487        Fn0Repr[0] as "fn(0)" =>;
1488    );
1489
1490    impl_fn!(
1491        /// A function with 1 argument.
1492        Fn1;
1493        Fn1Repr[1] as "fn(1)" => A: 0;
1494    );
1495
1496    impl_fn!(
1497        /// A function with 2 arguments.
1498        Fn2;
1499        Fn2Repr[2] as "fn(2)" => A: 0, B: 1;
1500    );
1501
1502    impl_fn!(
1503        /// A function with 3 arguments.
1504        Fn3;
1505        Fn3Repr[3] as "fn(3)" => A: 0, B: 1, C: 2;
1506    );
1507
1508    impl_fn!(
1509        /// A function with 4 arguments.
1510        Fn4;
1511        Fn4Repr[4] as "fn(4)" => A: 0, B: 1, C: 2, D: 3;
1512    );
1513
1514    impl_fn!(
1515        /// A function with 5 arguments.
1516        Fn5;
1517        Fn5Repr[5] as "fn(5)" => A: 0, B: 1, C: 2, D: 3, E: 4;
1518    );
1519
1520    impl_fn!(
1521        /// A function with 6 arguments.
1522        Fn6;
1523        Fn6Repr[6] as "fn(6)" => A: 0, B: 1, C: 2, D: 3, E: 4, F: 5;
1524    );
1525
1526    impl_fn!(
1527        /// A function with 7 arguments.
1528        Fn7;
1529        Fn7Repr[7] as "fn(7)" => A: 0, B: 1, C: 2, D: 3, E: 4, F: 5, G: 6;
1530    );
1531}