diff --git a/crates/rune/src/modules/ops.rs b/crates/rune/src/modules/ops.rs index 3ed055811..b51055214 100644 --- a/crates/rune/src/modules/ops.rs +++ b/crates/rune/src/modules/ops.rs @@ -179,6 +179,17 @@ pub fn module() -> Result { { m.ty::()?; + + m.function_meta(ControlFlow::partial_eq__meta)?; + m.implement_trait::(rune::item!(::std::cmp::PartialEq))?; + + m.function_meta(ControlFlow::eq__meta)?; + m.implement_trait::(rune::item!(::std::cmp::Eq))?; + + m.function_meta(ControlFlow::string_debug__meta)?; + + m.function_meta(ControlFlow::clone__meta)?; + m.implement_trait::(rune::item!(::std::clone::Clone))?; } m.ty::()?; diff --git a/crates/rune/src/runtime/control_flow.rs b/crates/rune/src/runtime/control_flow.rs index 39af9a2e2..888371457 100644 --- a/crates/rune/src/runtime/control_flow.rs +++ b/crates/rune/src/runtime/control_flow.rs @@ -1,10 +1,12 @@ use core::ops; +use crate as rune; use crate::alloc::clone::TryClone; use crate::alloc::fmt::TryWrite; -use crate::runtime::{Formatter, FromValue, ProtocolCaller, ToValue, Value, VmResult}; use crate::Any; +use super::{EnvProtocolCaller, Formatter, FromValue, ProtocolCaller, ToValue, Value, VmResult}; + /// Used to tell an operation whether it should exit early or go on as usual. /// /// This acts as the basis of the [`TRY`] protocol in Rune. @@ -21,9 +23,8 @@ use crate::Any; /// assert_eq!(c, ControlFlow::Continue(42)); /// ``` #[derive(Debug, Clone, TryClone, Any)] -#[rune(crate)] #[try_clone(crate)] -#[rune(builtin, static_type = CONTROL_FLOW)] +#[rune(static_type = CONTROL_FLOW)] pub enum ControlFlow { /// Move on to the next phase of the operation as normal. #[rune(constructor)] @@ -34,25 +35,29 @@ pub enum ControlFlow { } impl ControlFlow { - pub(crate) fn string_debug_with( - &self, - f: &mut Formatter, - caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { - match self { - ControlFlow::Continue(value) => { - vm_try!(vm_write!(f, "Continue(")); - vm_try!(Value::string_debug_with(value, f, caller)); - vm_try!(vm_write!(f, ")")); - } - ControlFlow::Break(value) => { - vm_try!(vm_write!(f, "Break(")); - vm_try!(Value::string_debug_with(value, f, caller)); - vm_try!(vm_write!(f, ")")); - } - } - - VmResult::Ok(()) + /// Test two control flows for partial equality. + /// + /// # Examples + /// + /// ```rune + /// use std::ops::partial_eq; + /// + /// assert_eq! { + /// partial_eq(ControlFlow::Continue(true), ControlFlow::Continue(true)), + /// true + /// }; + /// assert_eq! { + /// partial_eq(ControlFlow::Continue(true), ControlFlow::Break(false)), + /// false + /// }; + /// assert_eq! { + /// partial_eq(ControlFlow::Break(false), ControlFlow::Continue(true)), + /// false + /// }; + /// ``` + #[rune::function(keep, protocol = PARTIAL_EQ)] + pub(crate) fn partial_eq(&self, other: &Self) -> VmResult { + Self::partial_eq_with(self, other, &mut EnvProtocolCaller) } pub(crate) fn partial_eq_with( @@ -69,6 +74,31 @@ impl ControlFlow { } } + /// Test two control flows for total equality. + /// + /// # Examples + /// + /// ```rune + /// use std::ops::eq; + /// + /// assert_eq! { + /// eq(ControlFlow::Continue(true), ControlFlow::Continue(true)), + /// true + /// }; + /// assert_eq! { + /// eq(ControlFlow::Continue(true), ControlFlow::Break(false)), + /// false + /// }; + /// assert_eq! { + /// eq(ControlFlow::Break(false), ControlFlow::Continue(true)), + /// false + /// }; + /// ``` + #[rune::function(keep, protocol = EQ)] + pub(crate) fn eq(&self, other: &ControlFlow) -> VmResult { + self.eq_with(other, &mut EnvProtocolCaller) + } + pub(crate) fn eq_with( &self, other: &ControlFlow, @@ -80,14 +110,55 @@ impl ControlFlow { _ => VmResult::Ok(false), } } -} -from_value2!( - ControlFlow, - into_control_flow_ref, - into_control_flow_mut, - into_control_flow -); + /// Debug print the control flow. + /// + /// # Examples + /// + /// ```rune + /// let string = format!("{:?}", ControlFlow::Continue(true)); + /// ``` + #[rune::function(keep, protocol = STRING_DEBUG)] + pub(crate) fn string_debug(&self, f: &mut Formatter) -> VmResult<()> { + Self::string_debug_with(self, f, &mut EnvProtocolCaller) + } + + pub(crate) fn string_debug_with( + &self, + f: &mut Formatter, + caller: &mut dyn ProtocolCaller, + ) -> VmResult<()> { + match self { + ControlFlow::Continue(value) => { + vm_try!(vm_write!(f, "Continue(")); + vm_try!(Value::string_debug_with(value, f, caller)); + vm_try!(vm_write!(f, ")")); + } + ControlFlow::Break(value) => { + vm_try!(vm_write!(f, "Break(")); + vm_try!(Value::string_debug_with(value, f, caller)); + vm_try!(vm_write!(f, ")")); + } + } + + VmResult::Ok(()) + } + + /// Clone the control flow. + /// + /// # Examples + /// + /// ```rune + /// let flow = ControlFlow::Continue("Hello World"); + /// let flow2 = flow.clone(); + /// + /// assert_eq!(flow, flow2); + /// ``` + #[rune::function(keep, protocol = CLONE)] + pub(crate) fn clone(&self) -> VmResult { + VmResult::Ok(vm_try!(self.try_clone())) + } +} impl ToValue for ops::ControlFlow where @@ -114,11 +185,13 @@ where { #[inline] fn from_value(value: Value) -> VmResult { - VmResult::Ok(match vm_try!(value.into_control_flow()) { + VmResult::Ok(match &*vm_try!(value.borrow_ref::()) { ControlFlow::Continue(value) => { - ops::ControlFlow::Continue(vm_try!(C::from_value(value))) + ops::ControlFlow::Continue(vm_try!(C::from_value(value.clone()))) + } + ControlFlow::Break(value) => { + ops::ControlFlow::Break(vm_try!(B::from_value(value.clone()))) } - ControlFlow::Break(value) => ops::ControlFlow::Break(vm_try!(B::from_value(value))), }) } } diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index 6d59f265c..56e2a9ea3 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -414,7 +414,6 @@ impl Value { Mutable::Vec(value) => Mutable::Vec(vm_try!(value.try_clone())), Mutable::Tuple(value) => Mutable::Tuple(vm_try!(value.try_clone())), Mutable::Object(value) => Mutable::Object(vm_try!(value.try_clone())), - Mutable::ControlFlow(value) => Mutable::ControlFlow(vm_try!(value.try_clone())), Mutable::Stream(value) => Mutable::Stream(vm_try!(value.try_clone())), Mutable::Generator(value) => Mutable::Generator(vm_try!(value.try_clone())), Mutable::GeneratorState(value) => { @@ -492,9 +491,6 @@ impl Value { Mutable::Object(value) => { vm_try!(vm_write!(f, "{value:?}")); } - Mutable::ControlFlow(value) => { - vm_try!(ControlFlow::string_debug_with(value, f, caller)); - } Mutable::Future(value) => { vm_try!(vm_write!(f, "{value:?}")); } @@ -821,16 +817,6 @@ impl Value { into_vec, } - into! { - /// Coerce into a [`ControlFlow`]. - ControlFlow(ControlFlow), - into_control_flow_ref, - into_control_flow_mut, - borrow_control_flow_ref, - borrow_control_flow_mut, - into_control_flow, - } - into! { /// Coerce into a [`Function`]. Function(Function), @@ -1142,9 +1128,6 @@ impl Value { }); } (BorrowRefRepr::Mutable(a), BorrowRefRepr::Mutable(b2)) => match (&**a, &*b2) { - (Mutable::ControlFlow(a), Mutable::ControlFlow(b)) => { - return ControlFlow::partial_eq_with(a, b, caller); - } (Mutable::EmptyStruct(a), Mutable::EmptyStruct(b)) => { if a.rtti.hash == b.rtti.hash { // NB: don't get any future ideas, this must fall through to @@ -1336,9 +1319,6 @@ impl Value { (Mutable::Object(a), Mutable::Object(b)) => { return Object::eq_with(a, b, Value::eq_with, caller); } - (Mutable::ControlFlow(a), Mutable::ControlFlow(b)) => { - return ControlFlow::eq_with(a, b, caller); - } (Mutable::EmptyStruct(a), Mutable::EmptyStruct(b)) => { if a.rtti.hash == b.rtti.hash { // NB: don't get any future ideas, this must fall through to @@ -1940,7 +1920,6 @@ inline_from! { } from! { - ControlFlow => ControlFlow, Function => Function, GeneratorState => GeneratorState, Vec => Vec, @@ -1959,6 +1938,7 @@ any_from! { String, Bytes, Format, + ControlFlow, } from_container! { @@ -2237,8 +2217,6 @@ pub(crate) enum Mutable { Tuple(OwnedTuple), /// An object. Object(Object), - /// A control flow indicator. - ControlFlow(ControlFlow), /// A stored future. Future(Future), /// A Stream. @@ -2269,7 +2247,6 @@ impl Mutable { Mutable::Vec(..) => TypeInfo::static_type(static_type::VEC), Mutable::Tuple(..) => TypeInfo::static_type(static_type::TUPLE), Mutable::Object(..) => TypeInfo::static_type(static_type::OBJECT), - Mutable::ControlFlow(..) => TypeInfo::static_type(static_type::CONTROL_FLOW), Mutable::Future(..) => TypeInfo::static_type(static_type::FUTURE), Mutable::Stream(..) => TypeInfo::static_type(static_type::STREAM), Mutable::Generator(..) => TypeInfo::static_type(static_type::GENERATOR), @@ -2293,7 +2270,6 @@ impl Mutable { Mutable::Vec(..) => static_type::VEC.hash, Mutable::Tuple(..) => static_type::TUPLE.hash, Mutable::Object(..) => static_type::OBJECT.hash, - Mutable::ControlFlow(..) => static_type::CONTROL_FLOW.hash, Mutable::Future(..) => static_type::FUTURE.hash, Mutable::Stream(..) => static_type::STREAM.hash, Mutable::Generator(..) => static_type::GENERATOR.hash, diff --git a/crates/rune/src/runtime/value/serde.rs b/crates/rune/src/runtime/value/serde.rs index e9bf8929c..b851dbf85 100644 --- a/crates/rune/src/runtime/value/serde.rs +++ b/crates/rune/src/runtime/value/serde.rs @@ -84,9 +84,6 @@ impl ser::Serialize for Value { Mutable::Function(..) => { Err(ser::Error::custom("cannot serialize function pointers")) } - Mutable::ControlFlow(..) => { - Err(ser::Error::custom("cannot serialize `start..end` ranges")) - } }, BorrowRefRepr::Any(value) => match value.type_hash() { String::HASH => {