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 ca2687e commit 8b6317d
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 117 deletions.
2 changes: 1 addition & 1 deletion crates/rune/src/compile/v1/assemble.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,7 @@ fn block_without_scope<'a, 'hir>(
Ok(Asm::new(hir, ()))
}

/// Assemble #[builtin] format_args!(...) macro.
/// Assemble #[builtin] format!(...) macro.
#[instrument_ast(span = format)]
fn builtin_format<'a, 'hir>(
cx: &mut Ctxt<'a, 'hir, '_>,
Expand Down
4 changes: 1 addition & 3 deletions crates/rune/src/exported_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ macro_rules! vm_write {
($($tt:tt)*) => {
match core::write!($($tt)*) {
Ok(()) => $crate::runtime::VmResult::Ok(()),
Err(err) => {
return $crate::runtime::VmResult::Err($crate::runtime::VmError::from(err));
}
Err(err) => $crate::runtime::VmResult::Err($crate::runtime::VmError::from(err)),
}
};
}
Expand Down
70 changes: 61 additions & 9 deletions crates/rune/src/modules/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ use core::fmt;

use crate as rune;
use crate::alloc::fmt::TryWrite;
use crate::alloc::prelude::*;
use crate::compile;
use crate::macros::{FormatArgs, MacroContext, TokenStream};
use crate::parse::Parser;
use crate::runtime::{Format, Formatter, VmResult};
use crate::runtime::{EnvProtocolCaller, Format, Formatter, VmResult};
use crate::{ContextError, Module};

/// Formatting text.
Expand All @@ -23,14 +24,20 @@ use crate::{ContextError, Module};
/// ```
#[rune::module(::std::fmt)]
pub fn module() -> Result<Module, ContextError> {
let mut module = Module::from_meta(self::module_meta)?.with_unique("std::fmt");

module.ty::<Format>()?;
module.ty::<Formatter>()?;
module.ty::<fmt::Error>()?;
module.function_meta(fmt_error_string_display)?;
module.macro_meta(format)?;
Ok(module)
let mut m = Module::from_meta(self::module_meta)?.with_unique("std::fmt");

m.ty::<Formatter>()?;
m.ty::<fmt::Error>()?;
m.function_meta(fmt_error_string_display)?;
m.macro_meta(format)?;

m.ty::<Format>()?;
m.function_meta(format_string_display__meta)?;
m.function_meta(format_string_debug__meta)?;
m.function_meta(format_clone__meta)?;
m.implement_trait::<Format>(rune::item!(::std::clone::Clone))?;

Ok(m)
}

#[rune::function(instance, protocol = STRING_DISPLAY)]
Expand Down Expand Up @@ -58,3 +65,48 @@ pub(crate) fn format(
let expanded = args.expand(cx)?;
Ok(expanded.into_token_stream(cx)?)
}

/// Write a display representation of a format specification.
///
/// # Examples
///
/// ```rune
/// let value = #[builtin] format!("Hello", fill = '0', width = 10);
/// assert_eq!(format!("{value}"), "Hello00000");
/// ```
#[rune::function(keep, instance, protocol = STRING_DISPLAY)]
fn format_string_display(format: &Format, f: &mut Formatter) -> VmResult<()> {
VmResult::Ok(vm_try!(format.spec.format(
&format.value,
f,
&mut EnvProtocolCaller
)))
}

/// Write a debug representation of a format specification.
///
/// # Examples
///
/// ```rune
/// let value = #[builtin] format!("Hello", fill = '0', width = 10);
/// let string = format!("{value:?}");
/// assert!(string is String);
/// ```
#[rune::function(keep, instance, protocol = STRING_DEBUG)]
fn format_string_debug(format: &Format, f: &mut Formatter) -> VmResult<()> {
VmResult::Ok(vm_try!(vm_write!(f, "{format:?}")))
}

/// Clones a format specification.
///
/// # Examples
///
/// ```rune
/// let value = #[builtin] format!("Hello", fill = '0', width = 10);
/// let vlaue2 = value.clone();
/// assert_eq!(format!("{value}"), "Hello00000");
/// ```
#[rune::function(keep, instance, protocol = CLONE)]
fn format_clone(this: &Format) -> VmResult<Format> {
VmResult::Ok(vm_try!(this.try_clone()))
}
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
137 changes: 105 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;
///
/// 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;
///
/// 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,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<Self> {
VmResult::Ok(vm_try!(self.try_clone()))
}
}

impl<B, C> ToValue for ops::ControlFlow<B, C>
where
Expand All @@ -114,11 +185,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))),
})
}
}
5 changes: 2 additions & 3 deletions crates/rune/src/runtime/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,15 @@ impl fmt::Display for AlignmentFromStrError {

/// A format specification, wrapping an inner value.
#[derive(Any, Debug, Clone, TryClone)]
#[rune(builtin, static_type = FORMAT)]
#[rune(static_type = FORMAT)]
pub struct Format {
/// The value being formatted.
pub(crate) value: Value,
/// The specification.
#[try_clone(copy)]
pub(crate) spec: FormatSpec,
}

from_value2!(Format, into_format_ref, into_format_mut, into_format);

/// A format specification.
#[derive(Debug, Clone, Copy, TryClone, Serialize, Deserialize, Decode, Encode)]
#[try_clone(copy)]
Expand Down
1 change: 1 addition & 0 deletions crates/rune/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ mod vec_tuple;
pub use self::vec_tuple::VecTuple;

mod vm;
use self::vm::CallResultOnly;
pub use self::vm::{CallFrame, Isolated, Vm};

mod vm_call;
Expand Down
Loading

0 comments on commit 8b6317d

Please sign in to comment.