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}