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}