@@ -7,7 +7,7 @@ use crate::error::{Error, Result};
77use crate :: state:: { Lua , RawLua } ;
88use crate :: traits:: FromLua ;
99use crate :: userdata:: AnyUserData ;
10- use crate :: util:: get_userdata;
10+ use crate :: util:: { check_stack , get_userdata, take_userdata } ;
1111use crate :: value:: Value ;
1212
1313use super :: cell:: { UserDataStorage , UserDataVariant } ;
@@ -440,6 +440,66 @@ impl<T> DerefMut for UserDataRefMutInner<T> {
440440 }
441441}
442442
443+ /// A wrapper type that takes ownership of a userdata value.
444+ ///
445+ /// It implements [`FromLua`] and can be used to receive a typed userdata from Lua by taking
446+ /// ownership of it.
447+ /// The original Lua userdata is marked as destructed and cannot be used further.
448+ pub struct UserDataOwned < T > ( pub T ) ;
449+
450+ impl < T > Deref for UserDataOwned < T > {
451+ type Target = T ;
452+
453+ #[ inline]
454+ fn deref ( & self ) -> & T {
455+ & self . 0
456+ }
457+ }
458+
459+ impl < T > DerefMut for UserDataOwned < T > {
460+ #[ inline]
461+ fn deref_mut ( & mut self ) -> & mut T {
462+ & mut self . 0
463+ }
464+ }
465+
466+ impl < T : fmt:: Debug > fmt:: Debug for UserDataOwned < T > {
467+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
468+ ( * * self ) . fmt ( f)
469+ }
470+ }
471+
472+ impl < T : fmt:: Display > fmt:: Display for UserDataOwned < T > {
473+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
474+ ( * * self ) . fmt ( f)
475+ }
476+ }
477+
478+ impl < T : ' static > FromLua for UserDataOwned < T > {
479+ fn from_lua ( value : Value , _: & Lua ) -> Result < Self > {
480+ try_value_to_userdata :: < T > ( value) ?. take ( ) . map ( UserDataOwned )
481+ }
482+
483+ unsafe fn from_stack ( idx : c_int , lua : & RawLua ) -> Result < Self > {
484+ let state = lua. state ( ) ;
485+ let type_id = lua. get_userdata_type_id :: < T > ( state, idx) ?;
486+ match type_id {
487+ Some ( type_id) if type_id == TypeId :: of :: < T > ( ) => {
488+ let ud = get_userdata :: < UserDataStorage < T > > ( state, idx) ;
489+ if ( * ud) . has_exclusive_access ( ) {
490+ check_stack ( state, 1 ) ?;
491+ take_userdata :: < UserDataStorage < T > > ( state, idx)
492+ . into_inner ( )
493+ . map ( UserDataOwned )
494+ } else {
495+ Err ( Error :: UserDataBorrowMutError )
496+ }
497+ }
498+ _ => Err ( Error :: UserDataTypeMismatch ) ,
499+ }
500+ }
501+ }
502+
443503#[ inline]
444504fn try_value_to_userdata < T > ( value : Value ) -> Result < AnyUserData > {
445505 match value {
@@ -464,6 +524,10 @@ mod assertions {
464524 static_assertions:: assert_impl_all!( UserDataRefMut <( ) >: Sync , Send ) ;
465525 #[ cfg( feature = "send" ) ]
466526 static_assertions:: assert_not_impl_all!( UserDataRefMut <std:: rc:: Rc <( ) >>: Send , Sync ) ;
527+ #[ cfg( feature = "send" ) ]
528+ static_assertions:: assert_impl_all!( UserDataOwned <( ) >: Send , Sync ) ;
529+ #[ cfg( feature = "send" ) ]
530+ static_assertions:: assert_not_impl_all!( UserDataOwned <std:: rc:: Rc <( ) >>: Send , Sync ) ;
467531
468532 #[ cfg( not( feature = "send" ) ) ]
469533 static_assertions:: assert_not_impl_all!( UserDataRef <( ) >: Send , Sync ) ;
0 commit comments