rune/runtime/
control_flow.rs

1use core::ops;
2
3use crate as rune;
4use crate::alloc;
5use crate::alloc::clone::TryClone;
6use crate::alloc::fmt::TryWrite;
7use crate::Any;
8
9use super::{
10    EnvProtocolCaller, Formatter, FromValue, ProtocolCaller, RuntimeError, ToValue, Value, VmError,
11};
12
13/// Used to tell an operation whether it should exit early or go on as usual.
14///
15/// This acts as the basis of the [`TRY`] protocol in Rune.
16///
17/// [`TRY`]: crate::runtime::Protocol::TRY
18///
19/// # Examples
20///
21/// ```rune
22/// use std::ops::ControlFlow;
23///
24/// let c = ControlFlow::Continue(42);
25/// assert_eq!(c.0, 42);
26/// assert_eq!(c, ControlFlow::Continue(42));
27/// ```
28#[derive(Debug, Clone, TryClone, Any)]
29#[try_clone(crate)]
30#[rune(item = ::std::ops)]
31pub enum ControlFlow {
32    /// Move on to the next phase of the operation as normal.
33    #[rune(constructor)]
34    Continue(#[rune(get, set)] Value),
35    /// Exit the operation without running subsequent phases.
36    #[rune(constructor)]
37    Break(#[rune(get, set)] Value),
38}
39
40impl ControlFlow {
41    /// Test two control flows for partial equality.
42    ///
43    /// # Examples
44    ///
45    /// ```rune
46    /// use std::ops::{partial_eq, ControlFlow};
47    ///
48    /// assert_eq! {
49    ///     partial_eq(ControlFlow::Continue(true), ControlFlow::Continue(true)),
50    ///     true
51    /// };
52    /// assert_eq! {
53    ///     partial_eq(ControlFlow::Continue(true), ControlFlow::Break(false)),
54    ///     false
55    /// };
56    /// assert_eq! {
57    ///     partial_eq(ControlFlow::Break(false), ControlFlow::Continue(true)),
58    ///     false
59    /// };
60    /// ```
61    #[rune::function(keep, protocol = PARTIAL_EQ)]
62    pub(crate) fn partial_eq(&self, other: &Self) -> Result<bool, VmError> {
63        Self::partial_eq_with(self, other, &mut EnvProtocolCaller)
64    }
65
66    pub(crate) fn partial_eq_with(
67        &self,
68        other: &Self,
69        caller: &mut dyn ProtocolCaller,
70    ) -> Result<bool, VmError> {
71        match (self, other) {
72            (ControlFlow::Continue(a), ControlFlow::Continue(b)) => {
73                Value::partial_eq_with(a, b, caller)
74            }
75            (ControlFlow::Break(a), ControlFlow::Break(b)) => Value::partial_eq_with(a, b, caller),
76            _ => Ok(false),
77        }
78    }
79
80    /// Test two control flows for total equality.
81    ///
82    /// # Examples
83    ///
84    /// ```rune
85    /// use std::ops::{eq, ControlFlow};
86    ///
87    /// assert_eq! {
88    ///     eq(ControlFlow::Continue(true), ControlFlow::Continue(true)),
89    ///     true
90    /// };
91    /// assert_eq! {
92    ///     eq(ControlFlow::Continue(true), ControlFlow::Break(false)),
93    ///     false
94    /// };
95    /// assert_eq! {
96    ///     eq(ControlFlow::Break(false), ControlFlow::Continue(true)),
97    ///     false
98    /// };
99    /// ```
100    #[rune::function(keep, protocol = EQ)]
101    pub(crate) fn eq(&self, other: &ControlFlow) -> Result<bool, VmError> {
102        self.eq_with(other, &mut EnvProtocolCaller)
103    }
104
105    pub(crate) fn eq_with(
106        &self,
107        other: &ControlFlow,
108        caller: &mut dyn ProtocolCaller,
109    ) -> Result<bool, VmError> {
110        match (self, other) {
111            (ControlFlow::Continue(a), ControlFlow::Continue(b)) => Value::eq_with(a, b, caller),
112            (ControlFlow::Break(a), ControlFlow::Break(b)) => Value::eq_with(a, b, caller),
113            _ => Ok(false),
114        }
115    }
116
117    /// Debug print the control flow.
118    ///
119    /// # Examples
120    ///
121    /// ```rune
122    /// use std::ops::ControlFlow;
123    ///
124    /// let string = format!("{:?}", ControlFlow::Continue(true));
125    /// ```
126    #[rune::function(keep, protocol = DEBUG_FMT)]
127    pub(crate) fn debug_fmt(&self, f: &mut Formatter) -> Result<(), VmError> {
128        Self::debug_fmt_with(self, f, &mut EnvProtocolCaller)
129    }
130
131    pub(crate) fn debug_fmt_with(
132        &self,
133        f: &mut Formatter,
134        caller: &mut dyn ProtocolCaller,
135    ) -> Result<(), VmError> {
136        match self {
137            ControlFlow::Continue(value) => {
138                write!(f, "Continue(")?;
139                Value::debug_fmt_with(value, f, caller)?;
140                write!(f, ")")?;
141            }
142            ControlFlow::Break(value) => {
143                write!(f, "Break(")?;
144                Value::debug_fmt_with(value, f, caller)?;
145                write!(f, ")")?;
146            }
147        }
148
149        Ok(())
150    }
151
152    /// Clone the control flow.
153    ///
154    /// # Examples
155    ///
156    /// ```rune
157    /// use std::ops::ControlFlow;
158    ///
159    /// let flow = ControlFlow::Continue("Hello World");
160    /// let flow2 = flow.clone();
161    ///
162    /// assert_eq!(flow, flow2);
163    /// ```
164    #[rune::function(keep, protocol = CLONE)]
165    pub(crate) fn clone(&self) -> alloc::Result<Self> {
166        self.try_clone()
167    }
168}
169
170impl<B, C> ToValue for ops::ControlFlow<B, C>
171where
172    B: ToValue,
173    C: ToValue,
174{
175    #[inline]
176    fn to_value(self) -> Result<Value, RuntimeError> {
177        let value = match self {
178            ops::ControlFlow::Continue(value) => ControlFlow::Continue(C::to_value(value)?),
179            ops::ControlFlow::Break(value) => ControlFlow::Break(B::to_value(value)?),
180        };
181
182        Ok(Value::try_from(value)?)
183    }
184}
185
186impl<B, C> FromValue for ops::ControlFlow<B, C>
187where
188    B: FromValue,
189    C: FromValue,
190{
191    #[inline]
192    fn from_value(value: Value) -> Result<Self, RuntimeError> {
193        Ok(match &*value.borrow_ref::<ControlFlow>()? {
194            ControlFlow::Continue(value) => {
195                ops::ControlFlow::Continue(C::from_value(value.clone())?)
196            }
197            ControlFlow::Break(value) => ops::ControlFlow::Break(B::from_value(value.clone())?),
198        })
199    }
200}