diff --git a/crates/rune-modules/src/base64.rs b/crates/rune-modules/src/base64.rs index 3c3f939f4..d40688bc0 100644 --- a/crates/rune-modules/src/base64.rs +++ b/crates/rune-modules/src/base64.rs @@ -96,7 +96,6 @@ impl From for DecodeError { impl DecodeError { #[rune::function(instance, protocol = STRING_DISPLAY)] fn string_display(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{}", self.inner); - VmResult::Ok(()) + rune::vm_write!(f, "{}", self.inner) } } diff --git a/crates/rune-modules/src/http.rs b/crates/rune-modules/src/http.rs index aacf5d46f..7967d18a6 100644 --- a/crates/rune-modules/src/http.rs +++ b/crates/rune-modules/src/http.rs @@ -108,8 +108,7 @@ impl From for Error { impl Error { #[rune::function(instance, protocol = STRING_DISPLAY)] fn string_display(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{}", self.inner); - VmResult::Ok(()) + rune::vm_write!(f, "{}", self.inner) } } @@ -189,8 +188,7 @@ pub struct StatusCode { impl StatusCode { #[rune::function(instance, protocol = STRING_DISPLAY)] fn string_display(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{}", self.inner); - VmResult::Ok(()) + rune::vm_write!(f, "{}", self.inner) } } diff --git a/crates/rune-modules/src/json.rs b/crates/rune-modules/src/json.rs index 11967b429..846141036 100644 --- a/crates/rune-modules/src/json.rs +++ b/crates/rune-modules/src/json.rs @@ -30,7 +30,7 @@ //! ``` use rune::{ContextError, Module, vm_write, Any}; -use rune::runtime::{Bytes, Value, Formatter}; +use rune::runtime::{Bytes, Formatter, Value, VmResult}; use rune::alloc::{Vec, String}; use rune::alloc::fmt::TryWrite; @@ -64,14 +64,14 @@ struct Error { } impl Error { - #[rune::function(vm_result, protocol = STRING_DISPLAY)] - pub(crate) fn display(&self, f: &mut Formatter) { - vm_write!(f, "{}", self.error); + #[rune::function(protocol = STRING_DISPLAY)] + pub(crate) fn display(&self, f: &mut Formatter) -> VmResult<()> { + vm_write!(f, "{}", self.error) } - #[rune::function(vm_result, protocol = STRING_DEBUG)] - pub(crate) fn debug(&self, f: &mut Formatter) { - vm_write!(f, "{:?}", self.error); + #[rune::function(protocol = STRING_DEBUG)] + pub(crate) fn debug(&self, f: &mut Formatter) -> VmResult<()> { + vm_write!(f, "{:?}", self.error) } } diff --git a/crates/rune-modules/src/process.rs b/crates/rune-modules/src/process.rs index 0b4c5f722..a4d4d9945 100644 --- a/crates/rune-modules/src/process.rs +++ b/crates/rune-modules/src/process.rs @@ -148,8 +148,7 @@ struct ExitStatus { impl ExitStatus { #[rune::function(protocol = STRING_DISPLAY)] fn string_display(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{}", self.status); - VmResult::Ok(()) + rune::vm_write!(f, "{}", self.status) } #[rune::function] diff --git a/crates/rune-modules/src/toml.rs b/crates/rune-modules/src/toml.rs index 90cce86a0..dce6ad0f9 100644 --- a/crates/rune-modules/src/toml.rs +++ b/crates/rune-modules/src/toml.rs @@ -67,14 +67,12 @@ pub mod de { impl Error { #[rune::function(protocol = STRING_DISPLAY)] pub(crate) fn display(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{}", self.error); - VmResult::Ok(()) + vm_write!(f, "{}", self.error) } #[rune::function(protocol = STRING_DEBUG)] pub(crate) fn debug(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self.error); - VmResult::Ok(()) + vm_write!(f, "{:?}", self.error) } } @@ -89,7 +87,7 @@ pub mod ser { //! Serializer types for the toml module. use rune::{Any, Module, ContextError, vm_write}; - use rune::runtime::Formatter; + use rune::runtime::{Formatter, VmResult}; use rune::alloc::fmt::TryWrite; pub fn module(_stdio: bool) -> Result { @@ -107,14 +105,14 @@ pub mod ser { } impl Error { - #[rune::function(vm_result, protocol = STRING_DISPLAY)] - pub(crate) fn display(&self, f: &mut Formatter) { - vm_write!(f, "{}", self.error); + #[rune::function(protocol = STRING_DISPLAY)] + pub(crate) fn display(&self, f: &mut Formatter) -> VmResult<()> { + vm_write!(f, "{}", self.error) } - #[rune::function(vm_result, protocol = STRING_DEBUG)] - pub(crate) fn debug(&self, f: &mut Formatter) { - vm_write!(f, "{:?}", self.error); + #[rune::function(protocol = STRING_DEBUG)] + pub(crate) fn debug(&self, f: &mut Formatter) -> VmResult<()> { + vm_write!(f, "{:?}", self.error) } } diff --git a/crates/rune/src/any.rs b/crates/rune/src/any.rs index a742f6fd3..b0f359c58 100644 --- a/crates/rune/src/any.rs +++ b/crates/rune/src/any.rs @@ -1,5 +1,6 @@ use core::any; +use crate::alloc::String; use crate::compile::Named; use crate::runtime::{AnyTypeInfo, TypeHash}; @@ -124,3 +125,5 @@ cfg_std! { } crate::__internal_impl_any!(::std::error, anyhow::Error); + +impl Any for String {} diff --git a/crates/rune/src/compile/error.rs b/crates/rune/src/compile/error.rs index 802d7d963..3e8f3293b 100644 --- a/crates/rune/src/compile/error.rs +++ b/crates/rune/src/compile/error.rs @@ -20,7 +20,7 @@ use crate::macros::{SyntheticId, SyntheticKind}; use crate::parse::{Expectation, IntoExpectation, LexerMode}; use crate::runtime::debug::DebugSignature; use crate::runtime::unit::EncodeError; -use crate::runtime::{AccessError, RuntimeError, TypeInfo, TypeOf, VmError}; +use crate::runtime::{AccessError, AnyObjError, RuntimeError, TypeInfo, TypeOf, VmError}; #[cfg(feature = "std")] use crate::source; use crate::{Hash, Item, ItemBuf, SourceId}; @@ -1307,6 +1307,13 @@ impl From for ErrorKind { } } +impl From for ErrorKind { + #[inline] + fn from(error: AnyObjError) -> Self { + Self::from(RuntimeError::from(error)) + } +} + impl From for ErrorKind { #[inline] fn from(error: EncodeError) -> Self { diff --git a/crates/rune/src/compile/ir/eval.rs b/crates/rune/src/compile/ir/eval.rs index 6099c1a69..260f8fc5d 100644 --- a/crates/rune/src/compile/ir/eval.rs +++ b/crates/rune/src/compile/ir/eval.rs @@ -7,7 +7,8 @@ use crate::ast::{Span, Spanned}; use crate::compile::ir::{self}; use crate::compile::{self, WithSpan}; use crate::query::Used; -use crate::runtime::{Inline, Mutable, Object, OwnedTuple, Value, ValueBorrowRef}; +use crate::runtime::{Inline, Object, OwnedTuple, Value, ValueBorrowRef}; +use crate::TypeHash; /// The outcome of a constant evaluation. pub enum EvalOutcome { @@ -139,18 +140,22 @@ fn eval_ir_binary( return Ok(Value::from(out)); } - (ValueBorrowRef::Mutable(a), ValueBorrowRef::Mutable(b)) => { - let out = 'out: { - if let (Mutable::String(a), Mutable::String(b)) = (&*a, &*b) { + (ValueBorrowRef::Any(a), ValueBorrowRef::Any(b)) => { + let value = 'out: { + if let (String::HASH, String::HASH) = (a.type_hash(), b.type_hash()) { + let a = a.borrow_ref::().with_span(span)?; + let b = b.borrow_ref::().with_span(span)?; + if let ir::IrBinaryOp::Add = ir.op { - break 'out Mutable::String(add_strings(a, b).with_span(span)?); + let string = add_strings(&a, &b).with_span(span)?; + break 'out Value::new(string).with_span(span)?; } } return Err(EvalOutcome::not_const(span)); }; - return Ok(Value::try_from(out).with_span(span)?); + return Ok(value); } _ => (), } @@ -366,15 +371,16 @@ fn eval_ir_template( return Err(EvalOutcome::not_const(ir)); } }, - ValueBorrowRef::Mutable(value) => match &*value { - Mutable::String(s) => { - buf.try_push_str(s)?; + ValueBorrowRef::Any(value) => match value.type_hash() { + String::HASH => { + let s = value.borrow_ref::().with_span(ir)?; + buf.try_push_str(&s)?; } _ => { return Err(EvalOutcome::not_const(ir)); } }, - ValueBorrowRef::Any(..) => { + ValueBorrowRef::Mutable(..) => { return Err(EvalOutcome::not_const(ir)); } } diff --git a/crates/rune/src/exported_macros.rs b/crates/rune/src/exported_macros.rs index 61589781b..3abd5cc0c 100644 --- a/crates/rune/src/exported_macros.rs +++ b/crates/rune/src/exported_macros.rs @@ -53,7 +53,7 @@ macro_rules! vm_panic { macro_rules! vm_write { ($($tt:tt)*) => { match core::write!($($tt)*) { - Ok(()) => (), + Ok(()) => $crate::runtime::VmResult::Ok(()), Err(err) => { return $crate::runtime::VmResult::Err($crate::runtime::VmError::from(err)); } diff --git a/crates/rune/src/macros/format_args.rs b/crates/rune/src/macros/format_args.rs index cd9e3befd..f0de49298 100644 --- a/crates/rune/src/macros/format_args.rs +++ b/crates/rune/src/macros/format_args.rs @@ -7,8 +7,7 @@ use crate::ast::{self, Span, Spanned}; use crate::compile::{self, WithSpan}; use crate::macros::{quote, MacroContext, Quote, ToTokens, TokenStream}; use crate::parse::{Parse, Parser, Peek, Peeker}; -use crate::runtime::format; -use crate::runtime::{Inline, Mutable, OwnedValue}; +use crate::runtime::{format, Inline}; /// A format specification: A format string followed by arguments to be /// formatted in accordance with that string. @@ -49,14 +48,7 @@ impl FormatArgs { } } - let format = format.take_value().with_span(&self.format)?; - - let OwnedValue::Mutable(Mutable::String(format)) = format else { - return Err(compile::Error::msg( - &self.format, - "format argument must be a string", - )); - }; + let format = format.into_any::().with_span(&self.format)?; let mut unused_pos = (0..pos.len()).try_collect::>()?; let mut unused_named = named diff --git a/crates/rune/src/modules/any.rs b/crates/rune/src/modules/any.rs index 975277487..b61a97b29 100644 --- a/crates/rune/src/modules/any.rs +++ b/crates/rune/src/modules/any.rs @@ -52,8 +52,7 @@ fn type_of_val(value: Value) -> VmResult { /// ``` #[rune::function(instance, protocol = STRING_DISPLAY)] fn format_type(ty: Type, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", ty); - VmResult::Ok(()) + vm_write!(f, "{:?}", ty) } /// Get the type name of a value. diff --git a/crates/rune/src/modules/cmp.rs b/crates/rune/src/modules/cmp.rs index 0a8978334..2d374ab2b 100644 --- a/crates/rune/src/modules/cmp.rs +++ b/crates/rune/src/modules/cmp.rs @@ -297,6 +297,5 @@ fn ordering_eq(this: Ordering, other: Ordering) -> bool { /// ``` #[rune::function(instance, protocol = STRING_DEBUG)] fn ordering_string_debug(this: Ordering, s: &mut Formatter) -> VmResult<()> { - vm_write!(s, "{:?}", this); - VmResult::Ok(()) + vm_write!(s, "{:?}", this) } diff --git a/crates/rune/src/modules/collections/hash_map.rs b/crates/rune/src/modules/collections/hash_map.rs index 1c2461054..738982e83 100644 --- a/crates/rune/src/modules/collections/hash_map.rs +++ b/crates/rune/src/modules/collections/hash_map.rs @@ -516,21 +516,21 @@ impl HashMap { f: &mut Formatter, caller: &mut dyn ProtocolCaller, ) -> VmResult<()> { - vm_write!(f, "{{"); + vm_try!(vm_write!(f, "{{")); let mut it = self.table.iter().peekable(); while let Some((key, value)) = it.next() { vm_try!(key.string_debug_with(f, caller)); - vm_write!(f, ": "); + vm_try!(vm_write!(f, ": ")); vm_try!(value.string_debug_with(f, caller)); if it.peek().is_some() { - vm_write!(f, ", "); + vm_try!(vm_write!(f, ", ")); } } - vm_write!(f, "}}"); + vm_try!(vm_write!(f, "}}")); VmResult::Ok(()) } diff --git a/crates/rune/src/modules/collections/hash_set.rs b/crates/rune/src/modules/collections/hash_set.rs index 8c301a265..98ed82442 100644 --- a/crates/rune/src/modules/collections/hash_set.rs +++ b/crates/rune/src/modules/collections/hash_set.rs @@ -428,19 +428,19 @@ impl HashSet { } fn string_debug_with(&self, f: &mut Formatter, _: &mut dyn ProtocolCaller) -> VmResult<()> { - vm_write!(f, "{{"); + vm_try!(vm_write!(f, "{{")); let mut it = self.table.iter().peekable(); while let Some(value) = it.next() { - vm_write!(f, "{:?}", value); + vm_try!(vm_write!(f, "{:?}", value)); if it.peek().is_some() { - vm_write!(f, ", "); + vm_try!(vm_write!(f, ", ")); } } - vm_write!(f, "}}"); + vm_try!(vm_write!(f, "}}")); VmResult::Ok(()) } diff --git a/crates/rune/src/modules/collections/vec_deque.rs b/crates/rune/src/modules/collections/vec_deque.rs index 7ab8e5a4f..1191545d4 100644 --- a/crates/rune/src/modules/collections/vec_deque.rs +++ b/crates/rune/src/modules/collections/vec_deque.rs @@ -588,17 +588,17 @@ impl VecDeque { ) -> VmResult<()> { let mut it = self.inner.iter().peekable(); - vm_write!(f, "["); + vm_try!(vm_write!(f, "[")); while let Some(value) = it.next() { vm_try!(value.string_debug_with(f, caller)); if it.peek().is_some() { - vm_write!(f, ", "); + vm_try!(vm_write!(f, ", ")); } } - vm_write!(f, "]"); + vm_try!(vm_write!(f, "]")); VmResult::Ok(()) } diff --git a/crates/rune/src/modules/f64.rs b/crates/rune/src/modules/f64.rs index 2400bdcbb..194161e95 100644 --- a/crates/rune/src/modules/f64.rs +++ b/crates/rune/src/modules/f64.rs @@ -461,7 +461,7 @@ fn partial_cmp(this: f64, rhs: f64) -> Option { this.partial_cmp(&rhs) } -/// Perform a partial ordered comparison between two floats. +/// Perform a totally ordered comparison between two floats. /// /// # Examples /// diff --git a/crates/rune/src/modules/fmt.rs b/crates/rune/src/modules/fmt.rs index 9623774c9..13ad52897 100644 --- a/crates/rune/src/modules/fmt.rs +++ b/crates/rune/src/modules/fmt.rs @@ -35,8 +35,7 @@ pub fn module() -> Result { #[rune::function(instance, protocol = STRING_DISPLAY)] fn fmt_error_string_display(error: &fmt::Error, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{}", error); - VmResult::Ok(()) + vm_write!(f, "{error}") } /// Format a string using a format specifier. diff --git a/crates/rune/src/modules/i64.rs b/crates/rune/src/modules/i64.rs index 6f3a52e80..0c40f0a1e 100644 --- a/crates/rune/src/modules/i64.rs +++ b/crates/rune/src/modules/i64.rs @@ -606,7 +606,7 @@ fn partial_cmp(this: i64, rhs: i64) -> Option { this.partial_cmp(&rhs) } -/// Perform a partial ordered comparison between two integers. +/// Perform a totally ordered comparison between two integers. /// /// # Examples /// diff --git a/crates/rune/src/modules/io.rs b/crates/rune/src/modules/io.rs index 29904b4dc..36546ceea 100644 --- a/crates/rune/src/modules/io.rs +++ b/crates/rune/src/modules/io.rs @@ -40,6 +40,8 @@ pub fn module( module.ty::()?; #[cfg(feature = "std")] module.function_meta(io_error_string_display)?; + #[cfg(feature = "std")] + module.function_meta(io_error_string_debug)?; #[cfg(feature = "std")] if stdio { @@ -81,8 +83,13 @@ pub fn module( #[rune::function(instance, protocol = STRING_DISPLAY)] #[cfg(feature = "std")] fn io_error_string_display(error: &io::Error, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{error}"); - VmResult::Ok(()) + vm_write!(f, "{error}") +} + +#[rune::function(instance, protocol = STRING_DEBUG)] +#[cfg(feature = "std")] +fn io_error_string_debug(error: &io::Error, f: &mut Formatter) -> VmResult<()> { + vm_write!(f, "{error:?}") } #[cfg(feature = "std")] diff --git a/crates/rune/src/modules/iter.rs b/crates/rune/src/modules/iter.rs index 675e25621..f57f765f2 100644 --- a/crates/rune/src/modules/iter.rs +++ b/crates/rune/src/modules/iter.rs @@ -8,8 +8,8 @@ use crate::modules::collections::VecDeque; use crate::modules::collections::{HashMap, HashSet}; use crate::runtime::range::RangeIter; use crate::runtime::{ - FromValue, Function, Inline, InstAddress, Mutable, Object, Output, OwnedTuple, Protocol, - TypeHash, Value, ValueBorrowRef, Vec, VmErrorKind, VmResult, + FromValue, Function, Inline, InstAddress, Object, Output, OwnedTuple, Protocol, TypeHash, + Value, ValueBorrowRef, Vec, VmErrorKind, VmResult, }; use crate::shared::Caller; use crate::{Any, ContextError, Module, Params}; @@ -489,17 +489,21 @@ pub fn module() -> Result { ValueBorrowRef::Inline(Inline::Char(c)) => { vm_try!(string.try_push(*c)); } - ValueBorrowRef::Mutable(value) => match &*value { - Mutable::String(s) => { - vm_try!(string.try_push_str(s)); + ValueBorrowRef::Inline(value) => { + return VmResult::expected::(value.type_info()); + } + ValueBorrowRef::Mutable(value) => { + return VmResult::expected::(value.type_info()); + } + ValueBorrowRef::Any(value) => match value.type_hash() { + String::HASH => { + let s = vm_try!(value.borrow_ref::()); + vm_try!(string.try_push_str(&s)); } - actual => { - return VmResult::expected::(actual.type_info()); + _ => { + return VmResult::expected::(value.type_info()); } }, - actual => { - return VmResult::expected::(actual.type_info()); - } } } diff --git a/crates/rune/src/modules/mem.rs b/crates/rune/src/modules/mem.rs index 7684a7643..614de8366 100644 --- a/crates/rune/src/modules/mem.rs +++ b/crates/rune/src/modules/mem.rs @@ -86,14 +86,12 @@ impl Snapshot { #[rune::function(protocol = STRING_DISPLAY)] fn display(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{}", self.inner); - VmResult::Ok(()) + vm_write!(f, "{}", self.inner) } #[rune::function(protocol = STRING_DEBUG)] fn debug(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self.inner); - VmResult::Ok(()) + vm_write!(f, "{:?}", self.inner) } } diff --git a/crates/rune/src/modules/string.rs b/crates/rune/src/modules/string.rs index 446813a0a..80163413b 100644 --- a/crates/rune/src/modules/string.rs +++ b/crates/rune/src/modules/string.rs @@ -6,14 +6,15 @@ use core::num::{ParseFloatError, ParseIntError}; use core::str::Utf8Error; use crate as rune; +use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::alloc::string::FromUtf8Error; use crate::alloc::{String, Vec}; use crate::compile::Named; use crate::runtime::{ - Bytes, FromValue, Function, Inline, MaybeTypeOf, Mutable, Panic, Range, RangeFrom, RangeFull, - RangeInclusive, RangeTo, RangeToInclusive, Ref, ToValue, TypeOf, Value, ValueBorrowRef, - VmErrorKind, VmResult, + Bytes, Formatter, FromValue, Function, Hasher, Inline, MaybeTypeOf, Mutable, Panic, Range, + RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Ref, ToValue, TypeOf, Value, + ValueBorrowRef, VmErrorKind, VmResult, }; use crate::{Any, ContextError, Module, TypeHash}; @@ -39,7 +40,6 @@ pub fn module() -> Result { m.function_meta(string_from_str)?; m.function_meta(string_new)?; m.function_meta(string_with_capacity)?; - m.function_meta(cmp)?; m.function_meta(len)?; m.function_meta(starts_with)?; m.function_meta(ends_with)?; @@ -76,6 +76,23 @@ pub fn module() -> Result { m.function_meta(clone__meta)?; m.implement_trait::(rune::item!(::std::clone::Clone))?; + m.function_meta(partial_eq__meta)?; + m.implement_trait::(rune::item!(::std::cmp::PartialEq))?; + + m.function_meta(eq__meta)?; + m.implement_trait::(rune::item!(::std::cmp::Eq))?; + + m.function_meta(partial_cmp__meta)?; + m.implement_trait::(rune::item!(::std::cmp::PartialOrd))?; + + m.function_meta(cmp__meta)?; + m.implement_trait::(rune::item!(::std::cmp::Ord))?; + + m.function_meta(hash__meta)?; + + m.function_meta(string_display__meta)?; + m.function_meta(string_debug__meta)?; + m.ty::()?; m.function_meta(Chars::next__meta)?; m.function_meta(Chars::next_back__meta)?; @@ -164,7 +181,6 @@ fn from_utf8(bytes: &[u8]) -> VmResult> { /// /// ```rune /// let s = "hello"; -/// /// assert_eq!(b"hello", s.as_bytes()); /// assert!(is_readable(s)); /// ``` @@ -258,11 +274,6 @@ fn string_with_capacity(capacity: usize) -> VmResult { VmResult::Ok(vm_try!(String::try_with_capacity(capacity))) } -#[rune::function(instance)] -fn cmp(lhs: &str, rhs: &str) -> Ordering { - lhs.cmp(rhs) -} - /// Returns the length of `self`. /// /// This length is in bytes, not [`char`]s or graphemes. In other words, it @@ -548,7 +559,7 @@ fn reserve_exact(this: &mut String, additional: usize) -> VmResult<()> { /// ```rune /// let s = "hello"; /// assert_eq!(b"hello", s.into_bytes()); -/// assert!(is_readable(s)); +/// assert!(!is_readable(s)); /// ``` #[rune::function(instance)] fn into_bytes(s: String) -> Bytes { @@ -624,8 +635,129 @@ fn char_at(s: &str, index: usize) -> Option { /// assert_ne!(a, c); /// ``` #[rune::function(keep, instance, protocol = CLONE)] -fn clone(s: &String) -> VmResult { - VmResult::Ok(vm_try!(s.try_clone())) +fn clone(this: &String) -> VmResult { + VmResult::Ok(vm_try!(this.try_clone())) +} + +/// Test two strings for partial equality. +/// +/// # Examples +/// +/// ```rune +/// use std::ops::partial_eq; +/// +/// assert_eq!(partial_eq("a", "a"), true); +/// assert_eq!(partial_eq("a", "ab"), false); +/// assert_eq!(partial_eq("ab", "a"), false); +/// ``` +#[rune::function(keep, instance, protocol = PARTIAL_EQ)] +#[inline] +fn partial_eq(this: &str, rhs: &str) -> bool { + this.eq(rhs) +} + +/// Test two strings for total equality. +/// +/// # Examples +/// +/// ```rune +/// use std::ops::eq; +/// +/// assert_eq!(eq("a", "a"), true); +/// assert_eq!(eq("a", "ab"), false); +/// assert_eq!(eq("ab", "a"), false); +/// ``` +#[rune::function(keep, instance, protocol = EQ)] +#[inline] +fn eq(this: &str, rhs: &str) -> bool { + this.eq(rhs) +} + +/// Perform a partial ordered comparison between two strings. +/// +/// # Examples +/// +/// ```rune +/// assert!("a" < "ab"); +/// assert!("ab" > "a"); +/// assert!("a" == "a"); +/// ``` +/// +/// Using explicit functions: +/// +/// ```rune +/// use std::cmp::Ordering; +/// use std::ops::partial_cmp; +/// +/// assert_eq!(partial_cmp("a", "ab"), Some(Ordering::Less)); +/// assert_eq!(partial_cmp("ab", "a"), Some(Ordering::Greater)); +/// assert_eq!(partial_cmp("a", "a"), Some(Ordering::Equal)); +/// ``` +#[rune::function(keep, instance, protocol = PARTIAL_CMP)] +#[inline] +fn partial_cmp(this: &str, rhs: &str) -> Option { + this.partial_cmp(rhs) +} + +/// Perform a totally ordered comparison between two strings. +/// +/// # Examples +/// +/// ```rune +/// use std::cmp::Ordering; +/// use std::ops::cmp; +/// +/// assert_eq!(cmp("a", "ab"), Ordering::Less); +/// assert_eq!(cmp("ab", "a"), Ordering::Greater); +/// assert_eq!(cmp("a", "a"), Ordering::Equal); +/// ``` +#[rune::function(keep, instance, protocol = CMP)] +#[inline] +fn cmp(this: &str, rhs: &str) -> Ordering { + this.cmp(rhs) +} + +/// Hash the string. +/// +/// # Examples +/// +/// ```rune +/// use std::ops::hash; +/// +/// let a = "hello"; +/// let b = "hello"; +/// +/// assert_eq!(hash(a), hash(b)); +/// ``` +#[rune::function(keep, instance, protocol = HASH)] +fn hash(this: &str, hasher: &mut Hasher) { + hasher.write_str(this); +} + +/// Write a display representation of a string. +/// +/// # Examples +/// +/// ```rune +/// println!("{}", "Hello"); +/// ``` +#[rune::function(keep, instance, protocol = STRING_DISPLAY)] +#[inline] +fn string_display(this: &str, f: &mut Formatter) -> VmResult<()> { + rune::vm_write!(f, "{this}") +} + +/// Write a debug representation of a string. +/// +/// # Examples +/// +/// ```rune +/// println!("{:?}", "Hello"); +/// ``` +#[rune::function(keep, instance, protocol = STRING_DEBUG)] +#[inline] +fn string_debug(this: &str, f: &mut Formatter) -> VmResult<()> { + rune::vm_write!(f, "{this:?}") } /// Shrinks the capacity of this `String` to match its length. @@ -762,12 +894,6 @@ fn split(this: Ref, value: Value) -> VmResult { vm_try!(rune::to_value(Split::new(this, *c))) } ValueBorrowRef::Mutable(value) => match &*value { - Mutable::String(ref s) => { - vm_try!(rune::to_value(Split::new( - this, - vm_try!(Box::try_from(s.as_str())) - ))) - } Mutable::Function(ref f) => { vm_try!(rune::to_value(Split::new(this, vm_try!(f.try_clone())))) } @@ -778,11 +904,27 @@ fn split(this: Ref, value: Value) -> VmResult { ]) } }, - actual => { + ValueBorrowRef::Any(value) => match value.type_hash() { + String::HASH => { + let s = vm_try!(value.borrow_ref::()); + + vm_try!(rune::to_value(Split::new( + this, + vm_try!(Box::try_from(s.as_str())) + ))) + } + _ => { + return VmResult::err([ + VmErrorKind::expected::(value.type_info()), + VmErrorKind::bad_argument(0), + ]); + } + }, + value => { return VmResult::err([ - VmErrorKind::expected::(actual.type_info()), + VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), - ]) + ]); } }; @@ -805,7 +947,6 @@ fn split_once(this: &str, value: Value) -> VmResult> { let outcome = match vm_try!(value.borrow_ref()) { ValueBorrowRef::Inline(Inline::Char(pat)) => this.split_once(*pat), ValueBorrowRef::Mutable(value) => match &*value { - Mutable::String(s) => this.split_once(s.as_str()), Mutable::Function(f) => { let mut err = None; @@ -833,6 +974,18 @@ fn split_once(this: &str, value: Value) -> VmResult> { ]) } }, + ValueBorrowRef::Any(value) => match value.type_hash() { + String::HASH => { + let s = vm_try!(value.borrow_ref::()); + this.split_once(s.as_str()) + } + _ => { + return VmResult::err([ + VmErrorKind::expected::(value.type_info()), + VmErrorKind::bad_argument(0), + ]); + } + }, ref actual => { return VmResult::err([ VmErrorKind::expected::(actual.type_info()), diff --git a/crates/rune/src/runtime/access.rs b/crates/rune/src/runtime/access.rs index bf9f14645..f9293649a 100644 --- a/crates/rune/src/runtime/access.rs +++ b/crates/rune/src/runtime/access.rs @@ -12,11 +12,17 @@ const MOVED: usize = 1usize.rotate_right(1); /// Mask indicating if the value is exclusively set or moved. const MASK: usize = EXCLUSIVE | MOVED; -/// An error raised while downcasting. -#[derive(Debug, PartialEq)] -#[allow(missing_docs)] +/// An error raised when failing to access a value. +/// +/// Access errors can be raised for various reasons, such as: +/// * The value you are trying to access is an empty placeholder. +/// * The value is already being accessed in an incompatible way, such as trying +/// to access a value exclusively twice. +/// * The value has been taken and is no longer present. +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] #[non_exhaustive] -pub(crate) struct AccessError { +pub struct AccessError { kind: AccessErrorKind, } @@ -64,7 +70,8 @@ impl From for AccessError { } } -#[derive(Debug, PartialEq)] +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] pub(crate) enum AccessErrorKind { Empty, NotAccessibleRef(Snapshot), diff --git a/crates/rune/src/runtime/any_obj.rs b/crates/rune/src/runtime/any_obj.rs index 69825a7fa..7e70288a3 100644 --- a/crates/rune/src/runtime/any_obj.rs +++ b/crates/rune/src/runtime/any_obj.rs @@ -13,6 +13,13 @@ use super::{ RefVtable, Snapshot, TypeInfo, VmErrorKind, }; +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] +pub(super) enum AnyObjErrorKind { + Cast(AnyTypeInfo, TypeInfo), + AccessError(AccessError), +} + /// Errors caused when accessing or coercing an [`AnyObj`]. #[cfg_attr(test, derive(PartialEq))] pub struct AnyObjError { @@ -30,11 +37,17 @@ impl AnyObjError { } } -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq))] -pub(super) enum AnyObjErrorKind { - Cast(AnyTypeInfo, TypeInfo), - AccessError(AccessError), +impl core::error::Error for AnyObjError {} + +impl fmt::Display for AnyObjError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.kind { + AnyObjErrorKind::Cast(expected, actual) => { + write!(f, "Expected type `{expected}` but found `{actual}`") + } + AnyObjErrorKind::AccessError(error) => error.fmt(f), + } + } } impl fmt::Debug for AnyObjError { @@ -370,6 +383,31 @@ impl AnyObj { } } + /// Try to borrow a reference to the interior value while checking for + /// shared access. + /// + /// Returns `None` if the interior type is not `T`. + /// + /// This prevents other exclusive accesses from being performed while the + /// guard returned from this function is live. + pub fn try_borrow_ref(&self) -> Result>, AccessError> + where + T: Any, + { + let vtable = vtable(self); + + if (vtable.type_id)() != TypeId::of::() { + return Ok(None); + } + + // SAFETY: We've checked for the appropriate type just above. + unsafe { + let guard = self.shared.as_ref().access.shared()?; + let data = vtable.as_ptr(self.shared); + Ok(Some(BorrowRef::new(data, guard))) + } + } + /// Returns some mutable reference to the boxed value if it is of type `T`. pub fn borrow_mut(&self) -> Result, AnyObjError> where diff --git a/crates/rune/src/runtime/args.rs b/crates/rune/src/runtime/args.rs index 3b1e6e4c7..0b7f35028 100644 --- a/crates/rune/src/runtime/args.rs +++ b/crates/rune/src/runtime/args.rs @@ -3,7 +3,8 @@ use core::fmt; use crate::alloc::Vec; use crate::runtime::{GuardedArgs, Stack, ToValue, Value, VmResult}; -#[derive(Debug, PartialEq)] +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] pub(crate) struct DynArgsUsed; impl fmt::Display for DynArgsUsed { diff --git a/crates/rune/src/runtime/const_value.rs b/crates/rune/src/runtime/const_value.rs index cf72c8b66..b7931e6ca 100644 --- a/crates/rune/src/runtime/const_value.rs +++ b/crates/rune/src/runtime/const_value.rs @@ -6,6 +6,7 @@ use crate::runtime::{ self, Bytes, FromValue, Inline, Mutable, Object, OwnedTuple, ToValue, TypeInfo, Value, ValueBorrowRef, VmErrorKind, VmResult, }; +use crate::TypeHash; /// A constant value. #[derive(Debug, Deserialize, Serialize)] @@ -54,7 +55,6 @@ impl ConstValue { } }, ValueBorrowRef::Mutable(value) => match &*value { - Mutable::String(s) => Self::String(vm_try!(s.try_to_owned())), Mutable::Option(option) => Self::Option(match option { Some(some) => Some(vm_try!(Box::try_new(vm_try!(Self::from_value_ref(some))))), None => None, @@ -95,11 +95,17 @@ impl ConstValue { }) } }, - value => { - return VmResult::err(VmErrorKind::ConstNotSupported { - actual: value.type_info(), - }) - } + ValueBorrowRef::Any(value) => match value.type_hash() { + String::HASH => { + let s = vm_try!(value.borrow_ref::()); + Self::String(vm_try!(s.try_to_owned())) + } + _ => { + return VmResult::err(VmErrorKind::ConstNotSupported { + actual: value.type_info(), + }); + } + }, }) } diff --git a/crates/rune/src/runtime/control_flow.rs b/crates/rune/src/runtime/control_flow.rs index 81fc5a0f3..39af9a2e2 100644 --- a/crates/rune/src/runtime/control_flow.rs +++ b/crates/rune/src/runtime/control_flow.rs @@ -41,14 +41,14 @@ impl ControlFlow { ) -> VmResult<()> { match self { ControlFlow::Continue(value) => { - vm_write!(f, "Continue("); + vm_try!(vm_write!(f, "Continue(")); vm_try!(Value::string_debug_with(value, f, caller)); - vm_write!(f, ")"); + vm_try!(vm_write!(f, ")")); } ControlFlow::Break(value) => { - vm_write!(f, "Break("); + vm_try!(vm_write!(f, "Break(")); vm_try!(Value::string_debug_with(value, f, caller)); - vm_write!(f, ")"); + vm_try!(vm_write!(f, ")")); } } diff --git a/crates/rune/src/runtime/format.rs b/crates/rune/src/runtime/format.rs index 1b5c5b300..1a73a2341 100644 --- a/crates/rune/src/runtime/format.rs +++ b/crates/rune/src/runtime/format.rs @@ -13,10 +13,8 @@ use crate as rune; use crate::alloc::clone::TryClone; use crate::alloc::fmt::TryWrite; use crate::alloc::String; -use crate::runtime::{ - Formatter, Inline, Mutable, ProtocolCaller, Value, ValueRef, VmErrorKind, VmResult, -}; -use crate::Any; +use crate::runtime::{Formatter, Inline, ProtocolCaller, Value, ValueRef, VmErrorKind, VmResult}; +use crate::{Any, TypeHash}; /// Error raised when trying to parse a type string and it fails. #[derive(Debug, Clone, Copy)] @@ -132,7 +130,7 @@ impl FormatSpec { /// Format the given float. fn format_float(&self, buf: &mut String, n: f64) -> VmResult<()> { if let Some(precision) = self.precision { - vm_write!(buf, "{:.*}", precision.get(), n); + vm_try!(vm_write!(buf, "{:.*}", precision.get(), n)); } else { let mut buffer = ryu::Buffer::new(); vm_try!(buf.try_push_str(buffer.format(n))); @@ -231,18 +229,19 @@ impl FormatSpec { break 'fallback; } }, - ValueRef::Mutable(value) => match &*vm_try!(value.borrow_ref()) { - Mutable::String(s) => { - vm_try!(f.buf_mut().try_push_str(s)); + ValueRef::Mutable(..) => { + break 'fallback; + } + ValueRef::Any(value) => match value.type_hash() { + String::HASH => { + let s = vm_try!(value.borrow_ref::()); + vm_try!(f.buf_mut().try_push_str(&s)); vm_try!(self.format_fill(f, self.align, self.fill, None)); } _ => { break 'fallback; } }, - ValueRef::Any(..) => { - break 'fallback; - } } return VmResult::Ok(()); @@ -274,17 +273,18 @@ impl FormatSpec { break 'fallback; } }, - ValueRef::Mutable(value) => match &*vm_try!(value.borrow_ref()) { - Mutable::String(s) => { - vm_write!(f, "{s:?}"); + ValueRef::Mutable(..) => { + break 'fallback; + } + ValueRef::Any(value) => match value.type_hash() { + String::HASH => { + let s = vm_try!(value.borrow_ref::()); + vm_try!(vm_write!(f, "{s:?}")); } _ => { break 'fallback; } }, - ValueRef::Any(..) => { - break 'fallback; - } } return VmResult::Ok(()); @@ -297,7 +297,7 @@ impl FormatSpec { match vm_try!(value.as_inline()) { Some(Inline::Integer(n)) => { let (n, align, fill, sign) = self.int_traits(*n); - vm_write!(f.buf_mut(), "{:X}", n); + vm_try!(vm_write!(f.buf_mut(), "{:X}", n)); vm_try!(self.format_fill(f, align, fill, sign)); } _ => { @@ -312,7 +312,7 @@ impl FormatSpec { match vm_try!(value.as_inline()) { Some(Inline::Integer(n)) => { let (n, align, fill, sign) = self.int_traits(*n); - vm_write!(f.buf_mut(), "{:x}", n); + vm_try!(vm_write!(f.buf_mut(), "{:x}", n)); vm_try!(self.format_fill(f, align, fill, sign)); } _ => { @@ -327,7 +327,7 @@ impl FormatSpec { match vm_try!(value.as_inline()) { Some(Inline::Integer(n)) => { let (n, align, fill, sign) = self.int_traits(*n); - vm_write!(f.buf_mut(), "{:b}", n); + vm_try!(vm_write!(f.buf_mut(), "{:b}", n)); vm_try!(self.format_fill(f, align, fill, sign)); } _ => { @@ -342,7 +342,7 @@ impl FormatSpec { match vm_try!(value.as_inline()) { Some(Inline::Integer(n)) => { let (n, align, fill, sign) = self.int_traits(*n); - vm_write!(f.buf_mut(), "{:p}", n as *const ()); + vm_try!(vm_write!(f.buf_mut(), "{:p}", n as *const ())); vm_try!(self.format_fill(f, align, fill, sign)); } _ => { diff --git a/crates/rune/src/runtime/from_value.rs b/crates/rune/src/runtime/from_value.rs index 82ac6d8ef..b371beca9 100644 --- a/crates/rune/src/runtime/from_value.rs +++ b/crates/rune/src/runtime/from_value.rs @@ -1,7 +1,7 @@ use core::cmp::Ordering; -use crate::alloc; -use crate::runtime::{AnyObj, Mut, Mutable, RawAnyGuard, Ref, Value, ValueRepr, VmError, VmResult}; +use crate::alloc::{self, String}; +use crate::runtime::{AnyObj, Mut, RawAnyGuard, Ref, Value, VmError, VmResult}; use crate::Any; /// Cheap conversion trait to convert something infallibly into a dynamic [`Value`]. @@ -255,17 +255,9 @@ where from_value_ref!(Option, into_option_ref, into_option_mut, into_option); -impl FromValue for alloc::String { - fn from_value(value: Value) -> VmResult { - let string = vm_try!(value.borrow_string_ref()); - let string = string.as_ref(); - VmResult::Ok(vm_try!(alloc::String::try_from(string))) - } -} - impl FromValue for ::rust_alloc::string::String { fn from_value(value: Value) -> VmResult { - let string = vm_try!(alloc::String::from_value(value)); + let string = vm_try!(String::from_value(value)); let string = ::rust_alloc::string::String::from(string); VmResult::Ok(string) } @@ -288,75 +280,12 @@ impl FromValue for ::rust_alloc::boxed::Box { } } -impl FromValue for Mut { - fn from_value(value: Value) -> VmResult { - let value = match vm_try!(value.into_repr()) { - ValueRepr::Inline(value) => { - return VmResult::expected::(value.type_info()); - } - ValueRepr::Mutable(value) => vm_try!(value.into_mut()), - ValueRepr::Any(value) => { - return VmResult::expected::(value.type_info()); - } - }; - - let result = Mut::try_map(value, |kind| match kind { - Mutable::String(string) => Some(string), - _ => None, - }); - - match result { - Ok(string) => VmResult::Ok(string), - Err(actual) => VmResult::expected::(actual.type_info()), - } - } -} - -impl FromValue for Ref { - fn from_value(value: Value) -> VmResult { - let value = match vm_try!(value.into_repr()) { - ValueRepr::Inline(value) => { - return VmResult::expected::(value.type_info()); - } - ValueRepr::Mutable(value) => vm_try!(value.into_ref()), - ValueRepr::Any(value) => { - return VmResult::expected::(value.type_info()); - } - }; - - let result = Ref::try_map(value, |value| match value { - Mutable::String(string) => Some(string), - _ => None, - }); - - match result { - Ok(string) => VmResult::Ok(string), - Err(actual) => VmResult::expected::(actual.type_info()), - } - } -} - impl FromValue for Ref { fn from_value(value: Value) -> VmResult { - let value = match vm_try!(value.into_repr()) { - ValueRepr::Inline(value) => { - return VmResult::expected::(value.type_info()); - } - ValueRepr::Mutable(value) => vm_try!(value.into_ref()), - ValueRepr::Any(value) => { - return VmResult::expected::(value.type_info()); - } - }; - - let result = Ref::try_map(value, |kind| match kind { - Mutable::String(string) => Some(string.as_str()), - _ => None, - }); - - match result { - Ok(string) => VmResult::Ok(string), - Err(actual) => VmResult::expected::(actual.type_info()), - } + VmResult::Ok(Ref::map( + vm_try!(Ref::::from_value(value)), + String::as_str, + )) } } @@ -364,28 +293,9 @@ impl UnsafeToRef for str { type Guard = RawAnyGuard; unsafe fn unsafe_to_ref<'a>(value: Value) -> VmResult<(&'a Self, Self::Guard)> { - let value = match vm_try!(value.into_repr()) { - ValueRepr::Inline(value) => { - return VmResult::expected::(value.type_info()); - } - ValueRepr::Mutable(value) => vm_try!(value.into_ref()), - ValueRepr::Any(value) => { - return VmResult::expected::(value.type_info()); - } - }; - - let result = Ref::try_map(value, |value| match value { - Mutable::String(string) => Some(string.as_str()), - _ => None, - }); - - match result { - Ok(string) => { - let (string, guard) = Ref::into_raw(string); - VmResult::Ok((string.as_ref(), guard)) - } - Err(actual) => VmResult::expected::(actual.type_info()), - } + let string = vm_try!(value.into_any_ref::()); + let (string, guard) = Ref::into_raw(string); + VmResult::Ok((string.as_ref().as_str(), guard)) } } @@ -393,86 +303,29 @@ impl UnsafeToMut for str { type Guard = RawAnyGuard; unsafe fn unsafe_to_mut<'a>(value: Value) -> VmResult<(&'a mut Self, Self::Guard)> { - let value = match vm_try!(value.into_repr()) { - ValueRepr::Inline(value) => { - return VmResult::expected::(value.type_info()); - } - ValueRepr::Mutable(value) => vm_try!(value.into_mut()), - ValueRepr::Any(value) => { - return VmResult::expected::(value.type_info()); - } - }; - - let result = Mut::try_map(value, |kind| match kind { - Mutable::String(string) => Some(string.as_mut_str()), - _ => None, - }); - - match result { - Ok(string) => { - let (mut string, guard) = Mut::into_raw(string); - VmResult::Ok((string.as_mut(), guard)) - } - Err(actual) => VmResult::expected::(actual.type_info()), - } + let string = vm_try!(value.into_any_mut::()); + let (mut string, guard) = Mut::into_raw(string); + VmResult::Ok((string.as_mut().as_mut_str(), guard)) } } -impl UnsafeToRef for alloc::String { +impl UnsafeToRef for String { type Guard = RawAnyGuard; unsafe fn unsafe_to_ref<'a>(value: Value) -> VmResult<(&'a Self, Self::Guard)> { - let value = match vm_try!(value.into_repr()) { - ValueRepr::Inline(value) => { - return VmResult::expected::(value.type_info()); - } - ValueRepr::Mutable(value) => vm_try!(value.into_ref()), - ValueRepr::Any(value) => { - return VmResult::expected::(value.type_info()); - } - }; - - let result = Ref::try_map(value, |value| match value { - Mutable::String(string) => Some(string), - _ => None, - }); - - match result { - Ok(string) => { - let (string, guard) = Ref::into_raw(string); - VmResult::Ok((string.as_ref(), guard)) - } - Err(actual) => VmResult::expected::(actual.type_info()), - } + let string = vm_try!(value.into_any_ref::()); + let (string, guard) = Ref::into_raw(string); + VmResult::Ok((string.as_ref(), guard)) } } -impl UnsafeToMut for alloc::String { +impl UnsafeToMut for String { type Guard = RawAnyGuard; unsafe fn unsafe_to_mut<'a>(value: Value) -> VmResult<(&'a mut Self, Self::Guard)> { - let value = match vm_try!(value.into_repr()) { - ValueRepr::Inline(value) => { - return VmResult::expected::(value.type_info()); - } - ValueRepr::Mutable(value) => vm_try!(value.into_mut()), - ValueRepr::Any(value) => { - return VmResult::expected::(value.type_info()); - } - }; - - let result = Mut::try_map(value, |value| match value { - Mutable::String(string) => Some(string), - _ => None, - }); - - match result { - Ok(string) => { - let (mut string, guard) = Mut::into_raw(string); - VmResult::Ok((string.as_mut(), guard)) - } - Err(actual) => VmResult::expected::(actual.type_info()), - } + let string = vm_try!(value.into_any_mut::()); + let (mut string, guard) = Mut::into_raw(string); + VmResult::Ok((string.as_mut(), guard)) } } @@ -580,7 +433,7 @@ cfg_std! { }; } - impl_map!(::std::collections::HashMap, alloc::String); + impl_map!(::std::collections::HashMap, String); impl_map!(::std::collections::HashMap<::rust_alloc::string::String, T>, ::rust_alloc::string::String); } @@ -607,7 +460,7 @@ macro_rules! impl_try_map { }; } -impl_try_map!(alloc::HashMap, alloc::String); +impl_try_map!(alloc::HashMap, String); #[cfg(feature = "alloc")] impl_try_map!(alloc::HashMap<::rust_alloc::string::String, T>, ::rust_alloc::string::String); diff --git a/crates/rune/src/runtime/mod.rs b/crates/rune/src/runtime/mod.rs index 2058565dd..d28956a9f 100644 --- a/crates/rune/src/runtime/mod.rs +++ b/crates/rune/src/runtime/mod.rs @@ -10,9 +10,8 @@ mod steps_between; use self::steps_between::StepsBetween; mod access; -pub(crate) use self::access::{ - Access, AccessError, AccessErrorKind, AccessGuard, RawAccessGuard, Snapshot, -}; +pub use self::access::AccessError; +pub(crate) use self::access::{Access, AccessErrorKind, AccessGuard, RawAccessGuard, Snapshot}; mod borrow_mut; pub use self::borrow_mut::BorrowMut; @@ -165,12 +164,14 @@ pub(crate) use self::unit::UnitFn; pub use self::unit::{Unit, UnitStorage}; mod value; +#[cfg(any(test, feature = "cli"))] +pub(crate) use self::value::OwnedValue; pub use self::value::{ EmptyStruct, RawValueGuard, Rtti, Struct, TupleStruct, TypeValue, Value, ValueMutGuard, ValueRefGuard, VariantRtti, }; pub(crate) use self::value::{ - Inline, Mutable, OwnedValue, ValueBorrowRef, ValueMut, ValueRef, ValueRepr, ValueShared, + Inline, Mutable, ValueBorrowRef, ValueMut, ValueRef, ValueRepr, ValueShared, }; mod variant; diff --git a/crates/rune/src/runtime/panic.rs b/crates/rune/src/runtime/panic.rs index 5a707bb70..2c6a37c91 100644 --- a/crates/rune/src/runtime/panic.rs +++ b/crates/rune/src/runtime/panic.rs @@ -42,6 +42,7 @@ impl From for Panic { } } +#[cfg(test)] impl PartialEq for Panic { #[inline] fn eq(&self, _: &Self) -> bool { diff --git a/crates/rune/src/runtime/stack.rs b/crates/rune/src/runtime/stack.rs index 2f93f94c3..f07ce9b80 100644 --- a/crates/rune/src/runtime/stack.rs +++ b/crates/rune/src/runtime/stack.rs @@ -9,7 +9,8 @@ use crate::alloc::{self, Vec}; use crate::runtime::{InstAddress, Output, Value, VmErrorKind}; /// An error raised when accessing an address on the stack. -#[derive(Debug, PartialEq)] +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] #[non_exhaustive] pub struct StackError { addr: InstAddress, @@ -25,7 +26,8 @@ impl fmt::Display for StackError { impl core::error::Error for StackError {} /// An error raised when accessing a slice on the stack. -#[derive(Debug, PartialEq)] +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] #[non_exhaustive] pub struct SliceError { addr: InstAddress, diff --git a/crates/rune/src/runtime/tuple.rs b/crates/rune/src/runtime/tuple.rs index 50fca3f64..1d83b8390 100644 --- a/crates/rune/src/runtime/tuple.rs +++ b/crates/rune/src/runtime/tuple.rs @@ -6,8 +6,8 @@ use crate as rune; use crate::alloc::clone::TryClone; use crate::alloc::{self, Box}; use crate::runtime::{ - ConstValue, FromValue, Mut, Mutable, OwnedValue, RawAnyGuard, Ref, ToValue, UnsafeToMut, - UnsafeToRef, Value, ValueShared, VmErrorKind, VmResult, + ConstValue, FromValue, Mut, Mutable, RawAnyGuard, Ref, ToValue, UnsafeToMut, UnsafeToRef, + Value, ValueRepr, ValueShared, VmErrorKind, VmResult, }; #[cfg(feature = "alloc")] use crate::runtime::{Hasher, ProtocolCaller}; @@ -280,16 +280,16 @@ impl TryFrom<::rust_alloc::boxed::Box<[ConstValue]>> for OwnedTuple { impl FromValue for OwnedTuple { fn from_value(value: Value) -> VmResult { - match vm_try!(value.take_value()) { - OwnedValue::Inline(value) => match value { + match vm_try!(value.into_repr()) { + ValueRepr::Inline(value) => match value { Inline::Unit => VmResult::Ok(Self::new()), actual => VmResult::expected::(actual.type_info()), }, - OwnedValue::Mutable(value) => match value { + ValueRepr::Mutable(value) => match vm_try!(value.take()) { Mutable::Tuple(tuple) => VmResult::Ok(tuple), actual => VmResult::expected::(actual.type_info()), }, - OwnedValue::Any(value) => VmResult::expected::(value.type_info()), + ValueRepr::Any(value) => VmResult::expected::(value.type_info()), } } } diff --git a/crates/rune/src/runtime/type_info.rs b/crates/rune/src/runtime/type_info.rs index e533215a8..c071cf91e 100644 --- a/crates/rune/src/runtime/type_info.rs +++ b/crates/rune/src/runtime/type_info.rs @@ -101,7 +101,7 @@ impl fmt::Display for TypeInfo { write!(f, "{}", rtti.item)?; } TypeInfoKind::Any(info) => { - write!(f, "{}", info.name)?; + write!(f, "{info}")?; } } @@ -125,3 +125,10 @@ impl AnyTypeInfo { Self { name, hash } } } + +impl fmt::Display for AnyTypeInfo { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.name.fmt(f) + } +} diff --git a/crates/rune/src/runtime/unit/storage.rs b/crates/rune/src/runtime/unit/storage.rs index 01a8f34b8..62b16d5d5 100644 --- a/crates/rune/src/runtime/unit/storage.rs +++ b/crates/rune/src/runtime/unit/storage.rs @@ -205,7 +205,8 @@ enum EncodeErrorKind { /// Error indicating that a bad instruction was located at the given instruction /// pointer. -#[derive(Debug, PartialEq)] +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] pub struct BadInstruction { pub(crate) ip: usize, } @@ -221,7 +222,8 @@ impl core::error::Error for BadInstruction {} /// Error indicating that a bad instruction was located at the given instruction /// pointer. -#[derive(Debug, PartialEq)] +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] pub struct BadJump { pub(crate) jump: usize, } diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index 4b341f5a8..e6962f4e0 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -366,7 +366,7 @@ impl Value { vm_try!(f.push_str(buffer.format(*float))); } Inline::Bool(bool) => { - vm_write!(f, "{bool}"); + vm_try!(vm_write!(f, "{bool}")); } Inline::Byte(byte) => { let mut buffer = itoa::Buffer::new(); @@ -380,14 +380,11 @@ impl Value { Mutable::Format(format) => { vm_try!(format.spec.format(&format.value, f, caller)); } - Mutable::String(string) => { - vm_try!(f.push_str(string)); - } _ => { break 'fallback; } }, - ValueBorrowRef::Any(..) => { + _ => { break 'fallback; } } @@ -428,7 +425,6 @@ impl Value { }); } ValueBorrowRef::Mutable(value) => match &*value { - Mutable::String(value) => Mutable::String(vm_try!(value.try_clone())), Mutable::Bytes(value) => Mutable::Bytes(vm_try!(value.try_clone())), Mutable::Vec(value) => Mutable::Vec(vm_try!(value.try_clone())), Mutable::Tuple(value) => Mutable::Tuple(vm_try!(value.try_clone())), @@ -491,11 +487,11 @@ impl Value { 'fallback: { let value = match self.repr { Repr::Empty => { - vm_write!(f, ""); + vm_try!(vm_write!(f, "")); return VmResult::Ok(()); } Repr::Inline(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); return VmResult::Ok(()); } Repr::Mutable(ref value) => value, @@ -503,59 +499,56 @@ impl Value { }; match &*vm_try!(value.borrow_ref()) { - Mutable::String(value) => { - vm_write!(f, "{value:?}"); - } Mutable::Bytes(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::Vec(value) => { vm_try!(Vec::string_debug_with(value, f, caller)); } Mutable::Tuple(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::Object(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::ControlFlow(value) => { vm_try!(ControlFlow::string_debug_with(value, f, caller)); } Mutable::Future(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::Stream(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::Generator(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::GeneratorState(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::Option(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::Result(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::EmptyStruct(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::TupleStruct(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::Struct(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::Variant(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::Function(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Mutable::Format(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } }; @@ -572,18 +565,18 @@ impl Value { } CallResultOnly::Unsupported(value) => match &value.repr { Repr::Empty => { - vm_write!(f, ""); + vm_try!(vm_write!(f, "")); } Repr::Inline(value) => { - vm_write!(f, "{value:?}"); + vm_try!(vm_write!(f, "{value:?}")); } Repr::Mutable(value) => { let ty = vm_try!(value.borrow_ref()).type_info(); - vm_write!(f, "<{ty} object at {value:p}>"); + vm_try!(vm_write!(f, "<{ty} object at {value:p}>")); } Repr::Any(value) => { let ty = value.type_info(); - vm_write!(f, "<{ty} object at {value:p}>"); + vm_try!(vm_write!(f, "<{ty} object at {value:p}>")); } }, } @@ -725,31 +718,17 @@ impl Value { self.borrow_string_ref() } - /// Borrow the value of a string as a reference. + /// Borrow the interior value as a string reference. pub fn borrow_string_ref(&self) -> Result, RuntimeError> { - let value = match self.borrow_ref()? { - ValueBorrowRef::Mutable(value) => value, - actual => { - return Err(RuntimeError::expected::(actual.type_info())); - } - }; - - let result = BorrowRef::try_map(value, |kind| match kind { - Mutable::String(string) => Some(string.as_str()), - _ => None, - }); - - match result { - Ok(s) => Ok(s), - Err(actual) => Err(RuntimeError::expected::(actual.type_info())), - } + let string = self.borrow_any_ref::()?; + Ok(BorrowRef::map(string, String::as_str)) } /// Take the current value as a string. #[inline] pub fn into_string(self) -> Result { match self.take_value()? { - OwnedValue::Mutable(Mutable::String(string)) => Ok(string), + OwnedValue::Any(value) => Ok(value.downcast()?), actual => Err(RuntimeError::expected::(actual.type_info())), } } @@ -978,9 +957,12 @@ impl Value { /// This consumes the underlying value. #[inline] pub fn into_any_obj(self) -> Result { - match self.take_value()? { - OwnedValue::Any(value) => Ok(value), - ref actual => Err(RuntimeError::expected_any_obj(actual.type_info())), + match self.into_repr()? { + ValueRepr::Inline(value) => Err(RuntimeError::expected_any_obj(value.type_info())), + ValueRepr::Mutable(value) => Err(RuntimeError::expected_any_obj( + value.borrow_ref()?.type_info(), + )), + ValueRepr::Any(value) => Ok(value), } } @@ -1016,12 +998,13 @@ impl Value { where T: Any, { - match self.into_repr()? { - ValueRepr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), - ValueRepr::Mutable(value) => Err(RuntimeError::expected_any::( + match self.repr { + Repr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), + Repr::Mutable(value) => Err(RuntimeError::expected_any::( value.borrow_ref()?.type_info(), )), - ValueRepr::Any(value) => Ok(value.into_ref()?), + Repr::Any(value) => Ok(value.into_ref()?), + Repr::Empty => Err(RuntimeError::from(AccessError::empty())), } } @@ -1055,12 +1038,13 @@ impl Value { where T: Any, { - match self.into_repr()? { - ValueRepr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), - ValueRepr::Mutable(value) => Err(RuntimeError::expected_any::( + match self.repr { + Repr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), + Repr::Mutable(value) => Err(RuntimeError::expected_any::( value.borrow_ref()?.type_info(), )), - ValueRepr::Any(value) => Ok(value.into_mut()?), + Repr::Any(value) => Ok(value.into_mut()?), + Repr::Empty => Err(RuntimeError::from(AccessError::empty())), } } @@ -1124,9 +1108,16 @@ impl Value { where T: Any, { - let value = match self.take_value()? { - OwnedValue::Any(any) => any, - actual => return Err(RuntimeError::expected_any::(actual.type_info())), + let value = match self.into_repr()? { + ValueRepr::Inline(value) => { + return Err(RuntimeError::expected_any::(value.type_info())) + } + ValueRepr::Mutable(value) => { + return Err(RuntimeError::expected_any::( + value.borrow_ref()?.type_info(), + )) + } + ValueRepr::Any(any) => any, }; Ok(value.downcast::()?) @@ -1237,9 +1228,6 @@ impl Value { break 'fallback; } - (Mutable::String(a), Mutable::String(b)) => { - return VmResult::Ok(*a == *b); - } (Mutable::Option(a), Mutable::Option(b)) => match (a, b) { (Some(a), Some(b)) => return Value::partial_eq_with(a, b, caller), (None, None) => return VmResult::Ok(true), @@ -1325,10 +1313,6 @@ impl Value { } }, ValueBorrowRef::Mutable(value) => match &*value { - Mutable::String(string) => { - hasher.write_str(string); - return VmResult::Ok(()); - } Mutable::Bytes(bytes) => { hasher.write(bytes); return VmResult::Ok(()); @@ -1341,7 +1325,7 @@ impl Value { } _ => {} }, - ValueBorrowRef::Any(..) => {} + _ => {} } let mut args = DynGuardedArgs::new((hasher,)); @@ -1429,9 +1413,6 @@ impl Value { return Variant::eq_with(a, b, caller); } } - (Mutable::String(a), Mutable::String(b)) => { - return VmResult::Ok(*a == *b); - } (Mutable::Option(a), Mutable::Option(b)) => match (a, b) { (Some(a), Some(b)) => return Value::eq_with(a, b, caller), (None, None) => return VmResult::Ok(true), @@ -1532,9 +1513,6 @@ impl Value { return Variant::partial_cmp_with(a, b, caller); } } - (Mutable::String(a), Mutable::String(b)) => { - return VmResult::Ok(a.partial_cmp(b)); - } (Mutable::Option(a), Mutable::Option(b)) => match (a, b) { (Some(a), Some(b)) => return Value::partial_cmp_with(a, b, caller), (None, None) => return VmResult::Ok(Some(Ordering::Equal)), @@ -1630,9 +1608,6 @@ impl Value { return Variant::cmp_with(a, b, caller); } } - (Mutable::String(a), Mutable::String(b)) => { - return VmResult::Ok(a.cmp(b)); - } (Mutable::Option(a), Mutable::Option(b)) => match (a, b) { (Some(a), Some(b)) => return Value::cmp_with(a, b, caller), (None, None) => return VmResult::Ok(Ordering::Equal), @@ -1681,7 +1656,7 @@ impl Value { /// /// let value = rune::to_value(u32::MAX)?; /// - /// assert_eq!(value.try_as_integer::(), Ok(u32::MAX as u64)); + /// assert_eq!(value.try_as_integer::()?, u32::MAX as u64); /// assert!(value.try_as_integer::().is_err()); /// /// # Ok::<(), rune::support::Error>(()) @@ -1771,6 +1746,18 @@ impl Value { } } + pub(crate) fn try_borrow_ref(&self) -> Result>, AccessError> + where + T: Any, + { + match &self.repr { + Repr::Inline(..) => Ok(None), + Repr::Mutable(..) => Ok(None), + Repr::Any(value) => value.try_borrow_ref(), + Repr::Empty => Err(AccessError::empty()), + } + } + pub(crate) fn value_ref(&self) -> Result, AccessError> { match &self.repr { Repr::Inline(value) => Ok(ValueRef::Inline(value)), @@ -1975,7 +1962,6 @@ inline_from! { } from! { - String => String, Bytes => Bytes, ControlFlow => ControlFlow, Function => Function, @@ -1993,6 +1979,10 @@ from! { Stream => Stream, } +any_from! { + String, +} + from_container! { Option => Option, Result => Result, @@ -2263,8 +2253,6 @@ impl Inline { } pub(crate) enum Mutable { - /// A UTF-8 string. - String(String), /// A byte string. Bytes(Bytes), /// A vector containing any values. @@ -2304,7 +2292,6 @@ pub(crate) enum Mutable { impl Mutable { pub(crate) fn type_info(&self) -> TypeInfo { match self { - Mutable::String(..) => TypeInfo::static_type(static_type::STRING), Mutable::Bytes(..) => TypeInfo::static_type(static_type::BYTES), Mutable::Vec(..) => TypeInfo::static_type(static_type::VEC), Mutable::Tuple(..) => TypeInfo::static_type(static_type::TUPLE), @@ -2331,7 +2318,6 @@ impl Mutable { /// *enum*, and not the type hash of the variant itself. pub(crate) fn type_hash(&self) -> Hash { match self { - Mutable::String(..) => static_type::STRING.hash, Mutable::Bytes(..) => static_type::BYTES.hash, Mutable::Vec(..) => static_type::VEC.hash, Mutable::Tuple(..) => static_type::TUPLE.hash, diff --git a/crates/rune/src/runtime/value/macros.rs b/crates/rune/src/runtime/value/macros.rs index af8eaa60e..2fec5b964 100644 --- a/crates/rune/src/runtime/value/macros.rs +++ b/crates/rune/src/runtime/value/macros.rs @@ -277,6 +277,30 @@ macro_rules! from { }; } +macro_rules! any_from { + ($($ty:ty),* $(,)*) => { + $( + impl TryFrom<$ty> for Value { + type Error = alloc::Error; + + #[inline] + fn try_from(value: $ty) -> Result { + Value::new(value) + } + } + + impl IntoOutput for $ty { + type Output = $ty; + + #[inline] + fn into_output(self) -> VmResult { + VmResult::Ok(self) + } + } + )* + }; +} + macro_rules! inline_from { ($($variant:ident => $ty:ty),* $(,)*) => { $( diff --git a/crates/rune/src/runtime/value/serde.rs b/crates/rune/src/runtime/value/serde.rs index bc5892e45..ab32893ad 100644 --- a/crates/rune/src/runtime/value/serde.rs +++ b/crates/rune/src/runtime/value/serde.rs @@ -3,6 +3,7 @@ use core::fmt; use crate::alloc; use crate::alloc::prelude::*; use crate::runtime::{Bytes, Inline, Mutable, Object, ValueBorrowRef, Vec}; +use crate::TypeHash; use serde::de::{self, Deserialize as _, Error as _}; use serde::ser::{self, Error as _, SerializeMap as _, SerializeSeq as _}; @@ -37,7 +38,6 @@ impl ser::Serialize for Value { Inline::Ordering(..) => Err(ser::Error::custom("cannot serialize orderings")), }, ValueBorrowRef::Mutable(value) => match &*value { - Mutable::String(string) => serializer.serialize_str(string), Mutable::Bytes(bytes) => serializer.serialize_bytes(bytes), Mutable::Vec(vec) => { let mut serializer = serializer.serialize_seq(Some(vec.len()))?; @@ -92,9 +92,13 @@ impl ser::Serialize for Value { Err(ser::Error::custom("cannot serialize `start..end` ranges")) } }, - ValueBorrowRef::Any(..) => { - Err(ser::Error::custom("cannot serialize external references")) - } + ValueBorrowRef::Any(value) => match value.type_hash() { + String::HASH => { + let string = value.borrow_ref::().map_err(S::Error::custom)?; + serializer.serialize_str(string.as_str()) + } + _ => Err(ser::Error::custom("cannot serialize external references")), + }, } } } diff --git a/crates/rune/src/runtime/vec.rs b/crates/rune/src/runtime/vec.rs index ab26a963e..3bc18bfec 100644 --- a/crates/rune/src/runtime/vec.rs +++ b/crates/rune/src/runtime/vec.rs @@ -242,17 +242,17 @@ impl Vec { caller: &mut dyn ProtocolCaller, ) -> VmResult<()> { let mut it = this.iter().peekable(); - vm_write!(f, "["); + vm_try!(vm_write!(f, "[")); while let Some(value) = it.next() { vm_try!(value.string_debug_with(f, caller)); if it.peek().is_some() { - vm_write!(f, ", "); + vm_try!(vm_write!(f, ", ")); } } - vm_write!(f, "]"); + vm_try!(vm_write!(f, "]")); VmResult::Ok(()) } diff --git a/crates/rune/src/runtime/vm.rs b/crates/rune/src/runtime/vm.rs index 5ee4cab35..920a3eafe 100644 --- a/crates/rune/src/runtime/vm.rs +++ b/crates/rune/src/runtime/vm.rs @@ -2480,15 +2480,11 @@ impl Vm { let value = vm_try!(self.stack.at(value)); 'fallback: { - let ValueBorrowRef::Mutable(field) = vm_try!(index.borrow_ref()) else { + let Some(field) = vm_try!(index.try_borrow_ref::()) else { break 'fallback; }; - let Mutable::String(field) = &*field else { - break 'fallback; - }; - - if vm_try!(Self::try_object_slot_index_set(target, field, value)) { + if vm_try!(Self::try_object_slot_index_set(target, &field, value)) { return VmResult::Ok(()); } }; @@ -2634,24 +2630,21 @@ impl Vm { let index = vm_try!(self.stack.at(index)); let target = vm_try!(self.stack.at(target)); - match vm_try!(index.borrow_ref()) { - ValueBorrowRef::Inline(value) => { - if let Inline::Integer(index) = value { - let Ok(index) = usize::try_from(*index) else { - return err(VmErrorKind::MissingIndexInteger { - target: vm_try!(target.type_info()), - index: VmIntegerRepr::from(*index), - }); - }; + match vm_try!(index.value_ref()) { + ValueRef::Inline(Inline::Integer(index)) => { + let Ok(index) = usize::try_from(*index) else { + return err(VmErrorKind::MissingIndexInteger { + target: vm_try!(target.type_info()), + index: VmIntegerRepr::from(*index), + }); + }; - if let Some(value) = vm_try!(Self::try_tuple_like_index_get(target, index)) - { - break 'store value; - } + if let Some(value) = vm_try!(Self::try_tuple_like_index_get(target, index)) { + break 'store value; } } - ValueBorrowRef::Mutable(value) => { - if let Mutable::String(index) = &*value { + ValueRef::Any(value) => { + if let Some(index) = vm_try!(value.try_borrow_ref::()) { if let Some(value) = vm_try!(Self::try_object_like_index_get(target, index.as_str())) { @@ -2659,7 +2652,7 @@ impl Vm { } } } - ValueBorrowRef::Any(..) => (), + _ => {} } let target = target.clone(); @@ -2967,7 +2960,7 @@ impl Vm { vm_try!(value.string_display_with(&mut f, &mut *self)); } - vm_try!(out.store(&mut self.stack, Mutable::String(f.string))); + vm_try!(out.store(&mut self.stack, f.string)); VmResult::Ok(()) } @@ -3083,11 +3076,7 @@ impl Vm { let v = vm_try!(self.stack.at(addr)); let is_match = 'out: { - let ValueBorrowRef::Mutable(value) = vm_try!(v.borrow_ref()) else { - break 'out false; - }; - - let Mutable::String(actual) = &*value else { + let Some(actual) = vm_try!(v.try_borrow_ref::()) else { break 'out false; }; diff --git a/crates/rune/src/runtime/vm_error.rs b/crates/rune/src/runtime/vm_error.rs index 094b7e2ec..9ee481bfe 100644 --- a/crates/rune/src/runtime/vm_error.rs +++ b/crates/rune/src/runtime/vm_error.rs @@ -451,7 +451,7 @@ impl From for VmErrorKind { } /// An opaque simple runtime error. -#[derive(Debug, PartialEq)] +#[cfg_attr(test, derive(PartialEq))] pub struct RuntimeError { error: VmErrorKind, } @@ -493,6 +493,13 @@ impl RuntimeError { } } +impl fmt::Debug for RuntimeError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.error.fmt(f) + } +} + impl From for RuntimeError { fn from(value: AnyObjError) -> Self { match value.into_kind() { @@ -540,8 +547,8 @@ impl fmt::Display for RuntimeError { impl core::error::Error for RuntimeError {} /// The kind of error encountered. -#[derive(Debug, PartialEq)] -#[non_exhaustive] +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] #[doc(hidden)] pub(crate) enum VmErrorKind { AllocError { diff --git a/crates/rune/src/tests/string_debug.rs b/crates/rune/src/tests/string_debug.rs index 106868230..dceca1440 100644 --- a/crates/rune/src/tests/string_debug.rs +++ b/crates/rune/src/tests/string_debug.rs @@ -9,9 +9,7 @@ pub struct NativeStructWithProtocol; impl NativeStructWithProtocol { #[rune::function(protocol = STRING_DEBUG)] fn string_debug(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self); - - VmResult::Ok(()) + vm_write!(f, "{self:?}") } }