@@ -4,25 +4,36 @@ use std::cell::UnsafeCell;
4
4
use std:: marker:: PhantomData ;
5
5
use std:: string:: String as StdString ;
6
6
7
- use mlua:: { AnyUserData , Error , Lua , Result , UserDataRef } ;
7
+ use mlua:: { AnyUserData , Error , Lua , ObjectLike , Result , UserData , UserDataMethods , UserDataRef } ;
8
8
use static_assertions:: { assert_impl_all, assert_not_impl_all} ;
9
9
10
10
#[ test]
11
- fn test_userdata_multithread_access ( ) -> Result < ( ) > {
11
+ fn test_userdata_multithread_access_send_only ( ) -> Result < ( ) > {
12
12
let lua = Lua :: new ( ) ;
13
13
14
14
// This type is `Send` but not `Sync`.
15
- struct MyUserData ( #[ allow( unused) ] StdString , PhantomData < UnsafeCell < ( ) > > ) ;
16
-
15
+ struct MyUserData ( StdString , PhantomData < UnsafeCell < ( ) > > ) ;
17
16
assert_impl_all ! ( MyUserData : Send ) ;
18
17
assert_not_impl_all ! ( MyUserData : Sync ) ;
19
18
20
- lua. globals ( ) . set (
21
- "ud" ,
22
- AnyUserData :: wrap ( MyUserData ( "hello" . to_string ( ) , PhantomData ) ) ,
23
- ) ?;
19
+ impl UserData for MyUserData {
20
+ fn add_methods < M : UserDataMethods < Self > > ( methods : & mut M ) {
21
+ methods. add_method ( "method" , |lua, this, ( ) | {
22
+ let ud = lua. globals ( ) . get :: < AnyUserData > ( "ud" ) ?;
23
+ assert ! ( ( ud. call_method:: <( ) >( "method2" , ( ) ) . err( ) . unwrap( ) . to_string( ) )
24
+ . contains( "error borrowing userdata" ) ) ;
25
+ Ok ( this. 0 . clone ( ) )
26
+ } ) ;
27
+
28
+ methods. add_method ( "method2" , |_, _, ( ) | Ok ( ( ) ) ) ;
29
+ }
30
+ }
31
+
32
+ lua. globals ( )
33
+ . set ( "ud" , MyUserData ( "hello" . to_string ( ) , PhantomData ) ) ?;
34
+
24
35
// We acquired the exclusive reference.
25
- let _ud1 = lua. globals ( ) . get :: < UserDataRef < MyUserData > > ( "ud" ) ?;
36
+ let ud = lua. globals ( ) . get :: < UserDataRef < MyUserData > > ( "ud" ) ?;
26
37
27
38
std:: thread:: scope ( |s| {
28
39
s. spawn ( || {
@@ -31,5 +42,45 @@ fn test_userdata_multithread_access() -> Result<()> {
31
42
} ) ;
32
43
} ) ;
33
44
45
+ drop ( ud) ;
46
+ lua. load ( "ud:method()" ) . exec ( ) . unwrap ( ) ;
47
+
48
+ Ok ( ( ) )
49
+ }
50
+
51
+ #[ test]
52
+ fn test_userdata_multithread_access_sync ( ) -> Result < ( ) > {
53
+ let lua = Lua :: new ( ) ;
54
+
55
+ // This type is `Send` and `Sync`.
56
+ struct MyUserData ( StdString ) ;
57
+ assert_impl_all ! ( MyUserData : Send , Sync ) ;
58
+
59
+ impl UserData for MyUserData {
60
+ fn add_methods < M : UserDataMethods < Self > > ( methods : & mut M ) {
61
+ methods. add_method ( "method" , |lua, this, ( ) | {
62
+ let ud = lua. globals ( ) . get :: < AnyUserData > ( "ud" ) ?;
63
+ assert ! ( ud. call_method:: <( ) >( "method2" , ( ) ) . is_ok( ) ) ;
64
+ Ok ( this. 0 . clone ( ) )
65
+ } ) ;
66
+
67
+ methods. add_method ( "method2" , |_, _, ( ) | Ok ( ( ) ) ) ;
68
+ }
69
+ }
70
+
71
+ lua. globals ( ) . set ( "ud" , MyUserData ( "hello" . to_string ( ) ) ) ?;
72
+
73
+ // We acquired the shared reference.
74
+ let _ud = lua. globals ( ) . get :: < UserDataRef < MyUserData > > ( "ud" ) ?;
75
+
76
+ std:: thread:: scope ( |s| {
77
+ s. spawn ( || {
78
+ // Getting another shared reference for `Sync` type is allowed.
79
+ let _ = lua. globals ( ) . get :: < UserDataRef < MyUserData > > ( "ud" ) . unwrap ( ) ;
80
+ } ) ;
81
+ } ) ;
82
+
83
+ lua. load ( "ud:method()" ) . exec ( ) . unwrap ( ) ;
84
+
34
85
Ok ( ( ) )
35
86
}
0 commit comments