rune/runtime/
inst.rs

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