@@ -151,7 +151,7 @@ impl Value {
151151 /// This might invoke the `__tostring` metamethod for non-primitive types (eg. tables,
152152 /// functions).
153153 pub fn to_string ( & self ) -> Result < String > {
154- unsafe fn invoke_to_string ( vref : & ValueRef ) -> Result < String > {
154+ unsafe fn invoke_tostring ( vref : & ValueRef ) -> Result < String > {
155155 let lua = vref. lua . lock ( ) ;
156156 let state = lua. state ( ) ;
157157 let _guard = StackGuard :: new ( state) ;
@@ -178,9 +178,9 @@ impl Value {
178178 | Value :: Function ( Function ( vref) )
179179 | Value :: Thread ( Thread ( vref, ..) )
180180 | Value :: UserData ( AnyUserData ( vref) )
181- | Value :: Other ( vref) => unsafe { invoke_to_string ( vref) } ,
181+ | Value :: Other ( vref) => unsafe { invoke_tostring ( vref) } ,
182182 #[ cfg( feature = "luau" ) ]
183- Value :: Buffer ( crate :: Buffer ( vref) ) => unsafe { invoke_to_string ( vref) } ,
183+ Value :: Buffer ( crate :: Buffer ( vref) ) => unsafe { invoke_tostring ( vref) } ,
184184 Value :: Error ( err) => Ok ( err. to_string ( ) ) ,
185185 }
186186 }
@@ -545,6 +545,24 @@ impl Value {
545545 ident : usize ,
546546 visited : & mut HashSet < * const c_void > ,
547547 ) -> fmt:: Result {
548+ unsafe fn invoke_tostring_dbg ( vref : & ValueRef ) -> Result < Option < String > > {
549+ let lua = vref. lua . lock ( ) ;
550+ let state = lua. state ( ) ;
551+ let _guard = StackGuard :: new ( state) ;
552+ check_stack ( state, 3 ) ?;
553+
554+ lua. push_ref ( vref) ;
555+ protect_lua ! ( state, 1 , 1 , fn ( state) {
556+ // Try `__todebugstring` metamethod first, then `__tostring`
557+ if ffi:: luaL_callmeta( state, -1 , cstr!( "__todebugstring" ) ) == 0 {
558+ if ffi:: luaL_callmeta( state, -1 , cstr!( "__tostring" ) ) == 0 {
559+ ffi:: lua_pushnil( state) ;
560+ }
561+ }
562+ } ) ?;
563+ Ok ( lua. pop_value ( ) . as_string ( ) . map ( |s| s. to_string_lossy ( ) ) )
564+ }
565+
548566 match self {
549567 Value :: Nil => write ! ( fmt, "nil" ) ,
550568 Value :: Boolean ( b) => write ! ( fmt, "{b}" ) ,
@@ -561,15 +579,17 @@ impl Value {
561579 t @ Value :: Table ( _) => write ! ( fmt, "table: {:?}" , t. to_pointer( ) ) ,
562580 f @ Value :: Function ( _) => write ! ( fmt, "function: {:?}" , f. to_pointer( ) ) ,
563581 t @ Value :: Thread ( _) => write ! ( fmt, "thread: {:?}" , t. to_pointer( ) ) ,
564- u @ Value :: UserData ( ud) => {
565- // Try `__name/__type` first then `__tostring`
566- let name = ud. type_name ( ) . ok ( ) . flatten ( ) ;
567- let s = name
568- . map ( |name| format ! ( "{name}: {:?}" , u. to_pointer( ) ) )
569- . or_else ( || u. to_string ( ) . ok ( ) )
570- . unwrap_or_else ( || format ! ( "userdata: {:?}" , u. to_pointer( ) ) ) ;
571- write ! ( fmt, "{s}" )
572- }
582+ u @ Value :: UserData ( ud) => unsafe {
583+ // Try converting to a (debug) string first, with fallback to `__name/__type`
584+ match invoke_tostring_dbg ( & ud. 0 ) {
585+ Ok ( Some ( s) ) => write ! ( fmt, "{s}" ) ,
586+ _ => {
587+ let name = ud. type_name ( ) . ok ( ) . flatten ( ) ;
588+ let name = name. as_deref ( ) . unwrap_or ( "userdata" ) ;
589+ write ! ( fmt, "{name}: {:?}" , u. to_pointer( ) )
590+ }
591+ }
592+ } ,
573593 #[ cfg( feature = "luau" ) ]
574594 buf @ Value :: Buffer ( _) => write ! ( fmt, "buffer: {:?}" , buf. to_pointer( ) ) ,
575595 Value :: Error ( e) if recursive => write ! ( fmt, "{e:?}" ) ,
0 commit comments