From 4bc845ad5d4747b41f947941a59c8be997514a30 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Mon, 28 Oct 2024 19:24:19 +0100 Subject: [PATCH] rune: Store Format in AnyObj instead of Mutable (relates #844) --- crates/rune/src/compile/v1/assemble.rs | 2 +- crates/rune/src/exported_macros.rs | 4 +- crates/rune/src/modules/fmt.rs | 70 ++++++++++++++++++++++---- crates/rune/src/runtime/format.rs | 5 +- crates/rune/src/runtime/mod.rs | 1 + crates/rune/src/runtime/value.rs | 48 ++++-------------- crates/rune/src/runtime/value/serde.rs | 3 -- crates/rune/src/runtime/vm.rs | 2 +- 8 files changed, 78 insertions(+), 57 deletions(-) diff --git a/crates/rune/src/compile/v1/assemble.rs b/crates/rune/src/compile/v1/assemble.rs index 0d351028a..79bb76491 100644 --- a/crates/rune/src/compile/v1/assemble.rs +++ b/crates/rune/src/compile/v1/assemble.rs @@ -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, '_>, diff --git a/crates/rune/src/exported_macros.rs b/crates/rune/src/exported_macros.rs index 3abd5cc0c..a57fa4fdc 100644 --- a/crates/rune/src/exported_macros.rs +++ b/crates/rune/src/exported_macros.rs @@ -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)), } }; } diff --git a/crates/rune/src/modules/fmt.rs b/crates/rune/src/modules/fmt.rs index 13ad52897..83b84f4bc 100644 --- a/crates/rune/src/modules/fmt.rs +++ b/crates/rune/src/modules/fmt.rs @@ -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. @@ -23,14 +24,20 @@ use crate::{ContextError, Module}; /// ``` #[rune::module(::std::fmt)] pub fn module() -> Result { - let mut module = Module::from_meta(self::module_meta)?.with_unique("std::fmt"); - - module.ty::()?; - module.ty::()?; - module.ty::()?; - 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::()?; + m.ty::()?; + m.function_meta(fmt_error_string_display)?; + m.macro_meta(format)?; + + m.ty::()?; + m.function_meta(format_string_display__meta)?; + m.function_meta(format_string_debug__meta)?; + m.function_meta(format_clone__meta)?; + m.implement_trait::(rune::item!(::std::clone::Clone))?; + + Ok(m) } #[rune::function(instance, protocol = STRING_DISPLAY)] @@ -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 { + VmResult::Ok(vm_try!(this.try_clone())) +} diff --git a/crates/rune/src/runtime/format.rs b/crates/rune/src/runtime/format.rs index fde6bbf0a..1ddf1d7cc 100644 --- a/crates/rune/src/runtime/format.rs +++ b/crates/rune/src/runtime/format.rs @@ -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)] diff --git a/crates/rune/src/runtime/mod.rs b/crates/rune/src/runtime/mod.rs index 28fd69fb4..cbc560481 100644 --- a/crates/rune/src/runtime/mod.rs +++ b/crates/rune/src/runtime/mod.rs @@ -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; diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index 0ed7828c5..6d59f265c 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -20,18 +20,18 @@ use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::alloc::{self, String}; use crate::compile::meta; -use crate::runtime::static_type; -use crate::runtime::vm::CallResultOnly; -use crate::runtime::{ - AccessError, AnyObj, AnyObjDrop, BorrowMut, BorrowRef, Bytes, ConstValue, ControlFlow, - DynGuardedArgs, EnvProtocolCaller, Format, Formatter, FromValue, Function, Future, Generator, - GeneratorState, IntoOutput, Iterator, MaybeTypeOf, Mut, Object, OwnedTuple, Protocol, - ProtocolCaller, RawAnyObjGuard, Ref, RuntimeError, Shared, Snapshot, Stream, ToValue, Type, - TypeInfo, Variant, Vec, Vm, VmErrorKind, VmIntegerRepr, VmResult, +use crate::{Any, Hash}; + +use super::static_type; +use super::{ + AccessError, AnyObj, AnyObjDrop, BorrowMut, BorrowRef, Bytes, CallResultOnly, ConstValue, + ControlFlow, DynGuardedArgs, EnvProtocolCaller, Format, Formatter, FromValue, Function, Future, + Generator, GeneratorState, IntoOutput, Iterator, MaybeTypeOf, Mut, Object, OwnedTuple, + Protocol, ProtocolCaller, RawAnyObjGuard, Ref, RuntimeError, Shared, Snapshot, Stream, ToValue, + Type, TypeInfo, Variant, Vec, Vm, VmErrorKind, VmIntegerRepr, VmResult, }; #[cfg(feature = "alloc")] -use crate::runtime::{Hasher, Tuple}; -use crate::{Any, Hash}; +use super::{Hasher, Tuple}; /// Defined guard for a reference value. /// @@ -370,14 +370,6 @@ impl Value { break 'fallback; } }, - BorrowRefRepr::Mutable(value) => match &*value { - Mutable::Format(format) => { - vm_try!(format.spec.format(&format.value, f, caller)); - } - _ => { - break 'fallback; - } - }, _ => { break 'fallback; } @@ -435,7 +427,6 @@ impl Value { Mutable::Struct(value) => Mutable::Struct(vm_try!(value.try_clone())), Mutable::Variant(value) => Mutable::Variant(vm_try!(value.try_clone())), Mutable::Function(value) => Mutable::Function(vm_try!(value.try_clone())), - Mutable::Format(value) => Mutable::Format(vm_try!(value.try_clone())), _ => { break 'fallback; } @@ -537,9 +528,6 @@ impl Value { Mutable::Function(value) => { vm_try!(vm_write!(f, "{value:?}")); } - Mutable::Format(value) => { - vm_try!(vm_write!(f, "{value:?}")); - } }; return VmResult::Ok(()); @@ -873,16 +861,6 @@ impl Value { into_generator, } - into! { - /// Coerce into a [`Format`]. - Format(Format), - into_format_ref, - into_format_mut, - borrow_format_ref, - borrow_format_mut, - into_format, - } - into! { /// Coerce into [`Tuple`]. Tuple(OwnedTuple), @@ -1973,7 +1951,6 @@ from! { Object => Object, Tuple => OwnedTuple, Generator => Generator, - Format => Format, Future => Future, Stream => Stream, } @@ -1981,6 +1958,7 @@ from! { any_from! { String, Bytes, + Format, } from_container! { @@ -2283,8 +2261,6 @@ pub(crate) enum Mutable { Variant(Variant), /// A stored function pointer. Function(Function), - /// A value being formatted. - Format(Format), } impl Mutable { @@ -2301,7 +2277,6 @@ impl Mutable { Mutable::Option(..) => TypeInfo::static_type(static_type::OPTION), Mutable::Result(..) => TypeInfo::static_type(static_type::RESULT), Mutable::Function(..) => TypeInfo::static_type(static_type::FUNCTION), - Mutable::Format(..) => TypeInfo::static_type(static_type::FORMAT), Mutable::EmptyStruct(empty) => empty.type_info(), Mutable::TupleStruct(tuple) => tuple.type_info(), Mutable::Struct(object) => object.type_info(), @@ -2326,7 +2301,6 @@ impl Mutable { Mutable::Result(..) => static_type::RESULT.hash, Mutable::Option(..) => static_type::OPTION.hash, Mutable::Function(..) => static_type::FUNCTION.hash, - Mutable::Format(..) => static_type::FORMAT.hash, Mutable::EmptyStruct(empty) => empty.rtti.hash, Mutable::TupleStruct(tuple) => tuple.rtti.hash, Mutable::Struct(object) => object.rtti.hash, diff --git a/crates/rune/src/runtime/value/serde.rs b/crates/rune/src/runtime/value/serde.rs index 89203eab8..e9bf8929c 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::Format(..) => { - Err(ser::Error::custom("cannot serialize format specifications")) - } Mutable::ControlFlow(..) => { Err(ser::Error::custom("cannot serialize `start..end` ranges")) } diff --git a/crates/rune/src/runtime/vm.rs b/crates/rune/src/runtime/vm.rs index 7293b6e0c..829291827 100644 --- a/crates/rune/src/runtime/vm.rs +++ b/crates/rune/src/runtime/vm.rs @@ -2966,7 +2966,7 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_format(&mut self, addr: InstAddress, spec: FormatSpec, out: Output) -> VmResult<()> { let value = vm_try!(self.stack.at(addr)).clone(); - vm_try!(out.store(&mut self.stack, Mutable::Format(Format { value, spec }))); + vm_try!(out.store(&mut self.stack, || Format { value, spec })); VmResult::Ok(()) }