Skip to content

Commit

Permalink
rune: Store ControlFlow in AnyObj instead of Mutable (relates #844)
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Oct 28, 2024
1 parent ee99a1b commit 51418c0
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 60 deletions.
11 changes: 11 additions & 0 deletions crates/rune/src/modules/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,17 @@ pub fn module() -> Result<Module, ContextError> {

{
m.ty::<ControlFlow>()?;

m.function_meta(ControlFlow::partial_eq__meta)?;
m.implement_trait::<ControlFlow>(rune::item!(::std::cmp::PartialEq))?;

m.function_meta(ControlFlow::eq__meta)?;
m.implement_trait::<ControlFlow>(rune::item!(::std::cmp::Eq))?;

m.function_meta(ControlFlow::string_debug__meta)?;

m.function_meta(ControlFlow::clone__meta)?;
m.implement_trait::<ControlFlow>(rune::item!(::std::clone::Clone))?;
}

m.ty::<Function>()?;
Expand Down
141 changes: 109 additions & 32 deletions crates/rune/src/runtime/control_flow.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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)]
Expand All @@ -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, ControlFlow};
///
/// 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<bool> {
Self::partial_eq_with(self, other, &mut EnvProtocolCaller)
}

pub(crate) fn partial_eq_with(
Expand All @@ -69,6 +74,31 @@ impl ControlFlow {
}
}

/// Test two control flows for total equality.
///
/// # Examples
///
/// ```rune
/// use std::ops::{eq, ControlFlow};
///
/// 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<bool> {
self.eq_with(other, &mut EnvProtocolCaller)
}

pub(crate) fn eq_with(
&self,
other: &ControlFlow,
Expand All @@ -80,14 +110,59 @@ 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
/// use std::ops::ControlFlow;
///
/// 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
/// use std::ops::ControlFlow;
///
/// 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<Self> {
VmResult::Ok(vm_try!(self.try_clone()))
}
}

impl<B, C> ToValue for ops::ControlFlow<B, C>
where
Expand All @@ -114,11 +189,13 @@ where
{
#[inline]
fn from_value(value: Value) -> VmResult<Self> {
VmResult::Ok(match vm_try!(value.into_control_flow()) {
VmResult::Ok(match &*vm_try!(value.borrow_ref::<ControlFlow>()) {
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))),
})
}
}
26 changes: 1 addition & 25 deletions crates/rune/src/runtime/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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:?}"));
}
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1940,7 +1920,6 @@ inline_from! {
}

from! {
ControlFlow => ControlFlow,
Function => Function,
GeneratorState => GeneratorState,
Vec => Vec,
Expand All @@ -1959,6 +1938,7 @@ any_from! {
String,
Bytes,
Format,
ControlFlow,
}

from_container! {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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),
Expand All @@ -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,
Expand Down
3 changes: 0 additions & 3 deletions crates/rune/src/runtime/value/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down

0 comments on commit 51418c0

Please sign in to comment.