rune/runtime/
inst.rs

1use core::cmp::Ordering;
2use core::fmt;
3
4#[cfg(feature = "musli")]
5use musli::{Decode, Encode};
6use rune_macros::InstDisplay;
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate as rune;
11use crate::alloc;
12use crate::alloc::prelude::*;
13use crate::Hash;
14
15use super::{Call, FormatSpec, Type, Value};
16
17/// An instruction in the virtual machine.
18#[derive(Clone, Copy)]
19#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
20#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))]
21pub struct Inst {
22    pub(crate) kind: Kind,
23}
24
25impl Inst {
26    #[inline]
27    pub(crate) fn new(kind: Kind) -> Self {
28        Self { kind }
29    }
30}
31
32impl fmt::Display for Inst {
33    #[inline]
34    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
35        self.kind.fmt(fmt)
36    }
37}
38
39impl fmt::Debug for Inst {
40    #[inline]
41    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
42        self.kind.fmt(fmt)
43    }
44}
45
46impl TryClone for Inst {
47    #[inline]
48    fn try_clone(&self) -> alloc::Result<Self> {
49        Ok(Self {
50            kind: self.kind.try_clone()?,
51        })
52    }
53}
54
55/// Pre-canned panic reasons.
56///
57/// To formulate a custom reason, use
58/// [`VmError::panic`][crate::runtime::VmError::panic].
59#[derive(Debug, TryClone, Clone, Copy)]
60#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
61#[cfg_attr(feature = "musli", derive(Decode, Encode))]
62#[try_clone(copy)]
63pub(crate) enum PanicReason {
64    /// A pattern didn't match where it unconditionally has to.
65    UnmatchedPattern,
66}
67
68impl PanicReason {
69    /// The identifier of the panic.
70    fn ident(&self) -> &'static str {
71        match *self {
72            Self::UnmatchedPattern => "unmatched pattern",
73        }
74    }
75}
76
77impl fmt::Display for PanicReason {
78    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
79        match *self {
80            Self::UnmatchedPattern => write!(fmt, "pattern did not match")?,
81        }
82
83        Ok(())
84    }
85}
86
87/// The kind of an instruction in the virtual machine.
88#[derive(Debug, TryClone, Clone, Copy, InstDisplay)]
89#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
90#[cfg_attr(feature = "musli", derive(Decode, Encode))]
91#[try_clone(copy)]
92pub(crate) enum Kind {
93    /// Make sure that the memory region has `size` slots of memory available.
94    Allocate {
95        /// The size of the memory region to allocate.
96        size: usize,
97    },
98    /// Not operator. Takes a boolean from the top of the stack  and inverts its
99    /// logical value.
100    ///
101    /// # Operation
102    ///
103    /// ```text
104    /// <bool>
105    /// => <bool>
106    /// ```
107    Not {
108        /// The operand to negate.
109        addr: Address,
110        /// Whether the produced value from the not should be kept or not.
111        out: Output,
112    },
113    /// Negate the numerical value on the stack.
114    ///
115    /// # Operation
116    ///
117    /// ```text
118    /// <number>
119    /// => <number>
120    /// ```
121    Neg {
122        /// The operand to negate.
123        addr: Address,
124        /// Whether the produced value from the negation should be kept or not.
125        out: Output,
126    },
127    /// Construct a closure that takes the given number of arguments and
128    /// captures `count` elements from the top of the stack.
129    ///
130    /// # Operation
131    ///
132    /// ```text
133    /// <value..>
134    /// => <fn>
135    /// ```
136    #[cfg_attr(feature = "musli", musli(packed))]
137    Closure {
138        /// The hash of the internally stored closure function.
139        hash: Hash,
140        /// Where to load captured values from.
141        addr: Address,
142        /// The number of captured values to store in the environment.
143        count: usize,
144        /// Where to store the produced closure.
145        out: Output,
146    },
147    /// Perform a function call within the same unit.
148    ///
149    /// It will construct a new stack frame which includes the last `args`
150    /// number of entries.
151    #[cfg_attr(feature = "musli", musli(packed))]
152    CallOffset {
153        /// The offset of the function being called in the same unit.
154        offset: usize,
155        /// The calling convention to use.
156        call: Call,
157        /// The address where the arguments are stored.
158        addr: Address,
159        /// The number of arguments passed in at `addr`.
160        args: usize,
161        /// Whether the return value should be kept or not.
162        out: Output,
163    },
164    /// Call a function by hash.
165    ///
166    /// The function will be looked up in the unit and context. The arguments
167    /// passed to the function call are stored at `addr`, where `size`
168    /// determines the number of arguments. The arguments will be dropped.
169    ///
170    /// The return value of the function call will be written to `out`.
171    #[cfg_attr(feature = "musli", musli(packed))]
172    Call {
173        /// The hash of the function to call.
174        hash: Hash,
175        /// The address of the arguments being passed.
176        addr: Address,
177        /// The number of arguments passed in at `addr`.
178        args: usize,
179        /// Whether the return value should be kept or not.
180        out: Output,
181    },
182    /// Call an associated function.
183    ///
184    /// The instance being called should be the the object at address `addr`.
185    /// The number of arguments specified should include this object.
186    ///
187    /// The return value of the function call will be written to `out`.
188    #[cfg_attr(feature = "musli", musli(packed))]
189    CallAssociated {
190        /// The hash of the name of the function to call.
191        hash: Hash,
192        /// The address of arguments being passed.
193        addr: Address,
194        /// The number of arguments passed in at `addr`.
195        args: usize,
196        /// Whether the return value should be kept or not.
197        out: Output,
198    },
199    /// Look up an instance function.
200    ///
201    /// The instance being used is stored at `addr`, and the function hash to look up is `hash`.
202    #[cfg_attr(feature = "musli", musli(packed))]
203    LoadInstanceFn {
204        /// The address of the instance for which the function is being loaded.
205        addr: Address,
206        /// The name hash of the instance function.
207        hash: Hash,
208        /// Where to store the loaded instance function.
209        out: Output,
210    },
211    /// Perform a function call on a function pointer stored on the stack.
212    ///
213    /// # Operation
214    ///
215    /// ```text
216    /// <fn>
217    /// <args...>
218    /// => <ret>
219    /// ```
220    #[cfg_attr(feature = "musli", musli(packed))]
221    CallFn {
222        /// The address of the function being called.
223        function: Address,
224        /// The address of the arguments being passed.
225        addr: Address,
226        /// The number of arguments passed in at `addr`.
227        args: usize,
228        /// Whether the returned value from calling the function should be kept
229        /// or not.
230        out: Output,
231    },
232    /// Perform an index get operation. Pushing the result on the stack.
233    ///
234    /// # Operation
235    ///
236    /// ```text
237    /// <target>
238    /// <index>
239    /// => <value>
240    /// ```
241    #[cfg_attr(feature = "musli", musli(packed))]
242    IndexGet {
243        /// How the target is addressed.
244        target: Address,
245        /// How the index is addressed.
246        index: Address,
247        /// Whether the produced value should be kept or not.
248        out: Output,
249    },
250    /// Set the given index of the tuple on the stack, with the given value.
251    ///
252    /// # Operation
253    ///
254    /// ```text
255    /// <value>
256    /// <tuple>
257    /// => *nothing*
258    /// ```
259    #[cfg_attr(feature = "musli", musli(packed))]
260    TupleIndexSet {
261        /// The object being assigned to.
262        target: Address,
263        /// The index to set.
264        index: usize,
265        /// The value being assigned.
266        value: Address,
267    },
268    /// Get the given index out of a tuple from the given variable slot.
269    /// Errors if the item doesn't exist or the item is not a tuple.
270    ///
271    /// # Operation
272    ///
273    /// ```text
274    /// => <value>
275    /// ```
276    #[cfg_attr(feature = "musli", musli(packed))]
277    TupleIndexGetAt {
278        /// The address where the tuple we are getting from is stored.
279        addr: Address,
280        /// The index to fetch.
281        index: usize,
282        /// Whether the produced value should be kept or not.
283        out: Output,
284    },
285    /// Set the given index out of an object on the top of the stack.
286    /// Errors if the item doesn't exist or the item is not an object.
287    ///
288    /// The index is identifier by a static string slot, which is provided as an
289    /// argument.
290    ///
291    /// # Operation
292    ///
293    /// ```text
294    /// <object>
295    /// <value>
296    /// =>
297    /// ```
298    #[cfg_attr(feature = "musli", musli(packed))]
299    ObjectIndexSet {
300        /// The object being assigned to.
301        target: Address,
302        /// The static string slot corresponding to the index to set.
303        slot: usize,
304        /// The value being assigned.
305        value: Address,
306    },
307    /// Get the given index out of an object from the given variable slot.
308    /// Errors if the item doesn't exist or the item is not an object.
309    ///
310    /// The index is identifier by a static string slot, which is provided as an
311    /// argument.
312    ///
313    /// # Operation
314    ///
315    /// ```text
316    /// => <value>
317    /// ```
318    #[cfg_attr(feature = "musli", musli(packed))]
319    ObjectIndexGetAt {
320        /// The address where the object is stored.
321        addr: Address,
322        /// The static string slot corresponding to the index to fetch.
323        slot: usize,
324        /// Where to store the fetched value.
325        out: Output,
326    },
327    /// Perform an index set operation.
328    ///
329    /// # Operation
330    ///
331    /// ```text
332    /// <target>
333    /// <index>
334    /// <value>
335    /// => *noop*
336    /// ```
337    IndexSet {
338        /// The object being assigned to.
339        target: Address,
340        /// The index to set.
341        index: Address,
342        /// The value being assigned.
343        value: Address,
344    },
345    /// Await the future that is on the stack and push the value that it
346    /// produces.
347    ///
348    /// # Operation
349    ///
350    /// ```text
351    /// <future>
352    /// => <value>
353    /// ```
354    Await {
355        /// Address of the future being awaited.
356        addr: Address,
357        /// Whether the produced value from the await should be kept or not.
358        out: Output,
359    },
360    /// Select over `len` futures stored at address `addr`.
361    ///
362    /// Once a branch has been matched, will store the branch that matched in
363    /// the branch register and perform a jump by the index of the branch that
364    /// matched.
365    ///
366    /// Will also store the output if the future into `value`. If no branch
367    /// matched, the empty value will be stored.
368    #[cfg_attr(feature = "musli", musli(packed))]
369    Select {
370        /// The base address of futures being waited on.
371        addr: Address,
372        /// The number of futures to poll.
373        len: usize,
374        /// Where to store the value produced by the future that completed.
375        value: Output,
376    },
377    /// Load the given function by hash and push onto the stack.
378    ///
379    /// # Operation
380    ///
381    /// ```text
382    /// => <value>
383    /// ```
384    #[cfg_attr(feature = "musli", musli(packed))]
385    LoadFn {
386        /// The hash of the function to push.
387        hash: Hash,
388        /// Where to store the loaded function.
389        out: Output,
390    },
391    /// Push a value onto the stack.
392    ///
393    /// # Operation
394    ///
395    /// ```text
396    /// => <value>
397    /// ```
398    #[cfg_attr(feature = "musli", musli(packed))]
399    Store {
400        /// The value to push.
401        value: InstValue,
402        /// Where the value is being copied to.
403        out: Output,
404    },
405    /// Copy a variable from a location `offset` relative to the current call
406    /// frame.
407    ///
408    /// A copy is very cheap. It simply means pushing a reference to the stack.
409    #[cfg_attr(feature = "musli", musli(packed))]
410    Copy {
411        /// Address of the value being copied.
412        addr: Address,
413        /// Where the value is being copied to.
414        out: Output,
415    },
416    /// Move a variable from a location `offset` relative to the current call
417    /// frame.
418    #[cfg_attr(feature = "musli", musli(packed))]
419    Move {
420        /// Address of the value being moved.
421        addr: Address,
422        /// Where the value is being moved to.
423        out: Output,
424    },
425    /// Drop the given value set.
426    #[cfg_attr(feature = "musli", musli(packed))]
427    Drop {
428        /// An indicator of the set of addresses to drop.
429        set: usize,
430    },
431    /// Swap two values on the stack using their offsets relative to the current
432    /// stack frame.
433    #[cfg_attr(feature = "musli", musli(packed))]
434    Swap {
435        /// Offset to the first value.
436        a: Address,
437        /// Offset to the second value.
438        b: Address,
439    },
440    /// Pop the current stack frame and restore the instruction pointer from it.
441    ///
442    /// The stack frame will be cleared, and the value on the top of the stack
443    /// will be left on top of it.
444    #[cfg_attr(feature = "musli", musli(packed))]
445    Return {
446        /// The address of the value to return.
447        addr: Address,
448    },
449    /// Pop the current stack frame and restore the instruction pointer from it.
450    ///
451    /// The stack frame will be cleared, and a unit value will be pushed to the
452    /// top of the stack.
453    ReturnUnit,
454    /// Unconditionally jump to `offset` relative to the current instruction
455    /// pointer.
456    ///
457    /// # Operation
458    ///
459    /// ```text
460    /// *nothing*
461    /// => *nothing*
462    /// ```
463    #[cfg_attr(feature = "musli", musli(packed))]
464    Jump {
465        /// Offset to jump to.
466        jump: usize,
467    },
468    /// Jump to `offset` relative to the current instruction pointer if the
469    /// condition is `true`.
470    ///
471    /// # Operation
472    ///
473    /// ```text
474    /// <boolean>
475    /// => *nothing*
476    /// ```
477    #[cfg_attr(feature = "musli", musli(packed))]
478    JumpIf {
479        /// The address of the condition for the jump.
480        cond: Address,
481        /// Offset to jump to.
482        jump: usize,
483    },
484    /// Jump to the given offset If the top of the stack is false.
485    ///
486    /// # Operation
487    ///
488    /// ```text
489    /// <bool>
490    /// => *noop*
491    /// ```
492    #[cfg_attr(feature = "musli", musli(packed))]
493    JumpIfNot {
494        /// The address of the condition for the jump.
495        cond: Address,
496        /// The offset to jump if the condition is true.
497        jump: usize,
498    },
499    /// Construct a vector at `out`, populating it with `count` elements from
500    /// `addr`.
501    ///
502    /// The values at `addr` are dropped.
503    #[cfg_attr(feature = "musli", musli(packed))]
504    Vec {
505        /// Where the arguments to the vector are stored.
506        addr: Address,
507        /// The number of elements in the vector.
508        count: usize,
509        /// Where to store the produced vector.
510        out: Output,
511    },
512    /// Construct a one element tuple at `out`, populating it with `count`
513    /// elements from `addr`.
514    ///
515    /// The values at `addr` are not dropped.
516    #[cfg_attr(feature = "musli", musli(packed))]
517    Tuple1 {
518        /// Tuple arguments.
519        #[inst_display(display_with = DisplayArray::new)]
520        addr: [Address; 1],
521        /// Where to store the produced tuple.
522        out: Output,
523    },
524    /// Construct a two element tuple at `out`, populating it with `count`
525    /// elements from `addr`.
526    ///
527    /// The values at `addr` are not dropped.
528    #[cfg_attr(feature = "musli", musli(packed))]
529    Tuple2 {
530        /// Tuple arguments.
531        #[inst_display(display_with = DisplayArray::new)]
532        addr: [Address; 2],
533        /// Where to store the produced tuple.
534        out: Output,
535    },
536    /// Construct a three element tuple at `out`, populating it with `count`
537    /// elements from `addr`.
538    ///
539    /// The values at `addr` are not dropped.
540    #[cfg_attr(feature = "musli", musli(packed))]
541    Tuple3 {
542        /// Tuple arguments.
543        #[inst_display(display_with = DisplayArray::new)]
544        addr: [Address; 3],
545        /// Where to store the produced tuple.
546        out: Output,
547    },
548    /// Construct a four element tuple at `out`, populating it with `count`
549    /// elements from `addr`.
550    ///
551    /// The values at `addr` are not dropped.
552    #[cfg_attr(feature = "musli", musli(packed))]
553    Tuple4 {
554        /// Tuple arguments.
555        #[inst_display(display_with = DisplayArray::new)]
556        addr: [Address; 4],
557        /// Where to store the produced tuple.
558        out: Output,
559    },
560    /// Construct a tuple at `out`, populating it with `count` elements from
561    /// `addr`.
562    ///
563    /// Unlike `TupleN` variants, values at `addr` are dropped.
564    #[cfg_attr(feature = "musli", musli(packed))]
565    Tuple {
566        /// Where the arguments to the tuple are stored.
567        addr: Address,
568        /// The number of elements in the tuple.
569        count: usize,
570        /// Where to store the produced tuple.
571        out: Output,
572    },
573    /// Take the tuple that is on top of the stack and push its content onto the
574    /// stack.
575    ///
576    /// This is used to unpack an environment for closures - if the closure has
577    /// an environment.
578    ///
579    /// # Operation
580    ///
581    /// ```text
582    /// <tuple>
583    /// => <value...>
584    /// ```
585    Environment {
586        /// The tuple to push.
587        addr: Address,
588        /// The expected size of the tuple.
589        count: usize,
590        /// Where to unpack the environment.
591        out: Output,
592    },
593    /// Construct a push an object onto the stack. The number of elements
594    /// in the object are determined the slot of the object keys `slot` and are
595    /// popped from the stack.
596    ///
597    /// For each element, a value is popped corresponding to the object key.
598    ///
599    /// # Operation
600    ///
601    /// ```text
602    /// <value..>
603    /// => <object>
604    /// ```
605    #[cfg_attr(feature = "musli", musli(packed))]
606    Object {
607        /// Where the arguments to the tuple are stored.
608        addr: Address,
609        /// The static slot of the object keys.
610        slot: usize,
611        /// Where to store the produced tuple.
612        out: Output,
613    },
614    /// Construct a range.
615    ///
616    /// The arguments loaded are determined by the range being constructed.
617    #[cfg_attr(feature = "musli", musli(packed))]
618    Range {
619        /// The kind of the range, which determines the number arguments on the
620        /// stack.
621        range: InstRange,
622        /// Where to store the produced range.
623        out: Output,
624    },
625    /// Construct a struct of type `hash` at `out`, populating it with fields
626    /// from `addr`. The number of fields and their names is determined by the
627    /// `slot` being referenced.
628    ///
629    /// The values at `addr` are dropped.
630    #[cfg_attr(feature = "musli", musli(packed))]
631    Struct {
632        /// The address to load fields from.
633        addr: Address,
634        /// The type of the struct to construct.
635        hash: Hash,
636        /// Where to write the constructed struct.
637        out: Output,
638    },
639    /// Construct a struct from a constant.
640    ///
641    /// The values at `addr` are dropped.
642    #[cfg_attr(feature = "musli", musli(packed))]
643    ConstConstruct {
644        /// Where constructor arguments are stored.
645        addr: Address,
646        /// The type of the struct to construct.
647        hash: Hash,
648        /// The number of constructor arguments.
649        count: usize,
650        /// Where to write the constructed struct.
651        out: Output,
652    },
653    /// Load a literal string from a static string slot.
654    ///
655    /// # Operation
656    ///
657    /// ```text
658    /// => <string>
659    /// ```
660    #[cfg_attr(feature = "musli", musli(packed))]
661    String {
662        /// The static string slot to load the string from.
663        slot: usize,
664        /// Where to store the string.
665        out: Output,
666    },
667    /// Load a literal byte string from a static byte string slot.
668    ///
669    /// # Operation
670    ///
671    /// ```text
672    /// => <bytes>
673    /// ```
674    #[cfg_attr(feature = "musli", musli(packed))]
675    Bytes {
676        /// The static byte string slot to load the string from.
677        slot: usize,
678        /// Where to store the bytes.
679        out: Output,
680    },
681    /// Pop the given number of values from the stack, and concatenate a string
682    /// from them.
683    ///
684    /// This is a dedicated template-string optimization.
685    ///
686    /// # Operation
687    ///
688    /// ```text
689    /// <value...>
690    /// => <string>
691    /// ```
692    #[cfg_attr(feature = "musli", musli(packed))]
693    StringConcat {
694        /// Where the strings to concatenate are stored.
695        addr: Address,
696        /// The number of items to pop from the stack.
697        len: usize,
698        /// The minimum string size used.
699        size_hint: usize,
700        /// Where to store the produced string.
701        out: Output,
702    },
703    /// Push a combined format specification and value onto the stack. The value
704    /// used is the last value on the stack.
705    #[cfg_attr(feature = "musli", musli(packed))]
706    Format {
707        /// Address of the value being formatted.
708        addr: Address,
709        /// The format specification to use.
710        spec: FormatSpec,
711        /// Where to store the produced format.
712        out: Output,
713    },
714    /// Perform the try operation which takes the value at the given `address`
715    /// and tries to unwrap it or return from the current call frame.
716    ///
717    /// # Operation
718    ///
719    /// ```text
720    /// <value>
721    /// => <boolean>
722    /// ```
723    #[cfg_attr(feature = "musli", musli(packed))]
724    Try {
725        /// Address of value to try.
726        addr: Address,
727        /// Where to store the value in case there is a continuation.
728        out: Output,
729    },
730    /// Test if the top of the stack is a specific character.
731    ///
732    /// # Operation
733    ///
734    /// ```text
735    /// <value>
736    /// => <boolean>
737    /// ```
738    #[cfg_attr(feature = "musli", musli(packed))]
739    EqChar {
740        /// Address of the value to compare.
741        addr: Address,
742        /// The character to test against.
743        #[inst_display(display_with = DisplayDebug::new)]
744        value: char,
745        /// Where to store the result of the comparison.
746        out: Output,
747    },
748    /// Test if the specified value is a specific signed integer.
749    #[cfg_attr(feature = "musli", musli(packed))]
750    EqSigned {
751        /// Address of the value to compare.
752        addr: Address,
753        /// The value to test against.
754        value: i64,
755        /// Where to store the result of the comparison.
756        out: Output,
757    },
758    /// Test if the specified value is a specific unsigned integer.
759    #[cfg_attr(feature = "musli", musli(packed))]
760    EqUnsigned {
761        /// Address of the value to compare.
762        addr: Address,
763        /// The value to test against.
764        value: u64,
765        /// Where to store the result of the comparison.
766        out: Output,
767    },
768    /// Test if the top of the stack is a specific boolean.
769    ///
770    /// # Operation
771    ///
772    /// ```text
773    /// <value>
774    /// => <boolean>
775    /// ```
776    #[cfg_attr(feature = "musli", musli(packed))]
777    EqBool {
778        /// Address of the value to compare.
779        addr: Address,
780        /// The value to test against.
781        value: bool,
782        /// Where to store the result of the comparison.
783        out: Output,
784    },
785    /// Compare the top of the stack against a static string slot.
786    ///
787    /// # Operation
788    ///
789    /// ```text
790    /// <value>
791    /// => <boolean>
792    /// ```
793    #[cfg_attr(feature = "musli", musli(packed))]
794    EqString {
795        /// Address of the value to compare.
796        addr: Address,
797        /// The slot to test against.
798        slot: usize,
799        /// Where to store the result of the comparison.
800        out: Output,
801    },
802    /// Compare the top of the stack against a static bytes slot.
803    ///
804    /// # Operation
805    ///
806    /// ```text
807    /// <value>
808    /// => <boolean>
809    /// ```
810    #[cfg_attr(feature = "musli", musli(packed))]
811    EqBytes {
812        /// Address of the value to compare.
813        addr: Address,
814        /// The slot to test against.
815        slot: usize,
816        /// Where to store the result of the comparison.
817        out: Output,
818    },
819    /// Test if the specified type matches.
820    ///
821    /// # Operation
822    ///
823    /// ```text
824    /// <value>
825    /// => <boolean>
826    /// ```
827    #[cfg_attr(feature = "musli", musli(packed))]
828    MatchType {
829        /// The type hash to match against.
830        hash: Hash,
831        /// The variant hash to match against.
832        variant_hash: Hash,
833        /// The address of the value to test.
834        addr: Address,
835        /// Where to store the output.
836        out: Output,
837    },
838    /// Test that the top of the stack is a tuple with the given length
839    /// requirements.
840    ///
841    /// # Operation
842    ///
843    /// ```text
844    /// <value>
845    /// => <boolean>
846    /// ```
847    #[cfg_attr(feature = "musli", musli(packed))]
848    MatchSequence {
849        /// Type constraints that the sequence must match.
850        hash: Hash,
851        /// The minimum length to test for.
852        len: usize,
853        /// Whether the operation should check exact `true` or minimum length
854        /// `false`.
855        exact: bool,
856        /// The address of the value to test.
857        addr: Address,
858        /// Where to store the output.
859        out: Output,
860    },
861    /// Test that the top of the stack is an object matching the given slot of
862    /// object keys.
863    ///
864    /// # Operation
865    ///
866    /// ```text
867    /// <object>
868    /// => <boolean>
869    /// ```
870    #[cfg_attr(feature = "musli", musli(packed))]
871    MatchObject {
872        /// The slot of object keys to use.
873        slot: usize,
874        /// Whether the operation should check exact `true` or minimum length
875        /// `false`.
876        exact: bool,
877        /// The address of the value to test.
878        addr: Address,
879        /// Where to store the output.
880        out: Output,
881    },
882    /// Perform a generator yield where the value yielded is expected to be
883    /// found at the top of the stack.
884    ///
885    /// This causes the virtual machine to suspend itself.
886    ///
887    /// # Operation
888    ///
889    /// ```text
890    /// <value>
891    /// => <value>
892    /// ```
893    Yield {
894        /// Address of the value being yielded.
895        addr: Address,
896        /// Where to store the produced resume value.
897        out: Output,
898    },
899    /// Perform a generator yield with a unit.
900    ///
901    /// This causes the virtual machine to suspend itself.
902    ///
903    /// # Operation
904    ///
905    /// ```text
906    /// => <unit>
907    /// ```
908    YieldUnit {
909        /// Where to store the produced resume value.
910        out: Output,
911    },
912    /// An operation.
913    #[cfg_attr(feature = "musli", musli(packed))]
914    Op {
915        /// The kind of operation.
916        op: InstOp,
917        /// The address of the first argument.
918        a: Address,
919        /// The address of the second argument.
920        b: Address,
921        /// Whether the produced value from the operation should be kept or not.
922        out: Output,
923    },
924    /// An arithmetic operation.
925    #[cfg_attr(feature = "musli", musli(packed))]
926    Arithmetic {
927        /// The kind of operation.
928        op: InstArithmeticOp,
929        /// The address of the first argument.
930        a: Address,
931        /// The address of the second argument.
932        b: Address,
933        /// Whether the produced value from the operation should be kept or not.
934        out: Output,
935    },
936    /// A bitwise operation.
937    #[cfg_attr(feature = "musli", musli(packed))]
938    Bitwise {
939        /// The kind of operation.
940        op: InstBitwiseOp,
941        /// The address of the first argument.
942        a: Address,
943        /// The address of the second argument.
944        b: Address,
945        /// Whether the produced value from the operation should be kept or not.
946        out: Output,
947    },
948    /// A shift operation.
949    #[cfg_attr(feature = "musli", musli(packed))]
950    Shift {
951        /// The kind of operation.
952        op: InstShiftOp,
953        /// The address of the first argument.
954        a: Address,
955        /// The address of the second argument.
956        b: Address,
957        /// Whether the produced value from the operation should be kept or not.
958        out: Output,
959    },
960    /// Instruction for assigned arithmetic operations.
961    #[cfg_attr(feature = "musli", musli(packed))]
962    AssignArithmetic {
963        /// The kind of operation.
964        op: InstArithmeticOp,
965        /// The target of the operation.
966        target: InstTarget,
967        /// The value being assigned.
968        rhs: Address,
969    },
970    /// Instruction for assigned bitwise operations.
971    #[cfg_attr(feature = "musli", musli(packed))]
972    AssignBitwise {
973        /// The kind of operation.
974        op: InstBitwiseOp,
975        /// The target of the operation.
976        target: InstTarget,
977        /// The value being assigned.
978        rhs: Address,
979    },
980    /// Instruction for assigned shift operations.
981    #[cfg_attr(feature = "musli", musli(packed))]
982    AssignShift {
983        /// The kind of operation.
984        op: InstShiftOp,
985        /// The target of the operation.
986        target: InstTarget,
987        /// The value being assigned.
988        rhs: Address,
989    },
990    /// Advance an iterator at the given position.
991    #[cfg_attr(feature = "musli", musli(packed))]
992    IterNext {
993        /// The address of the iterator to advance.
994        addr: Address,
995        /// A relative jump to perform if the iterator could not be advanced.
996        jump: usize,
997        /// Where to store the produced value from the iterator.
998        out: Output,
999    },
1000    /// Cause the VM to panic and error out without a reason.
1001    ///
1002    /// This should only be used during testing or extreme scenarios that are
1003    /// completely unrecoverable.
1004    #[cfg_attr(feature = "musli", musli(packed))]
1005    Panic {
1006        /// The reason for the panic.
1007        #[inst_display(display_with = PanicReason::ident)]
1008        reason: PanicReason,
1009    },
1010}
1011
1012impl Kind {
1013    /// Construct an instruction to push a unit.
1014    pub(crate) fn unit(out: Output) -> Self {
1015        Self::Store {
1016            value: InstValue::Unit,
1017            out,
1018        }
1019    }
1020
1021    /// Construct an instruction to push a boolean.
1022    pub(crate) fn bool(b: bool, out: Output) -> Self {
1023        Self::Store {
1024            value: InstValue::Bool(b),
1025            out,
1026        }
1027    }
1028
1029    /// Construct an instruction to push a character.
1030    pub(crate) fn char(c: char, out: Output) -> Self {
1031        Self::Store {
1032            value: InstValue::Char(c),
1033            out,
1034        }
1035    }
1036
1037    /// Construct an instruction to push an integer.
1038    pub(crate) fn signed(v: i64, out: Output) -> Self {
1039        Self::Store {
1040            value: InstValue::Integer(v),
1041            out,
1042        }
1043    }
1044
1045    /// Construct an instruction to push an unsigned integer.
1046    pub(crate) fn unsigned(v: u64, out: Output) -> Self {
1047        Self::Store {
1048            value: InstValue::Unsigned(v),
1049            out,
1050        }
1051    }
1052
1053    /// Construct an instruction to push a float.
1054    pub(crate) fn float(v: f64, out: Output) -> Self {
1055        Self::Store {
1056            value: InstValue::Float(v),
1057            out,
1058        }
1059    }
1060
1061    /// Construct an instruction to push a type.
1062    pub(crate) fn ty(ty: Type, out: Output) -> Self {
1063        Self::Store {
1064            value: InstValue::Type(ty),
1065            out,
1066        }
1067    }
1068
1069    /// Construct an instruction to push an ordering.
1070    pub(crate) fn ordering(ordering: Ordering, out: Output) -> Self {
1071        Self::Store {
1072            value: InstValue::Ordering(ordering),
1073            out,
1074        }
1075    }
1076
1077    /// Construct an instruction to push a type hash.
1078    pub(crate) fn hash(hash: Hash, out: Output) -> Self {
1079        Self::Store {
1080            value: InstValue::Hash(hash),
1081            out,
1082        }
1083    }
1084}
1085
1086/// What to do with the output of an instruction.
1087#[derive(TryClone, Clone, Copy, PartialEq, Eq, Hash)]
1088#[try_clone(copy)]
1089#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
1090#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))]
1091pub struct Output {
1092    offset: usize,
1093}
1094
1095impl Output {
1096    /// Construct a keep output kind.
1097    #[inline]
1098    pub(crate) fn keep(offset: usize) -> Self {
1099        assert_ne!(offset, usize::MAX, "Address is invalid");
1100        Self { offset }
1101    }
1102
1103    /// Construct a discard output kind.
1104    #[inline]
1105    pub(crate) fn discard() -> Self {
1106        Self { offset: usize::MAX }
1107    }
1108
1109    /// Check if the output is a keep.
1110    #[inline(always)]
1111    pub(crate) fn as_addr(&self) -> Option<Address> {
1112        if self.offset == usize::MAX {
1113            None
1114        } else {
1115            Some(Address::new(self.offset))
1116        }
1117    }
1118}
1119
1120impl fmt::Display for Output {
1121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1122        if self.offset == usize::MAX {
1123            write!(f, "discard")
1124        } else {
1125            write!(f, "keep({})", self.offset)
1126        }
1127    }
1128}
1129
1130impl fmt::Debug for Output {
1131    #[inline]
1132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1133        fmt::Display::fmt(self, f)
1134    }
1135}
1136
1137/// How an instruction addresses a value.
1138#[derive(Default, TryClone, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
1139#[repr(transparent)]
1140#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
1141#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))]
1142#[try_clone(copy)]
1143pub struct Address {
1144    offset: usize,
1145}
1146
1147impl Address {
1148    /// The first possible address.
1149    pub const ZERO: Address = Address { offset: 0 };
1150
1151    /// An invalid address.
1152    pub const INVALID: Address = Address { offset: usize::MAX };
1153
1154    /// Construct a new address.
1155    #[inline]
1156    pub(crate) const fn new(offset: usize) -> Self {
1157        Self { offset }
1158    }
1159
1160    /// Get the offset of the address.
1161    #[inline]
1162    pub(crate) fn offset(self) -> usize {
1163        self.offset
1164    }
1165
1166    /// Get the address as an output.
1167    #[inline]
1168    pub(crate) fn output(self) -> Output {
1169        Output::keep(self.offset)
1170    }
1171}
1172
1173impl fmt::Display for Address {
1174    #[inline]
1175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1176        if self.offset == usize::MAX {
1177            write!(f, "invalid")
1178        } else {
1179            self.offset.fmt(f)
1180        }
1181    }
1182}
1183
1184impl fmt::Debug for Address {
1185    #[inline]
1186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1187        fmt::Display::fmt(self, f)
1188    }
1189}
1190
1191/// Range limits of a range expression.
1192#[derive(Debug, TryClone, Clone, Copy)]
1193#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1194#[cfg_attr(feature = "musli", derive(Decode, Encode))]
1195#[try_clone(copy)]
1196pub(crate) enum InstRange {
1197    /// `start..`.
1198    RangeFrom {
1199        /// The start address of the range.
1200        start: Address,
1201    },
1202    /// `..`.
1203    RangeFull,
1204    /// `start..=end`.
1205    RangeInclusive {
1206        /// The start address of the range.
1207        start: Address,
1208        /// The end address of the range.
1209        end: Address,
1210    },
1211    /// `..=end`.
1212    RangeToInclusive {
1213        /// The end address of the range.
1214        end: Address,
1215    },
1216    /// `..end`.
1217    RangeTo {
1218        /// The end address of the range.
1219        end: Address,
1220    },
1221    /// `start..end`.
1222    Range {
1223        /// The start address of the range.
1224        start: Address,
1225        /// The end address of the range.
1226        end: Address,
1227    },
1228}
1229
1230impl fmt::Display for InstRange {
1231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1232        match self {
1233            InstRange::RangeFrom { start } => write!(f, "{start}.."),
1234            InstRange::RangeFull => write!(f, ".."),
1235            InstRange::RangeInclusive { start, end } => write!(f, "{start}..={end}"),
1236            InstRange::RangeToInclusive { end } => write!(f, "..={end}"),
1237            InstRange::RangeTo { end } => write!(f, "..{end}"),
1238            InstRange::Range { start, end } => write!(f, "{start}..{end}"),
1239        }
1240    }
1241}
1242
1243/// The target of an operation.
1244#[derive(Debug, TryClone, Clone, Copy)]
1245#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1246#[cfg_attr(feature = "musli", derive(Decode, Encode))]
1247#[try_clone(copy)]
1248pub(crate) enum InstTarget {
1249    /// Target is an offset to the current call frame.
1250    #[cfg_attr(feature = "musli", musli(packed))]
1251    Address(Address),
1252    /// Target the field of an object.
1253    #[cfg_attr(feature = "musli", musli(packed))]
1254    Field(Address, usize),
1255    /// Target a tuple field.
1256    #[cfg_attr(feature = "musli", musli(packed))]
1257    TupleField(Address, usize),
1258}
1259
1260impl fmt::Display for InstTarget {
1261    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1262        match self {
1263            Self::Address(addr) => write!(f, "address({addr})"),
1264            Self::Field(addr, slot) => write!(f, "field({addr}, {slot})"),
1265            Self::TupleField(addr, slot) => write!(f, "tuple-field({addr}, {slot})"),
1266        }
1267    }
1268}
1269
1270/// An operation between two values on the machine.
1271#[derive(Debug, TryClone, Clone, Copy)]
1272#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1273#[cfg_attr(feature = "musli", derive(Decode, Encode))]
1274#[try_clone(copy)]
1275pub(crate) enum InstArithmeticOp {
1276    /// The add operation. `a + b`.
1277    Add,
1278    /// The sub operation. `a - b`.
1279    Sub,
1280    /// The multiply operation. `a * b`.
1281    Mul,
1282    /// The division operation. `a / b`.
1283    Div,
1284    /// The remainder operation. `a % b`.
1285    Rem,
1286}
1287
1288impl fmt::Display for InstArithmeticOp {
1289    #[inline]
1290    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1291        match self {
1292            Self::Add => {
1293                write!(f, "+")?;
1294            }
1295            Self::Sub => {
1296                write!(f, "-")?;
1297            }
1298            Self::Mul => {
1299                write!(f, "*")?;
1300            }
1301            Self::Div => {
1302                write!(f, "/")?;
1303            }
1304            Self::Rem => {
1305                write!(f, "%")?;
1306            }
1307        }
1308
1309        Ok(())
1310    }
1311}
1312
1313/// An operation between two values on the machine.
1314#[derive(Debug, TryClone, Clone, Copy)]
1315#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1316#[cfg_attr(feature = "musli", derive(Decode, Encode))]
1317#[try_clone(copy)]
1318pub(crate) enum InstBitwiseOp {
1319    /// The bitwise and operation. `a & b`.
1320    BitAnd,
1321    /// The bitwise xor operation. `a ^ b`.
1322    BitXor,
1323    /// The bitwise or operation. `a | b`.
1324    BitOr,
1325}
1326
1327impl fmt::Display for InstBitwiseOp {
1328    #[inline]
1329    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1330        match self {
1331            Self::BitAnd => {
1332                write!(f, "&")?;
1333            }
1334            Self::BitXor => {
1335                write!(f, "^")?;
1336            }
1337            Self::BitOr => {
1338                write!(f, "|")?;
1339            }
1340        }
1341
1342        Ok(())
1343    }
1344}
1345
1346/// An operation between two values on the machine.
1347#[derive(Debug, TryClone, Clone, Copy)]
1348#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1349#[cfg_attr(feature = "musli", derive(Decode, Encode))]
1350#[try_clone(copy)]
1351pub(crate) enum InstShiftOp {
1352    /// The shift left operation. `a << b`.
1353    Shl,
1354    /// The shift right operation. `a << b`.
1355    Shr,
1356}
1357
1358impl fmt::Display for InstShiftOp {
1359    #[inline]
1360    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1361        match self {
1362            Self::Shl => {
1363                write!(f, "<<")?;
1364            }
1365            Self::Shr => {
1366                write!(f, ">>")?;
1367            }
1368        }
1369
1370        Ok(())
1371    }
1372}
1373
1374/// An operation between two values on the machine.
1375#[derive(Debug, TryClone, Clone, Copy)]
1376#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1377#[cfg_attr(feature = "musli", derive(Decode, Encode))]
1378#[try_clone(copy)]
1379pub(crate) enum InstOp {
1380    /// Compare two values on the stack for lt and push the result as a
1381    /// boolean on the stack.
1382    Lt,
1383    /// Compare two values on the stack for lte and push the result as a
1384    /// boolean on the stack.
1385    Le,
1386    /// Compare two values on the stack for gt and push the result as a
1387    /// boolean on the stack.
1388    Gt,
1389    /// Compare two values on the stack for gte and push the result as a
1390    /// boolean on the stack.
1391    Ge,
1392    /// Compare two values on the stack for equality and push the result as a
1393    /// boolean on the stack.
1394    ///
1395    /// # Operation
1396    ///
1397    /// ```text
1398    /// <b>
1399    /// <a>
1400    /// => <bool>
1401    /// ```
1402    Eq,
1403    /// Compare two values on the stack for inequality and push the result as a
1404    /// boolean on the stack.
1405    ///
1406    /// # Operation
1407    ///
1408    /// ```text
1409    /// <b>
1410    /// <a>
1411    /// => <bool>
1412    /// ```
1413    Neq,
1414    /// Coerce a value into the given type.
1415    ///
1416    /// # Operation
1417    ///
1418    /// ```text
1419    /// <type>
1420    /// <value>
1421    /// => <boolean>
1422    /// ```
1423    As,
1424    /// Test if the top of the stack is an instance of the second item on the
1425    /// stack.
1426    ///
1427    /// # Operation
1428    ///
1429    /// ```text
1430    /// <type>
1431    /// <value>
1432    /// => <boolean>
1433    /// ```
1434    Is,
1435    /// Test if the top of the stack is not an instance of the second item on
1436    /// the stack.
1437    ///
1438    /// # Operation
1439    ///
1440    /// ```text
1441    /// <type>
1442    /// <value>
1443    /// => <boolean>
1444    /// ```
1445    IsNot,
1446    /// Pop two values from the stack and test if they are both boolean true.
1447    ///
1448    /// # Operation
1449    ///
1450    /// ```text
1451    /// <boolean>
1452    /// <boolean>
1453    /// => <boolean>
1454    /// ```
1455    And,
1456    /// Pop two values from the stack and test if either of them are boolean
1457    /// true.
1458    ///
1459    /// # Operation
1460    ///
1461    /// ```text
1462    /// <boolean>
1463    /// <boolean>
1464    /// => <boolean>
1465    /// ```
1466    Or,
1467}
1468
1469impl fmt::Display for InstOp {
1470    #[inline]
1471    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1472        match self {
1473            Self::Lt => {
1474                write!(f, "<")?;
1475            }
1476            Self::Gt => {
1477                write!(f, ">")?;
1478            }
1479            Self::Le => {
1480                write!(f, "<=")?;
1481            }
1482            Self::Ge => {
1483                write!(f, ">=")?;
1484            }
1485            Self::Eq => {
1486                write!(f, "==")?;
1487            }
1488            Self::Neq => {
1489                write!(f, "!=")?;
1490            }
1491            Self::As => {
1492                write!(f, "as")?;
1493            }
1494            Self::Is => {
1495                write!(f, "is")?;
1496            }
1497            Self::IsNot => {
1498                write!(f, "is not")?;
1499            }
1500            Self::And => {
1501                write!(f, "&&")?;
1502            }
1503            Self::Or => {
1504                write!(f, "||")?;
1505            }
1506        }
1507
1508        Ok(())
1509    }
1510}
1511
1512/// A literal value that can be pushed.
1513#[derive(Debug, TryClone, Clone, Copy)]
1514#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1515#[cfg_attr(feature = "musli", derive(Decode, Encode))]
1516#[try_clone(copy)]
1517pub(crate) enum InstValue {
1518    /// An empty tuple.
1519    Unit,
1520    /// A boolean.
1521    #[cfg_attr(feature = "musli", musli(packed))]
1522    Bool(bool),
1523    /// A character.
1524    #[cfg_attr(feature = "musli", musli(packed))]
1525    Char(char),
1526    /// An unsigned integer.
1527    #[cfg_attr(feature = "musli", musli(packed))]
1528    Unsigned(u64),
1529    /// An integer.
1530    #[cfg_attr(feature = "musli", musli(packed))]
1531    Integer(i64),
1532    /// A float.
1533    #[cfg_attr(feature = "musli", musli(packed))]
1534    Float(f64),
1535    /// A type hash.
1536    #[cfg_attr(feature = "musli", musli(packed))]
1537    Type(Type),
1538    /// An ordering.
1539    Ordering(
1540        #[cfg_attr(feature = "musli", musli(with = crate::musli::ordering))]
1541        #[cfg_attr(feature = "serde", serde(with = "crate::serde::ordering"))]
1542        Ordering,
1543    ),
1544    /// A hash.
1545    #[cfg_attr(feature = "musli", musli(packed))]
1546    Hash(Hash),
1547}
1548
1549impl InstValue {
1550    /// Convert into a value that can be pushed onto the stack.
1551    pub(crate) fn into_value(self) -> Value {
1552        match self {
1553            Self::Unit => Value::unit(),
1554            Self::Bool(v) => Value::from(v),
1555            Self::Char(v) => Value::from(v),
1556            Self::Unsigned(v) => Value::from(v),
1557            Self::Integer(v) => Value::from(v),
1558            Self::Float(v) => Value::from(v),
1559            Self::Type(v) => Value::from(v),
1560            Self::Ordering(v) => Value::from(v),
1561            Self::Hash(v) => Value::from(v),
1562        }
1563    }
1564}
1565
1566impl fmt::Display for InstValue {
1567    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1568        match self {
1569            Self::Unit => write!(f, "()")?,
1570            Self::Bool(v) => write!(f, "{v}")?,
1571            Self::Char(v) => write!(f, "{v:?}")?,
1572            Self::Unsigned(v) => write!(f, "{v}u64")?,
1573            Self::Integer(v) => write!(f, "{v}i64")?,
1574            Self::Float(v) => write!(f, "{v}")?,
1575            Self::Type(v) => write!(f, "{}", v.into_hash())?,
1576            Self::Ordering(v) => write!(f, "{v:?}")?,
1577            Self::Hash(v) => write!(f, "{v:?}")?,
1578        }
1579
1580        Ok(())
1581    }
1582}
1583
1584#[repr(transparent)]
1585struct DisplayArray<T>(T)
1586where
1587    T: ?Sized;
1588
1589impl<T> DisplayArray<[T]> {
1590    #[inline]
1591    fn new(value: &[T]) -> &Self {
1592        // SAFETY: The `DisplayArray` struct is a transparent wrapper around the
1593        // value.
1594        unsafe { &*(value as *const [T] as *const Self) }
1595    }
1596}
1597
1598impl<T> fmt::Display for DisplayArray<[T]>
1599where
1600    T: fmt::Display,
1601{
1602    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1603        let mut it = self.0.iter();
1604
1605        write!(f, "[")?;
1606        let last = it.next_back();
1607
1608        for value in it {
1609            write!(f, "{value}, ")?;
1610        }
1611
1612        if let Some(last) = last {
1613            last.fmt(f)?;
1614        }
1615
1616        write!(f, "]")?;
1617        Ok(())
1618    }
1619}
1620
1621#[repr(transparent)]
1622struct DisplayDebug<T>(T)
1623where
1624    T: ?Sized;
1625
1626impl<T> DisplayDebug<T>
1627where
1628    T: ?Sized,
1629{
1630    #[inline]
1631    fn new(value: &T) -> &Self {
1632        // SAFETY: The `DisplayDebug` struct is a transparent wrapper around the
1633        // value.
1634        unsafe { &*(value as *const T as *const Self) }
1635    }
1636}
1637
1638impl<T> fmt::Display for DisplayDebug<T>
1639where
1640    T: ?Sized + fmt::Debug,
1641{
1642    #[inline]
1643    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1644        fmt::Debug::fmt(&self.0, f)
1645    }
1646}