ad_astra/runtime/
object.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    any::TypeId,
37    cmp::Ordering,
38    fmt::{Debug, Display, Formatter},
39    hash::Hasher,
40    ops::Deref,
41};
42
43use ahash::AHashMap;
44use lady_deirdre::sync::Lazy;
45
46use crate::{
47    report::{debug_unreachable, system_panic},
48    runtime::{
49        ops::OperatorKind,
50        Arg,
51        Cell,
52        ComponentHint,
53        Ident,
54        InvocationMeta,
55        Origin,
56        RuntimeError,
57        RuntimeResult,
58        ScriptType,
59        TypeHint,
60        TypeMeta,
61        __intrinsics::{
62            AddAssignOperator,
63            AddOperator,
64            AndOperator,
65            AssignOperator,
66            BindingOperator,
67            BitAndAssignOperator,
68            BitAndOperator,
69            BitOrAssignOperator,
70            BitOrOperator,
71            BitXorAssignOperator,
72            BitXorOperator,
73            CloneOperator,
74            ComponentDeclaration,
75            ConcatOperator,
76            DebugOperator,
77            DeclarationGroup,
78            DefaultOperator,
79            DisplayOperator,
80            DivAssignOperator,
81            DivOperator,
82            DynHasher,
83            FieldOperator,
84            HashOperator,
85            InvocationOperator,
86            MulAssignOperator,
87            MulOperator,
88            NegOperator,
89            NoneOperator,
90            NotOperator,
91            OperatorDeclaration,
92            OrOperator,
93            OrdOperator,
94            PartialEqOperator,
95            PartialOrdOperator,
96            RemAssignOperator,
97            RemOperator,
98            ShlAssignOperator,
99            ShlOperator,
100            ShrAssignOperator,
101            ShrOperator,
102            SubAssignOperator,
103            SubOperator,
104        },
105    },
106};
107
108/// A wrapper for [Cell] that provides type-specific operations with the Cell
109/// data.
110///
111/// You can construct this object using [Cell::into_object].
112///
113/// To discover which operations are available for this Object, you can explore
114/// its [Prototype] using the [Object::prototype] function.
115pub struct Object {
116    receiver: Cell,
117    ty: &'static TypeMeta,
118    prototype: &'static Prototype,
119}
120
121impl Object {
122    /// Calls an assignment operator (`lhs = rhs`) on this Object as the
123    /// left-hand side (LHS) of the operation.
124    ///
125    /// The `origin` parameter specifies the Rust or Script source code range
126    /// that spans the operator.
127    ///
128    /// The `lhs` parameter specifies the Rust or Script source code range
129    /// that spans the left-hand operand (this Object).
130    ///
131    /// The `rhs` parameter specifies the right-hand side (RHS) of the operation,
132    /// including the source code range and the data of the RHS.
133    ///
134    /// The function returns a [RuntimeError] if the Object's type does not
135    /// support the ["assign" operator](Prototype::implements_assign) or if
136    /// the operator's implementation returns a RuntimeError.
137    #[inline]
138    pub fn assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
139        if let Some(operator) = &self.prototype.assign {
140            return (operator.invoke)(origin, self.arg(lhs), rhs);
141        }
142
143        Err(RuntimeError::UndefinedOperator {
144            access_origin: origin,
145            receiver_origin: Some(self.receiver.origin()),
146            receiver_type: self.ty,
147            operator: OperatorKind::Assign,
148        })
149    }
150
151    /// Returns a Cell that points to a component of the object
152    /// (e.g., an object's method or a predefined field), such as `foo.bar`.
153    ///
154    /// The `origin` parameter specifies the Rust or Script source code range
155    /// that spans the operator.
156    ///
157    /// The `lhs` parameter specifies the Rust or Script source code range
158    /// that spans the left-hand operand (this Object).
159    ///
160    /// The `rhs` parameter specifies the name of the component/field. You
161    /// can obtain the component's identifier using, for example, the
162    /// [FieldSymbol::ident](crate::analysis::symbols::FieldSymbol::ident)
163    /// function.
164    ///
165    /// The function returns a [RuntimeError] if the Object's type does not
166    /// have this [component](Prototype::hint_component) or if the
167    /// component fetching implementation returns a RuntimeError.
168    #[inline(always)]
169    pub fn component(self, origin: Origin, lhs: Origin, rhs: Ident) -> RuntimeResult<Cell> {
170        let key = rhs.as_ref();
171
172        let Some(component) = self.prototype.components.get(key) else {
173            return Err(RuntimeError::UnknownField {
174                access_origin: origin,
175                receiver_origin: self.receiver.origin(),
176                receiver_type: self.ty,
177                field: String::from(key),
178            });
179        };
180
181        (component.constructor)(origin, self.arg(lhs))
182    }
183
184    /// Similar to [Object::component], but if the Object's type does not have a
185    /// component with the specified name, it falls back to [Object::field].
186    #[inline(always)]
187    pub fn component_or_field(
188        self,
189        origin: Origin,
190        lhs: Origin,
191        rhs: Ident,
192    ) -> RuntimeResult<Cell> {
193        let key = rhs.as_ref();
194
195        if let Some(component) = self.prototype.components.get(key) {
196            return (component.constructor)(origin, self.arg(lhs));
197        };
198
199        if let Some(operator) = &self.prototype.field {
200            return (operator.invoke)(origin, self.arg(lhs), rhs);
201        };
202
203        Err(RuntimeError::UnknownField {
204            access_origin: origin,
205            receiver_origin: self.receiver.origin(),
206            receiver_type: self.ty,
207            field: String::from(key),
208        })
209    }
210
211    /// Returns a Cell that points to a field resolved at runtime, such as
212    /// `foo.bar`.
213    ///
214    /// The `origin` parameter specifies the Rust or Script source code range
215    /// that spans the operator.
216    ///
217    /// The `lhs` parameter specifies the Rust or Script source code range
218    /// that spans the left-hand operand (this Object).
219    ///
220    /// The `rhs` parameter specifies the name of the field. You can obtain
221    /// the field's identifier using, for example, the
222    /// [FieldSymbol::ident](crate::analysis::symbols::FieldSymbol::ident)
223    /// function.
224    ///
225    /// The function returns a [RuntimeError] if the Object's type does not
226    /// implement a [runtime field resolver](Prototype::implements_field) or if
227    /// the resolver's implementation returns a RuntimeError.
228    #[inline(always)]
229    pub fn field(self, origin: Origin, lhs: Origin, rhs: Ident) -> RuntimeResult<Cell> {
230        let Some(operator) = &self.prototype.field else {
231            return Err(RuntimeError::UndefinedOperator {
232                access_origin: origin,
233                receiver_origin: Some(self.receiver.origin()),
234                receiver_type: self.ty,
235                operator: OperatorKind::Field,
236            });
237        };
238
239        (operator.invoke)(origin, self.arg(lhs), rhs)
240    }
241
242    /// Calls a Clone operator (`*foo`) on this Object, creating a clone of
243    /// the underlying Cell's data.
244    ///
245    /// The `origin` parameter specifies the Rust or Script source code range
246    /// that spans the operator.
247    ///
248    /// The `rhs` parameter specifies the Rust or Script source code range
249    /// that spans the operand (this Object).
250    ///
251    /// The function returns a [RuntimeError] if the Object's type does not
252    /// support the ["clone" operator](Prototype::implements_clone) or if the
253    /// operator's implementation returns a RuntimeError.
254    #[inline]
255    pub fn clone(self, origin: Origin, rhs: Origin) -> RuntimeResult<Cell> {
256        let Some(operator) = &self.prototype.clone else {
257            return Err(RuntimeError::UndefinedOperator {
258                access_origin: origin,
259                receiver_origin: Some(rhs),
260                receiver_type: self.ty,
261                operator: OperatorKind::Clone,
262            });
263        };
264
265        (operator.invoke)(origin, self.arg(rhs))
266    }
267
268    /// Calls a Debug operator on this Object to format the underlying
269    /// Cell's data for debugging purposes.
270    ///
271    /// The `origin` parameter specifies the Rust or Script source code range
272    /// that spans the operator.
273    ///
274    /// The `lhs` parameter specifies the Rust or Script source code range
275    /// that spans the operand (this Object).
276    ///
277    /// The `formatter` parameter specifies the Rust [Formatter] that will be
278    /// passed to the [Debug::fmt] function.
279    ///
280    /// The function returns a [RuntimeError] if the Object's type does not
281    /// support the ["debug" operator](Prototype::implements_debug) or if the
282    /// operator's implementation returns a RuntimeError.
283    #[inline]
284    pub fn debug(
285        self,
286        origin: Origin,
287        lhs: Origin,
288        formatter: &mut Formatter<'_>,
289    ) -> RuntimeResult<()> {
290        let Some(operator) = &self.prototype.debug else {
291            return Err(RuntimeError::UndefinedOperator {
292                access_origin: origin,
293                receiver_origin: Some(self.receiver.origin()),
294                receiver_type: self.ty,
295                operator: OperatorKind::Debug,
296            });
297        };
298
299        (operator.invoke)(origin, self.arg(lhs), formatter)
300    }
301
302    /// Calls a Display operator on this Object to format the underlying
303    /// Cell's data for display purposes.
304    ///
305    /// The `origin` parameter specifies the Rust or Script source code range
306    /// that spans the operator.
307    ///
308    /// The `lhs` parameter specifies the Rust or Script source code range
309    /// that spans the operand (this Object).
310    ///
311    /// The `formatter` parameter specifies the Rust [Formatter] that will be
312    /// passed to the [Display::fmt] function.
313    ///
314    /// The function returns a [RuntimeError] if the Object's type does not
315    /// support the ["display" operator](Prototype::implements_display) or if
316    /// the operator's implementation returns a RuntimeError.
317    #[inline]
318    pub fn display(
319        self,
320        origin: Origin,
321        lhs: Origin,
322        formatter: &mut Formatter<'_>,
323    ) -> RuntimeResult<()> {
324        let Some(operator) = &self.prototype.display else {
325            return Err(RuntimeError::UndefinedOperator {
326                access_origin: origin,
327                receiver_origin: Some(self.receiver.origin()),
328                receiver_type: self.ty,
329                operator: OperatorKind::Display,
330            });
331        };
332
333        (operator.invoke)(origin, self.arg(lhs), formatter)
334    }
335
336    /// Calls an equality operator (`lhs == rhs`) on this Object as the
337    /// left-hand side (LHS) of the operation.
338    ///
339    /// The `origin` parameter specifies the Rust or Script source code range
340    /// that spans the operator.
341    ///
342    /// The `lhs` parameter specifies the Rust or Script source code range
343    /// that spans the left-hand operand (this Object).
344    ///
345    /// The `rhs` parameter specifies the right-hand side (RHS) of the
346    /// operation, including the source code range and the data of the RHS.
347    ///
348    /// The function returns a [RuntimeError] if the Object's type does not
349    /// support the [equality operator](Prototype::implements_partial_eq) or if
350    /// the operator's implementation returns a RuntimeError.
351    ///
352    /// Note that in the current model of script interpretation, partial
353    /// equality ([PartialEq]) also serves the purpose of full equality ([Eq]).
354    #[inline]
355    pub fn partial_eq(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<bool> {
356        let Some(operator) = &self.prototype.partial_eq else {
357            return Err(RuntimeError::UndefinedOperator {
358                access_origin: origin,
359                receiver_origin: Some(self.receiver.origin()),
360                receiver_type: self.ty,
361                operator: OperatorKind::PartialEq,
362            });
363        };
364
365        (operator.invoke)(origin, self.arg(lhs), rhs)
366    }
367
368    /// Calls a partial ordering operator (`lhs >= rhs`, `lhs < rhs`, etc.) on
369    /// this Object as the left-hand side (LHS) of the operation.
370    ///
371    /// Returns the result of the objects' comparison via [PartialOrd].
372    ///
373    /// The `origin` parameter specifies the Rust or Script source code range
374    /// that spans the operator.
375    ///
376    /// The `lhs` parameter specifies the Rust or Script source code range
377    /// that spans the left-hand operand (this Object).
378    ///
379    /// The `rhs` parameter specifies the right-hand side (RHS) of the operation,
380    /// including the source code range and the data of the RHS.
381    ///
382    /// The function returns a [RuntimeError] if the Object's type does not
383    /// support the
384    /// [partial ordering operator](Prototype::implements_partial_ord) or if the
385    /// operator's implementation returns a RuntimeError.
386    #[inline]
387    pub fn partial_ord(
388        self,
389        origin: Origin,
390        lhs: Origin,
391        rhs: Arg,
392    ) -> RuntimeResult<Option<Ordering>> {
393        let Some(operator) = &self.prototype.partial_ord else {
394            return Err(RuntimeError::UndefinedOperator {
395                access_origin: origin,
396                receiver_origin: Some(self.receiver.origin()),
397                receiver_type: self.ty,
398                operator: OperatorKind::PartialOrd,
399            });
400        };
401
402        (operator.invoke)(origin, self.arg(lhs), rhs)
403    }
404
405    /// Calls a full ordering operator (`lhs >= rhs`, `lhs < rhs`, etc.) on
406    /// this Object as the left-hand side (LHS) of the operation.
407    ///
408    /// Returns the result of the objects' comparison via [Ord].
409    ///
410    /// The `origin` parameter specifies the Rust or Script source code range
411    /// that spans the operator.
412    ///
413    /// The `lhs` parameter specifies the Rust or Script source code range
414    /// that spans the left-hand operand (this Object).
415    ///
416    /// The `rhs` parameter specifies the right-hand side (RHS) of the operation,
417    /// including the source code range and the data of the RHS.
418    ///
419    /// The function returns a [RuntimeError] if the Object's type does not
420    /// support the [full ordering operator](Prototype::implements_ord) or if
421    /// the operator's implementation returns a RuntimeError.
422    #[inline]
423    pub fn ord(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Ordering> {
424        let Some(operator) = &self.prototype.ord else {
425            return Err(RuntimeError::UndefinedOperator {
426                access_origin: origin,
427                receiver_origin: Some(self.receiver.origin()),
428                receiver_type: self.ty,
429                operator: OperatorKind::Ord,
430            });
431        };
432
433        return (operator.invoke)(origin, self.arg(lhs), rhs);
434    }
435
436    /// Similar to [Object::ord], but if the Object's type does not support the
437    /// [full ordering operator](Prototype::implements_ord), it falls back to
438    /// [Object::partial_ord]. If the partial ordering returns None, this
439    /// function returns a [RuntimeError] indicating that the
440    /// ["ord" operator](OperatorKind::Ord) is not supported.
441    #[inline]
442    pub fn ord_fallback(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Ordering> {
443        if let Some(operator) = &self.prototype.ord {
444            return (operator.invoke)(origin, self.arg(lhs), rhs);
445        };
446
447        let receiver_type = self.ty;
448        let receiver_origin = self.receiver.origin();
449
450        if let Some(operator) = &self.prototype.partial_ord {
451            if let Some(ordering) = (operator.invoke)(origin, self.arg(lhs), rhs)? {
452                return Ok(ordering);
453            }
454        };
455
456        Err(RuntimeError::UndefinedOperator {
457            access_origin: origin,
458            receiver_origin: Some(receiver_origin),
459            receiver_type,
460            operator: OperatorKind::Ord,
461        })
462    }
463
464    /// Feeds this Object's content into the specified `hasher`.
465    ///
466    /// The `origin` parameter specifies the Rust or Script source code range
467    /// that spans the hashing operator.
468    ///
469    /// The `lhs` parameter specifies the Rust or Script source code range
470    /// that spans the hashing operand (this Object).
471    ///
472    /// The function returns a [RuntimeError] if the Object's type does not
473    /// support the ["hash" operator](Prototype::implements_hash) or if the
474    /// operator's implementation returns a RuntimeError.
475    #[inline]
476    pub fn hash(self, origin: Origin, lhs: Origin, hasher: &mut impl Hasher) -> RuntimeResult<()> {
477        let Some(operator) = &self.prototype.hash else {
478            return Err(RuntimeError::UndefinedOperator {
479                access_origin: origin,
480                receiver_origin: Some(self.receiver.origin()),
481                receiver_type: self.ty,
482                operator: OperatorKind::Hash,
483            });
484        };
485
486        let mut hasher = DynHasher::new(hasher);
487
488        (operator.invoke)(origin, self.arg(lhs), &mut hasher)
489    }
490
491    /// Calls an invocation operator (`func(arg1, arg2, arg3)`) on this Object
492    /// as the left-hand side (LHS) of the operation.
493    ///
494    /// The `origin` parameter specifies the Rust or Script source code range
495    /// that spans the operator.
496    ///
497    /// The `lhs` parameter specifies the Rust or Script source code range
498    /// that spans the left-hand operand (this Object).
499    ///
500    /// The `rhs` parameter specifies the right-hand side (RHS) of the operation,
501    /// including the source code range and the data of the RHS.
502    ///
503    /// The function returns a [RuntimeError] if the Object's type does not
504    /// support the ["invoke" operator](Prototype::implements_invoke) or if the
505    /// operator's implementation returns a RuntimeError.
506    #[inline]
507    pub fn invoke(self, origin: Origin, lhs: Origin, arguments: &mut [Arg]) -> RuntimeResult<Cell> {
508        let Some(operator) = &self.prototype.invocation else {
509            return Err(RuntimeError::UndefinedOperator {
510                access_origin: origin,
511                receiver_origin: Some(self.receiver.origin()),
512                receiver_type: self.ty,
513                operator: OperatorKind::Invocation,
514            });
515        };
516
517        (operator.invoke)(origin, self.arg(lhs), arguments)
518    }
519
520    /// Sets the invocation context of the object.
521    ///
522    /// The meaning of the binding operator is type-dependent, but usually it
523    /// sets the context in which this object will be [invoked](Self::invoke).
524    ///
525    /// For example, in the `foo.bar()` code, the interpreter would first bind
526    /// "bar" to "foo," assuming "foo" is the
527    /// [receiver-parameter](InvocationMeta::receiver) of the "bar" function.
528    /// Then, the interpreter would call the invocation operator on the bound
529    /// "bar" Object.
530    ///
531    /// The `origin` parameter specifies the Rust or Script source code range
532    /// that spans the operator.
533    ///
534    /// The `lhs` parameter specifies the Rust or Script source code range
535    /// that spans the left-hand operand (this Object).
536    ///
537    /// The `rhs` parameter specifies the binding context
538    /// (the source code range and the data of the context Cell).
539    ///
540    /// The function returns a [RuntimeError] if the Object's type does not
541    /// support the ["binding" operator](Prototype::implements_binding) or if
542    /// the operator's implementation returns a RuntimeError.
543    #[inline]
544    pub fn bind(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
545        let Some(operator) = &self.prototype.binding else {
546            return Err(RuntimeError::UndefinedOperator {
547                access_origin: origin,
548                receiver_origin: Some(self.receiver.origin()),
549                receiver_type: self.ty,
550                operator: OperatorKind::Binding,
551            });
552        };
553
554        (operator.invoke)(origin, self.arg(lhs), rhs)
555    }
556
557    /// Calls an addition operator (`lhs + rhs`) on this Object as the
558    /// left-hand side (LHS) of the operation.
559    ///
560    /// The `origin` parameter specifies the Rust or Script source code range
561    /// that spans the operator.
562    ///
563    /// The `lhs` parameter specifies the Rust or Script source code range
564    /// that spans the left-hand operand (this Object).
565    ///
566    /// The `rhs` parameter specifies the right-hand side (RHS) of the
567    /// operation, including the source code range and the data of the RHS.
568    ///
569    /// The function returns a [RuntimeError] if the Object's type does not
570    /// support the ["add" operator](Prototype::implements_add) or if the
571    /// operator's implementation returns a RuntimeError.
572    #[inline]
573    pub fn add(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
574        let Some(operator) = &self.prototype.add else {
575            return Err(RuntimeError::UndefinedOperator {
576                access_origin: origin,
577                receiver_origin: Some(self.receiver.origin()),
578                receiver_type: self.ty,
579                operator: OperatorKind::Add,
580            });
581        };
582
583        (operator.invoke)(origin, self.arg(lhs), rhs)
584    }
585
586    /// Calls an addition-assignment operator (`lhs += rhs`) on this Object as
587    /// the left-hand side (LHS) of the operation.
588    ///
589    /// The `origin` parameter specifies the Rust or Script source code range
590    /// that spans the operator.
591    ///
592    /// The `lhs` parameter specifies the Rust or Script source code range
593    /// that spans the left-hand operand (this Object).
594    ///
595    /// The `rhs` parameter specifies the right-hand side (RHS) of the
596    /// operation, including the source code range and the data of the RHS.
597    ///
598    /// The function returns a [RuntimeError] if the Object's type does not
599    /// support the ["add-assign" operator](Prototype::implements_add_assign) or
600    /// if the operator's implementation returns a RuntimeError.
601    #[inline]
602    pub fn add_assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
603        let Some(operator) = &self.prototype.add_assign else {
604            return Err(RuntimeError::UndefinedOperator {
605                access_origin: origin,
606                receiver_origin: Some(self.receiver.origin()),
607                receiver_type: self.ty,
608                operator: OperatorKind::AddAssign,
609            });
610        };
611
612        (operator.invoke)(origin, self.arg(lhs), rhs)
613    }
614
615    /// Similar to [Object::add_assign], but if the Object's type does not
616    /// support the ["add-assign" operator](Prototype::implements_add_assign),
617    /// it falls back to [Object::add], and then to [Object::assign].
618    ///
619    /// If the fallback operators are also not supported, this function returns
620    /// a [RuntimeError] indicating that the
621    /// ["add-assign" operator](OperatorKind::AddAssign) is not supported.
622    #[inline]
623    pub fn add_assign_fallback(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
624        if let Some(operator) = &self.prototype.add_assign {
625            return (operator.invoke)(origin, self.arg(lhs), rhs);
626        };
627
628        if let (Some(assign_op), Some(fb_op)) = (&self.prototype.assign, &self.prototype.add) {
629            let lhs = self.arg(lhs);
630
631            let rhs_origin = rhs.origin;
632            let rhs_cell = (fb_op.invoke)(origin, lhs.clone(), rhs)?;
633
634            let rhs = Arg {
635                origin: rhs_origin,
636                data: rhs_cell,
637            };
638
639            return (assign_op.invoke)(origin, lhs, rhs);
640        }
641
642        Err(RuntimeError::UndefinedOperator {
643            access_origin: origin,
644            receiver_origin: Some(self.receiver.origin()),
645            receiver_type: self.ty,
646            operator: OperatorKind::AddAssign,
647        })
648    }
649
650    /// Calls a subtraction operator (`lhs - rhs`) on this Object as the
651    /// left-hand side (LHS) of the operation.
652    ///
653    /// The `origin` parameter specifies the Rust or Script source code range
654    /// that spans the operator.
655    ///
656    /// The `lhs` parameter specifies the Rust or Script source code range
657    /// that spans the left-hand operand (this Object).
658    ///
659    /// The `rhs` parameter specifies the right-hand side (RHS) of the operation,
660    /// including the source code range and the data of the RHS.
661    ///
662    /// The function returns a [RuntimeError] if the Object's type does not
663    /// support the ["sub" operator](Prototype::implements_sub) or if the
664    /// operator's implementation returns a RuntimeError.
665    #[inline]
666    pub fn sub(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
667        let Some(operator) = &self.prototype.sub else {
668            return Err(RuntimeError::UndefinedOperator {
669                access_origin: origin,
670                receiver_origin: Some(self.receiver.origin()),
671                receiver_type: self.ty,
672                operator: OperatorKind::Sub,
673            });
674        };
675
676        (operator.invoke)(origin, self.arg(lhs), rhs)
677    }
678
679    /// Calls a subtraction-assignment operator (`lhs -= rhs`) on this Object
680    /// as the left-hand side (LHS) of the operation.
681    ///
682    /// The `origin` parameter specifies the Rust or Script source code range
683    /// that spans the operator.
684    ///
685    /// The `lhs` parameter specifies the Rust or Script source code range
686    /// that spans the left-hand operand (this Object).
687    ///
688    /// The `rhs` parameter specifies the right-hand side (RHS) of the operation,
689    /// including the source code range and the data of the RHS.
690    ///
691    /// The function returns a [RuntimeError] if the Object's type does not
692    /// support the ["sub-assign" operator](Prototype::implements_sub_assign) or
693    /// if the operator's implementation returns a RuntimeError.
694    #[inline]
695    pub fn sub_assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
696        let Some(operator) = &self.prototype.sub_assign else {
697            return Err(RuntimeError::UndefinedOperator {
698                access_origin: origin,
699                receiver_origin: Some(self.receiver.origin()),
700                receiver_type: self.ty,
701                operator: OperatorKind::SubAssign,
702            });
703        };
704
705        (operator.invoke)(origin, self.arg(lhs), rhs)
706    }
707
708    /// Similar to [Object::sub_assign], but if the Object's type does not
709    /// support the ["sub-assign" operator](Prototype::implements_sub_assign),
710    /// it falls back to [Object::sub], and then to [Object::assign].
711    ///
712    /// If the fallback operators are also not supported, this function returns
713    /// a [RuntimeError] indicating that the
714    /// ["sub-assign" operator](OperatorKind::SubAssign) is not supported.
715    #[inline]
716    pub fn sub_assign_fallback(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
717        if let Some(operator) = &self.prototype.sub_assign {
718            return (operator.invoke)(origin, self.arg(lhs), rhs);
719        };
720
721        if let (Some(assign_op), Some(fb_op)) = (&self.prototype.assign, &self.prototype.sub) {
722            let lhs = self.arg(lhs);
723
724            let rhs_origin = rhs.origin;
725            let rhs_cell = (fb_op.invoke)(origin, lhs.clone(), rhs)?;
726
727            let rhs = Arg {
728                origin: rhs_origin,
729                data: rhs_cell,
730            };
731
732            return (assign_op.invoke)(origin, lhs, rhs);
733        }
734
735        Err(RuntimeError::UndefinedOperator {
736            access_origin: origin,
737            receiver_origin: Some(self.receiver.origin()),
738            receiver_type: self.ty,
739            operator: OperatorKind::SubAssign,
740        })
741    }
742
743    /// Calls a multiplication operator (`lhs * rhs`) on this Object as the
744    /// left-hand side (LHS) of the operation.
745    ///
746    /// The `origin` parameter specifies the Rust or Script source code range
747    /// that spans the operator.
748    ///
749    /// The `lhs` parameter specifies the Rust or Script source code range
750    /// that spans the left-hand operand (this Object).
751    ///
752    /// The `rhs` parameter specifies the right-hand side (RHS) of the
753    /// operation, including the source code range and the data of the RHS.
754    ///
755    /// The function returns a [RuntimeError] if the Object's type does not
756    /// support the ["mul" operator](Prototype::implements_mul) or if the
757    /// operator's implementation returns a RuntimeError.
758    #[inline]
759    pub fn mul(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
760        let Some(operator) = &self.prototype.mul else {
761            return Err(RuntimeError::UndefinedOperator {
762                access_origin: origin,
763                receiver_origin: Some(self.receiver.origin()),
764                receiver_type: self.ty,
765                operator: OperatorKind::Mul,
766            });
767        };
768
769        (operator.invoke)(origin, self.arg(lhs), rhs)
770    }
771
772    /// Calls a multiplication-assignment operator (`lhs *= rhs`) on this
773    /// Object as the left-hand side (LHS) of the operation.
774    ///
775    /// The `origin` parameter specifies the Rust or Script source code range
776    /// that spans the operator.
777    ///
778    /// The `lhs` parameter specifies the Rust or Script source code range
779    /// that spans the left-hand operand (this Object).
780    ///
781    /// The `rhs` parameter specifies the right-hand side (RHS) of the operation,
782    /// including the source code range and the data of the RHS.
783    ///
784    /// The function returns a [RuntimeError] if the Object's type does not
785    /// support the ["mul-assign" operator](Prototype::implements_mul_assign) or
786    /// if the operator's implementation returns a RuntimeError.
787    #[inline]
788    pub fn mul_assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
789        let Some(operator) = &self.prototype.mul_assign else {
790            return Err(RuntimeError::UndefinedOperator {
791                access_origin: origin,
792                receiver_origin: Some(self.receiver.origin()),
793                receiver_type: self.ty,
794                operator: OperatorKind::MulAssign,
795            });
796        };
797
798        (operator.invoke)(origin, self.arg(lhs), rhs)
799    }
800
801    /// Similar to [Object::mul_assign], but if the Object's type does not
802    /// support the ["mul-assign" operator](Prototype::implements_mul_assign),
803    /// it falls back to [Object::mul], and then to [Object::assign].
804    ///
805    /// If the fallback operators are also not supported, this function returns
806    /// a [RuntimeError] indicating that the
807    /// ["mul-assign" operator](OperatorKind::MulAssign) is not supported.
808    #[inline]
809    pub fn mul_assign_fallback(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
810        if let Some(operator) = &self.prototype.mul_assign {
811            return (operator.invoke)(origin, self.arg(lhs), rhs);
812        };
813
814        if let (Some(assign_op), Some(fb_op)) = (&self.prototype.assign, &self.prototype.mul) {
815            let lhs = self.arg(lhs);
816
817            let rhs_origin = rhs.origin;
818            let rhs_cell = (fb_op.invoke)(origin, lhs.clone(), rhs)?;
819
820            let rhs = Arg {
821                origin: rhs_origin,
822                data: rhs_cell,
823            };
824
825            return (assign_op.invoke)(origin, lhs, rhs);
826        }
827
828        Err(RuntimeError::UndefinedOperator {
829            access_origin: origin,
830            receiver_origin: Some(self.receiver.origin()),
831            receiver_type: self.ty,
832            operator: OperatorKind::MulAssign,
833        })
834    }
835
836    /// Calls a division operator (`lhs / rhs`) on this Object as the
837    /// left-hand side (LHS) of the operation.
838    ///
839    /// The `origin` parameter specifies the Rust or Script source code range
840    /// that spans the operator.
841    ///
842    /// The `lhs` parameter specifies the Rust or Script source code range
843    /// that spans the left-hand operand (this Object).
844    ///
845    /// The `rhs` parameter specifies the right-hand side (RHS) of the
846    /// operation, including the source code range and the data of the RHS.
847    ///
848    /// The function returns a [RuntimeError] if the Object's type does not
849    /// support the ["div" operator](Prototype::implements_div) or if the
850    /// operator's implementation returns a RuntimeError.
851    #[inline]
852    pub fn div(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
853        let Some(operator) = &self.prototype.div else {
854            return Err(RuntimeError::UndefinedOperator {
855                access_origin: origin,
856                receiver_origin: Some(self.receiver.origin()),
857                receiver_type: self.ty,
858                operator: OperatorKind::Div,
859            });
860        };
861
862        (operator.invoke)(origin, self.arg(lhs), rhs)
863    }
864
865    /// Calls a division-assignment operator (`lhs /= rhs`) on this
866    /// Object as the left-hand side (LHS) of the operation.
867    ///
868    /// The `origin` parameter specifies the Rust or Script source code range
869    /// that spans the operator.
870    ///
871    /// The `lhs` parameter specifies the Rust or Script source code range
872    /// that spans the left-hand operand (this Object).
873    ///
874    /// The `rhs` parameter specifies the right-hand side (RHS) of the
875    /// operation, including the source code range and the data of the RHS.
876    ///
877    /// The function returns a [RuntimeError] if the Object's type does not
878    /// support the ["div-assign" operator](Prototype::implements_div_assign) or
879    /// if the operator's implementation returns a RuntimeError.
880    #[inline]
881    pub fn div_assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
882        let Some(operator) = &self.prototype.div_assign else {
883            return Err(RuntimeError::UndefinedOperator {
884                access_origin: origin,
885                receiver_origin: Some(self.receiver.origin()),
886                receiver_type: self.ty,
887                operator: OperatorKind::DivAssign,
888            });
889        };
890
891        (operator.invoke)(origin, self.arg(lhs), rhs)
892    }
893
894    /// Similar to [Object::div_assign], but if the Object's type does not
895    /// support the ["div-assign" operator](Prototype::implements_div_assign),
896    /// it falls back to [Object::div], and then to [Object::assign].
897    ///
898    /// If the fallback operators are also not supported, this function returns
899    /// a [RuntimeError] indicating that the
900    /// ["div-assign" operator](OperatorKind::DivAssign) is not supported.
901    #[inline]
902    pub fn div_assign_fallback(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
903        if let Some(operator) = &self.prototype.div_assign {
904            return (operator.invoke)(origin, self.arg(lhs), rhs);
905        };
906
907        if let (Some(assign_op), Some(fb_op)) = (&self.prototype.assign, &self.prototype.div) {
908            let lhs = self.arg(lhs);
909
910            let rhs_origin = rhs.origin;
911            let rhs_cell = (fb_op.invoke)(origin, lhs.clone(), rhs)?;
912
913            let rhs = Arg {
914                origin: rhs_origin,
915                data: rhs_cell,
916            };
917
918            return (assign_op.invoke)(origin, lhs, rhs);
919        }
920
921        Err(RuntimeError::UndefinedOperator {
922            access_origin: origin,
923            receiver_origin: Some(self.receiver.origin()),
924            receiver_type: self.ty,
925            operator: OperatorKind::DivAssign,
926        })
927    }
928
929    /// Calls a logical conjunction operator (`lhs && rhs`) on this Object as
930    /// the left-hand side (LHS) of the operation.
931    ///
932    /// The `origin` parameter specifies the Rust or Script source code range
933    /// that spans the operator.
934    ///
935    /// The `lhs` parameter specifies the Rust or Script source code range
936    /// that spans the left-hand operand (this Object).
937    ///
938    /// The `rhs` parameter specifies the right-hand side (RHS) of the
939    /// operation, including the source code range and the data of the RHS.
940    ///
941    /// The function returns a [RuntimeError] if the Object's type does not
942    /// support the ["and" operator](Prototype::implements_and) or if the
943    /// operator's implementation returns a RuntimeError.
944    #[inline]
945    pub fn and(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
946        let Some(operator) = &self.prototype.and else {
947            return Err(RuntimeError::UndefinedOperator {
948                access_origin: origin,
949                receiver_origin: Some(self.receiver.origin()),
950                receiver_type: self.ty,
951                operator: OperatorKind::And,
952            });
953        };
954
955        (operator.invoke)(origin, self.arg(lhs), rhs)
956    }
957
958    /// Calls a logical disjunction operator (`lhs || rhs`) on this Object as
959    /// the left-hand side (LHS) of the operation.
960    ///
961    /// The `origin` parameter specifies the Rust or Script source code range
962    /// that spans the operator.
963    ///
964    /// The `lhs` parameter specifies the Rust or Script source code range
965    /// that spans the left-hand operand (this Object).
966    ///
967    /// The `rhs` parameter specifies the right-hand side (RHS) of the
968    /// operation, including the source code range and the data of the RHS.
969    ///
970    /// The function returns a [RuntimeError] if the Object's type does not
971    /// support the ["or" operator](Prototype::implements_or) or if the
972    /// operator's implementation returns a RuntimeError.
973    #[inline]
974    pub fn or(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
975        let Some(operator) = &self.prototype.or else {
976            return Err(RuntimeError::UndefinedOperator {
977                access_origin: origin,
978                receiver_origin: Some(self.receiver.origin()),
979                receiver_type: self.ty,
980                operator: OperatorKind::Or,
981            });
982        };
983
984        (operator.invoke)(origin, self.arg(lhs), rhs)
985    }
986
987    /// Calls a logical negation operator (`!rhs`) on this Object.
988    ///
989    /// The `origin` parameter specifies the Rust or Script source code range
990    /// that spans the operator.
991    ///
992    /// The `rhs` parameter specifies the Rust or Script source code range
993    /// that spans the operand (this Object).
994    ///
995    /// The function returns a [RuntimeError] if the Object's type does not
996    /// support the ["not" operator](Prototype::implements_not) or if the
997    /// operator's implementation returns a RuntimeError.
998    #[inline]
999    pub fn not(self, origin: Origin, rhs: Origin) -> RuntimeResult<Cell> {
1000        let Some(operator) = &self.prototype.not else {
1001            return Err(RuntimeError::UndefinedOperator {
1002                access_origin: origin,
1003                receiver_origin: Some(self.receiver.origin()),
1004                receiver_type: self.ty,
1005                operator: OperatorKind::Not,
1006            });
1007        };
1008
1009        (operator.invoke)(origin, self.arg(rhs))
1010    }
1011
1012    /// Calls a numeric negation operator (`-rhs`) on this Object.
1013    ///
1014    /// The `origin` parameter specifies the Rust or Script source code range
1015    /// that spans the operator.
1016    ///
1017    /// The `rhs` parameter specifies the Rust or Script source code range
1018    /// that spans the operand (this Object).
1019    ///
1020    /// The function returns a [RuntimeError] if the Object's type does not
1021    /// support the ["neg" operator](Prototype::implements_neg) or if the
1022    /// operator's implementation returns a RuntimeError.
1023    #[inline]
1024    pub fn neg(self, origin: Origin, rhs: Origin) -> RuntimeResult<Cell> {
1025        let Some(operator) = &self.prototype.neg else {
1026            return Err(RuntimeError::UndefinedOperator {
1027                access_origin: origin,
1028                receiver_origin: Some(self.receiver.origin()),
1029                receiver_type: self.ty,
1030                operator: OperatorKind::Neg,
1031            });
1032        };
1033
1034        (operator.invoke)(origin, self.arg(rhs))
1035    }
1036
1037    /// Calls a bitwise conjunction operator (`lhs & rhs`) on this Object as the
1038    /// left-hand side (LHS) of the operation.
1039    ///
1040    /// The `origin` parameter specifies the Rust or Script source code range
1041    /// that spans the operator.
1042    ///
1043    /// The `lhs` parameter specifies the Rust or Script source code range
1044    /// that spans the left-hand operand (this Object).
1045    ///
1046    /// The `rhs` parameter specifies the right-hand side (RHS) of the
1047    /// operation, including the source code range and the data of the RHS.
1048    ///
1049    /// The function returns a [RuntimeError] if the Object's type does not
1050    /// support the ["bit-and" operator](Prototype::implements_bit_and) or if
1051    /// the operator's implementation returns a RuntimeError.
1052    #[inline]
1053    pub fn bit_and(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
1054        let Some(operator) = &self.prototype.bit_and else {
1055            return Err(RuntimeError::UndefinedOperator {
1056                access_origin: origin,
1057                receiver_origin: Some(self.receiver.origin()),
1058                receiver_type: self.ty,
1059                operator: OperatorKind::BitAnd,
1060            });
1061        };
1062
1063        (operator.invoke)(origin, self.arg(lhs), rhs)
1064    }
1065
1066    /// Calls a bitwise conjunction and assignment operator (`lhs &= rhs`) on
1067    /// this Object as the left-hand side (LHS) of the operation.
1068    ///
1069    /// The `origin` parameter specifies the Rust or Script source code range
1070    /// that spans the operator.
1071    ///
1072    /// The `lhs` parameter specifies the Rust or Script source code range
1073    /// that spans the left-hand operand (this Object).
1074    ///
1075    /// The `rhs` parameter specifies the right-hand side (RHS) of the
1076    /// operation, including the source code range and the data of the RHS.
1077    ///
1078    /// The function returns a [RuntimeError] if the Object's type does not
1079    /// support the
1080    /// ["bit-and-assign" operator](Prototype::implements_bit_and_assign) or if
1081    /// the operator's implementation returns a RuntimeError.
1082    #[inline]
1083    pub fn bit_and_assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
1084        let Some(operator) = &self.prototype.bit_and_assign else {
1085            return Err(RuntimeError::UndefinedOperator {
1086                access_origin: origin,
1087                receiver_origin: Some(self.receiver.origin()),
1088                receiver_type: self.ty,
1089                operator: OperatorKind::BitAndAssign,
1090            });
1091        };
1092
1093        (operator.invoke)(origin, self.arg(lhs), rhs)
1094    }
1095
1096    /// Similar to [Object::bit_and_assign], but if the Object's type does not
1097    /// support the
1098    /// ["bit-and-assign" operator](Prototype::implements_bit_and_assign), it
1099    /// falls back to [Object::bit_and], and then to [Object::assign].
1100    ///
1101    /// If the fallback operators are also not supported, this function returns
1102    /// a [RuntimeError] indicating that the
1103    /// ["bit-and-assign" operator](OperatorKind::BitAndAssign) is not
1104    /// supported.
1105    #[inline]
1106    pub fn bit_and_assign_fallback(
1107        self,
1108        origin: Origin,
1109        lhs: Origin,
1110        rhs: Arg,
1111    ) -> RuntimeResult<()> {
1112        if let Some(operator) = &self.prototype.bit_and_assign {
1113            return (operator.invoke)(origin, self.arg(lhs), rhs);
1114        };
1115
1116        if let (Some(assign_op), Some(fb_op)) = (&self.prototype.assign, &self.prototype.bit_and) {
1117            let lhs = self.arg(lhs);
1118
1119            let rhs_origin = rhs.origin;
1120            let rhs_cell = (fb_op.invoke)(origin, lhs.clone(), rhs)?;
1121
1122            let rhs = Arg {
1123                origin: rhs_origin,
1124                data: rhs_cell,
1125            };
1126
1127            return (assign_op.invoke)(origin, lhs, rhs);
1128        }
1129
1130        Err(RuntimeError::UndefinedOperator {
1131            access_origin: origin,
1132            receiver_origin: Some(self.receiver.origin()),
1133            receiver_type: self.ty,
1134            operator: OperatorKind::BitAndAssign,
1135        })
1136    }
1137
1138    /// Calls a bitwise disjunction operator (`lhs | rhs`) on this Object as the
1139    /// left-hand side (LHS) of the operation.
1140    ///
1141    /// The `origin` parameter specifies the Rust or Script source code range
1142    /// that spans the operator.
1143    ///
1144    /// The `lhs` parameter specifies the Rust or Script source code range
1145    /// that spans the left-hand operand (this Object).
1146    ///
1147    /// The `rhs` parameter specifies the right-hand side (RHS) of the
1148    /// operation, including the source code range and the data of the RHS.
1149    ///
1150    /// The function returns a [RuntimeError] if the Object's type does not
1151    /// support the ["bit-or" operator](Prototype::implements_bit_or) or if the
1152    /// operator's implementation returns a RuntimeError.
1153    #[inline]
1154    pub fn bit_or(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
1155        let Some(operator) = &self.prototype.bit_or else {
1156            return Err(RuntimeError::UndefinedOperator {
1157                access_origin: origin,
1158                receiver_origin: Some(self.receiver.origin()),
1159                receiver_type: self.ty,
1160                operator: OperatorKind::BitOr,
1161            });
1162        };
1163
1164        (operator.invoke)(origin, self.arg(lhs), rhs)
1165    }
1166
1167    /// Calls a bitwise disjunction and assignment operator (`lhs |= rhs`) on
1168    /// this Object as the left-hand side (LHS) of the operation.
1169    ///
1170    /// The `origin` parameter specifies the Rust or Script source code range
1171    /// that spans the operator.
1172    ///
1173    /// The `lhs` parameter specifies the Rust or Script source code range
1174    /// that spans the left-hand operand (this Object).
1175    ///
1176    /// The `rhs` parameter specifies the right-hand side (RHS) of the
1177    /// operation, including the source code range and the data of the RHS.
1178    ///
1179    /// The function returns a [RuntimeError] if the Object's type does not
1180    /// support the
1181    /// ["bit-or-assign" operator](Prototype::implements_bit_or_assign) or if
1182    /// the operator's implementation returns a RuntimeError.
1183    #[inline]
1184    pub fn bit_or_assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
1185        let Some(operator) = &self.prototype.bit_or_assign else {
1186            return Err(RuntimeError::UndefinedOperator {
1187                access_origin: origin,
1188                receiver_origin: Some(self.receiver.origin()),
1189                receiver_type: self.ty,
1190                operator: OperatorKind::BitOrAssign,
1191            });
1192        };
1193
1194        (operator.invoke)(origin, self.arg(lhs), rhs)
1195    }
1196
1197    /// Similar to [Object::bit_or_assign], but if the Object's type does not
1198    /// support the
1199    /// ["bit-or-assign" operator](Prototype::implements_bit_or_assign), it
1200    /// falls back to [Object::bit_or], and then to [Object::assign].
1201    ///
1202    /// If the fallback operators are also not supported, this function returns
1203    /// a [RuntimeError] indicating that the
1204    /// ["bit-or-assign" operator](OperatorKind::BitOrAssign) is not supported.
1205    #[inline]
1206    pub fn bit_or_assign_fallback(
1207        self,
1208        origin: Origin,
1209        lhs: Origin,
1210        rhs: Arg,
1211    ) -> RuntimeResult<()> {
1212        if let Some(operator) = &self.prototype.bit_or_assign {
1213            return (operator.invoke)(origin, self.arg(lhs), rhs);
1214        };
1215
1216        if let (Some(assign_op), Some(fb_op)) = (&self.prototype.assign, &self.prototype.bit_or) {
1217            let lhs = self.arg(lhs);
1218
1219            let rhs_origin = rhs.origin;
1220            let rhs_cell = (fb_op.invoke)(origin, lhs.clone(), rhs)?;
1221
1222            let rhs = Arg {
1223                origin: rhs_origin,
1224                data: rhs_cell,
1225            };
1226
1227            return (assign_op.invoke)(origin, lhs, rhs);
1228        }
1229
1230        Err(RuntimeError::UndefinedOperator {
1231            access_origin: origin,
1232            receiver_origin: Some(self.receiver.origin()),
1233            receiver_type: self.ty,
1234            operator: OperatorKind::BitOrAssign,
1235        })
1236    }
1237
1238    /// Calls a bitwise exclusive disjunction operator (`lhs ^ rhs`) on this
1239    /// Object as the left-hand side (LHS) of the operation.
1240    ///
1241    /// The `origin` parameter specifies the Rust or Script source code range
1242    /// that spans the operator.
1243    ///
1244    /// The `lhs` parameter specifies the Rust or Script source code range
1245    /// that spans the left-hand operand (this Object).
1246    ///
1247    /// The `rhs` parameter specifies the right-hand side (RHS) of the
1248    /// operation, including the source code range and the data of the RHS.
1249    ///
1250    /// The function returns a [RuntimeError] if the Object's type does not
1251    /// support the ["bit-xor" operator](Prototype::implements_bit_xor) or if
1252    /// the operator's implementation returns a RuntimeError.
1253    #[inline]
1254    pub fn bit_xor(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
1255        let Some(operator) = &self.prototype.bit_xor else {
1256            return Err(RuntimeError::UndefinedOperator {
1257                access_origin: origin,
1258                receiver_origin: Some(self.receiver.origin()),
1259                receiver_type: self.ty,
1260                operator: OperatorKind::BitXor,
1261            });
1262        };
1263
1264        (operator.invoke)(origin, self.arg(lhs), rhs)
1265    }
1266
1267    /// Calls a bitwise exclusive disjunction and assignment operator
1268    /// (`lhs ^= rhs`) on this Object as the left-hand side (LHS) of the
1269    /// operation.
1270    ///
1271    /// The `origin` parameter specifies the Rust or Script source code range
1272    /// that spans the operator.
1273    ///
1274    /// The `lhs` parameter specifies the Rust or Script source code range
1275    /// that spans the left-hand operand (this Object).
1276    ///
1277    /// The `rhs` parameter specifies the right-hand side (RHS) of the operation,
1278    /// including the source code range and the data of the RHS.
1279    ///
1280    /// The function returns a [RuntimeError] if the Object's type does not
1281    /// support the
1282    /// ["bit-xor-assign" operator](Prototype::implements_bit_xor_assign) or if
1283    /// the operator's implementation returns a RuntimeError.
1284    #[inline]
1285    pub fn bit_xor_assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
1286        let Some(operator) = &self.prototype.bit_xor_assign else {
1287            return Err(RuntimeError::UndefinedOperator {
1288                access_origin: origin,
1289                receiver_origin: Some(self.receiver.origin()),
1290                receiver_type: self.ty,
1291                operator: OperatorKind::BitXorAssign,
1292            });
1293        };
1294
1295        (operator.invoke)(origin, self.arg(lhs), rhs)
1296    }
1297
1298    /// Similar to [Object::bit_xor_assign], but if the Object's type does not
1299    /// support the
1300    /// ["bit-xor-assign" operator](Prototype::implements_bit_xor_assign), it
1301    /// falls back to [Object::bit_xor], and then to [Object::assign].
1302    ///
1303    /// If the fallback operators are also not supported, this function returns
1304    /// a [RuntimeError] indicating that the
1305    /// ["bit-xor-assign" operator](OperatorKind::BitXorAssign) is not
1306    /// supported.
1307    #[inline]
1308    pub fn bit_xor_assign_fallback(
1309        self,
1310        origin: Origin,
1311        lhs: Origin,
1312        rhs: Arg,
1313    ) -> RuntimeResult<()> {
1314        if let Some(operator) = &self.prototype.bit_xor_assign {
1315            return (operator.invoke)(origin, self.arg(lhs), rhs);
1316        };
1317
1318        if let (Some(assign_op), Some(fb_op)) = (&self.prototype.assign, &self.prototype.bit_xor) {
1319            let lhs = self.arg(lhs);
1320
1321            let rhs_origin = rhs.origin;
1322            let rhs_cell = (fb_op.invoke)(origin, lhs.clone(), rhs)?;
1323
1324            let rhs = Arg {
1325                origin: rhs_origin,
1326                data: rhs_cell,
1327            };
1328
1329            return (assign_op.invoke)(origin, lhs, rhs);
1330        }
1331
1332        Err(RuntimeError::UndefinedOperator {
1333            access_origin: origin,
1334            receiver_origin: Some(self.receiver.origin()),
1335            receiver_type: self.ty,
1336            operator: OperatorKind::BitXorAssign,
1337        })
1338    }
1339
1340    /// Calls a bitwise left shift operator (`lhs << rhs`) on this
1341    /// Object as the left-hand side (LHS) of the operation.
1342    ///
1343    /// The `origin` parameter specifies the Rust or Script source code range
1344    /// that spans the operator.
1345    ///
1346    /// The `lhs` parameter specifies the Rust or Script source code range
1347    /// that spans the left-hand operand (this Object).
1348    ///
1349    /// The `rhs` parameter specifies the right-hand side (RHS) of the
1350    /// operation, including the source code range and the data of the RHS.
1351    ///
1352    /// The function returns a [RuntimeError] if the Object's type does not
1353    /// support the ["shl" operator](Prototype::implements_shl) or if the
1354    /// operator's implementation returns a RuntimeError.
1355    #[inline]
1356    pub fn shl(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
1357        let Some(operator) = &self.prototype.shl else {
1358            return Err(RuntimeError::UndefinedOperator {
1359                access_origin: origin,
1360                receiver_origin: Some(self.receiver.origin()),
1361                receiver_type: self.ty,
1362                operator: OperatorKind::Shl,
1363            });
1364        };
1365
1366        (operator.invoke)(origin, self.arg(lhs), rhs)
1367    }
1368
1369    /// Calls a bitwise left shift and assignment operator (`lhs <<= rhs`) on
1370    /// this Object as the left-hand side (LHS) of the operation.
1371    ///
1372    /// The `origin` parameter specifies the Rust or Script source code range
1373    /// that spans the operator.
1374    ///
1375    /// The `lhs` parameter specifies the Rust or Script source code range
1376    /// that spans the left-hand operand (this Object).
1377    ///
1378    /// The `rhs` parameter specifies the right-hand side (RHS) of the
1379    /// operation, including the source code range and the data of the RHS.
1380    ///
1381    /// The function returns a [RuntimeError] if the Object's type does not
1382    /// support the ["shl-assign" operator](Prototype::implements_shl_assign) or
1383    /// if the operator's implementation returns a RuntimeError.
1384    #[inline]
1385    pub fn shl_assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
1386        let Some(operator) = &self.prototype.shl_assign else {
1387            return Err(RuntimeError::UndefinedOperator {
1388                access_origin: origin,
1389                receiver_origin: Some(self.receiver.origin()),
1390                receiver_type: self.ty,
1391                operator: OperatorKind::ShlAssign,
1392            });
1393        };
1394
1395        (operator.invoke)(origin, self.arg(lhs), rhs)
1396    }
1397
1398    /// Similar to [Object::shl_assign], but if the Object's type does not
1399    /// support the ["shl-assign" operator](Prototype::implements_shl_assign),
1400    /// it falls back to [Object::shl], and then to [Object::assign].
1401    ///
1402    /// If the fallback operators are also not supported, this function returns
1403    /// a [RuntimeError] indicating that the
1404    /// ["shl-assign" operator](OperatorKind::ShlAssign) is not supported.
1405    #[inline]
1406    pub fn shl_assign_fallback(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
1407        if let Some(operator) = &self.prototype.shl_assign {
1408            return (operator.invoke)(origin, self.arg(lhs), rhs);
1409        };
1410
1411        if let (Some(assign_op), Some(fb_op)) = (&self.prototype.assign, &self.prototype.shl) {
1412            let lhs = self.arg(lhs);
1413
1414            let rhs_origin = rhs.origin;
1415            let rhs_cell = (fb_op.invoke)(origin, lhs.clone(), rhs)?;
1416
1417            let rhs = Arg {
1418                origin: rhs_origin,
1419                data: rhs_cell,
1420            };
1421
1422            return (assign_op.invoke)(origin, lhs, rhs);
1423        }
1424
1425        Err(RuntimeError::UndefinedOperator {
1426            access_origin: origin,
1427            receiver_origin: Some(self.receiver.origin()),
1428            receiver_type: self.ty,
1429            operator: OperatorKind::ShlAssign,
1430        })
1431    }
1432
1433    /// Calls a bitwise right shift operator (`lhs >> rhs`) on this
1434    /// Object as the left-hand side (LHS) of the operation.
1435    ///
1436    /// The `origin` parameter specifies the Rust or Script source code range
1437    /// that spans the operator.
1438    ///
1439    /// The `lhs` parameter specifies the Rust or Script source code range
1440    /// that spans the left-hand operand (this Object).
1441    ///
1442    /// The `rhs` parameter specifies the right-hand side (RHS) of the
1443    /// operation, including the source code range and the data of the RHS.
1444    ///
1445    /// The function returns a [RuntimeError] if the Object's type does not
1446    /// support the ["shr" operator](Prototype::implements_shr) or if the
1447    /// operator's implementation returns a RuntimeError.
1448    #[inline]
1449    pub fn shr(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
1450        let Some(operator) = &self.prototype.shr else {
1451            return Err(RuntimeError::UndefinedOperator {
1452                access_origin: origin,
1453                receiver_origin: Some(self.receiver.origin()),
1454                receiver_type: self.ty,
1455                operator: OperatorKind::Shr,
1456            });
1457        };
1458
1459        (operator.invoke)(origin, self.arg(lhs), rhs)
1460    }
1461
1462    /// Calls a bitwise right shift and assignment operator (`lhs >>= rhs`) on
1463    /// this Object as the left-hand side (LHS) of the operation.
1464    ///
1465    /// The `origin` parameter specifies the Rust or Script source code range
1466    /// that spans the operator.
1467    ///
1468    /// The `lhs` parameter specifies the Rust or Script source code range
1469    /// that spans the left-hand operand (this Object).
1470    ///
1471    /// The `rhs` parameter specifies the right-hand side (RHS) of the
1472    /// operation, including the source code range and the data of the RHS.
1473    ///
1474    /// The function returns a [RuntimeError] if the Object's type does not
1475    /// support the ["shr-assign" operator](Prototype::implements_shr_assign) or
1476    /// if the operator's implementation returns a RuntimeError.
1477    #[inline]
1478    pub fn shr_assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
1479        let Some(operator) = &self.prototype.shr_assign else {
1480            return Err(RuntimeError::UndefinedOperator {
1481                access_origin: origin,
1482                receiver_origin: Some(self.receiver.origin()),
1483                receiver_type: self.ty,
1484                operator: OperatorKind::ShrAssign,
1485            });
1486        };
1487
1488        (operator.invoke)(origin, self.arg(lhs), rhs)
1489    }
1490
1491    /// Same as [Object::shr_assign], but if the Object's type does not
1492    /// support an ["shr-assign" operator](Prototype::implements_shr_assign),
1493    /// falls back to the [Object::shr], and then to the [Object::assign].
1494    ///
1495    /// If the falling-back operators are not supported as well, this
1496    /// function returns [RuntimeError] indicating that the
1497    /// ["shr-assign" operator](OperatorKind::ShrAssign) is not supported.
1498    #[inline]
1499    pub fn shr_assign_fallback(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
1500        if let Some(operator) = &self.prototype.shr_assign {
1501            return (operator.invoke)(origin, self.arg(lhs), rhs);
1502        };
1503
1504        if let (Some(assign_op), Some(fb_op)) = (&self.prototype.assign, &self.prototype.shr) {
1505            let lhs = self.arg(lhs);
1506
1507            let rhs_origin = rhs.origin;
1508            let rhs_cell = (fb_op.invoke)(origin, lhs.clone(), rhs)?;
1509
1510            let rhs = Arg {
1511                origin: rhs_origin,
1512                data: rhs_cell,
1513            };
1514
1515            return (assign_op.invoke)(origin, lhs, rhs);
1516        }
1517
1518        Err(RuntimeError::UndefinedOperator {
1519            access_origin: origin,
1520            receiver_origin: Some(self.receiver.origin()),
1521            receiver_type: self.ty,
1522            operator: OperatorKind::ShrAssign,
1523        })
1524    }
1525
1526    /// Calls a remainder of division operator (`lhs % rhs`) on this Object as
1527    /// the left-hand side (LHS) of the operation.
1528    ///
1529    /// The `origin` parameter specifies the Rust or Script source code range
1530    /// that spans the operator.
1531    ///
1532    /// The `lhs` parameter specifies the Rust or Script source code range
1533    /// that spans the left-hand operand (this Object).
1534    ///
1535    /// The `rhs` parameter specifies the right-hand side (RHS) of the operation,
1536    /// including the source code range and the data of the RHS.
1537    ///
1538    /// The function returns a [RuntimeError] if the Object's type does not
1539    /// support the ["rem" operator](Prototype::implements_rem) or if the
1540    /// operator's implementation returns a RuntimeError.
1541    #[inline]
1542    pub fn rem(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<Cell> {
1543        let Some(operator) = &self.prototype.rem else {
1544            return Err(RuntimeError::UndefinedOperator {
1545                access_origin: origin,
1546                receiver_origin: Some(self.receiver.origin()),
1547                receiver_type: self.ty,
1548                operator: OperatorKind::Rem,
1549            });
1550        };
1551
1552        (operator.invoke)(origin, self.arg(lhs), rhs)
1553    }
1554
1555    /// Calls a remainder of division and assignment operator (`lhs %= rhs`) on
1556    /// this Object as the left-hand side (LHS) of the operation.
1557    ///
1558    /// The `origin` parameter specifies the Rust or Script source code range
1559    /// that spans the operator.
1560    ///
1561    /// The `lhs` parameter specifies the Rust or Script source code range
1562    /// that spans the left-hand operand (this Object).
1563    ///
1564    /// The `rhs` parameter specifies the right-hand side (RHS) of the operation,
1565    /// including the source code range and the data of the RHS.
1566    ///
1567    /// The function returns a [RuntimeError] if the Object's type does not
1568    /// support the ["rem-assign" operator](Prototype::implements_rem_assign) or
1569    /// if the operator's implementation returns a RuntimeError.
1570    #[inline]
1571    pub fn rem_assign(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
1572        let Some(operator) = &self.prototype.rem_assign else {
1573            return Err(RuntimeError::UndefinedOperator {
1574                access_origin: origin,
1575                receiver_origin: Some(self.receiver.origin()),
1576                receiver_type: self.ty,
1577                operator: OperatorKind::RemAssign,
1578            });
1579        };
1580
1581        (operator.invoke)(origin, self.arg(lhs), rhs)
1582    }
1583
1584    /// Similar to [Object::rem_assign], but if the Object's type does not
1585    /// support the ["rem-assign" operator](Prototype::implements_rem_assign),
1586    /// it falls back to [Object::rem], and then to [Object::assign].
1587    ///
1588    /// If the fallback operators are also not supported, this
1589    /// function returns a [RuntimeError] indicating that the
1590    /// ["rem-assign" operator](OperatorKind::RemAssign) is not supported.
1591    #[inline]
1592    pub fn rem_assign_fallback(self, origin: Origin, lhs: Origin, rhs: Arg) -> RuntimeResult<()> {
1593        if let Some(operator) = &self.prototype.rem_assign {
1594            return (operator.invoke)(origin, self.arg(lhs), rhs);
1595        };
1596
1597        if let (Some(assign_op), Some(fb_op)) = (&self.prototype.assign, &self.prototype.rem) {
1598            let lhs = self.arg(lhs);
1599
1600            let rhs_origin = rhs.origin;
1601            let rhs_cell = (fb_op.invoke)(origin, lhs.clone(), rhs)?;
1602
1603            let rhs = Arg {
1604                origin: rhs_origin,
1605                data: rhs_cell,
1606            };
1607
1608            return (assign_op.invoke)(origin, lhs, rhs);
1609        }
1610
1611        Err(RuntimeError::UndefinedOperator {
1612            access_origin: origin,
1613            receiver_origin: Some(self.receiver.origin()),
1614            receiver_type: self.ty,
1615            operator: OperatorKind::RemAssign,
1616        })
1617    }
1618
1619    /// Returns a reference to the underlying [Cell] of this Object.
1620    #[inline(always)]
1621    pub fn cell(&self) -> &Cell {
1622        &self.receiver
1623    }
1624
1625    /// Returns the metadata of the Object's type (similar to [Cell::ty]).
1626    #[inline(always)]
1627    pub fn ty(&self) -> &'static TypeMeta {
1628        self.ty
1629    }
1630
1631    /// Returns a [Prototype] of the Object's type, which describes the
1632    /// operations available for this type.
1633    #[inline(always)]
1634    pub fn prototype(&self) -> &'static Prototype {
1635        self.prototype
1636    }
1637
1638    /// Converts this object back into the underlying Cell.
1639    ///
1640    /// This operation is the reverse of [Cell::into_object].
1641    #[inline(always)]
1642    pub fn into_cell(self) -> Cell {
1643        self.receiver
1644    }
1645
1646    #[inline(always)]
1647    fn arg(self, origin: Origin) -> Arg {
1648        Arg {
1649            origin,
1650            data: self.receiver,
1651        }
1652    }
1653}
1654
1655impl Cell {
1656    /// Converts a low-level Cell API into an Object, a higher-level Cell
1657    /// wrapper. This allows you to work with the Cell data as if it were an
1658    /// object of the [ScriptType].
1659    #[inline(always)]
1660    pub fn into_object(self) -> Object {
1661        let ty = self.ty();
1662        let prototype = ty.prototype();
1663
1664        Object {
1665            receiver: self,
1666            ty,
1667            prototype,
1668        }
1669    }
1670}
1671
1672/// A metadata about the available operations on the [type](TypeMeta).
1673///
1674/// The type's operations are exposed using the [export](crate::export) macro.
1675///
1676/// You can obtain this object from various API functions, including the
1677/// [TypeMeta::prototype] function.
1678///
1679/// The [Display] implementation for this object returns a map of all available
1680/// components (i.e., methods and fields) of the type.
1681#[derive(Default)]
1682pub struct Prototype {
1683    components: AHashMap<&'static str, ComponentDeclaration>,
1684    assign: Option<AssignOperator>,
1685    concat: Option<ConcatOperator>,
1686    field: Option<FieldOperator>,
1687    clone: Option<CloneOperator>,
1688    debug: Option<DebugOperator>,
1689    display: Option<DisplayOperator>,
1690    partial_eq: Option<PartialEqOperator>,
1691    default: Option<DefaultOperator>,
1692    partial_ord: Option<PartialOrdOperator>,
1693    ord: Option<OrdOperator>,
1694    hash: Option<HashOperator>,
1695    invocation: Option<InvocationOperator>,
1696    binding: Option<BindingOperator>,
1697    add: Option<AddOperator>,
1698    add_assign: Option<AddAssignOperator>,
1699    sub: Option<SubOperator>,
1700    sub_assign: Option<SubAssignOperator>,
1701    mul: Option<MulOperator>,
1702    mul_assign: Option<MulAssignOperator>,
1703    div: Option<DivOperator>,
1704    div_assign: Option<DivAssignOperator>,
1705    and: Option<AndOperator>,
1706    or: Option<OrOperator>,
1707    not: Option<NotOperator>,
1708    neg: Option<NegOperator>,
1709    bit_and: Option<BitAndOperator>,
1710    bit_and_assign: Option<BitAndAssignOperator>,
1711    bit_or: Option<BitOrOperator>,
1712    bit_or_assign: Option<BitOrAssignOperator>,
1713    bit_xor: Option<BitXorOperator>,
1714    bit_xor_assign: Option<BitXorAssignOperator>,
1715    shl: Option<ShlOperator>,
1716    shl_assign: Option<ShlAssignOperator>,
1717    shr: Option<ShrOperator>,
1718    shr_assign: Option<ShrAssignOperator>,
1719    rem: Option<RemOperator>,
1720    rem_assign: Option<RemAssignOperator>,
1721    none: Option<NoneOperator>,
1722}
1723
1724impl Debug for Prototype {
1725    #[inline(always)]
1726    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
1727        Display::fmt(self, formatter)
1728    }
1729}
1730
1731impl Display for Prototype {
1732    #[inline]
1733    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
1734        let mut debug_map = formatter.debug_map();
1735
1736        for component in self.components.values() {
1737            debug_map.entry(&component.name.string, &format_args!("{}", component.hint));
1738        }
1739
1740        debug_map.finish()
1741    }
1742}
1743
1744impl Prototype {
1745    /// Returns true if the underlying type has a component (a method or a
1746    /// field) with the specified `name`.
1747    ///
1748    /// If this function returns true, the [Object::component] supports
1749    /// this component `name`.
1750    ///
1751    /// The components are exposed using the `#[export(component)]` macro
1752    /// attribute.
1753    #[inline(always)]
1754    pub fn implements_component(&self, name: &str) -> bool {
1755        self.components.contains_key(name)
1756    }
1757
1758    /// Returns true if the underlying type has a dynamic field resolver.
1759    ///
1760    /// If this function returns true, the [Object::field] operator is
1761    /// generally supported.
1762    ///
1763    /// Dynamic field resolvers are exposed using the
1764    /// [ScriptField](crate::runtime::ops::ScriptField) trait.
1765    #[inline(always)]
1766    pub fn implements_field(&self) -> bool {
1767        self.field.is_some()
1768    }
1769
1770    /// Returns true if the underlying type supports the assignment operator:
1771    /// `lhs = rhs`.
1772    ///
1773    /// If this function returns true, the [Object::assign] operator is
1774    /// generally supported.
1775    ///
1776    /// Assignment operators are exposed using the
1777    /// [ScriptAssign](crate::runtime::ops::ScriptAssign) trait.
1778    #[inline(always)]
1779    pub fn implements_assign(&self) -> bool {
1780        self.assign.is_some()
1781    }
1782
1783    /// Returns true if the underlying type supports array constructors:
1784    /// `[x, y, z]`.
1785    ///
1786    /// If this function returns true, the [TypeMeta::concat] constructor is
1787    /// generally supported.
1788    ///
1789    /// Concatenation operators are exposed using the
1790    /// [ScriptConcat](crate::runtime::ops::ScriptConcat) trait.
1791    #[inline(always)]
1792    pub fn implements_concat(&self) -> bool {
1793        self.concat.is_some()
1794    }
1795
1796    /// Returns true if the underlying type supports cloning: `*rhs`.
1797    ///
1798    /// If this function returns true, the [Object::clone] operator is
1799    /// generally supported.
1800    ///
1801    /// Cloning operators are exposed using the
1802    /// [ScriptClone](crate::runtime::ops::ScriptClone) trait.
1803    #[inline(always)]
1804    pub fn implements_clone(&self) -> bool {
1805        self.clone.is_some()
1806    }
1807
1808    /// Returns true if the underlying type supports debug formatting.
1809    ///
1810    /// If this function returns true, the [Object::debug] operator is
1811    /// generally supported.
1812    ///
1813    /// Debug formatting operators are exposed using the
1814    /// [ScriptDebug](crate::runtime::ops::ScriptDebug) trait.
1815    #[inline(always)]
1816    pub fn implements_debug(&self) -> bool {
1817        self.debug.is_some()
1818    }
1819
1820    /// Returns true if the underlying type supports display formatting.
1821    ///
1822    /// If this function returns true, the [Object::display] operator is
1823    /// generally supported.
1824    ///
1825    /// Display formatting operators are exposed using the
1826    /// [ScriptDisplay](crate::runtime::ops::ScriptDisplay) trait.
1827    #[inline(always)]
1828    pub fn implements_display(&self) -> bool {
1829        self.display.is_some()
1830    }
1831
1832    /// Returns true if the underlying type supports an equality operator:
1833    /// `lhs == rhs`.
1834    ///
1835    /// If this function returns true, the [Object::partial_eq] operator is
1836    /// generally supported.
1837    ///
1838    /// The assignment operators are exposed using the
1839    /// [ScriptPartialEq](crate::runtime::ops::ScriptPartialEq) trait.
1840    #[inline(always)]
1841    pub fn implements_partial_eq(&self) -> bool {
1842        self.partial_eq.is_some()
1843    }
1844
1845    /// Returns true if the underlying type supports default constructor.
1846    ///
1847    /// If this function returns true, the [TypeMeta::instantiate] constructor
1848    /// is generally supported.
1849    ///
1850    /// The default operators are exposed using the
1851    /// [ScriptDefault](crate::runtime::ops::ScriptDefault) trait.
1852    #[inline(always)]
1853    pub fn implements_default(&self) -> bool {
1854        self.default.is_some()
1855    }
1856
1857    /// Returns true if the underlying type supports a partial ordering
1858    /// operator: `lhs >= rhs`, `lhs < rhs`, etc.
1859    ///
1860    /// If this function returns true, the [Object::partial_ord] operator is
1861    /// generally supported.
1862    ///
1863    /// The partial ordering operators are exposed using the
1864    /// [ScriptPartialOrd](crate::runtime::ops::ScriptPartialOrd) trait.
1865    #[inline(always)]
1866    pub fn implements_partial_ord(&self) -> bool {
1867        self.partial_ord.is_some()
1868    }
1869
1870    /// Returns true if the underlying type supports a full ordering operator:
1871    /// `lhs >= rhs`, `lhs < rhs`, etc.
1872    ///
1873    /// If this function returns true, the [Object::ord] operator is
1874    /// generally supported.
1875    ///
1876    /// The full ordering operators are exposed using the
1877    /// [ScriptOrd](crate::runtime::ops::ScriptOrd) trait.
1878    #[inline(always)]
1879    pub fn implements_ord(&self) -> bool {
1880        self.ord.is_some()
1881    }
1882
1883    /// Returns true if the underlying type supports data hashing.
1884    ///
1885    /// If this function returns true, the [Object::hash] operator is
1886    /// generally supported.
1887    ///
1888    /// The hashing operators are exposed using the
1889    /// [ScriptHash](crate::runtime::ops::ScriptHash) trait.
1890    #[inline(always)]
1891    pub fn implements_hash(&self) -> bool {
1892        self.hash.is_some()
1893    }
1894
1895    /// Returns true if the underlying type supports an invocation operator:
1896    /// `foo(a, b, c)`.
1897    ///
1898    /// If this function returns true, the [Object::invoke] operator is
1899    /// generally supported.
1900    ///
1901    /// The invocation operators are exposed using the
1902    /// [ScriptInvocation](crate::runtime::ops::ScriptInvocation) trait.
1903    #[inline(always)]
1904    pub fn implements_invocation(&self) -> bool {
1905        self.invocation.is_some()
1906    }
1907
1908    /// Returns true if the underlying type supports context binding.
1909    ///
1910    /// If this function returns true, the [Object::bind] operator is
1911    /// generally supported.
1912    ///
1913    /// The binging operators are exposed using the
1914    /// [ScriptBinding](crate::runtime::ops::ScriptBinding) trait.
1915    #[inline(always)]
1916    pub fn implements_binding(&self) -> bool {
1917        self.binding.is_some()
1918    }
1919
1920    /// Returns true if the underlying type supports an addition operator:
1921    /// `lhs + rhs`.
1922    ///
1923    /// If this function returns true, the [Object::add] operator is
1924    /// generally supported.
1925    ///
1926    /// The addition operators are exposed using the
1927    /// [ScriptAdd](crate::runtime::ops::ScriptAdd) trait.
1928    #[inline(always)]
1929    pub fn implements_add(&self) -> bool {
1930        self.add.is_some()
1931    }
1932
1933    /// Returns true if the underlying type supports an addition and assignment
1934    /// operator: `lhs += rhs`.
1935    ///
1936    /// If this function returns true, the [Object::add_assign] operator is
1937    /// generally supported.
1938    ///
1939    /// The addition and assignment operators are exposed using the
1940    /// [ScriptAddAssign](crate::runtime::ops::ScriptAddAssign) trait.
1941    #[inline(always)]
1942    pub fn implements_add_assign(&self) -> bool {
1943        self.add_assign.is_some()
1944    }
1945
1946    /// Returns true if the underlying type supports a subtraction operator:
1947    /// `lhs - rhs`.
1948    ///
1949    /// If this function returns true, the [Object::sub] operator is
1950    /// generally supported.
1951    ///
1952    /// The subtraction operators are exposed using the
1953    /// [ScriptSub](crate::runtime::ops::ScriptSub) trait.
1954    #[inline(always)]
1955    pub fn implements_sub(&self) -> bool {
1956        self.sub.is_some()
1957    }
1958
1959    /// Returns true if the underlying type supports a subtraction and
1960    /// assignment operator: `lhs -= rhs`.
1961    ///
1962    /// If this function returns true, the [Object::sub_assign] operator is
1963    /// generally supported.
1964    ///
1965    /// The subtraction and assignment operators are exposed using the
1966    /// [ScriptSubAssign](crate::runtime::ops::ScriptSubAssign) trait.
1967    #[inline(always)]
1968    pub fn implements_sub_assign(&self) -> bool {
1969        self.sub_assign.is_some()
1970    }
1971
1972    /// Returns true if the underlying type supports a multiplication operator:
1973    /// `lhs * rhs`.
1974    ///
1975    /// If this function returns true, the [Object::mul] operator is
1976    /// generally supported.
1977    ///
1978    /// The multiplication operators are exposed using the
1979    /// [ScriptMul](crate::runtime::ops::ScriptMul) trait.
1980    #[inline(always)]
1981    pub fn implements_mul(&self) -> bool {
1982        self.mul.is_some()
1983    }
1984
1985    /// Returns true if the underlying type supports a multiplication and
1986    /// assignment operator: `lhs *= rhs`.
1987    ///
1988    /// If this function returns true, the [Object::sub_assign] operator is
1989    /// generally supported.
1990    ///
1991    /// The multiplication and assignment operators are exposed using the
1992    /// [ScriptMulAssign](crate::runtime::ops::ScriptMulAssign) trait.
1993    #[inline(always)]
1994    pub fn implements_mul_assign(&self) -> bool {
1995        self.mul_assign.is_some()
1996    }
1997
1998    /// Returns true if the underlying type supports a division operator:
1999    /// `lhs / rhs`.
2000    ///
2001    /// If this function returns true, the [Object::div] operator is
2002    /// generally supported.
2003    ///
2004    /// The division operators are exposed using the
2005    /// [ScriptDiv](crate::runtime::ops::ScriptDiv) trait.
2006    #[inline(always)]
2007    pub fn implements_div(&self) -> bool {
2008        self.div.is_some()
2009    }
2010
2011    /// Returns true if the underlying type supports a division and
2012    /// assignment operator: `lhs /= rhs`.
2013    ///
2014    /// If this function returns true, the [Object::div_assign] operator is
2015    /// generally supported.
2016    ///
2017    /// The division and assignment operators are exposed using the
2018    /// [ScriptDivAssign](crate::runtime::ops::ScriptDivAssign) trait.
2019    #[inline(always)]
2020    pub fn implements_div_assign(&self) -> bool {
2021        self.div_assign.is_some()
2022    }
2023
2024    /// Returns true if the underlying type supports a logical conjunction
2025    /// operator: `lhs && rhs`.
2026    ///
2027    /// If this function returns true, the [Object::and] operator is
2028    /// generally supported.
2029    ///
2030    /// The logical conjunction operators are exposed using the
2031    /// [ScriptAnd](crate::runtime::ops::ScriptAnd) trait.
2032    #[inline(always)]
2033    pub fn implements_and(&self) -> bool {
2034        self.and.is_some()
2035    }
2036
2037    /// Returns true if the underlying type supports a logical disjunction
2038    /// operator: `lhs || rhs`.
2039    ///
2040    /// If this function returns true, the [Object::or] operator is
2041    /// generally supported.
2042    ///
2043    /// The logical disjunction operators are exposed using the
2044    /// [ScriptOr](crate::runtime::ops::ScriptOr) trait.
2045    #[inline(always)]
2046    pub fn implements_or(&self) -> bool {
2047        self.or.is_some()
2048    }
2049
2050    /// Returns true if the underlying type supports a logical negation
2051    /// operator: `!foo`.
2052    ///
2053    /// If this function returns true, the [Object::not] operator is
2054    /// generally supported.
2055    ///
2056    /// The logical negation operators are exposed using the
2057    /// [ScriptNot](crate::runtime::ops::ScriptNot) trait.
2058    #[inline(always)]
2059    pub fn implements_not(&self) -> bool {
2060        self.not.is_some()
2061    }
2062
2063    /// Returns true if the underlying type supports a numeric negation
2064    /// operator: `-foo`.
2065    ///
2066    /// If this function returns true, the [Object::neg] operator is
2067    /// generally supported.
2068    ///
2069    /// The numeric negation operators are exposed using the
2070    /// [ScriptNeg](crate::runtime::ops::ScriptNeg) trait.
2071    #[inline(always)]
2072    pub fn implements_neg(&self) -> bool {
2073        self.neg.is_some()
2074    }
2075
2076    /// Returns true if the underlying type supports a bitwise conjunction
2077    /// operator: `lhs & rhs`.
2078    ///
2079    /// If this function returns true, the [Object::bit_and] operator is
2080    /// generally supported.
2081    ///
2082    /// The bitwise conjunction operators are exposed using the
2083    /// [ScriptBitAnd](crate::runtime::ops::ScriptBitAnd) trait.
2084    #[inline(always)]
2085    pub fn implements_bit_and(&self) -> bool {
2086        self.bit_and.is_some()
2087    }
2088
2089    /// Returns true if the underlying type supports a bitwise conjunction and
2090    /// assignment operator: `lhs &= rhs`.
2091    ///
2092    /// If this function returns true, the [Object::bit_and_assign] operator is
2093    /// generally supported.
2094    ///
2095    /// The bitwise conjunction and assignment operators are exposed using the
2096    /// [ScriptBitAndAssign](crate::runtime::ops::ScriptBitAndAssign) trait.
2097    #[inline(always)]
2098    pub fn implements_bit_and_assign(&self) -> bool {
2099        self.bit_and_assign.is_some()
2100    }
2101
2102    /// Returns true if the underlying type supports a bitwise disjunction
2103    /// operator: `lhs | rhs`.
2104    ///
2105    /// If this function returns true, the [Object::bit_or] operator is
2106    /// generally supported.
2107    ///
2108    /// The bitwise disjunction operators are exposed using the
2109    /// [ScriptBitOr](crate::runtime::ops::ScriptBitOr) trait.
2110    #[inline(always)]
2111    pub fn implements_bit_or(&self) -> bool {
2112        self.bit_or.is_some()
2113    }
2114
2115    /// Returns true if the underlying type supports a bitwise disjunction and
2116    /// assignment operator: `lhs |= rhs`.
2117    ///
2118    /// If this function returns true, the [Object::bit_or_assign] operator is
2119    /// generally supported.
2120    ///
2121    /// The bitwise disjunction and assignment operators are exposed using the
2122    /// [ScriptBitOrAssign](crate::runtime::ops::ScriptBitOrAssign) trait.
2123    #[inline(always)]
2124    pub fn implements_bit_or_assign(&self) -> bool {
2125        self.bit_or_assign.is_some()
2126    }
2127
2128    /// Returns true if the underlying type supports a bitwise exclusive
2129    /// disjunction operator: `lhs ^ rhs`.
2130    ///
2131    /// If this function returns true, the [Object::bit_xor] operator is
2132    /// generally supported.
2133    ///
2134    /// The bitwise exclusive disjunction operators are exposed using the
2135    /// [ScriptBitXor](crate::runtime::ops::ScriptBitXor) trait.
2136    #[inline(always)]
2137    pub fn implements_bit_xor(&self) -> bool {
2138        self.bit_xor.is_some()
2139    }
2140
2141    /// Returns true if the underlying type supports a bitwise exclusive
2142    /// disjunction and assignment operator: `lhs ^= rhs`.
2143    ///
2144    /// If this function returns true, the [Object::bit_xor_assign] operator is
2145    /// generally supported.
2146    ///
2147    /// The bitwise exclusive disjunction and assignment operators are exposed
2148    /// using the [ScriptBitXorAssign](crate::runtime::ops::ScriptBitXorAssign)
2149    /// trait.
2150    #[inline(always)]
2151    pub fn implements_bit_xor_assign(&self) -> bool {
2152        self.bit_xor_assign.is_some()
2153    }
2154
2155    /// Returns true if the underlying type supports a bitwise left shift
2156    /// operator: `lhs << rhs`.
2157    ///
2158    /// If this function returns true, the [Object::shl] operator is
2159    /// generally supported.
2160    ///
2161    /// The bitwise left shift operators are exposed using the
2162    /// [ScriptShl](crate::runtime::ops::ScriptShl) trait.
2163    #[inline(always)]
2164    pub fn implements_shl(&self) -> bool {
2165        self.shl.is_some()
2166    }
2167
2168    /// Returns true if the underlying type supports a bitwise left shift
2169    /// and assignment operator: `lhs <<= rhs`.
2170    ///
2171    /// If this function returns true, the [Object::shl_assign] operator is
2172    /// generally supported.
2173    ///
2174    /// The bitwise left shift and assignment operators are exposed
2175    /// using the [ScriptShlAssign](crate::runtime::ops::ScriptShlAssign)
2176    /// trait.
2177    #[inline(always)]
2178    pub fn implements_shl_assign(&self) -> bool {
2179        self.shl_assign.is_some()
2180    }
2181
2182    /// Returns true if the underlying type supports a bitwise right shift
2183    /// operator: `lhs >> rhs`.
2184    ///
2185    /// If this function returns true, the [Object::shr] operator is
2186    /// generally supported.
2187    ///
2188    /// The bitwise right shift operators are exposed using the
2189    /// [ScriptShr](crate::runtime::ops::ScriptShr) trait.
2190    #[inline(always)]
2191    pub fn implements_shr(&self) -> bool {
2192        self.shr.is_some()
2193    }
2194
2195    /// Returns true if the underlying type supports a bitwise right shift
2196    /// and assignment operator: `lhs >>= rhs`.
2197    ///
2198    /// If this function returns true, the [Object::shr_assign] operator is
2199    /// generally supported.
2200    ///
2201    /// The bitwise right shift and assignment operators are exposed
2202    /// using the [ScriptShrAssign](crate::runtime::ops::ScriptShrAssign)
2203    /// trait.
2204    #[inline(always)]
2205    pub fn implements_shr_assign(&self) -> bool {
2206        self.shr_assign.is_some()
2207    }
2208
2209    /// Returns true if the underlying type supports a reminder of division
2210    /// operator: `lhs % rhs`.
2211    ///
2212    /// If this function returns true, the [Object::rem] operator is
2213    /// generally supported.
2214    ///
2215    /// The reminder of division operators are exposed using the
2216    /// [ScriptRem](crate::runtime::ops::ScriptRem) trait.
2217    #[inline(always)]
2218    pub fn implements_rem(&self) -> bool {
2219        self.rem.is_some()
2220    }
2221
2222    /// Returns true if the underlying type supports a reminder of division
2223    /// and assignment operator: `lhs %= rhs`.
2224    ///
2225    /// If this function returns true, the [Object::rem_assign] operator is
2226    /// generally supported.
2227    ///
2228    /// The reminder of division and assignment operators are exposed
2229    /// using the [ScriptRemAssign](crate::runtime::ops::ScriptRemAssign)
2230    /// trait.
2231    #[inline(always)]
2232    pub fn implements_rem_assign(&self) -> bool {
2233        self.rem_assign.is_some()
2234    }
2235
2236    /// Returns true if this type represents void data. The query script
2237    /// operator `foo?` tests if the underlying object has "none"-type.
2238    ///
2239    /// In particular the [Nil](TypeMeta::nil) is a "none"-type.
2240    ///
2241    /// The none markers are exposed using the
2242    /// [ScriptNone](crate::runtime::ops::ScriptNone) trait.
2243    #[inline(always)]
2244    pub fn implements_none(&self) -> bool {
2245        self.none.is_some()
2246    }
2247
2248    /// Returns the right-hand side type of the assignment operator:
2249    /// `lhs = rhs`.
2250    ///
2251    /// The returned type metadata corresponds to the
2252    /// [ScriptAssign::RHS](crate::runtime::ops::ScriptAssign::RHS) associated
2253    /// type.
2254    ///
2255    /// If the assignment operator is not [supported](Self::implements_assign),
2256    /// the function returns None.
2257    #[inline(always)]
2258    pub fn hint_assign_rhs(&self) -> Option<&'static TypeMeta> {
2259        if let Some(operator) = &self.assign {
2260            return Some(operator.hint_rhs);
2261        }
2262
2263        None
2264    }
2265
2266    /// Returns the type of the result of objects concatenations:
2267    /// `[a, b, c]`.
2268    ///
2269    /// The returned type metadata corresponds to the
2270    /// [ScriptConcat::Result](crate::runtime::ops::ScriptConcat::Result)
2271    /// associated type.
2272    ///
2273    /// If the concatenation operator is not
2274    /// [supported](Self::implements_concat), the function returns None.
2275    #[inline(always)]
2276    pub fn hint_concat_result(&self) -> Option<&'static TypeMeta> {
2277        if let Some(operator) = &self.concat {
2278            return Some(operator.hint_result);
2279        }
2280
2281        None
2282    }
2283
2284    /// Returns the description of the type's component (e.g., a Rust struct
2285    /// method or field).
2286    ///
2287    /// The `name` parameter specifies the component's name (e.g., `foo.<name>`).
2288    ///
2289    /// If this type [does not have](Self::implements_component) the specified
2290    /// component, the function returns None.
2291    #[inline(always)]
2292    pub fn hint_component(&self, name: impl AsRef<str>) -> Option<ComponentHint> {
2293        if let Some(component) = self.components.get(name.as_ref()) {
2294            return Some(ComponentHint {
2295                name: component.name,
2296                ty: TypeHint::Type(component.hint),
2297                doc: component.doc,
2298            });
2299        }
2300
2301        None
2302    }
2303
2304    /// Enumerates all exported components of this type (e.g., all Rust struct
2305    /// methods and fields). The iterator yields descriptions for each
2306    /// component.
2307    #[inline(always)]
2308    pub fn hint_all_components(&self) -> impl Iterator<Item = ComponentHint> + '_ {
2309        self.components.values().map(|component| ComponentHint {
2310            name: component.name,
2311            ty: TypeHint::Type(component.hint),
2312            doc: component.doc,
2313        })
2314    }
2315
2316    /// Returns the number of all known exported components of this type (e.g.,
2317    /// the number of all Rust struct methods and fields).
2318    #[inline(always)]
2319    pub fn components_len(&self) -> usize {
2320        self.components.len()
2321    }
2322
2323    /// Returns the type of the result of objects concatenations:
2324    /// `[a, b, c]`.
2325    ///
2326    /// The returned type metadata corresponds to the
2327    /// [ScriptConcat::Result](crate::runtime::ops::ScriptConcat::Result)
2328    /// associated type.
2329    ///
2330    /// If the concatenation operator is not
2331    /// [supported](Self::implements_concat), the function returns None.
2332    #[inline(always)]
2333    pub fn hint_field(&self) -> Option<&'static TypeMeta> {
2334        if let Some(operator) = &self.field {
2335            return Some(operator.hint_result);
2336        }
2337
2338        None
2339    }
2340
2341    /// Returns the right-hand side type of the quality operator:
2342    /// `lhs == rhs`.
2343    ///
2344    /// The returned type metadata corresponds to the
2345    /// [ScriptPartialEq::RHS](crate::runtime::ops::ScriptPartialEq::RHS)
2346    /// associated type.
2347    ///
2348    /// If the equality operator is not [supported](Self::implements_partial_eq),
2349    /// the function returns None.
2350    #[inline(always)]
2351    pub fn hint_partial_eq_rhs(&self) -> Option<&'static TypeMeta> {
2352        if let Some(operator) = &self.partial_eq {
2353            return Some(operator.hint_rhs);
2354        }
2355
2356        None
2357    }
2358
2359    /// Returns the right-hand side type of the partial ordering operator:
2360    /// `lhs >= rhs`, `lhs < rhs`, etc.
2361    ///
2362    /// The returned type metadata corresponds to the
2363    /// [ScriptPartialOrd::RHS](crate::runtime::ops::ScriptPartialOrd::RHS)
2364    /// associated type.
2365    ///
2366    /// If the partial ordering operator is not
2367    /// [supported](Self::implements_partial_ord), the function returns None.
2368    #[inline(always)]
2369    pub fn hint_partial_ord_rhs(&self) -> Option<&'static TypeMeta> {
2370        if let Some(operator) = &self.partial_ord {
2371            return Some(operator.hint_rhs);
2372        }
2373
2374        None
2375    }
2376
2377    /// Returns the invocation operator description for the type:
2378    /// `foo(a, b, c)`.
2379    ///
2380    /// If the invocation operator is not
2381    /// [supported](Self::implements_invocation), the function returns None.
2382    #[inline(always)]
2383    pub fn hint_invocation(&self) -> Option<&'static InvocationMeta> {
2384        if let Some(operator) = &self.invocation {
2385            return (operator.hint)();
2386        }
2387
2388        None
2389    }
2390
2391    /// Returns the right-hand side type of the addition operator:
2392    /// `lhs + rhs`.
2393    ///
2394    /// The returned type metadata corresponds to the
2395    /// [ScriptAdd::RHS](crate::runtime::ops::ScriptAdd::RHS) associated
2396    /// type.
2397    ///
2398    /// If the addition operator is not [supported](Self::implements_add),
2399    /// the function returns None.
2400    #[inline(always)]
2401    pub fn hint_add_rhs(&self) -> Option<&'static TypeMeta> {
2402        if let Some(operator) = &self.add {
2403            return Some(operator.hint_rhs);
2404        }
2405
2406        None
2407    }
2408
2409    /// Returns the result type of the addition operator:
2410    /// `lhs + rhs`.
2411    ///
2412    /// The returned type metadata corresponds to the
2413    /// [ScriptAdd::Result](crate::runtime::ops::ScriptAdd::Result) associated
2414    /// type.
2415    ///
2416    /// If the addition operator is not [supported](Self::implements_add),
2417    /// the function returns None.
2418    #[inline(always)]
2419    pub fn hint_add_result(&self) -> Option<&'static TypeMeta> {
2420        if let Some(operator) = &self.add {
2421            return Some(operator.hint_result);
2422        }
2423
2424        None
2425    }
2426
2427    /// Returns the right-hand side type of the addition and assignment
2428    /// operator: `lhs += rhs`.
2429    ///
2430    /// The returned type metadata corresponds to the
2431    /// [ScriptAddAssign::RHS](crate::runtime::ops::ScriptAddAssign::RHS)
2432    /// associated type.
2433    ///
2434    /// If the addition and assignment operator is not
2435    /// [supported](Self::implements_add_assign), the function returns None.
2436    #[inline(always)]
2437    pub fn hint_add_assign_rhs(&self) -> Option<&'static TypeMeta> {
2438        if let Some(operator) = &self.add_assign {
2439            return Some(operator.hint_rhs);
2440        }
2441
2442        None
2443    }
2444
2445    /// Returns the right-hand side type of the subtraction operator:
2446    /// `lhs - rhs`.
2447    ///
2448    /// The returned type metadata corresponds to the
2449    /// [ScriptSub::RHS](crate::runtime::ops::ScriptSub::RHS) associated
2450    /// type.
2451    ///
2452    /// If the subtraction operator is not [supported](Self::implements_sub),
2453    /// the function returns None.
2454    #[inline(always)]
2455    pub fn hint_sub_rhs(&self) -> Option<&'static TypeMeta> {
2456        if let Some(operator) = &self.sub {
2457            return Some(operator.hint_rhs);
2458        }
2459
2460        None
2461    }
2462
2463    /// Returns the result type of the subtraction operator:
2464    /// `lhs - rhs`.
2465    ///
2466    /// The returned type metadata corresponds to the
2467    /// [ScriptSub::Result](crate::runtime::ops::ScriptSub::Result) associated
2468    /// type.
2469    ///
2470    /// If the subtraction operator is not [supported](Self::implements_sub),
2471    /// the function returns None.
2472    #[inline(always)]
2473    pub fn hint_sub_result(&self) -> Option<&'static TypeMeta> {
2474        if let Some(operator) = &self.sub {
2475            return Some(operator.hint_result);
2476        }
2477
2478        None
2479    }
2480
2481    /// Returns the right-hand side type of the subtraction and assignment
2482    /// operator: `lhs -= rhs`.
2483    ///
2484    /// The returned type metadata corresponds to the
2485    /// [ScriptSubAssign::RHS](crate::runtime::ops::ScriptSubAssign::RHS)
2486    /// associated type.
2487    ///
2488    /// If the subtraction and assignment operator is not
2489    /// [supported](Self::implements_sub_assign), the function returns None.
2490    #[inline(always)]
2491    pub fn hint_sub_assign_rhs(&self) -> Option<&'static TypeMeta> {
2492        if let Some(operator) = &self.sub_assign {
2493            return Some(operator.hint_rhs);
2494        }
2495
2496        None
2497    }
2498
2499    /// Returns the right-hand side type of the multiplication operator:
2500    /// `lhs * rhs`.
2501    ///
2502    /// The returned type metadata corresponds to the
2503    /// [ScriptMul::RHS](crate::runtime::ops::ScriptMul::RHS) associated
2504    /// type.
2505    ///
2506    /// If the multiplication operator is not [supported](Self::implements_mul),
2507    /// the function returns None.
2508    #[inline(always)]
2509    pub fn hint_mul_rhs(&self) -> Option<&'static TypeMeta> {
2510        if let Some(operator) = &self.mul {
2511            return Some(operator.hint_rhs);
2512        }
2513
2514        None
2515    }
2516
2517    /// Returns the result type of the multiplication operator:
2518    /// `lhs * rhs`.
2519    ///
2520    /// The returned type metadata corresponds to the
2521    /// [ScriptMul::Result](crate::runtime::ops::ScriptMul::Result) associated
2522    /// type.
2523    ///
2524    /// If the multiplication operator is not [supported](Self::implements_mul),
2525    /// the function returns None.
2526    #[inline(always)]
2527    pub fn hint_mul_result(&self) -> Option<&'static TypeMeta> {
2528        if let Some(operator) = &self.mul {
2529            return Some(operator.hint_result);
2530        }
2531
2532        None
2533    }
2534
2535    /// Returns the right-hand side type of the multiplication and assignment
2536    /// operator: `lhs *= rhs`.
2537    ///
2538    /// The returned type metadata corresponds to the
2539    /// [ScriptMulAssign::RHS](crate::runtime::ops::ScriptMulAssign::RHS)
2540    /// associated type.
2541    ///
2542    /// If the multiplication and assignment operator is not
2543    /// [supported](Self::implements_mul_assign), the function returns None.
2544    #[inline(always)]
2545    pub fn hint_mul_assign_rhs(&self) -> Option<&'static TypeMeta> {
2546        if let Some(operator) = &self.mul_assign {
2547            return Some(operator.hint_rhs);
2548        }
2549
2550        None
2551    }
2552
2553    /// Returns the right-hand side type of the division operator:
2554    /// `lhs / rhs`.
2555    ///
2556    /// The returned type metadata corresponds to the
2557    /// [ScriptDiv::RHS](crate::runtime::ops::ScriptDiv::RHS) associated
2558    /// type.
2559    ///
2560    /// If the division operator is not [supported](Self::implements_div),
2561    /// the function returns None.
2562    #[inline(always)]
2563    pub fn hint_div_rhs(&self) -> Option<&'static TypeMeta> {
2564        if let Some(operator) = &self.div {
2565            return Some(operator.hint_rhs);
2566        }
2567
2568        None
2569    }
2570
2571    /// Returns the result type of the division operator:
2572    /// `lhs / rhs`.
2573    ///
2574    /// The returned type metadata corresponds to the
2575    /// [ScriptDiv::Result](crate::runtime::ops::ScriptDiv::Result) associated
2576    /// type.
2577    ///
2578    /// If the division operator is not [supported](Self::implements_div),
2579    /// the function returns None.
2580    #[inline(always)]
2581    pub fn hint_div_result(&self) -> Option<&'static TypeMeta> {
2582        if let Some(operator) = &self.div {
2583            return Some(operator.hint_result);
2584        }
2585
2586        None
2587    }
2588
2589    /// Returns the right-hand side type of the division and assignment
2590    /// operator: `lhs /= rhs`.
2591    ///
2592    /// The returned type metadata corresponds to the
2593    /// [ScriptDivAssign::RHS](crate::runtime::ops::ScriptDivAssign::RHS)
2594    /// associated type.
2595    ///
2596    /// If the division and assignment operator is not
2597    /// [supported](Self::implements_div_assign), the function returns None.
2598    #[inline(always)]
2599    pub fn hint_div_assign_rhs(&self) -> Option<&'static TypeMeta> {
2600        if let Some(operator) = &self.div_assign {
2601            return Some(operator.hint_rhs);
2602        }
2603
2604        None
2605    }
2606
2607    /// Returns the right-hand side type of the logical conjunction operator:
2608    /// `lhs && rhs`.
2609    ///
2610    /// The returned type metadata corresponds to the
2611    /// [ScriptAnd::RHS](crate::runtime::ops::ScriptAnd::RHS) associated
2612    /// type.
2613    ///
2614    /// If the logical conjunction operator is not
2615    /// [supported](Self::implements_and), the function returns None.
2616    #[inline(always)]
2617    pub fn hint_and_rhs(&self) -> Option<&'static TypeMeta> {
2618        if let Some(operator) = &self.and {
2619            return Some(operator.hint_rhs);
2620        }
2621
2622        None
2623    }
2624
2625    /// Returns the result type of the logical conjunction operator:
2626    /// `lhs && rhs`.
2627    ///
2628    /// The returned type metadata corresponds to the
2629    /// [ScriptAnd::Result](crate::runtime::ops::ScriptAnd::Result) associated
2630    /// type.
2631    ///
2632    /// If the logical conjunction operator is not
2633    /// [supported](Self::implements_and), the function returns None.
2634    #[inline(always)]
2635    pub fn hint_and_result(&self) -> Option<&'static TypeMeta> {
2636        if let Some(operator) = &self.and {
2637            return Some(operator.hint_result);
2638        }
2639
2640        None
2641    }
2642
2643    /// Returns the right-hand side type of the logical disjunction operator:
2644    /// `lhs || rhs`.
2645    ///
2646    /// The returned type metadata corresponds to the
2647    /// [ScriptOr::RHS](crate::runtime::ops::ScriptOr::RHS) associated
2648    /// type.
2649    ///
2650    /// If the logical disjunction operator is not
2651    /// [supported](Self::implements_or), the function returns None.
2652    #[inline(always)]
2653    pub fn hint_or_rhs(&self) -> Option<&'static TypeMeta> {
2654        if let Some(operator) = &self.or {
2655            return Some(operator.hint_rhs);
2656        }
2657
2658        None
2659    }
2660
2661    /// Returns the result type of the logical disjunction operator:
2662    /// `lhs || rhs`.
2663    ///
2664    /// The returned type metadata corresponds to the
2665    /// [ScriptOr::Result](crate::runtime::ops::ScriptOr::Result) associated
2666    /// type.
2667    ///
2668    /// If the logical disjunction operator is not
2669    /// [supported](Self::implements_or), the function returns None.
2670    #[inline(always)]
2671    pub fn hint_or_result(&self) -> Option<&'static TypeMeta> {
2672        if let Some(operator) = &self.or {
2673            return Some(operator.hint_result);
2674        }
2675
2676        None
2677    }
2678
2679    /// Returns the result type of the logical negation operator:
2680    /// `!foo`.
2681    ///
2682    /// The returned type metadata corresponds to the
2683    /// [ScriptNot::Result](crate::runtime::ops::ScriptNot::Result) associated
2684    /// type.
2685    ///
2686    /// If the logical negation operator is not
2687    /// [supported](Self::implements_not), the function returns None.
2688    #[inline(always)]
2689    pub fn hint_not_result(&self) -> Option<&'static TypeMeta> {
2690        if let Some(operator) = &self.not {
2691            return Some(operator.hint_result);
2692        }
2693
2694        None
2695    }
2696
2697    /// Returns the result type of the numeric negation operator:
2698    /// `-foo`.
2699    ///
2700    /// The returned type metadata corresponds to the
2701    /// [ScriptNeg::Result](crate::runtime::ops::ScriptNeg::Result) associated
2702    /// type.
2703    ///
2704    /// If the numeric negation operator is not
2705    /// [supported](Self::implements_neg), the function returns None.
2706    #[inline(always)]
2707    pub fn hint_neg_result(&self) -> Option<&'static TypeMeta> {
2708        if let Some(operator) = &self.neg {
2709            return Some(operator.hint_result);
2710        }
2711
2712        None
2713    }
2714
2715    /// Returns the right-hand side type of the bitwise conjunction operator:
2716    /// `lhs & rhs`.
2717    ///
2718    /// The returned type metadata corresponds to the
2719    /// [ScriptBitAnd::RHS](crate::runtime::ops::ScriptBitAnd::RHS) associated
2720    /// type.
2721    ///
2722    /// If the bitwise conjunction operator is not
2723    /// [supported](Self::implements_bit_and), the function returns None.
2724    #[inline(always)]
2725    pub fn hint_bit_and_rhs(&self) -> Option<&'static TypeMeta> {
2726        if let Some(operator) = &self.bit_and {
2727            return Some(operator.hint_rhs);
2728        }
2729
2730        None
2731    }
2732
2733    /// Returns the result type of the bitwise conjunction operator:
2734    /// `lhs & rhs`.
2735    ///
2736    /// The returned type metadata corresponds to the
2737    /// [ScriptBitAnd::Result](crate::runtime::ops::ScriptBitAnd::Result)
2738    /// associated type.
2739    ///
2740    /// If the bitwise conjunction operator is not
2741    /// [supported](Self::implements_bit_and), the function returns None.
2742    #[inline(always)]
2743    pub fn hint_bit_and_result(&self) -> Option<&'static TypeMeta> {
2744        if let Some(operator) = &self.bit_and {
2745            return Some(operator.hint_result);
2746        }
2747
2748        None
2749    }
2750
2751    /// Returns the right-hand side type of the bitwise conjunction and
2752    /// assignment operator: `lhs &= rhs`.
2753    ///
2754    /// The returned type metadata corresponds to the
2755    /// [ScriptBitAndAssign::RHS](crate::runtime::ops::ScriptBitAndAssign::RHS)
2756    /// associated type.
2757    ///
2758    /// If the bitwise conjunction and assignment operator is not
2759    /// [supported](Self::implements_bit_and_assign), the function returns None.
2760    #[inline(always)]
2761    pub fn hint_bit_and_assign_rhs(&self) -> Option<&'static TypeMeta> {
2762        if let Some(operator) = &self.bit_and_assign {
2763            return Some(operator.hint_rhs);
2764        }
2765
2766        None
2767    }
2768
2769    /// Returns the right-hand side type of the bitwise disjunction operator:
2770    /// `lhs | rhs`.
2771    ///
2772    /// The returned type metadata corresponds to the
2773    /// [ScriptBitOr::RHS](crate::runtime::ops::ScriptBitOr::RHS) associated
2774    /// type.
2775    ///
2776    /// If the bitwise disjunction operator is not
2777    /// [supported](Self::implements_bit_or), the function returns None.
2778    #[inline(always)]
2779    pub fn hint_bit_or_rhs(&self) -> Option<&'static TypeMeta> {
2780        if let Some(operator) = &self.bit_or {
2781            return Some(operator.hint_rhs);
2782        }
2783
2784        None
2785    }
2786
2787    /// Returns the result type of the bitwise disjunction operator:
2788    /// `lhs | rhs`.
2789    ///
2790    /// The returned type metadata corresponds to the
2791    /// [ScriptBitOr::Result](crate::runtime::ops::ScriptBitOr::Result)
2792    /// associated type.
2793    ///
2794    /// If the bitwise disjunction operator is not
2795    /// [supported](Self::implements_bit_or), the function returns None.
2796    #[inline(always)]
2797    pub fn hint_bit_or_result(&self) -> Option<&'static TypeMeta> {
2798        if let Some(operator) = &self.bit_or {
2799            return Some(operator.hint_result);
2800        }
2801
2802        None
2803    }
2804
2805    /// Returns the right-hand side type of the bitwise disjunction and
2806    /// assignment operator: `lhs |= rhs`.
2807    ///
2808    /// The returned type metadata corresponds to the
2809    /// [ScriptBitOrAssign::RHS](crate::runtime::ops::ScriptBitOrAssign::RHS)
2810    /// associated type.
2811    ///
2812    /// If the bitwise disjunction and assignment operator is not
2813    /// [supported](Self::implements_bit_or_assign), the function returns None.
2814    #[inline(always)]
2815    pub fn hint_bit_or_assign_rhs(&self) -> Option<&'static TypeMeta> {
2816        if let Some(operator) = &self.bit_or_assign {
2817            return Some(operator.hint_rhs);
2818        }
2819
2820        None
2821    }
2822
2823    /// Returns the right-hand side type of the bitwise exclusive disjunction
2824    /// operator: `lhs ^ rhs`.
2825    ///
2826    /// The returned type metadata corresponds to the
2827    /// [ScriptBitXor::RHS](crate::runtime::ops::ScriptBitXor::RHS) associated
2828    /// type.
2829    ///
2830    /// If the bitwise exclusive disjunction operator is not
2831    /// [supported](Self::implements_bit_xor), the function returns None.
2832    #[inline(always)]
2833    pub fn hint_bit_xor_rhs(&self) -> Option<&'static TypeMeta> {
2834        if let Some(operator) = &self.bit_xor {
2835            return Some(operator.hint_rhs);
2836        }
2837
2838        None
2839    }
2840
2841    /// Returns the result type of the bitwise exclusive disjunction operator:
2842    /// `lhs ^ rhs`.
2843    ///
2844    /// The returned type metadata corresponds to the
2845    /// [ScriptBitXor::Result](crate::runtime::ops::ScriptBitXor::Result)
2846    /// associated type.
2847    ///
2848    /// If the bitwise exclusive disjunction operator is not
2849    /// [supported](Self::implements_bit_xor), the function returns None.
2850    #[inline(always)]
2851    pub fn hint_bit_xor_result(&self) -> Option<&'static TypeMeta> {
2852        if let Some(operator) = &self.bit_xor {
2853            return Some(operator.hint_result);
2854        }
2855
2856        None
2857    }
2858
2859    /// Returns the right-hand side type of the bitwise exclusive disjunction
2860    /// and assignment operator: `lhs ^= rhs`.
2861    ///
2862    /// The returned type metadata corresponds to the
2863    /// [ScriptBitXorAssign::RHS](crate::runtime::ops::ScriptBitXorAssign::RHS)
2864    /// associated type.
2865    ///
2866    /// If the bitwise exclusive disjunction and assignment operator is not
2867    /// [supported](Self::implements_bit_xor_assign), the function returns None.
2868    #[inline(always)]
2869    pub fn hint_bit_xor_assign_rhs(&self) -> Option<&'static TypeMeta> {
2870        if let Some(operator) = &self.bit_xor_assign {
2871            return Some(operator.hint_rhs);
2872        }
2873
2874        None
2875    }
2876
2877    /// Returns the right-hand side type of the bitwise left shift
2878    /// operator: `lhs << rhs`.
2879    ///
2880    /// The returned type metadata corresponds to the
2881    /// [ScriptShl::RHS](crate::runtime::ops::ScriptShl::RHS) associated
2882    /// type.
2883    ///
2884    /// If the bitwise left shift operator is not
2885    /// [supported](Self::implements_shl), the function returns None.
2886    #[inline(always)]
2887    pub fn hint_shl_rhs(&self) -> Option<&'static TypeMeta> {
2888        if let Some(operator) = &self.shl {
2889            return Some(operator.hint_rhs);
2890        }
2891
2892        None
2893    }
2894
2895    /// Returns the result type of the bitwise left shift operator:
2896    /// `lhs << rhs`.
2897    ///
2898    /// The returned type metadata corresponds to the
2899    /// [ScriptShl::Result](crate::runtime::ops::ScriptShl::Result)
2900    /// associated type.
2901    ///
2902    /// If the bitwise left shift operator is not
2903    /// [supported](Self::implements_shl), the function returns None.
2904    #[inline(always)]
2905    pub fn hint_shl_result(&self) -> Option<&'static TypeMeta> {
2906        if let Some(operator) = &self.shl {
2907            return Some(operator.hint_result);
2908        }
2909
2910        None
2911    }
2912
2913    /// Returns the right-hand side type of the left shift
2914    /// and assignment operator: `lhs <<= rhs`.
2915    ///
2916    /// The returned type metadata corresponds to the
2917    /// [ScriptShlAssign::RHS](crate::runtime::ops::ScriptShlAssign::RHS)
2918    /// associated type.
2919    ///
2920    /// If the left shift and assignment operator is not
2921    /// [supported](Self::implements_shl_assign), the function returns None.
2922    #[inline(always)]
2923    pub fn hint_shl_assign_rhs(&self) -> Option<&'static TypeMeta> {
2924        if let Some(operator) = &self.shl_assign {
2925            return Some(operator.hint_rhs);
2926        }
2927
2928        None
2929    }
2930
2931    /// Returns the right-hand side type of the bitwise right shift
2932    /// operator: `lhs >> rhs`.
2933    ///
2934    /// The returned type metadata corresponds to the
2935    /// [ScriptShr::RHS](crate::runtime::ops::ScriptShr::RHS) associated
2936    /// type.
2937    ///
2938    /// If the bitwise right shift operator is not
2939    /// [supported](Self::implements_shr), the function returns None.
2940    #[inline(always)]
2941    pub fn hint_shr_rhs(&self) -> Option<&'static TypeMeta> {
2942        if let Some(operator) = &self.shr {
2943            return Some(operator.hint_rhs);
2944        }
2945
2946        None
2947    }
2948
2949    /// Returns the result type of the bitwise right shift operator:
2950    /// `lhs >> rhs`.
2951    ///
2952    /// The returned type metadata corresponds to the
2953    /// [ScriptShr::Result](crate::runtime::ops::ScriptShr::Result)
2954    /// associated type.
2955    ///
2956    /// If the bitwise right shift operator is not
2957    /// [supported](Self::implements_shr), the function returns None.
2958    #[inline(always)]
2959    pub fn hint_shr_result(&self) -> Option<&'static TypeMeta> {
2960        if let Some(operator) = &self.shr {
2961            return Some(operator.hint_result);
2962        }
2963
2964        None
2965    }
2966
2967    /// Returns the right-hand side type of the right shift
2968    /// and assignment operator: `lhs >>= rhs`.
2969    ///
2970    /// The returned type metadata corresponds to the
2971    /// [ScriptShrAssign::RHS](crate::runtime::ops::ScriptShrAssign::RHS)
2972    /// associated type.
2973    ///
2974    /// If the right shift and assignment operator is not
2975    /// [supported](Self::implements_shr_assign), the function returns None.
2976    #[inline(always)]
2977    pub fn hint_shr_assign_rhs(&self) -> Option<&'static TypeMeta> {
2978        if let Some(operator) = &self.shr_assign {
2979            return Some(operator.hint_rhs);
2980        }
2981
2982        None
2983    }
2984
2985    /// Returns the right-hand side type of the reminder of division
2986    /// operator: `lhs % rhs`.
2987    ///
2988    /// The returned type metadata corresponds to the
2989    /// [ScriptRem::RHS](crate::runtime::ops::ScriptRem::RHS) associated
2990    /// type.
2991    ///
2992    /// If the reminder of division operator is not
2993    /// [supported](Self::implements_rem), the function returns None.
2994    #[inline(always)]
2995    pub fn hint_rem_rhs(&self) -> Option<&'static TypeMeta> {
2996        if let Some(operator) = &self.rem {
2997            return Some(operator.hint_rhs);
2998        }
2999
3000        None
3001    }
3002
3003    /// Returns the result type of the reminder of division operator:
3004    /// `lhs % rhs`.
3005    ///
3006    /// The returned type metadata corresponds to the
3007    /// [ScriptRem::Result](crate::runtime::ops::ScriptRem::Result)
3008    /// associated type.
3009    ///
3010    /// If the reminder of division operator is not
3011    /// [supported](Self::implements_rem), the function returns None.
3012    #[inline(always)]
3013    pub fn hint_rem_result(&self) -> Option<&'static TypeMeta> {
3014        if let Some(operator) = &self.rem {
3015            return Some(operator.hint_result);
3016        }
3017
3018        None
3019    }
3020
3021    /// Returns the right-hand side type of the reminder of division
3022    /// and assignment operator: `lhs %= rhs`.
3023    ///
3024    /// The returned type metadata corresponds to the
3025    /// [ScriptRemAssign::RHS](crate::runtime::ops::ScriptRemAssign::RHS)
3026    /// associated type.
3027    ///
3028    /// If the reminder of division and assignment operator is not
3029    /// [supported](Self::implements_rem_assign), the function returns None.
3030    #[inline(always)]
3031    pub fn hint_rem_assign_rhs(&self) -> Option<&'static TypeMeta> {
3032        if let Some(operator) = &self.rem_assign {
3033            return Some(operator.hint_rhs);
3034        }
3035
3036        None
3037    }
3038
3039    // Safety: The prototype describes type `T`.
3040    #[inline]
3041    pub(super) unsafe fn clone_first<T: ScriptType>(
3042        &self,
3043        access_origin: &Origin,
3044        slice_origin: &Origin,
3045        slice: &[T],
3046    ) -> RuntimeResult<T> {
3047        let clone_fn = match &self.clone {
3048            // Safety: Upheld by the caller.
3049            Some(operator) => unsafe { operator.clone_fn.into_fn::<T>() },
3050
3051            None => {
3052                return Err(RuntimeError::UndefinedOperator {
3053                    access_origin: *access_origin,
3054                    receiver_origin: Some(*slice_origin),
3055                    receiver_type: T::type_meta(),
3056                    operator: OperatorKind::Clone,
3057                });
3058            }
3059        };
3060
3061        let length = slice.len();
3062
3063        if slice.len() != 1 {
3064            return Err(RuntimeError::NonSingleton {
3065                access_origin: *access_origin,
3066                actual: length,
3067            });
3068        }
3069
3070        let first = match slice.first() {
3071            Some(first) => first,
3072
3073            // Safety: Slice length checked above.
3074            None => unsafe { debug_unreachable!("Missing slice first item.") },
3075        };
3076
3077        return Ok(clone_fn(first));
3078    }
3079
3080    // Safety: The prototype describes type `T`.
3081    #[inline]
3082    pub(super) unsafe fn clone_slice<T: ScriptType>(
3083        &self,
3084        access_origin: &Origin,
3085        slice_origin: &Origin,
3086        slice: &[T],
3087    ) -> RuntimeResult<Box<[T]>> {
3088        let clone_fn = match &self.clone {
3089            // Safety: Upheld by the caller.
3090            Some(operator) => unsafe { operator.clone_fn.into_fn::<T>() },
3091
3092            None => {
3093                return Err(RuntimeError::UndefinedOperator {
3094                    access_origin: *access_origin,
3095                    receiver_origin: Some(*slice_origin),
3096                    receiver_type: T::type_meta(),
3097                    operator: OperatorKind::Clone,
3098                });
3099            }
3100        };
3101
3102        return Ok(slice
3103            .iter()
3104            .map(clone_fn)
3105            .collect::<Vec<_>>()
3106            .into_boxed_slice());
3107    }
3108}
3109
3110impl TypeMeta {
3111    /// Returns a [Prototype] of the Rust type that describes the script
3112    /// operations available for this type.
3113    #[inline(always)]
3114    pub fn prototype(&self) -> &'static Prototype {
3115        let registry = PrototypeRegistry::get();
3116
3117        match registry.prototypes.get(self.id()) {
3118            Some(prototype) => prototype,
3119
3120            // Safety: Each TypeMeta has corresponding Prototype.
3121            None => unsafe { debug_unreachable!("TypeMeta without Prototype.") },
3122        }
3123    }
3124
3125    /// Creates an instance of this type using
3126    /// the [default constructor](Prototype::implements_default).
3127    ///
3128    /// The function returns [RuntimeError] if the default constructor is not
3129    /// exported for this type, or if the constructor's implementation returns
3130    /// a RuntimeError.
3131    #[inline]
3132    pub fn instantiate(&'static self, origin: Origin) -> RuntimeResult<Cell> {
3133        if let Some(operator) = &self.prototype().default {
3134            return (operator.invoke)(origin);
3135        }
3136
3137        Err(RuntimeError::UndefinedOperator {
3138            access_origin: origin,
3139            receiver_origin: None,
3140            receiver_type: self,
3141            operator: OperatorKind::Default,
3142        })
3143    }
3144
3145    /// Creates an array of objects by concatenating the data in `items` into
3146    /// a single slice in the resulting `Cell`.
3147    ///
3148    /// The `items` source array does not necessarily have to be an array of
3149    /// objects of the same type. The underlying implementation may attempt
3150    /// to cast them into other types. The source array may also contain "gaps"
3151    /// ([Nil Cells](Cell::nil)) and Cells with arrays. In this case, the
3152    /// canonical implementation of this operator typically flattens these
3153    /// sub-arrays. Additionally, the canonical implementation usually takes
3154    /// [Arg] objects from the `items` source slice.
3155    ///
3156    /// The `origin` parameter specifies the Rust or Script source code range
3157    /// that spans the operator (e.g., the script array declaration).
3158    ///
3159    /// The function returns a [RuntimeError] if the type does not
3160    /// support the ["concat" operator](Prototype::implements_concat), or if
3161    /// the operator's implementation returns a RuntimeError.
3162    #[inline]
3163    pub fn concat(&'static self, origin: Origin, items: &mut [Arg]) -> RuntimeResult<Cell> {
3164        if let Some(operator) = &self.prototype().concat {
3165            return (operator.invoke)(origin, items);
3166        }
3167
3168        Err(RuntimeError::UndefinedOperator {
3169            access_origin: origin,
3170            receiver_origin: None,
3171            receiver_type: self,
3172            operator: OperatorKind::Concat,
3173        })
3174    }
3175}
3176
3177struct PrototypeRegistry {
3178    prototypes: AHashMap<TypeId, Prototype>,
3179}
3180
3181impl PrototypeRegistry {
3182    #[inline(always)]
3183    fn get() -> &'static Self {
3184        static REGISTRY: Lazy<PrototypeRegistry> = Lazy::new(|| {
3185            let mut prototypes = TypeMeta::enumerate()
3186                .map(|id| (*id, Prototype::default()))
3187                .collect::<AHashMap<TypeId, _>>();
3188
3189            for group in DeclarationGroup::enumerate() {
3190                let origin = group.origin;
3191
3192                for declaration in &group.prototypes {
3193                    let declaration = declaration();
3194
3195                    let type_meta = match TypeMeta::by_id(&declaration.receiver) {
3196                        Some(meta) => meta,
3197
3198                        None => origin.blame("Unregistered TypeMeta."),
3199                    };
3200
3201                    let type_meta_package = type_meta.origin().package;
3202
3203                    let origin_package = match origin.package {
3204                        Some(package) => package,
3205                        None => {
3206                            system_panic!("DeclarationGroup origin without package.")
3207                        }
3208                    };
3209
3210                    match type_meta_package {
3211                        Some(type_meta_package) => {
3212                            if type_meta_package != origin_package {
3213                                origin.blame(&format!(
3214                                    "Type {} declared in the package \
3215                                    {}@{}. Type semantics can not be extended \
3216                                    from the foreign crate {}@{}.",
3217                                    type_meta,
3218                                    type_meta_package.0,
3219                                    type_meta_package.1,
3220                                    origin_package.0,
3221                                    origin_package.1,
3222                                ))
3223                            }
3224                        }
3225
3226                        None => origin.blame(&format!(
3227                            "Built-in type {} can not be extended from the \
3228                                foreign crate {}@{}.",
3229                            type_meta, origin_package.0, origin_package.1,
3230                        )),
3231                    }
3232
3233                    let prototype = match prototypes.get_mut(&declaration.receiver) {
3234                        Some(prototype) => prototype,
3235
3236                        None => {
3237                            // Safety:
3238                            //   1. TypeMeta existence checked above.
3239                            //   2. Each TypeMeta has corresponding Prototype.
3240                            unsafe { debug_unreachable!("Missing Prototype for registered type.") }
3241                        }
3242                    };
3243
3244                    for component in declaration.components {
3245                        let name = component.name.string;
3246
3247                        if let Some(previous) = prototype.components.get(name) {
3248                            let previous = previous.name.origin;
3249
3250                            component.name.origin.blame(&format!(
3251                                "Duplicate \"{type_meta}.{name}\" component \
3252                                declaration. The same component already \
3253                                declared in {previous}.",
3254                            ))
3255                        }
3256
3257                        if prototype.components.insert(name, component).is_some() {
3258                            // Safety: Uniqueness checked above.
3259                            unsafe { debug_unreachable!("Duplicate component entry.") };
3260                        }
3261                    }
3262
3263                    for operator in declaration.operators {
3264                        match operator {
3265                            OperatorDeclaration::Assign(operator) => {
3266                                if let Some(previous) = &prototype.assign {
3267                                    let previous = previous.origin;
3268
3269                                    operator.origin.blame(&format!(
3270                                        "Duplicate {type_meta} \
3271                                        Assign operator declaration. The same \
3272                                        operator already declared in {previous}.",
3273                                    ))
3274                                }
3275
3276                                prototype.assign = Some(operator);
3277                            }
3278
3279                            OperatorDeclaration::Concat(operator) => {
3280                                if let Some(previous) = &prototype.concat {
3281                                    let previous = previous.origin;
3282
3283                                    operator.origin.blame(&format!(
3284                                        "Duplicate {type_meta} \
3285                                        Concat operator declaration. The same \
3286                                        operator already declared in {previous}.",
3287                                    ))
3288                                }
3289
3290                                prototype.concat = Some(operator);
3291                            }
3292
3293                            OperatorDeclaration::Field(operator) => {
3294                                if let Some(previous) = &prototype.field {
3295                                    let previous = previous.origin;
3296
3297                                    operator.origin.blame(&format!(
3298                                        "Duplicate {type_meta} \
3299                                        Field operator declaration. The same \
3300                                        operator already declared in {previous}.",
3301                                    ))
3302                                }
3303
3304                                prototype.field = Some(operator);
3305                            }
3306
3307                            OperatorDeclaration::Clone(operator) => {
3308                                if let Some(previous) = &prototype.clone {
3309                                    let previous = previous.origin;
3310
3311                                    operator.origin.blame(&format!(
3312                                        "Duplicate {type_meta} \
3313                                        Clone operator declaration. The same \
3314                                        operator already declared in {previous}.",
3315                                    ))
3316                                }
3317
3318                                prototype.clone = Some(operator);
3319                            }
3320
3321                            OperatorDeclaration::Debug(operator) => {
3322                                if let Some(previous) = &prototype.debug {
3323                                    let previous = previous.origin;
3324
3325                                    operator.origin.blame(&format!(
3326                                        "Duplicate {type_meta} \
3327                                        Debug operator declaration. The same \
3328                                        operator already declared in {previous}.",
3329                                    ))
3330                                }
3331
3332                                prototype.debug = Some(operator);
3333                            }
3334
3335                            OperatorDeclaration::Display(operator) => {
3336                                if let Some(previous) = &prototype.display {
3337                                    let previous = previous.origin;
3338
3339                                    operator.origin.blame(&format!(
3340                                        "Duplicate {type_meta} \
3341                                        Display operator declaration. The same \
3342                                        operator already declared in {previous}.",
3343                                    ))
3344                                }
3345
3346                                prototype.display = Some(operator);
3347                            }
3348
3349                            OperatorDeclaration::PartialEq(operator) => {
3350                                if let Some(previous) = &prototype.partial_eq {
3351                                    let previous = previous.origin;
3352
3353                                    operator.origin.blame(&format!(
3354                                        "Duplicate {type_meta} \
3355                                        PartialEq operator declaration. The same \
3356                                        operator already declared in {previous}.",
3357                                    ))
3358                                }
3359
3360                                prototype.partial_eq = Some(operator);
3361                            }
3362
3363                            OperatorDeclaration::Default(operator) => {
3364                                if let Some(previous) = &prototype.default {
3365                                    let previous = previous.origin;
3366
3367                                    operator.origin.blame(&format!(
3368                                        "Duplicate {type_meta} \
3369                                        Default operator declaration. The same \
3370                                        operator already declared in {previous}.",
3371                                    ))
3372                                }
3373
3374                                prototype.default = Some(operator);
3375                            }
3376
3377                            OperatorDeclaration::PartialOrd(operator) => {
3378                                if let Some(previous) = &prototype.partial_ord {
3379                                    let previous = previous.origin;
3380
3381                                    operator.origin.blame(&format!(
3382                                        "Duplicate {type_meta} \
3383                                        PartialOrd operator declaration. The same \
3384                                        operator already declared in {previous}.",
3385                                    ))
3386                                }
3387
3388                                prototype.partial_ord = Some(operator);
3389                            }
3390
3391                            OperatorDeclaration::Ord(operator) => {
3392                                if let Some(previous) = &prototype.ord {
3393                                    let previous = previous.origin;
3394
3395                                    operator.origin.blame(&format!(
3396                                        "Duplicate {type_meta} \
3397                                        Ord operator declaration. The same \
3398                                        operator already declared in {previous}.",
3399                                    ))
3400                                }
3401
3402                                prototype.ord = Some(operator);
3403                            }
3404
3405                            OperatorDeclaration::Hash(operator) => {
3406                                if let Some(previous) = &prototype.hash {
3407                                    let previous = previous.origin;
3408
3409                                    operator.origin.blame(&format!(
3410                                        "Duplicate {type_meta} \
3411                                        Hash operator declaration. The same \
3412                                        operator already declared in {previous}.",
3413                                    ))
3414                                }
3415
3416                                prototype.hash = Some(operator);
3417                            }
3418
3419                            OperatorDeclaration::Invocation(operator) => {
3420                                if let Some(previous) = &prototype.invocation {
3421                                    let previous = previous.origin;
3422
3423                                    operator.origin.blame(&format!(
3424                                        "Duplicate {type_meta} \
3425                                        Invocation operator declaration. The same \
3426                                        operator already declared in {previous}.",
3427                                    ))
3428                                }
3429
3430                                prototype.invocation = Some(operator);
3431                            }
3432
3433                            OperatorDeclaration::Binding(operator) => {
3434                                if let Some(previous) = &prototype.binding {
3435                                    let previous = previous.origin;
3436
3437                                    operator.origin.blame(&format!(
3438                                        "Duplicate {type_meta} \
3439                                        Binding operator declaration. The same \
3440                                        operator already declared in {previous}.",
3441                                    ))
3442                                }
3443
3444                                prototype.binding = Some(operator);
3445                            }
3446
3447                            OperatorDeclaration::Add(operator) => {
3448                                if let Some(previous) = &prototype.add {
3449                                    let previous = previous.origin;
3450
3451                                    operator.origin.blame(&format!(
3452                                        "Duplicate {type_meta} \
3453                                        Add operator declaration. The same \
3454                                        operator already declared in {previous}.",
3455                                    ))
3456                                }
3457
3458                                prototype.add = Some(operator);
3459                            }
3460
3461                            OperatorDeclaration::AddAssign(operator) => {
3462                                if let Some(previous) = &prototype.add_assign {
3463                                    let previous = previous.origin;
3464
3465                                    operator.origin.blame(&format!(
3466                                        "Duplicate {type_meta} \
3467                                        AddAssign operator declaration. The same \
3468                                        operator already declared in {previous}.",
3469                                    ))
3470                                }
3471
3472                                prototype.add_assign = Some(operator);
3473                            }
3474
3475                            OperatorDeclaration::Sub(operator) => {
3476                                if let Some(previous) = &prototype.sub {
3477                                    let previous = previous.origin;
3478
3479                                    operator.origin.blame(&format!(
3480                                        "Duplicate {type_meta} \
3481                                        Sub operator declaration. The same \
3482                                        operator already declared in {previous}.",
3483                                    ))
3484                                }
3485
3486                                prototype.sub = Some(operator);
3487                            }
3488
3489                            OperatorDeclaration::SubAssign(operator) => {
3490                                if let Some(previous) = &prototype.sub_assign {
3491                                    let previous = previous.origin;
3492
3493                                    operator.origin.blame(&format!(
3494                                        "Duplicate {type_meta} \
3495                                        SubAssign operator declaration. The same \
3496                                        operator already declared in {previous}.",
3497                                    ))
3498                                }
3499
3500                                prototype.sub_assign = Some(operator);
3501                            }
3502
3503                            OperatorDeclaration::Mul(operator) => {
3504                                if let Some(previous) = &prototype.mul {
3505                                    let previous = previous.origin;
3506
3507                                    operator.origin.blame(&format!(
3508                                        "Duplicate {type_meta} \
3509                                        Mul operator declaration. The same \
3510                                        operator already declared in {previous}.",
3511                                    ))
3512                                }
3513
3514                                prototype.mul = Some(operator);
3515                            }
3516
3517                            OperatorDeclaration::MulAssign(operator) => {
3518                                if let Some(previous) = &prototype.mul_assign {
3519                                    let previous = previous.origin;
3520
3521                                    operator.origin.blame(&format!(
3522                                        "Duplicate {type_meta} \
3523                                        MulAssign operator declaration. The same \
3524                                        operator already declared in {previous}.",
3525                                    ))
3526                                }
3527
3528                                prototype.mul_assign = Some(operator);
3529                            }
3530
3531                            OperatorDeclaration::Div(operator) => {
3532                                if let Some(previous) = &prototype.div {
3533                                    let previous = previous.origin;
3534
3535                                    operator.origin.blame(&format!(
3536                                        "Duplicate {type_meta} \
3537                                        Div operator declaration. The same \
3538                                        operator already declared in {previous}.",
3539                                    ))
3540                                }
3541
3542                                prototype.div = Some(operator);
3543                            }
3544
3545                            OperatorDeclaration::DivAssign(operator) => {
3546                                if let Some(previous) = &prototype.div_assign {
3547                                    let previous = previous.origin;
3548
3549                                    operator.origin.blame(&format!(
3550                                        "Duplicate {type_meta} \
3551                                        DivAssign operator declaration. The same \
3552                                        operator already declared in {previous}.",
3553                                    ))
3554                                }
3555
3556                                prototype.div_assign = Some(operator);
3557                            }
3558
3559                            OperatorDeclaration::And(operator) => {
3560                                if let Some(previous) = &prototype.and {
3561                                    let previous = previous.origin;
3562
3563                                    operator.origin.blame(&format!(
3564                                        "Duplicate {type_meta} \
3565                                        And operator declaration. The same \
3566                                        operator already declared in {previous}.",
3567                                    ))
3568                                }
3569
3570                                prototype.and = Some(operator);
3571                            }
3572
3573                            OperatorDeclaration::Or(operator) => {
3574                                if let Some(previous) = &prototype.or {
3575                                    let previous = previous.origin;
3576
3577                                    operator.origin.blame(&format!(
3578                                        "Duplicate {type_meta} \
3579                                        Or operator declaration. The same \
3580                                        operator already declared in {previous}.",
3581                                    ))
3582                                }
3583
3584                                prototype.or = Some(operator);
3585                            }
3586
3587                            OperatorDeclaration::Not(operator) => {
3588                                if let Some(previous) = &prototype.not {
3589                                    let previous = previous.origin;
3590
3591                                    operator.origin.blame(&format!(
3592                                        "Duplicate {type_meta} \
3593                                        Not operator declaration. The same \
3594                                        operator already declared in {previous}.",
3595                                    ))
3596                                }
3597
3598                                prototype.not = Some(operator);
3599                            }
3600
3601                            OperatorDeclaration::Neg(operator) => {
3602                                if let Some(previous) = &prototype.neg {
3603                                    let previous = previous.origin;
3604
3605                                    operator.origin.blame(&format!(
3606                                        "Duplicate {type_meta} \
3607                                        Neg operator declaration. The same \
3608                                        operator already declared in {previous}.",
3609                                    ))
3610                                }
3611
3612                                prototype.neg = Some(operator);
3613                            }
3614
3615                            OperatorDeclaration::BitAnd(operator) => {
3616                                if let Some(previous) = &prototype.bit_and {
3617                                    let previous = previous.origin;
3618
3619                                    operator.origin.blame(&format!(
3620                                        "Duplicate {type_meta} \
3621                                        BitAnd operator declaration. The same \
3622                                        operator already declared in {previous}.",
3623                                    ))
3624                                }
3625
3626                                prototype.bit_and = Some(operator);
3627                            }
3628
3629                            OperatorDeclaration::BitAndAssign(operator) => {
3630                                if let Some(previous) = &prototype.bit_and_assign {
3631                                    let previous = previous.origin;
3632
3633                                    operator.origin.blame(&format!(
3634                                        "Duplicate {type_meta} \
3635                                        BitAndAssign operator declaration. The same \
3636                                        operator already declared in {previous}.",
3637                                    ))
3638                                }
3639
3640                                prototype.bit_and_assign = Some(operator);
3641                            }
3642
3643                            OperatorDeclaration::BitOr(operator) => {
3644                                if let Some(previous) = &prototype.bit_or {
3645                                    let previous = previous.origin;
3646
3647                                    operator.origin.blame(&format!(
3648                                        "Duplicate {type_meta} \
3649                                        BitOr operator declaration. The same \
3650                                        operator already declared in {previous}.",
3651                                    ))
3652                                }
3653
3654                                prototype.bit_or = Some(operator);
3655                            }
3656
3657                            OperatorDeclaration::BitOrAssign(operator) => {
3658                                if let Some(previous) = &prototype.bit_or_assign {
3659                                    let previous = previous.origin;
3660
3661                                    operator.origin.blame(&format!(
3662                                        "Duplicate {type_meta} \
3663                                        BitOrAssign operator declaration. The same \
3664                                        operator already declared in {previous}.",
3665                                    ))
3666                                }
3667
3668                                prototype.bit_or_assign = Some(operator);
3669                            }
3670
3671                            OperatorDeclaration::BitXor(operator) => {
3672                                if let Some(previous) = &prototype.bit_xor {
3673                                    let previous = previous.origin;
3674
3675                                    operator.origin.blame(&format!(
3676                                        "Duplicate {type_meta} \
3677                                        BitXor operator declaration. The same \
3678                                        operator already declared in {previous}.",
3679                                    ))
3680                                }
3681
3682                                prototype.bit_xor = Some(operator);
3683                            }
3684
3685                            OperatorDeclaration::BitXorAssign(operator) => {
3686                                if let Some(previous) = &prototype.bit_xor_assign {
3687                                    let previous = previous.origin;
3688
3689                                    operator.origin.blame(&format!(
3690                                        "Duplicate {type_meta} \
3691                                        BitXorAssign operator declaration. The same \
3692                                        operator already declared in {previous}.",
3693                                    ))
3694                                }
3695
3696                                prototype.bit_xor_assign = Some(operator);
3697                            }
3698
3699                            OperatorDeclaration::Shl(operator) => {
3700                                if let Some(previous) = &prototype.shl {
3701                                    let previous = previous.origin;
3702
3703                                    operator.origin.blame(&format!(
3704                                        "Duplicate {type_meta} \
3705                                        Shl operator declaration. The same \
3706                                        operator already declared in {previous}.",
3707                                    ))
3708                                }
3709
3710                                prototype.shl = Some(operator);
3711                            }
3712
3713                            OperatorDeclaration::ShlAssign(operator) => {
3714                                if let Some(previous) = &prototype.shl_assign {
3715                                    let previous = previous.origin;
3716
3717                                    operator.origin.blame(&format!(
3718                                        "Duplicate {type_meta} \
3719                                        ShlAssign operator declaration. The same \
3720                                        operator already declared in {previous}.",
3721                                    ))
3722                                }
3723
3724                                prototype.shl_assign = Some(operator);
3725                            }
3726
3727                            OperatorDeclaration::Shr(operator) => {
3728                                if let Some(previous) = &prototype.shr {
3729                                    let previous = previous.origin;
3730
3731                                    operator.origin.blame(&format!(
3732                                        "Duplicate {type_meta} \
3733                                        Shr operator declaration. The same \
3734                                        operator already declared in {previous}.",
3735                                    ))
3736                                }
3737
3738                                prototype.shr = Some(operator);
3739                            }
3740
3741                            OperatorDeclaration::ShrAssign(operator) => {
3742                                if let Some(previous) = &prototype.shr_assign {
3743                                    let previous = previous.origin;
3744
3745                                    operator.origin.blame(&format!(
3746                                        "Duplicate {type_meta} \
3747                                        ShrAssign operator declaration. The same \
3748                                        operator already declared in {previous}.",
3749                                    ))
3750                                }
3751
3752                                prototype.shr_assign = Some(operator);
3753                            }
3754
3755                            OperatorDeclaration::Rem(operator) => {
3756                                if let Some(previous) = &prototype.rem {
3757                                    let previous = previous.origin;
3758
3759                                    operator.origin.blame(&format!(
3760                                        "Duplicate {type_meta} \
3761                                        Rem operator declaration. The same \
3762                                        operator already declared in {previous}.",
3763                                    ))
3764                                }
3765
3766                                prototype.rem = Some(operator);
3767                            }
3768
3769                            OperatorDeclaration::RemAssign(operator) => {
3770                                if let Some(previous) = &prototype.rem_assign {
3771                                    let previous = previous.origin;
3772
3773                                    operator.origin.blame(&format!(
3774                                        "Duplicate {type_meta} \
3775                                        RemAssign operator declaration. The same \
3776                                        operator already declared in {previous}.",
3777                                    ))
3778                                }
3779
3780                                prototype.rem_assign = Some(operator);
3781                            }
3782
3783                            OperatorDeclaration::None(operator) => {
3784                                if let Some(previous) = &prototype.none {
3785                                    let previous = previous.origin;
3786
3787                                    operator.origin.blame(&format!(
3788                                        "Duplicate {type_meta} \
3789                                        None marker declaration. The same \
3790                                        marker already declared in {previous}.",
3791                                    ))
3792                                }
3793
3794                                prototype.none = Some(operator);
3795                            }
3796                        }
3797                    }
3798                }
3799            }
3800
3801            PrototypeRegistry { prototypes }
3802        });
3803
3804        REGISTRY.deref()
3805    }
3806}