rune/runtime/
label.rs

1//! A simple label used to jump to a code location.
2
3use core::cell::Cell;
4use core::fmt;
5use core::num::NonZeroUsize;
6
7use crate as rune;
8use crate::alloc::borrow::Cow;
9use crate::alloc::prelude::*;
10use rust_alloc::rc::Rc;
11
12#[cfg(feature = "musli")]
13use musli::{Decode, Encode};
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Serialize};
16
17/// A label that can be jumped to.
18#[derive(Debug, TryClone)]
19pub(crate) struct Label {
20    pub(crate) name: &'static str,
21    pub(crate) index: usize,
22    #[try_clone(with = Rc::clone)]
23    jump: Rc<Cell<Option<NonZeroUsize>>>,
24}
25
26impl Label {
27    /// Construct a new label.
28    #[inline]
29    pub(crate) fn new(name: &'static str, index: usize) -> Self {
30        Self {
31            name,
32            index,
33            jump: Rc::new(Cell::new(None)),
34        }
35    }
36
37    /// Get jump.
38    #[inline]
39    pub(crate) fn jump(&self) -> Option<usize> {
40        Some(self.jump.get()?.get().wrapping_sub(1))
41    }
42
43    /// Set jump.
44    #[inline]
45    pub(crate) fn set_jump(&self, jump: usize) -> bool {
46        let Some(jump) = NonZeroUsize::new(jump.wrapping_add(1)) else {
47            return false;
48        };
49
50        self.jump.replace(Some(jump));
51        true
52    }
53
54    /// Convert into owned label.
55    #[inline]
56    pub(crate) fn to_debug_label(&self) -> DebugLabel {
57        DebugLabel {
58            name: self.name.into(),
59            index: self.index,
60            jump: self.jump.get(),
61        }
62    }
63}
64
65impl fmt::Display for Label {
66    #[inline]
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        if let Some(jump) = self.jump() {
69            write!(f, "{}_{} ({jump})", self.name, self.index)
70        } else {
71            write!(f, "{}_{}", self.name, self.index)
72        }
73    }
74}
75
76/// A label that can be jumped to.
77#[derive(Debug, TryClone, PartialEq, Eq, Hash)]
78#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
79#[cfg_attr(feature = "musli", derive(Encode, Decode))]
80pub struct DebugLabel {
81    /// The name of the label.
82    name: Cow<'static, str>,
83    /// The index of the label.
84    index: usize,
85    /// The jump index of the label.
86    jump: Option<NonZeroUsize>,
87}
88
89impl DebugLabel {
90    /// Get jump.
91    #[inline]
92    pub(crate) fn jump(&self) -> Option<usize> {
93        Some(self.jump?.get().wrapping_sub(1))
94    }
95}
96
97impl fmt::Display for DebugLabel {
98    #[inline]
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100        write!(f, "{}_{}", self.name, self.index)?;
101
102        if let Some(jump) = self.jump() {
103            write!(f, " ({jump})")?;
104        }
105
106        Ok(())
107    }
108}