diff --git a/crates/rune/src/runtime/shared.rs b/crates/rune/src/runtime/shared.rs index cc19f12ff..94a45eb77 100644 --- a/crates/rune/src/runtime/shared.rs +++ b/crates/rune/src/runtime/shared.rs @@ -205,6 +205,12 @@ impl Shared { } } +impl fmt::Pointer for Shared { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&self.inner.as_ptr(), fmt) + } +} + impl TryClone for Shared { #[inline] fn try_clone(&self) -> alloc::Result { diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index 97c526216..9c33862ea 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -851,11 +851,16 @@ impl Value { vm_write!(f, "{:?}", value); } _ => { + // reborrow f to avoid moving it let result = - vm_try!(caller.call_protocol_fn(Protocol::STRING_DEBUG, self.clone(), (f,))); + caller.call_protocol_fn(Protocol::STRING_DEBUG, self.clone(), (&mut *f,)); - vm_try!(<()>::from_value(result)); - return VmResult::Ok(()); + if let VmResult::Ok(result) = result { + vm_try!(<()>::from_value(result)); + } else { + let type_info = vm_try!(self.type_info()); + vm_write!(f, "<{} object at {:p}>", type_info, self.inner); + } } }; diff --git a/crates/rune/src/tests.rs b/crates/rune/src/tests.rs index 24d7db9d9..729d37661 100644 --- a/crates/rune/src/tests.rs +++ b/crates/rune/src/tests.rs @@ -6,6 +6,7 @@ pub(crate) mod prelude { pub(crate) use crate as rune; pub(crate) use crate::alloc; + pub(crate) use crate::alloc::fmt::TryWrite; pub(crate) use crate::alloc::prelude::*; pub(crate) use crate::ast; pub(crate) use crate::compile::{self, ErrorKind, Item, ItemBuf, Located, Named}; @@ -14,9 +15,9 @@ pub(crate) mod prelude { pub(crate) use crate::module::InstallWith; pub(crate) use crate::parse; pub(crate) use crate::runtime::{ - self, AnyTypeInfo, Bytes, FullTypeOf, Function, MaybeTypeOf, Mut, Object, OwnedTuple, - Protocol, RawRef, RawStr, Ref, Stack, Tuple, TypeInfo, TypeOf, UnsafeToRef, ValueKind, - VecTuple, VmErrorKind, VmResult, + self, AnyTypeInfo, Bytes, Formatter, FullTypeOf, Function, MaybeTypeOf, Mut, Object, + OwnedTuple, Protocol, RawRef, RawStr, Ref, Stack, Tuple, TypeInfo, TypeOf, UnsafeToRef, + ValueKind, VecTuple, VmErrorKind, VmResult, }; pub(crate) use crate::support::Result; pub(crate) use crate::tests::run; @@ -450,6 +451,7 @@ mod reference_error; mod rename_type; mod result; mod stmt_reordering; +mod string_debug; mod tuple; mod type_name_native; mod type_name_rune; diff --git a/crates/rune/src/tests/string_debug.rs b/crates/rune/src/tests/string_debug.rs new file mode 100644 index 000000000..106868230 --- /dev/null +++ b/crates/rune/src/tests/string_debug.rs @@ -0,0 +1,60 @@ +//! Tests for `std::any::type_name_of_val(v)` for native types + +prelude!(); + +#[derive(Any, Debug)] +#[rune(item = ::native_crate)] +pub struct NativeStructWithProtocol; + +impl NativeStructWithProtocol { + #[rune::function(protocol = STRING_DEBUG)] + fn string_debug(&self, f: &mut Formatter) -> VmResult<()> { + vm_write!(f, "{:?}", self); + + VmResult::Ok(()) + } +} + +#[derive(Any)] +#[rune(item = ::native_crate)] +pub struct NativeStructWithoutProtocol; + +fn make_native_module() -> Result { + let mut module = Module::with_crate("native_crate")?; + module.ty::()?; + module.function_meta(NativeStructWithProtocol::string_debug)?; + module.ty::()?; + + Ok(module) +} + +#[test] +fn test_with_string_debug() { + let t1 = NativeStructWithProtocol; + assert_eq!( + rune_n! { + make_native_module().expect("failed making native module"), + (t1, ), + String => + pub fn main(v) { format!("{:?}", v) } + }, + "NativeStructWithProtocol" + ); +} + +#[test] +fn test_without_string_debug() { + let t1 = NativeStructWithoutProtocol; + let result = rune_n! { + make_native_module().expect("failed making native module"), + (t1, ), + String => + pub fn main(v) { format!("{:?}", v) } + }; + + assert!( + result.starts_with("